Merge m-i to m-c.
authorKyle Huey <khuey@kylehuey.com>
Wed, 02 Nov 2011 08:24:41 -0400
changeset 79563 06292dba305205f823d4043be55f35988806fc1d
parent 79562 185e913a7061366831528d6160466385cb552c1c (current diff)
parent 79551 53ba7abbf1daf97cf43da3bf41c757a2b157c6f2 (diff)
child 79564 631b19db4eb5a58084fc3153a46a968fcbf80dd6
child 79620 921e1db5cf11f7877a9f85bb91aa99fce618e2bc
push id3053
push userkhuey@mozilla.com
push dateWed, 02 Nov 2011 12:53:44 +0000
treeherdermozilla-inbound@80af665378fd [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.
browser/themes/gnomestripe/browser/browser.css
toolkit/content/tests/browser/common/mockFilePicker.js
--- a/browser/base/content/test/browser_save_video.js
+++ b/browser/base/content/test/browser_save_video.js
@@ -1,17 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.reset();
+
 /**
  * TestCase for bug 564387
  * <https://bugzilla.mozilla.org/show_bug.cgi?id=564387>
  */
 function test() {
   waitForExplicitFinish();
+  var fileName;
 
   gBrowser.loadURI("http://mochi.test:8888/browser/browser/base/content/test/bug564387.html");
 
   registerCleanupFunction(function () {
     gBrowser.addTab();
     gBrowser.removeCurrentTab();
   });
 
@@ -30,60 +34,57 @@ function test() {
     });
   });
 
   function contextMenuOpened(event) {
     event.currentTarget.removeEventListener("popupshown", contextMenuOpened);
 
     // Create the folder the video will be saved into.
     var destDir = createTemporarySaveDirectory();
+    var destFile = destDir.clone();
 
-    mockFilePickerSettings.destDir = destDir;
-    mockFilePickerSettings.filterIndex = 1; // kSaveAsType_URL
-    mockFilePickerRegisterer.register();
+    MockFilePicker.displayDirectory = destDir;
+    MockFilePicker.showCallback = function(fp) {
+      fileName = fp.defaultString;
+      destFile.append (fileName);
+      MockFilePicker.returnFiles = [destFile];
+      MockFilePicker.filterIndex = 1; // kSaveAsType_URL
+    };
 
     mockTransferCallback = onTransferComplete;
     mockTransferRegisterer.register();
 
     registerCleanupFunction(function () {
       mockTransferRegisterer.unregister();
-      mockFilePickerRegisterer.unregister();
+      MockFilePicker.reset();
       destDir.remove(true);
     });
 
     // Select "Save Video As" option from context menu
     var saveVideoCommand = document.getElementById("context-savevideo");
     saveVideoCommand.doCommand();
 
     event.target.hidePopup();
   }
 
   function onTransferComplete(downloadSuccess) {
     ok(downloadSuccess, "Video file should have been downloaded successfully");
 
-    // Read the name of the saved file.
-    var fileName = mockFilePickerResults.selectedFile.leafName;
-
     is(fileName, "Bug564387-expectedName.ogv",
        "Video file name is correctly retrieved from Content-Disposition http header");
 
     finish();
   }
 }
 
 Cc["@mozilla.org/moz/jssubscript-loader;1"]
   .getService(Ci.mozIJSSubScriptLoader)
   .loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js",
                  this);
 
-Cc["@mozilla.org/moz/jssubscript-loader;1"]
-  .getService(Ci.mozIJSSubScriptLoader)
-  .loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockFilePicker.js",
-                 this);
-
 function createTemporarySaveDirectory() {
   var saveDir = Cc["@mozilla.org/file/directory_service;1"]
                   .getService(Ci.nsIProperties)
                   .get("TmpD", Ci.nsIFile);
   saveDir.append("testsavedir");
   if (!saveDir.exists())
     saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
   return saveDir;
--- a/browser/components/dirprovider/Makefile.in
+++ b/browser/components/dirprovider/Makefile.in
@@ -40,17 +40,19 @@ topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = browserdir
 LIBRARY_NAME = browserdir_s
 
+ifdef ENABLE_TESTS
 DIRS = tests
+endif
 
 FORCE_STATIC_LIB = 1
 FORCE_USE_PIC = 1
 
 # Because we are an application component, link against the CRT statically
 # (on Windows, but only if we're not building our own CRT for jemalloc)
 ifndef MOZ_MEMORY
 USE_STATIC_LIBS      = 1
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -3187,27 +3187,30 @@ SessionStoreService.prototype = {
     if (aEntry.postdata_b64) {
       var postdata = atob(aEntry.postdata_b64);
       var stream = Cc["@mozilla.org/io/string-input-stream;1"].
                    createInstance(Ci.nsIStringInputStream);
       stream.setData(postdata, postdata.length);
       shEntry.postData = stream;
     }
 
+    let childDocIdents = {};
     if (aEntry.docIdentifier) {
       // If we have a serialized document identifier, try to find an SHEntry
       // which matches that doc identifier and adopt that SHEntry's
       // BFCacheEntry.  If we don't find a match, insert shEntry as the match
       // for the document identifier.
       let matchingEntry = aDocIdentMap[aEntry.docIdentifier];
       if (!matchingEntry) {
-        aDocIdentMap[aEntry.docIdentifier] = shEntry;
+        matchingEntry = {shEntry: shEntry, childDocIdents: childDocIdents};
+        aDocIdentMap[aEntry.docIdentifier] = matchingEntry;
       }
       else {
-        shEntry.adoptBFCacheEntry(matchingEntry);
+        shEntry.adoptBFCacheEntry(matchingEntry.shEntry);
+        childDocIdents = matchingEntry.childDocIdents;
       }
     }
 
     if (aEntry.owner_b64) {
       var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
                        createInstance(Ci.nsIStringInputStream);
       var binaryData = atob(aEntry.owner_b64);
       ownerInput.setData(binaryData, binaryData.length);
@@ -3219,18 +3222,34 @@ SessionStoreService.prototype = {
       } catch (ex) { debug(ex); }
     }
 
     if (aEntry.children && shEntry instanceof Ci.nsISHContainer) {
       for (var i = 0; i < aEntry.children.length; i++) {
         //XXXzpao Wallpaper patch for bug 514751
         if (!aEntry.children[i].url)
           continue;
+
+        // We're getting sessionrestore.js files with a cycle in the
+        // doc-identifier graph, likely due to bug 698656.  (That is, we have
+        // an entry where doc identifier A is an ancestor of doc identifier B,
+        // and another entry where doc identifier B is an ancestor of A.)
+        //
+        // If we were to respect these doc identifiers, we'd create a cycle in
+        // the SHEntries themselves, which causes the docshell to loop forever
+        // when it looks for the root SHEntry.
+        //
+        // So as a hack to fix this, we restrict the scope of a doc identifier
+        // to be a node's siblings and cousins, and pass childDocIdents, not
+        // aDocIdents, to _deserializeHistoryEntry.  That is, we say that two
+        // SHEntries with the same doc identifier have the same document iff
+        // they have the same parent or their parents have the same document.
+
         shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap,
-                                                       aDocIdentMap), i);
+                                                       childDocIdents), i);
       }
     }
     
     return shEntry;
   },
 
   /**
    * restores all sessionStorage "super cookies"
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -149,16 +149,18 @@ include $(topsrcdir)/config/rules.mk
 	browser_628270.js \
 	browser_635418.js \
 	browser_636279.js \
 	browser_645428.js \
 	browser_659591.js \
 	browser_662812.js \
 	browser_665702-state_session.js \
 	browser_682507.js \
+	browser_687710.js \
+	browser_687710_2.js \
 	browser_694378.js \
 	$(NULL)
 
 ifneq ($(OS_ARCH),Darwin)
 _BROWSER_TEST_FILES += \
 	browser_597071.js \
 	browser_625016.js \
 	$(NULL)
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_687710.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that sessionrestore handles cycles in the shentry graph properly.
+//
+// These cycles shouldn't be there in the first place, but they cause hangs
+// when they mysteriously appear (bug 687710).  Docshell code assumes this
+// graph is a tree and tires to walk to the root.  But if there's a cycle,
+// there is no root, and we loop forever.
+
+let stateBackup = ss.getBrowserState();
+
+let state = {windows:[{tabs:[{entries:[
+  {
+    docIdentifier: 1,
+    url: "http://example.com",
+    children: [
+      {
+        docIdentifier: 2,
+        url: "http://example.com"
+      }
+    ]
+  },
+  {
+    docIdentifier: 2,
+    url: "http://example.com",
+    children: [
+      {
+        docIdentifier: 1,
+        url: "http://example.com"
+      }
+    ]
+  }
+]}]}]}
+
+function test() {
+  registerCleanupFunction(function () {
+    ss.setBrowserState(stateBackup);
+  });
+
+  /* This test fails by hanging. */
+  ss.setBrowserState(JSON.stringify(state));
+  ok(true, "Didn't hang!");
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_687710_2.js
@@ -0,0 +1,64 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the fix for bug 687710 isn't too aggressive -- shentries which are
+// cousins should be able to share bfcache entries.
+
+let stateBackup = ss.getBrowserState();
+
+let state = {entries:[
+  {
+    docIdentifier: 1,
+    url: "http://example.com?1",
+    children: [{ docIdentifier: 10,
+                 url: "http://example.com?10" }]
+  },
+  {
+    docIdentifier: 1,
+    url: "http://example.com?1#a",
+    children: [{ docIdentifier: 10,
+                 url: "http://example.com?10#aa" }]
+  }
+]};
+
+function test()
+{
+  registerCleanupFunction(function () {
+    ss.setBrowserState(stateBackup);
+  });
+
+  let tab = gBrowser.addTab("about:blank");
+  ss.setTabState(tab, JSON.stringify(state));
+  let history = tab.linkedBrowser.webNavigation.sessionHistory;
+
+  is(history.count, 2, "history.count");
+  for (let i = 0; i < history.count; i++) {
+    for (let j = 0; j < history.count; j++) {
+      compareEntries(i, j, history);
+    }
+  }
+}
+
+function compareEntries(i, j, history)
+{
+  let e1 = history.getEntryAtIndex(i, false)
+                  .QueryInterface(Ci.nsISHEntry)
+                  .QueryInterface(Ci.nsISHContainer);
+
+  let e2 = history.getEntryAtIndex(j, false)
+                  .QueryInterface(Ci.nsISHEntry)
+                  .QueryInterface(Ci.nsISHContainer);
+
+  ok(e1.sharesDocumentWith(e2),
+     i + ' should share doc with ' + j);
+  is(e1.childCount, e2.childCount,
+     'Child count mismatch (' + i + ', ' + j + ')');
+
+  for (let c = 0; c < e1.childCount; c++) {
+    let c1 = e1.GetChildAt(c);
+    let c2 = e2.GetChildAt(c);
+
+    ok(c1.sharesDocumentWith(c2),
+       'Cousins should share documents. (' + i + ', ' + j + ', ' + c + ')');
+  }
+}
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -52,16 +52,18 @@
 
 %include ../../browserShared.inc
 %filter substitution
 %define toolbarHighlight rgba(255,255,255,.3)
 %define selectedTabHighlight rgba(255,255,255,.8) 1px, rgba(255,255,255,.5) 3px
 %define forwardTransitionLength 150ms
 %define conditionalForwardWithUrlbar       window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"][mode=icons],                #nav-bar:not([currentset])[mode=icons])                 > #unified-back-forward-button
 %define conditionalForwardWithUrlbar_small window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"][mode=icons][iconsize=small],#nav-bar:not([currentset])[mode=icons][iconsize=small]) > #unified-back-forward-button
+%define conditionalForwardWithUrlbarWidth 32
+%define conditionalForwardWithUrlbarWidth_small 24
 
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
 #main-menubar {
   -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
 }
@@ -625,28 +627,16 @@ toolbar[mode="full"] .toolbarbutton-1 > 
   -moz-transition: @forwardTransitionLength@ ease-out;
 }
 
 @conditionalForwardWithUrlbar@ > #forward-button[disabled] {
   -moz-transform: scale(0);
   opacity: 0;
   pointer-events: none;
 }
-@conditionalForwardWithUrlbar@ > #forward-button[disabled]:-moz-locale-dir(ltr) {
-  margin-left: -36px;
-}
-@conditionalForwardWithUrlbar@ > #forward-button[disabled]:-moz-locale-dir(rtl) {
-  margin-right: -36px;
-}
-@conditionalForwardWithUrlbar_small@ > #forward-button[disabled]:-moz-locale-dir(ltr) {
-  margin-left: -28px;
-}
-@conditionalForwardWithUrlbar_small@ > #forward-button[disabled]:-moz-locale-dir(rtl) {
-  margin-right: -28px;
-}
 
 #reload-button {
   list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar");
 }
 #reload-button[disabled="true"] {
   list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar&state=disabled");
 }
 
@@ -960,16 +950,50 @@ toolbar[iconsize="small"] #feed-button {
   -moz-appearance: toolbarbutton-dropdown;
 }
 
 #urlbar-container {
   -moz-box-orient: horizontal;
   -moz-box-align: stretch;
 }
 
+@conditionalForwardWithUrlbar@ + #urlbar-container {
+  -moz-padding-start: @conditionalForwardWithUrlbarWidth@px;
+  -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
+  position: relative;
+  pointer-events: none;
+}
+
+@conditionalForwardWithUrlbar_small@ + #urlbar-container {
+  -moz-padding-start: @conditionalForwardWithUrlbarWidth_small@px;
+  -moz-margin-start: -@conditionalForwardWithUrlbarWidth_small@px;
+}
+
+@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
+  pointer-events: all;
+}
+
+@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
+  -moz-transition: margin-left @forwardTransitionLength@ ease-out,
+                   margin-right @forwardTransitionLength@ ease-out;
+}
+
+@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
+  margin-left: -@conditionalForwardWithUrlbarWidth@px;
+}
+@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
+  margin-right: -@conditionalForwardWithUrlbarWidth@px;
+}
+@conditionalForwardWithUrlbar_small@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
+  margin-left: -@conditionalForwardWithUrlbarWidth_small@px;
+}
+@conditionalForwardWithUrlbar_small@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
+  margin-right: -@conditionalForwardWithUrlbarWidth_small@px;
+}
+
 #urlbar-icons {
   -moz-box-align: center;
 }
 
 .urlbar-icon {
   cursor: pointer;
   padding: 0 3px;
 }
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -738,23 +738,23 @@ user_pref("camino.use_system_proxy_setti
 
     def killPid(self, pid):
       os.kill(pid, signal.SIGKILL)
 
     def dumpScreen(self, utilityPath):
       self.haveDumpedScreen = True;
 
       # Need to figure out what tool and whether it write to a file or stdout
-      if UNIXISH:
+      if self.UNIXISH:
         utility = [os.path.join(utilityPath, "screentopng")]
         imgoutput = 'stdout'
-      elif IS_MAC:
+      elif self.IS_MAC:
         utility = ['/usr/sbin/screencapture', '-C', '-x', '-t', 'png']
         imgoutput = 'file'
-      elif IS_WIN32:
+      elif self.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:
         if imgoutput == 'file':
           tmpfd, imgfilename = tempfile.mkstemp(prefix='mozilla-test-fail_')
           os.close(tmpfd)
--- a/content/base/public/nsIImageLoadingContent.idl
+++ b/content/base/public/nsIImageLoadingContent.idl
@@ -37,16 +37,17 @@
 
 #include "imgIDecoderObserver.idl"
 
 interface imgIRequest;
 interface nsIChannel;
 interface nsIStreamListener;
 interface nsIURI;
 interface nsIDocument;
+interface nsIFrame;
 
 /**
  * This interface represents a content node that loads images.  The interface
  * exists to allow getting information on the images that the content node
  * loads and to allow registration of observers for the image loads.
  *
  * Implementors of this interface should handle all the mechanics of actually
  * loading an image -- getting the URI, checking with content policies and
@@ -60,17 +61,17 @@ interface nsIDocument;
  * observers to check which request they are getting notifications for.
  *
  * Observers added in mid-load will not get any notifications they
  * missed.  We should NOT freeze this interface without considering
  * this issue.  (It could be that the image status on imgIRequest is
  * sufficient, when combined with the imageBlockingStatus information.)
  */
 
-[scriptable, uuid(95c74255-df9a-4060-b5a0-0d111fcafe08)]
+[scriptable, uuid(f7debb84-2854-4731-a57b-1bd752ad71f8)]
 interface nsIImageLoadingContent : imgIDecoderObserver
 {
   /**
    * Request types.  Image loading content nodes attempt to do atomic
    * image changes when the image url is changed.  This means that
    * when the url changes the new image load will start, but the old
    * image will remain the "current" request until the new image is
    * fully loaded.  At that point, the old "current" request will be
@@ -124,16 +125,28 @@ interface nsIImageLoadingContent : imgID
    * is thrown)
    *
    * @throws NS_ERROR_UNEXPECTED if the request type requested is not
    * known
    */
   imgIRequest getRequest(in long aRequestType);
 
   /**
+   * Used to notify the image loading content node that a frame has been
+   * created.
+   */
+  [notxpcom] void frameCreated(in nsIFrame aFrame);
+
+  /**
+   * Used to notify the image loading content node that a frame has been
+   * destroyed.
+   */
+  [notxpcom] void frameDestroyed(in nsIFrame aFrame);
+
+  /**
    * Used to find out what type of request one is dealing with (eg
    * which request got passed through to the imgIDecoderObserver
    * interface of an observer)
    *
    * @param aRequest the request whose type we want to know
    *
    * @return an enum value saying what type this request is
    *
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -3220,16 +3220,17 @@ nsIDocument::TakeAnimationFrameListeners
 
 void
 nsDocument::DeleteShell()
 {
   mExternalResourceMap.HideViewers();
   if (IsEventHandlingEnabled()) {
     RevokeAnimationFrameNotifications();
   }
+
   mPresShell = nsnull;
 }
 
 void
 nsDocument::RevokeAnimationFrameNotifications()
 {
   if (mHavePendingPaint) {
     mPresShell->GetPresContext()->RefreshDriver()->RevokeBeforePaintEvent(this);
@@ -8354,42 +8355,25 @@ nsIDocument::SizeOf() const
   for (nsIContent* node = GetFirstChild(); node;
        node = node->GetNextNode(this)) {
     size += node->SizeOf();
   }
 
   return size;
 }
 
-class nsDispatchFullScreenChange : public nsRunnable
-{
-public:
-  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;
-};
-
-static void DispatchFullScreenChange(nsIDocument* aDocument, Element* aElement)
-{
-  nsCOMPtr<nsIRunnable> event(
-    new nsDispatchFullScreenChange(aDocument, aElement));
-  NS_DispatchToCurrentThread(event);
+static void
+DispatchFullScreenChange(nsINode* aTarget)
+{
+  nsRefPtr<nsPLDOMEvent> e =
+    new nsPLDOMEvent(aTarget,
+                     NS_LITERAL_STRING("mozfullscreenchange"),
+                     true,
+                     false);
+  e->PostDOMEvent();
 }
 
 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.
@@ -8465,17 +8449,17 @@ nsDocument::CancelFullScreen()
   if (!IsFullScreenDoc() || !GetWindow() || !sFullScreenDoc) {
     return;
   }
 
   // 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);
+      DispatchFullScreenChange(doc);
     }
     doc = doc->GetParentDocument();
   }
   sFullScreenDoc = nsnull;
 
   // Move the window out of full-screen mode.
   SetWindowFullScreen(this, false);
 
@@ -8518,60 +8502,68 @@ GetCommonAncestor(nsIDocument* aDoc1, ns
   }
   return parent;
 }
 
 void
 nsDocument::RequestFullScreen(Element* aElement)
 {
   if (!aElement || !nsContentUtils::IsFullScreenApiEnabled() || !GetWindow()) {
+    if (aElement) {
+      nsRefPtr<nsPLDOMEvent> e =
+        new nsPLDOMEvent(aElement,
+                         NS_LITERAL_STRING("mozfullscreenerror"),
+                         true,
+                         false);
+      e->PostDOMEvent();
+    }
     return;
   }
 
   // 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);
+      DispatchFullScreenChange(doc);
     }
     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);
+    DispatchFullScreenChange(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);
+      DispatchFullScreenChange(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 chrome to distinguish between browser and dom full-screen
@@ -8611,17 +8603,18 @@ nsDocument::GetMozFullScreen(bool *aFull
 
 NS_IMETHODIMP
 nsDocument::GetMozFullScreenEnabled(bool *aFullScreen)
 {
   NS_ENSURE_ARG_POINTER(aFullScreen);
   *aFullScreen = false;
 
   if (!nsContentUtils::IsFullScreenApiEnabled() ||
-      nsContentUtils::HasPluginWithUncontrolledEventDispatch(this)) {
+      nsContentUtils::HasPluginWithUncontrolledEventDispatch(this) ||
+      !IsVisible()) {
     return NS_OK;
   }
 
   // Ensure that all ancestor <iframe> elements have the mozallowfullscreen
   // boolean attribute set.
   nsINode* node = static_cast<nsINode*>(this);
   do {
     nsIContent* content = static_cast<nsIContent*>(node);
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -584,16 +584,17 @@ GK_ATOM(modifiers, "modifiers")
 GK_ATOM(monochrome, "monochrome")
 GK_ATOM(mousedown, "mousedown")
 GK_ATOM(mousemove, "mousemove")
 GK_ATOM(mouseout, "mouseout")
 GK_ATOM(mouseover, "mouseover")
 GK_ATOM(mousethrough, "mousethrough")
 GK_ATOM(mouseup, "mouseup")
 GK_ATOM(mozfullscreenchange, "mozfullscreenchange")
+GK_ATOM(mozfullscreenerror, "mozfullscreenerror")
 GK_ATOM(moz_opaque, "moz-opaque")
 GK_ATOM(moz_action_hint, "mozactionhint")
 GK_ATOM(x_moz_errormessage, "x-moz-errormessage")
 GK_ATOM(msthemecompatible, "msthemecompatible")
 GK_ATOM(multicol, "multicol")
 GK_ATOM(multiple, "multiple")
 GK_ATOM(name, "name")
 GK_ATOM(_namespace, "namespace")
@@ -702,16 +703,17 @@ GK_ATOM(onmouseleave, "onmouseleave")
 GK_ATOM(onmousemove, "onmousemove")
 GK_ATOM(onmouseout, "onmouseout")
 GK_ATOM(onmouseover, "onmouseover")
 GK_ATOM(onMozMouseHittest, "onMozMouseHittest")
 GK_ATOM(onmouseup, "onmouseup")
 GK_ATOM(onMozAfterPaint, "onMozAfterPaint")
 GK_ATOM(onMozBeforePaint, "onMozBeforePaint")
 GK_ATOM(onmozfullscreenchange, "onmozfullscreenchange")
+GK_ATOM(onmozfullscreenerror, "onmozfullscreenerror")
 GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll")
 GK_ATOM(onMozScrolledAreaChanged, "onMozScrolledAreaChanged")
 GK_ATOM(ononline, "ononline")
 GK_ATOM(onoffline, "onoffline")
 GK_ATOM(onopen, "onopen")
 GK_ATOM(onoverflow, "onoverflow")
 GK_ATOM(onoverflowchanged, "onoverflowchanged")
 GK_ATOM(onpagehide, "onpagehide")
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -67,16 +67,17 @@
 
 #include "nsIChannel.h"
 #include "nsIStreamListener.h"
 
 #include "nsIFrame.h"
 #include "nsIDOMNode.h"
 
 #include "nsContentUtils.h"
+#include "nsLayoutUtils.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsSVGEffects.h"
 
 #include "mozAutoDocUpdate.h"
 #include "mozilla/dom/Element.h"
 
@@ -110,17 +111,19 @@ nsImageLoadingContent::nsImageLoadingCon
     // mBroken starts out true, since an image without a URI is broken....
     mBroken(true),
     mUserDisabled(false),
     mSuppressed(false),
     mBlockingOnload(false),
     mNewRequestsWillNeedAnimationReset(false),
     mPendingRequestNeedsResetAnimation(false),
     mCurrentRequestNeedsResetAnimation(false),
-    mStateChangerDepth(0)
+    mStateChangerDepth(0),
+    mCurrentRequestRegistered(false),
+    mPendingRequestRegistered(false)
 {
   if (!nsContentUtils::GetImgLoader()) {
     mLoadingEnabled = false;
   }
 }
 
 void
 nsImageLoadingContent::DestroyImageLoadingContent()
@@ -191,17 +194,26 @@ nsImageLoadingContent::OnStartDecode(img
       (NS_SUCCEEDED(rv) && (loadFlags & nsIRequest::LOAD_BACKGROUND));
 
     // Block onload for non-background requests
     if (!background) {
       NS_ABORT_IF_FALSE(!mBlockingOnload, "Shouldn't already be blocking");
       SetBlockingOnload(true);
     }
   }
-
+  
+  bool* requestFlag = GetRegisteredFlagForRequest(aRequest);
+  if (requestFlag) {
+    nsLayoutUtils::RegisterImageRequest(GetFramePresContext(), aRequest,
+                                        requestFlag);
+  } else {
+    NS_ERROR("Starting to decode an image other than our current/pending "
+             "request?");
+  }
+  
   LOOP_OVER_OBSERVERS(OnStartDecode(aRequest));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsImageLoadingContent::OnStartContainer(imgIRequest* aRequest,
                                         imgIContainer* aContainer)
 {
@@ -324,16 +336,23 @@ nsImageLoadingContent::OnStopDecode(imgI
   // doing a paint first. This means that decode-on-draw images don't start
   // decoding, so we can't wait for them to finish. See bug 512435.
 
   // We can only do this if we have a presshell
   nsIDocument* doc = GetOurDocument();
   nsIPresShell* shell = doc ? doc->GetShell() : nsnull;
   if (shell) {
 
+    // Make sure that our image requests are deregistered from the refresh
+    // driver if they aren't animated. Note that this must be mCurrentRequest,
+    // or we would have aborted up above.
+    nsLayoutUtils::DeregisterImageRequestIfNotAnimated(GetFramePresContext(),
+                                                       mCurrentRequest,
+                                                       &mCurrentRequestRegistered);
+
     // We need to figure out whether to kick off decoding
     bool doRequestDecode = false;
 
     // If we haven't got the initial reflow yet, IsPaintingSuppressed actually
     // returns false
     if (!shell->DidInitialReflow())
       doRequestDecode = true;
 
@@ -496,16 +515,54 @@ nsImageLoadingContent::GetRequest(PRInt3
     *aRequest = nsnull;
     return NS_ERROR_UNEXPECTED;
   }
   
   NS_IF_ADDREF(*aRequest);
   return NS_OK;
 }
 
+NS_IMETHODIMP_(void)
+nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
+{
+  NS_ASSERTION(aFrame, "aFrame is null");
+
+  // We need to make sure that our image request is registered.
+  nsPresContext* presContext = aFrame->PresContext();
+
+  if (mCurrentRequest) {
+    nsLayoutUtils::RegisterImageRequest(presContext, mCurrentRequest,
+                                        &mCurrentRequestRegistered);
+    nsLayoutUtils::DeregisterImageRequestIfNotAnimated(presContext,
+                                                       mCurrentRequest,
+                                                       &mCurrentRequestRegistered);
+  } else if (mPendingRequest) {
+    // We don't need to do the same check for animation, because this will be
+    // done when decoding is finished.
+    nsLayoutUtils::RegisterImageRequest(presContext, mPendingRequest,
+                                        &mPendingRequestRegistered);
+  }
+}
+
+NS_IMETHODIMP_(void)
+nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
+{
+  NS_ASSERTION(aFrame, "aFrame is null");
+
+  // We need to make sure that our image request is deregistered.
+  if (mCurrentRequest) {
+    nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(),
+                                          mCurrentRequest,
+                                          &mCurrentRequestRegistered);
+  } else if (mPendingRequest) {
+    nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(),
+                                          mPendingRequest,
+                                          &mPendingRequestRegistered);
+  }
+}
 
 NS_IMETHODIMP
 nsImageLoadingContent::GetRequestType(imgIRequest* aRequest,
                                       PRInt32* aRequestType)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
 
   NS_PRECONDITION(aRequestType, "Null out param");
@@ -862,16 +919,33 @@ nsIDocument*
 nsImageLoadingContent::GetOurDocument()
 {
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
   NS_ENSURE_TRUE(thisContent, nsnull);
 
   return thisContent->OwnerDoc();
 }
 
+nsIFrame*
+nsImageLoadingContent::GetOurPrimaryFrame()
+{
+  nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
+  return thisContent->GetPrimaryFrame();
+}
+
+nsPresContext* nsImageLoadingContent::GetFramePresContext()
+{
+  nsIFrame* frame = GetOurPrimaryFrame();
+  if (!frame) {
+    return nsnull;
+  }
+
+  return frame->PresContext();
+}
+
 nsresult
 nsImageLoadingContent::StringToURI(const nsAString& aSpec,
                                    nsIDocument* aDocument,
                                    nsIURI** aURI)
 {
   NS_PRECONDITION(aDocument, "Must have a document");
   NS_PRECONDITION(aURI, "Null out param");
 
@@ -981,16 +1055,26 @@ nsImageLoadingContent::ClearCurrentReque
     // Even if we didn't have a current request, we might have been keeping
     // a URI as a placeholder for a failed load. Clear that now.
     mCurrentURI = nsnull;
     return;
   }
   NS_ABORT_IF_FALSE(!mCurrentURI,
                     "Shouldn't have both mCurrentRequest and mCurrentURI!");
 
+  // Deregister this image from the refresh driver so it no longer receives
+  // notifications.
+  nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mCurrentRequest,
+                                        &mCurrentRequestRegistered);
+
+  // Deregister this image from the refresh driver so it no longer receives
+  // notifications.
+  nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mCurrentRequest,
+                                        &mCurrentRequestRegistered);
+
   // Clean up the request.
   UntrackImage(mCurrentRequest);
   mCurrentRequest->CancelAndForgetObserver(aReason);
   mCurrentRequest = nsnull;
   mCurrentRequestNeedsResetAnimation = false;
 
   // We only block onload during the decoding of "current" images. This one is
   // going away, so we should unblock unconditionally here.
@@ -1004,22 +1088,39 @@ nsImageLoadingContent::ClearPendingReque
     return;
 
   // Push a null JSContext on the stack so that code that runs within
   // the below code doesn't think it's being called by JS. See bug
   // 604262.
   nsCxPusher pusher;
   pusher.PushNull();
 
+  // Deregister this image from the refresh driver so it no longer receives
+  // notifications.
+  nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest,
+                                        &mPendingRequestRegistered);
+
   UntrackImage(mPendingRequest);
   mPendingRequest->CancelAndForgetObserver(aReason);
   mPendingRequest = nsnull;
   mPendingRequestNeedsResetAnimation = false;
 }
 
+bool*
+nsImageLoadingContent::GetRegisteredFlagForRequest(imgIRequest* aRequest)
+{
+  if (aRequest == mCurrentRequest) {
+    return &mCurrentRequestRegistered;
+  } else if (aRequest == mPendingRequest) {
+    return &mPendingRequestRegistered;
+  } else {
+    return nsnull;
+  }
+}
+
 bool
 nsImageLoadingContent::HaveSize(imgIRequest *aImage)
 {
   // Handle the null case
   if (!aImage)
     return false;
 
   // Query the image
--- a/content/base/src/nsImageLoadingContent.h
+++ b/content/base/src/nsImageLoadingContent.h
@@ -142,16 +142,34 @@ protected:
    * and such).  Not named GetDocument to prevent ambiguous method
    * names in subclasses
    *
    * @return the document we belong to
    */
   nsIDocument* GetOurDocument();
 
   /**
+   * Helper function to get the frame associated with this content. Not named
+   * GetPrimaryFrame to prevent ambiguous method names in subclasses.
+   *
+   * @return The frame which we belong to, or nsnull if it doesn't exist.
+   */
+  nsIFrame* GetOurPrimaryFrame();
+
+  /**
+   * Helper function to get the PresContext associated with this content's
+   * frame. Not named GetPresContext to prevent ambiguous method names in
+   * subclasses.
+   *
+   * @return The nsPresContext associated with our frame, or nsnull if either
+   *         the frame doesn't exist, or the frame's prescontext doesn't exist.
+   */
+  nsPresContext* GetFramePresContext();
+
+  /**
    * CancelImageRequests is called by subclasses when they want to
    * cancel all image requests (for example when the subclass is
    * somehow not an image anymore).
    */
   void CancelImageRequests(bool aNotify);
 
   /**
    * UseAsPrimaryRequest is called by subclasses when they have an existing
@@ -298,16 +316,26 @@ protected:
 
   /**
    * Cancels and nulls-out the "current" and "pending" requests if they exist.
    */
   void ClearCurrentRequest(nsresult aReason);
   void ClearPendingRequest(nsresult aReason);
 
   /**
+   * Retrieve a pointer to the 'registered with the refresh driver' flag for
+   * which a particular image request corresponds.
+   *
+   * @returns A pointer to the boolean flag for a given image request, or
+   *          |nsnull| if the request is not either |mPendingRequest| or
+   *          |mCurrentRequest|.
+   */
+  bool* GetRegisteredFlagForRequest(imgIRequest* aRequest);
+
+  /**
    * Static helper method to tell us if we have the size of a request. The
    * image may be null.
    */
   static bool HaveSize(imgIRequest *aImage);
 
   /**
    * Adds/Removes a given imgIRequest from our document's tracker.
    *
@@ -377,11 +405,16 @@ protected:
   bool mNewRequestsWillNeedAnimationReset : 1;
 
 private:
   bool mPendingRequestNeedsResetAnimation : 1;
   bool mCurrentRequestNeedsResetAnimation : 1;
 
   /* The number of nested AutoStateChangers currently tracking our state. */
   PRUint8 mStateChangerDepth;
+
+  // Flags to indicate whether each of the current and pending requests are
+  // registered with the refresh driver.
+  bool mCurrentRequestRegistered;
+  bool mPendingRequestRegistered;
 };
 
 #endif // nsImageLoadingContent_h__
--- a/content/base/test/chrome/test_bug430050.xul
+++ b/content/base/test/chrome/test_bug430050.xul
@@ -31,17 +31,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     document.documentElement.addEventListener('DOMAttrModified',
       function(evt) {
         if (evt.target == evt.currentTarget) {
           document.getElementById('b').setAttribute("src",
                                                     "data:text/plain,failed");
           document.getElementById('b').loadURI('data:text/plain,succeeded',
                                                null,
                                                'UTF-8');
-          setTimeout(endTest, 0);
+          document.getElementById('b').addEventListener("load", endTest);
         }
       }, true);
     document.documentElement.setAttribute("foo", "bar");
   }
   
   SimpleTest.waitForExplicitFinish();
   addLoadEvent(startTest);
 
--- a/content/events/public/nsEventNameList.h
+++ b/content/events/public/nsEventNameList.h
@@ -266,16 +266,20 @@ EVENT(mouseover,
 EVENT(mouseup,
       NS_MOUSE_BUTTON_UP,
       EventNameType_All,
       NS_MOUSE_EVENT)
 EVENT(mozfullscreenchange,
       NS_FULLSCREENCHANGE,
       EventNameType_HTML,
       NS_EVENT_NULL)
+EVENT(mozfullscreenerror,
+      NS_FULLSCREENERROR,
+      EventNameType_HTML,
+      NS_EVENT_NULL)
 // Not supported yet; probably never because "wheel" is a better idea.
 // EVENT(mousewheel)
 EVENT(pause,
       NS_PAUSE,
       EventNameType_HTML,
       NS_EVENT_NULL)
 EVENT(play,
       NS_PLAY,
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -93,16 +93,17 @@ static const char* const sEventNames[] =
   "loadedmetadata", "loadeddata", "waiting", "playing", "canplay",
   "canplaythrough", "seeking", "seeked", "timeupdate", "ended", "ratechange",
   "durationchange", "volumechange", "MozAudioAvailable",
 #endif // MOZ_MEDIA
   "MozAfterPaint",
   "MozBeforePaint",
   "MozBeforeResize",
   "mozfullscreenchange",
+  "mozfullscreenerror",
   "MozSwipeGesture",
   "MozMagnifyGestureStart",
   "MozMagnifyGestureUpdate",
   "MozMagnifyGesture",
   "MozRotateGestureStart",
   "MozRotateGestureUpdate",
   "MozRotateGesture",
   "MozTapGesture",
@@ -1379,16 +1380,18 @@ const char* nsDOMEvent::GetEventName(PRU
   case NS_ANIMATION_ITERATION:
     return sEventNames[eDOMEvents_animationiteration];
   case NS_DEVICE_MOTION:
     return sEventNames[eDOMEvents_devicemotion];
   case NS_DEVICE_ORIENTATION:
     return sEventNames[eDOMEvents_deviceorientation];
   case NS_FULLSCREENCHANGE:
     return sEventNames[eDOMEvents_mozfullscreenchange];
+  case NS_FULLSCREENERROR:
+    return sEventNames[eDOMEvents_mozfullscreenerror];
   default:
     break;
   }
   // XXXldb We can hit this case for nsEvent objects that we didn't
   // create and that are not user defined events since this function and
   // SetEventType are incomplete.  (But fixing that requires fixing the
   // arrays in nsEventListenerManager too, since the events for which
   // this is a problem generally *are* created by nsDOMEvent.)
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -176,16 +176,17 @@ public:
     eDOMEvents_durationchange,
     eDOMEvents_volumechange,
     eDOMEvents_mozaudioavailable,
 #endif
     eDOMEvents_afterpaint,
     eDOMEvents_beforepaint,
     eDOMEvents_beforeresize,
     eDOMEvents_mozfullscreenchange,
+    eDOMEvents_mozfullscreenerror,
     eDOMEvents_MozSwipeGesture,
     eDOMEvents_MozMagnifyGestureStart,
     eDOMEvents_MozMagnifyGestureUpdate,
     eDOMEvents_MozMagnifyGesture,
     eDOMEvents_MozRotateGestureStart,
     eDOMEvents_MozRotateGestureUpdate,
     eDOMEvents_MozRotateGesture,
     eDOMEvents_MozTapGesture,
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -112,16 +112,17 @@
 #include "nsLayoutUtils.h"
 #include "nsContentCreatorFunctions.h"
 #include "mozAutoDocUpdate.h"
 #include "nsHtml5Module.h"
 #include "nsITextControlElement.h"
 #include "mozilla/dom/Element.h"
 #include "nsHTMLFieldSetElement.h"
 #include "nsHTMLMenuElement.h"
+#include "nsPLDOMEvent.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #include "nsThreadUtils.h"
 
@@ -3398,27 +3399,39 @@ 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.
+  nsIDocument* doc = OwnerDoc();
   if (!nsContentUtils::IsRequestFullScreenAllowed() ||
       !IsInDoc()) {
+    nsRefPtr<nsPLDOMEvent> e =
+      new nsPLDOMEvent(this,
+                       NS_LITERAL_STRING("mozfullscreenerror"),
+                       true,
+                       false);
+    e->PostDOMEvent();
     return NS_OK;
   }
 
-  nsIDocument* doc = OwnerDoc();
   nsCOMPtr<nsIDOMDocument> domDocument(do_QueryInterface(doc));
   NS_ENSURE_STATE(domDocument);
   bool fullScreenEnabled;
   domDocument->GetMozFullScreenEnabled(&fullScreenEnabled);
   if (!fullScreenEnabled) {
+    nsRefPtr<nsPLDOMEvent> e =
+      new nsPLDOMEvent(this,
+                       NS_LITERAL_STRING("mozfullscreenerror"),
+                       true,
+                       false);
+    e->PostDOMEvent();
     return NS_OK;
   }
 
   doc->RequestFullScreen(this);
 #ifdef DEBUG
   bool fullscreen;
   domDocument->GetMozFullScreen(&fullscreen);
   NS_ASSERTION(fullscreen, "Document should report fullscreen");
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -278,16 +278,17 @@ include $(topsrcdir)/config/rules.mk
 		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 \
+		file_fullscreen-hidden.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.html
+++ b/content/html/content/test/file_fullscreen-api.html
@@ -38,18 +38,20 @@ function is(a, b, msg) {
 */
 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;
+var fullscreendenied = false;
 
-var fullScreenChangeCount = 0;
+document.addEventListener("mozfullscreenerror", function(){fullscreendenied=true;}, false);
 
 function sendMouseClick(element) {
   synthesizeMouseAtCenter(element, {});
 }
 
 function setRequireTrustedContext(value) {
   opener.SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", value);
 }
@@ -148,55 +150,64 @@ function fullScreenChange(event) {
          "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.");
       break;
     }
     case 5: {
       ok(!document.mozFullScreen, "Should be back in non-full-screen mode (third time)");
       setRequireTrustedContext(true);
+      fullscreendenied = false;
       fullScreenElement().mozRequestFullScreen();
       ok(!document.mozFullScreen, "Should still be in normal mode, because calling context isn't trusted.");
 
-      button = document.createElement("button");
-      button.onclick = function(){fullScreenElement().mozRequestFullScreen();}
-      fullScreenElement().appendChild(button);
-      sendMouseClick(button);
+      setTimeout(
+        function() {
+          ok(fullscreendenied, "Request for fullscreen should have been denied because calling context isn't trusted");
+          button = document.createElement("button");
+          button.onclick = function(){fullScreenElement().mozRequestFullScreen();}
+          fullScreenElement().appendChild(button);
+          sendMouseClick(button);
+        }, 0);
       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");
+      fullscreendenied = false;
       fullScreenElement().mozRequestFullScreen();
-      ok(!document.mozFullScreen, "Should still be in normal mode, because pref is not enabled.");
+      setTimeout(
+        function() {
+          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");
-      fullScreenElement().appendChild(iframe);
-      iframe.src = iframeContents;
-      ok(!document.mozFullScreen, "Should still be in normal mode, because iframe did not have mozallowfullscreen attribute.");
-      fullScreenElement().removeChild(iframe);
-      iframe = null;
+          iframe = document.createElement("iframe");
+          fullScreenElement().appendChild(iframe);
+          iframe.src = iframeContents;
+          ok(!document.mozFullScreen, "Should still be in normal mode, because iframe did not have mozallowfullscreen attribute.");
+          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.nextTest();}, 0);
+          // Set timeout for calling finish(), so that any pending "mozfullscreenchange" events
+          // would have a chance to fire.
+          setTimeout(function(){opener.nextTest();}, 0);
+        }, 0);
       break;
     }
     default: {
       ok(false, "Should not receive any more fullscreenchange events!");
     }
   }
   fullScreenChangeCount++;
 }
--- a/content/html/content/test/file_fullscreen-denied.html
+++ b/content/html/content/test/file_fullscreen-denied.html
@@ -32,65 +32,78 @@ function 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 fullscreendenied = false;
+
+document.addEventListener("mozfullscreenerror", function(){fullscreendenied=true;}, false);
 
 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", {});
+  fullscreendenied = false;
+  setTimeout(
+    function() {
+      ok(!document.mozFullScreen, "Should not grant request in non-truested context");
+      ok(fullscreendenied, "Request in non-trusted event handler should be denied");
+      // 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", {});
+    }, 0);
 }
 
 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...
   }
+  fullscreendenied = false;
   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();
+      ok(fullscreendenied, "Request in long running event handler should be denied");
+      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, and we should not receive a fullscreenchange
+      // event in this document.
+      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);
     }, 0);
 }
 
 </script>
 </pre>
 <div id="full-screen-element"></div>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/file_fullscreen-hidden.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=697636
+-->
+<head>
+  <title>Test for Bug 697636</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="boom();">
+
+<iframe id="f" src="data:text/html,<body text=green>1" mozallowfullscreen></iframe>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=697636">Mozilla Bug 697636</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 697636 **/
+
+var frameWin;
+var e1;
+
+function boom()
+{
+  frameWin = document.getElementById("f").contentWindow;
+  e1 = frameWin.document.documentElement;
+  frameWin.location = "data:text/html,<body text=blue onload='parent.b2()'>2";
+}
+
+function b2()
+{
+  try { e1.mozRequestFullScreen(); } catch(e) { opener.ok(false, "Should not enter full-screen"); }
+  setTimeout(done, 0);
+}
+
+function done() {
+  opener.ok(!document.mozFullScreen, "Should not have entered full-screen mode in hidden document.");
+  opener.ok(!e1.ownerDocument.mozFullScreen, "Requesting owner should not have entered full-screen mode.");
+  opener.nextTest();
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/content/test/test_bug500885.html
+++ b/content/html/content/test/test_bug500885.html
@@ -2,99 +2,59 @@
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=500885
 -->
 <head>
   <title>Test for Bug 500885</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <script type="text/javascript" src="/tests/SimpleTest/mockObjects.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=500885">Mozilla Bug 500885</a>
 <div>
   <input id="file" type="file" />
 </div>
 <script type="text/javascript">
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-var Cu = Components.utils;
-var Ci = Components.interfaces;
-var Cr = Components.results;
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-function MockFilePicker() { };
-MockFilePicker.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker]),
-  init: function(aParent, aTitle, aMode) { },
-  appendFilters: function(aFilterMask) { },
-  appendFilter: function(aTitle, aFilter) { },
-  defaultString: "",
-  defaultExtension: "",
-  filterIndex: 0,
-  displayDirectory: null,
-  file: null,
-  get fileURL() {
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-  },
-  get files() {
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-  },
-  show: function MFP_show() {
-    return Ci.nsIFilePicker.returnOK;
-  }
-};
-
-var mockFilePickerRegisterer = 
-  new MockObjectRegisterer("@mozilla.org/filepicker;1",MockFilePicker);
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.reset();
+MockFilePicker.returnValue = MockFilePicker.returnOK;
 
 function test() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var wu = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                  .getInterface(Ci.nsIDOMWindowUtils);
-                  
+  // SpecialPowers.DOMWindowUtils doesn't appear to fire mouseEvents correctly
+  var wu = SpecialPowers.getDOMWindowUtils(window);
 
-  mockFilePickerRegisterer.register();
   try {
     var domActivateEvents;
     var fileInput = document.getElementById("file");
     var rect = fileInput.getBoundingClientRect();
 
     fileInput.addEventListener ("DOMActivate", function (e) {
-      ok("detail" in e, "DOMActivate should have .detail!");
-      is(e.detail, 1, "detail should be 1!");
+      ok("detail" in e, "DOMActivate should have .detail");
+      is(e.detail, 1, ".detail should be 1");
       domActivateEvents++;
     }, false);
 
     domActivateEvents = 0;
     wu.sendMouseEvent("mousedown", rect.left + 5, rect.top + 5, 0, 1, 0);
     wu.sendMouseEvent("mouseup", rect.left + 5, rect.top + 5, 0, 1, 0);
-    is(domActivateEvents, 1, "click on text field should only fire 1 DOMActivate event");
+    is(domActivateEvents, 1, "click on text field should fire 1 DOMActivate event");
 
     domActivateEvents = 0;
     wu.sendMouseEvent("mousedown", rect.right - 5, rect.top + 5, 0, 1, 0);
     wu.sendMouseEvent("mouseup", rect.right - 5, rect.top + 5, 0, 1, 0);
-    is(domActivateEvents, 1, "click on button should only fire 1 DOMActivate event");
+    is(domActivateEvents, 1, "click on button should fire 1 DOMActivate event");
 
   } finally {
-    SimpleTest.executeSoon(unregister);
-    
+    SimpleTest.executeSoon(SimpleTest.finish);
   }
 }
 
-function unregister()
-{
-  mockFilePickerRegisterer.unregister();
-  SimpleTest.finish();
-}
-
-window.onload = function() {
-  SimpleTest.waitForExplicitFinish();
-  setTimeout(test, 0);
-};
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(test);
 
 </script>
 </body>
 
 </html>
--- a/content/html/content/test/test_bug592802.html
+++ b/content/html/content/test/test_bug592802.html
@@ -2,17 +2,16 @@
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=592802
 -->
 <head>
   <title>Test for Bug 592802</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/mockObjects.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=592802">Mozilla Bug 592802</a>
 <p id="display"></p>
 <div id="content">
   <input id='a' type='file'>
   <input id='a2' type='file'>
@@ -21,173 +20,53 @@ https://bugzilla.mozilla.org/show_bug.cg
 <button id='b2' onclick="document.getElementById('a2').click();">Show Filepicker</button>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 592802 **/
 
 SimpleTest.waitForExplicitFinish();
 
-netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-
-var Cu = Components.utils;
-var Ci = Components.interfaces;
-var Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-function simpleEnumerator(items)
-{
-  this._items = items;
-  this._nextIndex = 0;
-}
-
-simpleEnumerator.prototype = {
-  QueryInterface: function(aIID)
-  {
-    if (Ci.nsISimpleEnumerator.equals(aIID) ||
-        Ci.nsISupports.equals(aIID)) {
-      return this;
-    }
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
-
-  hasMoreElements: function()
-  {
-    return this._nextIndex < this._items.length;
-  },
-
-  getNext: function()
-  {
-    if (!this.hasMoreElements()) {
-      throw Cr.NS_ERROR_FAILURE;
-    }
-
-    return this._items[this._nextIndex++];
-  }
-};
-
-function MockFilePicker()
-{
-}
-
-MockFilePicker.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker]),
-
-  // Constants
-  returnOK: 0, // the user hits OK (select a file)
-  returnCancel: 1, // the user cancel the file selection
-  returnReplace: 2, // the user replace the selection
-
-  // Properties
-  defaultExtension: "",
-  defaultString: "",
-  get displayDirectory() { return null; },
-  set displayDirectory(val) { },
-  get fileURL() { return null; },
-  filterIndex: 0,
-
-  get file() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
-    var fileName = "592808_file";
-    var fileData = "file content";
-
-    var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
-                           .getService(Components.interfaces.nsIProperties);
-    var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
-    testFile.append(fileName);
-    var outStream = Components.
-                    classes["@mozilla.org/network/file-output-stream;1"].
-                    createInstance(Components.interfaces.nsIFileOutputStream);
-    outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
-                   0666, 0);
-    outStream.write(fileData, fileData.length);
-    outStream.close();
-
-    return testFile;
-  },
-
-  get files() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
-    var fileName = "592808_file";
-    var fileData = "file content";
-
-    var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
-                           .getService(Components.interfaces.nsIProperties);
-    var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
-    testFile.append(fileName);
-    var outStream = Components.
-                    classes["@mozilla.org/network/file-output-stream;1"].
-                    createInstance(Components.interfaces.nsIFileOutputStream);
-    outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
-                   0666, 0);
-    outStream.write(fileData, fileData.length);
-    outStream.close();
-
-    return new simpleEnumerator([testFile]);
-  },
-
-  appendFilter: function(val) {},
-
-  appendFilters: function(val) {},
-
-  init: function() {},
-
-  show: function()
-  {
-    if (firstFilePickerShow) {
-      firstFilePickerShow = false;
-      return this.returnCancel;
-    } else {
-      return this.returnOK;
-    }
-  }
-};
-
-var mockFilePickerRegisterer =
-  new MockObjectRegisterer("@mozilla.org/filepicker;1",MockFilePicker);
-
-mockFilePickerRegisterer.register();
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.reset();
 
 var testData = [
 /* visibility | display | multiple */
   [ "",       "",     false ],
   [ "hidden", "",     false ],
   [ "",       "none", false ],
   [ "",       "",     true ],
   [ "hidden", "",     true ],
   [ "",       "none", true ],
 ];
 
 var testCounter = 0;
 var testNb = testData.length;
 
-var firstFilePickerShow = true;
-
 function finished()
 {
-  mockFilePickerRegisterer.unregister();
-
   SimpleTest.finish();
 }
 
 SimpleTest.waitForFocus(function() {
   // mockFilePicker will simulate a cancel for the first time the file picker will be shown.
+  MockFilePicker.returnValue = MockFilePicker.returnCancel;
+
   var b2 = document.getElementById('b2');
   b2.focus(); // Be sure the element is visible.
   document.getElementById('b2').addEventListener("change", function(aEvent) {
     aEvent.target.removeEventListener("change", arguments.callee, false);
     ok(false, "When cancel is received, change should not fire");
   }, false);
-  synthesizeMouse(b2, 2, 2, {});
+  b2.click();
 
   // Now, we can launch tests when file picker isn't canceled.
+  MockFilePicker.useAnyFile();
+  MockFilePicker.returnValue = MockFilePicker.returnOK;
+
   var b = document.getElementById('b');
   b.focus(); // Be sure the element is visible.
 
   document.getElementById('a').addEventListener("change", function(aEvent) {
     ok(true, "change event correctly sent");
     ok(aEvent.bubbles, "change event should bubble");
     ok(!aEvent.cancelable, "change event should not be cancelable");
     testCounter++;
@@ -198,20 +77,20 @@ SimpleTest.waitForFocus(function() {
     } else {
       var data = testData[testCounter];
       var a = document.getElementById('a');
       a.style.visibility = data[0];
       a.style.display = data[1];
       a.multiple = data[2];
 
       SimpleTest.executeSoon(function() {
-        synthesizeMouse(b, 2, 2, {});
+        b.click();
       });
     }
   }, false);
 
-  synthesizeMouse(b, 2, 2, {});
+  b.click();
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/test_fullscreen-api.html
+++ b/content/html/content/test/test_fullscreen-api.html
@@ -34,17 +34,18 @@ SpecialPowers.setBoolPref("full-screen-a
 
 // 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"
+  "file_fullscreen-plugins.html",
+  "file_fullscreen-hidden.html"
 ];
 
 var testWindow = null;
 var gTestIndex = 0;
 
 function nextTest() {
   if (testWindow) {
     testWindow.close();
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -136,16 +136,17 @@
 #include "nsIInlineSpellChecker.h"
 #include "nsRange.h"
 #include "mozAutoDocUpdate.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsHtml5Module.h"
 #include "prprf.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Preferences.h"
+#include "nsMimeTypes.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define NS_MAX_DOCUMENT_WRITE_DEPTH 20
 
 #define DETECTOR_CONTRACTID_MAX 127
 static char g_detector_contractid[DETECTOR_CONTRACTID_MAX + 1];
@@ -157,16 +158,17 @@ static bool gPlugDetector = false;
 
 // Find/Search Includes
 const PRInt32 kForward  = 0;
 const PRInt32 kBackward = 1;
 
 //#define DEBUG_charset
 
 #define NS_USE_NEW_VIEW_SOURCE 1
+#define NS_USE_NEW_PLAIN_TEXT 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
@@ -647,42 +649,56 @@ nsresult
 nsHTMLDocument::StartDocumentLoad(const char* aCommand,
                                   nsIChannel* aChannel,
                                   nsILoadGroup* aLoadGroup,
                                   nsISupports* aContainer,
                                   nsIStreamListener **aDocListener,
                                   bool aReset,
                                   nsIContentSink* aSink)
 {
+  nsCAutoString contentType;
+  aChannel->GetContentType(contentType);
+
   bool viewSource = aCommand && !nsCRT::strcmp(aCommand, "view-source") &&
     NS_USE_NEW_VIEW_SOURCE;
-  bool loadAsHtml5 = nsHtml5Module::sEnabled || viewSource;
+  bool plainText = (contentType.EqualsLiteral(TEXT_PLAIN) ||
+    contentType.EqualsLiteral(TEXT_CSS) ||
+    contentType.EqualsLiteral(APPLICATION_JAVASCRIPT) ||
+    contentType.EqualsLiteral(APPLICATION_XJAVASCRIPT) ||
+    contentType.EqualsLiteral(TEXT_ECMASCRIPT) ||
+    contentType.EqualsLiteral(APPLICATION_ECMASCRIPT) ||
+    contentType.EqualsLiteral(TEXT_JAVASCRIPT));
+  bool loadAsHtml5 = nsHtml5Module::sEnabled || viewSource || plainText;
+  if (!NS_USE_NEW_PLAIN_TEXT && !viewSource) {
+    plainText = false;
+  }
+
+  NS_ASSERTION(!(plainText && aSink),
+               "Someone tries to load plain text into a custom sink.");
 
   if (aSink) {
     loadAsHtml5 = false;
   }
 
-  nsCAutoString contentType;
-  aChannel->GetContentType(contentType);
-
   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 && !viewSource && !(contentType.EqualsLiteral("text/html") &&
+  if (loadAsHtml5 && !viewSource &&
+      (!(contentType.EqualsLiteral("text/html") || plainText) &&
       aCommand && !nsCRT::strcmp(aCommand, "view"))) {
     loadAsHtml5 = false;
   }
   
   // TODO: Proper about:blank treatment is bug 543435
   if (loadAsHtml5 && !viewSource) {
     // mDocumentURI hasn't been set, yet, so get the URI from the channel
     nsCOMPtr<nsIURI> uri;
@@ -726,19 +742,23 @@ nsHTMLDocument::StartDocumentLoad(const 
     return rv;
   }
 
   nsCOMPtr<nsICachingChannel> cachingChan = do_QueryInterface(aChannel);
 
   if (needsParser) {
     if (loadAsHtml5) {
       mParser = nsHtml5Module::NewHtml5Parser();
-      mParser->MarkAsNotScriptCreated((viewSource &&
-        !contentType.EqualsLiteral("text/html")) ?
-        "view-source-xml": aCommand);
+      if (plainText) {
+        mParser->MarkAsNotScriptCreated("plain-text");
+      } else if (viewSource && !contentType.EqualsLiteral("text/html")) {
+        mParser->MarkAsNotScriptCreated("view-source-xml");
+      } else {
+        mParser->MarkAsNotScriptCreated(aCommand);
+      }
     } else {
       mParser = do_CreateInstance(kCParserCID, &rv);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   PRInt32 textType = GET_BIDI_OPTION_TEXTTYPE(GetBidiOptions());
 
--- a/content/svg/content/src/nsSVGClass.cpp
+++ b/content/svg/content/src/nsSVGClass.cpp
@@ -108,33 +108,33 @@ nsresult
 nsSVGClass::ToDOMAnimatedString(nsIDOMSVGAnimatedString **aResult,
                                 nsSVGStylableElement *aSVGElement)
 {
   *aResult = new DOMAnimatedString(this, aSVGElement);
   NS_ADDREF(*aResult);
   return NS_OK;
 }
 
-#ifdef MOZ_SMIL
-nsISMILAttr*
-nsSVGClass::ToSMILAttr(nsSVGStylableElement *aSVGElement)
-{
-  return new SMILString(this, aSVGElement);
-}
-
 NS_IMETHODIMP
 nsSVGClass::DOMAnimatedString::GetAnimVal(nsAString& aResult)
 { 
 #ifdef MOZ_SMIL
   mSVGElement->FlushAnimations();
 #endif
   mVal->GetAnimValue(aResult, mSVGElement);
   return NS_OK;
 }
 
+#ifdef MOZ_SMIL
+nsISMILAttr*
+nsSVGClass::ToSMILAttr(nsSVGStylableElement *aSVGElement)
+{
+  return new SMILString(this, aSVGElement);
+}
+
 nsresult
 nsSVGClass::SMILString::ValueFromString(const nsAString& aStr,
                                         const nsISMILAnimationElement* /*aSrcElement*/,
                                         nsSMILValue& aValue,
                                         bool& aPreventCachingOfSandwich) const
 {
   nsSMILValue val(&SMILStringType::sSingleton);
 
--- a/content/svg/content/src/nsSVGClass.h
+++ b/content/svg/content/src/nsSVGClass.h
@@ -36,18 +36,21 @@
 
 #ifndef __NS_SVGCLASS_H__
 #define __NS_SVGCLASS_H__
 
 #include "nsIDOMSVGAnimatedString.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsString.h"
+#include "nsDOMError.h"
+
+#ifdef MOZ_SMIL
 #include "nsISMILAttr.h"
-#include "nsDOMError.h"
+#endif // MOZ_SMIL
 
 class nsSVGStylableElement;
 
 class nsSVGClass
 {
 
 public:
   void Init() {
--- a/content/svg/content/src/nsSVGStylableElement.cpp
+++ b/content/svg/content/src/nsSVGStylableElement.cpp
@@ -144,17 +144,19 @@ nsSVGStylableElement::DidAnimateClass()
   mClassAnimAttr->ParseAtomArray(src);
 
   nsIPresShell* shell = OwnerDoc()->GetShell();
   if (shell) {
     shell->RestyleForAnimation(this, eRestyle_Self);
   }
 }
 
+#ifdef MOZ_SMIL
 nsISMILAttr*
 nsSVGStylableElement::GetAnimatedAttr(PRInt32 aNamespaceID, nsIAtom* aName)
 {
   if (aNamespaceID == kNameSpaceID_None && 
       aName == nsGkAtoms::_class) {
     return mClassAttribute.ToSMILAttr(this);
   }
   return nsSVGStylableElementBase::GetAnimatedAttr(aNamespaceID, aName);
 }
+#endif // MOZ_SMIL
--- a/dom/interfaces/core/nsIInlineEventHandlers.idl
+++ b/dom/interfaces/core/nsIInlineEventHandlers.idl
@@ -34,17 +34,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 #include "domstubs.idl"
 
 %{ C++
 #include "jspubtd.h"
 %}
 
-[scriptable, uuid(4e9d7d5e-72c3-4fa3-94f9-55eac5a5996b)]
+[scriptable, uuid(5b3f9656-9d81-40e4-85ba-01f302177815)]
 interface nsIInlineEventHandlers : nsISupports
 {
   [implicit_jscontext] attribute jsval onabort;
   [implicit_jscontext] attribute jsval onblur;
   [implicit_jscontext] attribute jsval oncanplay;
   [implicit_jscontext] attribute jsval oncanplaythrough;
   [implicit_jscontext] attribute jsval onchange;
   [implicit_jscontext] attribute jsval onclick;
@@ -76,16 +76,17 @@ interface nsIInlineEventHandlers : nsISu
   [implicit_jscontext] attribute jsval onmousedown;
   [implicit_jscontext] attribute jsval onmousemove;
   [implicit_jscontext] attribute jsval onmouseout;
   [implicit_jscontext] attribute jsval onmouseover;
   [implicit_jscontext] attribute jsval onmouseup;
   // Not supported yet
   // [implicit_jscontext] attribute jsval onmousewheel;
   [implicit_jscontext] attribute jsval onmozfullscreenchange;
+  [implicit_jscontext] attribute jsval onmozfullscreenerror;
   [implicit_jscontext] attribute jsval onpause;
   [implicit_jscontext] attribute jsval onplay;
   [implicit_jscontext] attribute jsval onplaying;
   [implicit_jscontext] attribute jsval onprogress;
   [implicit_jscontext] attribute jsval onratechange;
   [implicit_jscontext] attribute jsval onreset;
   [implicit_jscontext] attribute jsval onscroll;
   [implicit_jscontext] attribute jsval onseeked;
--- a/gfx/angle/Makefile.in
+++ b/gfx/angle/Makefile.in
@@ -121,17 +121,17 @@ CSRCS   = \
         cpp.c \
         cppstruct.c \
         memory.c \
         scanner.c \
         symbols.c \
         tokens.c \
 	$(NULL)
 
-DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD
+DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD -DCOMPILER_IMPLEMENTATION
 
 #these defines are from ANGLE's build_angle.gyp
 DEFINES += -DANGLE_DISABLE_TRACE
 DEFINES += -DANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0
 
 EXTRA_DSO_LDOPTS = $(MOZALLOC_LIB)
 
 ifdef MOZ_ANGLE
--- a/gfx/angle/README.mozilla
+++ b/gfx/angle/README.mozilla
@@ -1,11 +1,11 @@
 This is the ANGLE project, from http://code.google.com/p/angleproject/
 
-Current revision: r802
+Current revision: r809
 
 == Applied local patches ==
 
 In this order:
   angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles
   angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
   angle-limit-identifiers-to-250-chars.patch - see bug 675625
   angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
--- a/gfx/angle/angle-intrinsic-msvc2005.patch
+++ b/gfx/angle/angle-intrinsic-msvc2005.patch
@@ -1,45 +1,10 @@
 # HG changeset patch
-# Parent cf38970fcf3b4bee12f09b3747b7b7711bc77ad8
-diff --git a/gfx/angle/angle-renaming-debug.patch b/gfx/angle/angle-renaming-debug.patch
---- a/gfx/angle/angle-renaming-debug.patch
-+++ b/gfx/angle/angle-renaming-debug.patch
-@@ -1,11 +1,10 @@
- # HG changeset patch
--# Parent 96359f46b01fdb37e791f564495e8b2755a05233
--
-+# Parent 70640278da97b0ca49e21c4bb52766b8af7db4db
- diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in
- --- a/gfx/angle/Makefile.in
- +++ b/gfx/angle/Makefile.in
- @@ -73,17 +73,17 @@ CPPSRCS = \
-          parseConst.cpp \
-          ParseHelper.cpp \
-          PoolAlloc.cpp \
-          QualifierAlive.cpp \
-@@ -129,17 +128,17 @@ diff --git a/gfx/angle/src/compiler/comp
-  
-  #include <assert.h>
-  
-  #ifdef _DEBUG
-  #define TRACE_ENABLED  // define to enable debug message tracing
- diff --git a/gfx/angle/src/compiler/osinclude.h b/gfx/angle/src/compiler/osinclude.h
- --- a/gfx/angle/src/compiler/osinclude.h
- +++ b/gfx/angle/src/compiler/osinclude.h
--@@ -32,17 +32,17 @@
-+@@ -30,17 +30,17 @@
-  #include <windows.h>
-  #elif defined(ANGLE_OS_POSIX)
-  #include <pthread.h>
-  #include <semaphore.h>
-  #include <errno.h>
-  #endif  // ANGLE_USE_NSPR
-  
-  
+# Parent b5604c321da4e3b5d6b0a940d18022a827061579
 diff --git a/gfx/angle/src/libGLESv2/Texture.cpp b/gfx/angle/src/libGLESv2/Texture.cpp
 --- a/gfx/angle/src/libGLESv2/Texture.cpp
 +++ b/gfx/angle/src/libGLESv2/Texture.cpp
 @@ -8,16 +8,22 @@
  // Texture2D and TextureCubeMap. Implements GL texture objects and related
  // functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
  
  #include "libGLESv2/Texture.h"
--- a/gfx/angle/angle-limit-identifiers-to-250-chars.patch
+++ b/gfx/angle/angle-limit-identifiers-to-250-chars.patch
@@ -1,26 +1,42 @@
 # HG changeset patch
-# Parent f9415c10c3ebd27856500cca7a0ee0f28a16f53c
-diff --git a/gfx/angle/src/compiler/preprocessor/scanner.h b/gfx/angle/src/compiler/preprocessor/scanner.h
---- a/gfx/angle/src/compiler/preprocessor/scanner.h
-+++ b/gfx/angle/src/compiler/preprocessor/scanner.h
-@@ -44,17 +44,19 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILI
- //
- // scanner.h
- //
+# Parent e8b87ef36a1dae3bbd7abb13c4bb0a0bb8f5b58c
+diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla
+--- a/gfx/angle/README.mozilla
++++ b/gfx/angle/README.mozilla
+@@ -2,16 +2,17 @@ This is the ANGLE project, from http://c
+ 
+ Current revision: r802
+ 
+ == Applied local patches ==
+ 
+ In this order:
+   angle-renaming-debug.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles
+   angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
++  angle-limit-identifiers-to-250-chars.patch - see bug 675625
  
- #if !defined(__SCANNER_H)
- #define __SCANNER_H 1
+ In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.
+ 
+ == How to update this ANGLE copy ==
+ 
+ 1. Unapply patches
+ 2. Apply diff with new ANGLE version
+ 3. Reapply patches.
+diff --git a/gfx/angle/src/compiler/preprocessor/length_limits.h b/gfx/angle/src/compiler/preprocessor/length_limits.h
+--- a/gfx/angle/src/compiler/preprocessor/length_limits.h
++++ b/gfx/angle/src/compiler/preprocessor/length_limits.h
+@@ -10,12 +10,14 @@
+ 
+ #if !defined(__LENGTH_LIMITS_H)
+ #define __LENGTH_LIMITS_H 1
+ 
+ // These constants are factored out from the rest of the headers to
+ // make it easier to reference them from the compiler sources.
  
  // These lengths do not include the NULL terminator.
 -#define MAX_SYMBOL_NAME_LEN 256
 +// see bug 675625: NVIDIA driver crash with lengths >= 253
 +// this is only an interim fix, the real fix is name mapping, see ANGLE bug 144 / r619
 +#define MAX_SYMBOL_NAME_LEN 250
  #define MAX_STRING_LEN 511
  
- #include "compiler/preprocessor/parser.h"
- 
- // Not really atom table stuff but needed first...
- 
- typedef struct SourceLoc_Rec {
-     unsigned short file, line;
+ #endif // !(defined(__LENGTH_LIMITS_H)
--- a/gfx/angle/angle-renaming-debug.patch
+++ b/gfx/angle/angle-renaming-debug.patch
@@ -1,10 +1,10 @@
 # HG changeset patch
-# Parent 70640278da97b0ca49e21c4bb52766b8af7db4db
+# Parent 0239f15c7212413b5cffe66aee9ae5a4feb28f16
 diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in
 --- a/gfx/angle/Makefile.in
 +++ b/gfx/angle/Makefile.in
 @@ -73,17 +73,17 @@ CPPSRCS = \
          parseConst.cpp \
          ParseHelper.cpp \
          PoolAlloc.cpp \
          QualifierAlive.cpp \
--- a/gfx/angle/src/build_angle.gyp
+++ b/gfx/angle/src/build_angle.gyp
@@ -12,16 +12,19 @@
   'targets': [
     {
       'target_name': 'translator_common',
       'type': 'static_library',
       'include_dirs': [
         '.',
         '../include',
       ],
+      'defines': [
+        'COMPILER_IMPLEMENTATION',
+      ],
       'sources': [
         'compiler/BaseTypes.h',
         'compiler/BuiltInFunctionEmulator.cpp',
         'compiler/BuiltInFunctionEmulator.h',
         'compiler/Common.h',
         'compiler/Compiler.cpp',
         'compiler/ConstantUnion.h',
         'compiler/debug.cpp',
@@ -55,33 +58,33 @@
         'compiler/ParseHelper.cpp',
         'compiler/ParseHelper.h',
         'compiler/PoolAlloc.cpp',
         'compiler/PoolAlloc.h',
         'compiler/QualifierAlive.cpp',
         'compiler/QualifierAlive.h',
         'compiler/RemoveTree.cpp',
         'compiler/RemoveTree.h',
-        'compiler/ShaderLang.cpp',
         'compiler/ShHandle.h',
         'compiler/SymbolTable.cpp',
         'compiler/SymbolTable.h',
         'compiler/Types.h',
         'compiler/util.cpp',
         'compiler/util.h',
         'compiler/ValidateLimitations.cpp',
         'compiler/ValidateLimitations.h',
         'compiler/VariableInfo.cpp',
         'compiler/VariableInfo.h',
         'compiler/preprocessor/atom.c',
         'compiler/preprocessor/atom.h',
         'compiler/preprocessor/compile.h',
         'compiler/preprocessor/cpp.c',
         'compiler/preprocessor/cpp.h',
         'compiler/preprocessor/cppstruct.c',
+        'compiler/preprocessor/length_limits.h',
         'compiler/preprocessor/memory.c',
         'compiler/preprocessor/memory.h',
         'compiler/preprocessor/parser.h',
         'compiler/preprocessor/preprocess.h',
         'compiler/preprocessor/scanner.c',
         'compiler/preprocessor/scanner.h',
         'compiler/preprocessor/slglobals.h',
         'compiler/preprocessor/symbols.c',
@@ -94,47 +97,55 @@
           'sources': ['compiler/ossource_win.cpp'],
         }, { # else: posix
           'sources': ['compiler/ossource_posix.cpp'],
         }],
       ],
     },
     {
       'target_name': 'translator_glsl',
-      'type': 'static_library',
+      'type': '<(component)',
       'dependencies': ['translator_common'],
       'include_dirs': [
         '.',
         '../include',
       ],
+      'defines': [
+        'COMPILER_IMPLEMENTATION',
+      ],
       'sources': [
         'compiler/CodeGenGLSL.cpp',
         'compiler/OutputESSL.cpp',
         'compiler/OutputESSL.h',        
         'compiler/OutputGLSLBase.cpp',
         'compiler/OutputGLSLBase.h',
         'compiler/OutputGLSL.cpp',
         'compiler/OutputGLSL.h',
+        'compiler/ShaderLang.cpp',
         'compiler/TranslatorESSL.cpp',
         'compiler/TranslatorESSL.h',
         'compiler/TranslatorGLSL.cpp',
         'compiler/TranslatorGLSL.h',
         'compiler/VersionGLSL.cpp',
         'compiler/VersionGLSL.h',
       ],
     },
     {
       'target_name': 'translator_hlsl',
-      'type': 'static_library',
+      'type': '<(component)',
       'dependencies': ['translator_common'],
       'include_dirs': [
         '.',
         '../include',
       ],
+      'defines': [
+        'COMPILER_IMPLEMENTATION',
+      ],
       'sources': [
+        'compiler/ShaderLang.cpp',
         'compiler/CodeGenHLSL.cpp',
         'compiler/OutputHLSL.cpp',
         'compiler/OutputHLSL.h',
         'compiler/TranslatorHLSL.cpp',
         'compiler/TranslatorHLSL.h',
         'compiler/UnfoldSelect.cpp',
         'compiler/UnfoldSelect.h',
         'compiler/SearchSymbol.cpp',
--- a/gfx/angle/src/common/version.h
+++ b/gfx/angle/src/common/version.h
@@ -1,10 +1,10 @@
 #define MAJOR_VERSION 0
 #define MINOR_VERSION 0
 #define BUILD_VERSION 0
-#define BUILD_REVISION 802
+#define BUILD_REVISION 809
 
 #define STRINGIFY(x) #x
 #define MACRO_STRINGIFY(x) STRINGIFY(x)
 
 #define REVISION_STRING MACRO_STRINGIFY(BUILD_REVISION)
 #define VERSION_STRING MACRO_STRINGIFY(MAJOR_VERSION) "." MACRO_STRINGIFY(MINOR_VERSION) "." MACRO_STRINGIFY(BUILD_VERSION) "." MACRO_STRINGIFY(BUILD_REVISION)
--- a/gfx/angle/src/compiler/Compiler.cpp
+++ b/gfx/angle/src/compiler/Compiler.cpp
@@ -1,10 +1,10 @@
 //
-// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
 
 #include "compiler/BuiltInFunctionEmulator.h"
 #include "compiler/DetectRecursion.h"
 #include "compiler/ForLoopUnroll.h"
 #include "compiler/Initialize.h"
@@ -247,17 +247,17 @@ void TCompiler::collectAttribsUniforms(T
 void TCompiler::mapLongVariableNames(TIntermNode* root)
 {
     MapLongVariableNames map(varyingLongNameMap);
     root->traverse(&map);
 }
 
 int TCompiler::getMappedNameMaxLength() const
 {
-    return MAX_IDENTIFIER_NAME_SIZE + 1;
+    return MAX_SHORTENED_IDENTIFIER_SIZE + 1;
 }
 
 const TExtensionBehavior& TCompiler::getExtensionBehavior() const
 {
     return extensionBehavior;
 }
 
 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
--- a/gfx/angle/src/compiler/MapLongVariableNames.cpp
+++ b/gfx/angle/src/compiler/MapLongVariableNames.cpp
@@ -5,38 +5,38 @@
 //
 
 #include "compiler/MapLongVariableNames.h"
 
 namespace {
 
 TString mapLongName(int id, const TString& name, bool isVarying)
 {
-    ASSERT(name.size() > MAX_IDENTIFIER_NAME_SIZE);
+    ASSERT(name.size() > MAX_SHORTENED_IDENTIFIER_SIZE);
     TStringStream stream;
     stream << "webgl_";
     if (isVarying)
         stream << "v";
     stream << id << "_";
-    stream << name.substr(0, MAX_IDENTIFIER_NAME_SIZE - stream.str().size());
+    stream << name.substr(0, MAX_SHORTENED_IDENTIFIER_SIZE - stream.str().size());
     return stream.str();
 }
 
 }  // anonymous namespace
 
 MapLongVariableNames::MapLongVariableNames(
     std::map<std::string, std::string>& varyingLongNameMap)
     : mVaryingLongNameMap(varyingLongNameMap)
 {
 }
 
 void MapLongVariableNames::visitSymbol(TIntermSymbol* symbol)
 {
     ASSERT(symbol != NULL);
-    if (symbol->getSymbol().size() > MAX_IDENTIFIER_NAME_SIZE) {
+    if (symbol->getSymbol().size() > MAX_SHORTENED_IDENTIFIER_SIZE) {
         switch (symbol->getQualifier()) {
           case EvqVaryingIn:
           case EvqVaryingOut:
           case EvqInvariantVaryingIn:
           case EvqInvariantVaryingOut:
             symbol->setSymbol(
                 mapVaryingLongName(symbol->getSymbol()));
             break;
--- a/gfx/angle/src/compiler/MapLongVariableNames.h
+++ b/gfx/angle/src/compiler/MapLongVariableNames.h
@@ -8,20 +8,20 @@
 #define COMPILER_MAP_LONG_VARIABLE_NAMES_H_
 
 #include "GLSLANG/ShaderLang.h"
 
 #include "compiler/intermediate.h"
 #include "compiler/VariableInfo.h"
 
 // This size does not include '\0' in the end.
-#define MAX_IDENTIFIER_NAME_SIZE 32
+#define MAX_SHORTENED_IDENTIFIER_SIZE 32
 
 // Traverses intermediate tree to map attributes and uniforms names that are
-// longer than MAX_IDENTIFIER_NAME_SIZE to MAX_IDENTIFIER_NAME_SIZE.
+// longer than MAX_SHORTENED_IDENTIFIER_SIZE to MAX_SHORTENED_IDENTIFIER_SIZE.
 class MapLongVariableNames : public TIntermTraverser {
 public:
     MapLongVariableNames(std::map<std::string, std::string>& varyingLongNameMap);
 
     virtual void visitSymbol(TIntermSymbol*);
     virtual bool visitLoop(Visit, TIntermLoop*);
 
 private:
--- a/gfx/angle/src/compiler/ParseHelper.cpp
+++ b/gfx/angle/src/compiler/ParseHelper.cpp
@@ -1420,16 +1420,63 @@ TIntermTyped* TParseContext::addConstStr
         recover();
 
         return 0;
     }
 
     return typedNode;
 }
 
+bool TParseContext::enterStructDeclaration(int line, const TString& identifier)
+{
+    ++structNestingLevel;
+
+    // Embedded structure definitions are not supported per GLSL ES spec.
+    // They aren't allowed in GLSL either, but we need to detect this here
+    // so we don't rely on the GLSL compiler to catch it.
+    if (structNestingLevel > 1) {
+        error(line, "", "Embedded struct definitions are not allowed", "");
+        return true;
+    }
+
+    return false;
+}
+
+void TParseContext::exitStructDeclaration()
+{
+    --structNestingLevel;
+}
+
+namespace {
+
+const int kWebGLMaxStructNesting = 4;
+
+}  // namespace
+
+bool TParseContext::structNestingErrorCheck(TSourceLoc line, const TType& fieldType)
+{
+    if (shaderSpec != SH_WEBGL_SPEC) {
+        return false;
+    }
+
+    if (fieldType.getBasicType() != EbtStruct) {
+        return false;
+    }
+
+    // We're already inside a structure definition at this point, so add
+    // one to the field's struct nesting.
+    if (1 + fieldType.getDeepestStructNesting() >= kWebGLMaxStructNesting) {
+        error(line, "", "", "Reference of struct type %s exceeds maximum struct nesting of %d",
+              fieldType.getTypeName().c_str(), kWebGLMaxStructNesting);
+        return true;
+    }
+
+    return false;
+}
+
 //
 // Parse an array of strings using yyparse.
 //
 // Returns 0 for success.
 //
 int PaParseStrings(int count, const char* const string[], const int length[],
                    TParseContext* context) {
     if ((count == 0) || (string == NULL))
--- a/gfx/angle/src/compiler/ParseHelper.h
+++ b/gfx/angle/src/compiler/ParseHelper.h
@@ -26,31 +26,48 @@ struct TPragma {
 };
 
 //
 // The following are extra variables needed during parsing, grouped together so
 // they can be passed to the parser without needing a global.
 //
 struct TParseContext {
     TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) :
-            intermediate(interm), symbolTable(symt), extensionBehavior(ext), infoSink(is), shaderType(type), shaderSpec(spec), compileOptions(options), checksPrecisionErrors(checksPrecErrors), sourcePath(sourcePath), treeRoot(0),
-            numErrors(0), lexAfterType(false), loopNestingLevel(0),
-            inTypeParen(false), contextPragma(true, false), scanner(NULL) {  }
+            intermediate(interm),
+            symbolTable(symt),
+            extensionBehavior(ext),
+            infoSink(is),
+            shaderType(type),
+            shaderSpec(spec),
+            compileOptions(options),
+            sourcePath(sourcePath),
+            treeRoot(0),
+            numErrors(0),
+            lexAfterType(false),
+            loopNestingLevel(0),
+            structNestingLevel(0),
+            inTypeParen(false),
+            currentFunctionType(NULL),
+            functionReturnsValue(false),
+            checksPrecisionErrors(checksPrecErrors),
+            contextPragma(true, false),
+            scanner(NULL) {  }
     TIntermediate& intermediate; // to hold and build a parse tree
     TSymbolTable& symbolTable;   // symbol table that goes with the language currently being parsed
     TExtensionBehavior& extensionBehavior;  // mapping between supported extensions and current behavior.
     TInfoSink& infoSink;
     ShShaderType shaderType;              // vertex or fragment language (future: pack or unpack)
     ShShaderSpec shaderSpec;              // The language specification compiler conforms to - GLES2 or WebGL.
     int compileOptions;
     const char* sourcePath;      // Path of source file or NULL.
     TIntermNode* treeRoot;       // root of parse tree being created
     int numErrors;
     bool lexAfterType;           // true if we've recognized a type, so can only be looking for an identifier
     int loopNestingLevel;        // 0 if outside all loops
+    int structNestingLevel;      // incremented while parsing a struct declaration
     bool inTypeParen;            // true if in parentheses, looking only for an identifier
     const TType* currentFunctionType;  // the return type of the function that's currently being parsed
     bool functionReturnsValue;   // true if a non-void function has a return
     bool checksPrecisionErrors;  // true if an error will be generated when a variable is declared without precision, explicit or implicit.
     struct TPragma contextPragma;
     TString HashErrMsg;
     bool AfterEOF;
     void* scanner;
@@ -100,16 +117,24 @@ struct TParseContext {
     TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, TSourceLoc);
     TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
     TIntermTyped* constructStruct(TIntermNode*, TType*, int, TSourceLoc, bool subset);
     TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, TSourceLoc, bool subset);
     TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc);
     TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc);
     TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line);
     TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc);
+
+    // Performs an error check for embedded struct declarations.
+    // Returns true if an error was raised due to the declaration of
+    // this struct.
+    bool enterStructDeclaration(TSourceLoc line, const TString& identifier);
+    void exitStructDeclaration();
+
+    bool structNestingErrorCheck(TSourceLoc line, const TType& fieldType);
 };
 
 int PaParseStrings(int count, const char* const string[], const int length[],
                    TParseContext* context);
 
 typedef TParseContext* TParseContextPointer;
 extern TParseContextPointer& GetGlobalParseContext();
 #define GlobalParseContext GetGlobalParseContext()
--- a/gfx/angle/src/compiler/ShaderLang.cpp
+++ b/gfx/angle/src/compiler/ShaderLang.cpp
@@ -1,39 +1,45 @@
 //
-// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
 
 //
 // Implement the top-level of interface to the compiler,
 // as defined in ShaderLang.h
 //
 
 #include "GLSLANG/ShaderLang.h"
 
 #include "compiler/InitializeDll.h"
+#include "compiler/preprocessor/length_limits.h"
 #include "compiler/ShHandle.h"
 
 //
 // This is the platform independent interface between an OGL driver
 // and the shading language compiler.
 //
 
-static int getVariableMaxLength(const TVariableInfoList& varList)
+static bool checkActiveUniformAndAttribMaxLengths(const ShHandle handle,
+                                                  int expectedValue)
 {
-    TString::size_type maxLen = 0;
-    for (TVariableInfoList::const_iterator i = varList.begin();
-         i != varList.end(); ++i)
-    {
-        maxLen = std::max(maxLen, i->name.size());
-    }
-    // Add 1 to include null-termination character.
-    return static_cast<int>(maxLen) + 1;
+    int activeUniformLimit = 0;
+    ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit);
+    int activeAttribLimit = 0;
+    ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit);
+    return (expectedValue == activeUniformLimit && expectedValue == activeAttribLimit);
+}
+
+static bool checkMappedNameMaxLength(const ShHandle handle, int expectedValue)
+{
+    int mappedNameMaxLength = 0;
+    ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength);
+    return (expectedValue == mappedNameMaxLength);
 }
 
 static void getVariableInfo(ShShaderInfo varType,
                             const ShHandle handle,
                             int index,
                             int* length,
                             int* size,
                             ShDataType* type,
@@ -54,19 +60,30 @@ static void getVariableInfo(ShShaderInfo
         compiler->getAttribs() : compiler->getUniforms();
     if (index < 0 || index >= static_cast<int>(varList.size()))
         return;
 
     const TVariableInfo& varInfo = varList[index];
     if (length) *length = varInfo.name.size();
     *size = varInfo.size;
     *type = varInfo.type;
-    strcpy(name, varInfo.name.c_str());
-    if (mappedName)
-        strcpy(mappedName, varInfo.mappedName.c_str());
+
+    // This size must match that queried by
+    // SH_ACTIVE_UNIFORM_MAX_LENGTH and SH_ACTIVE_ATTRIBUTE_MAX_LENGTH
+    // in ShGetInfo, below.
+    int activeUniformAndAttribLength = 1 + MAX_SYMBOL_NAME_LEN;
+    ASSERT(checkActiveUniformAndAttribMaxLengths(handle, activeUniformAndAttribLength));
+    strncpy(name, varInfo.name.c_str(), activeUniformAndAttribLength);
+    if (mappedName) {
+        // This size must match that queried by
+        // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below.
+        int maxMappedNameLength = 1 + MAX_SYMBOL_NAME_LEN;
+        ASSERT(checkMappedNameMaxLength(handle, maxMappedNameLength));
+        strncpy(mappedName, varInfo.mappedName.c_str(), maxMappedNameLength);
+    }
 }
 
 //
 // Driver must call this first, once, before doing any other
 // compiler operations.
 //
 int ShInitialize()
 {
@@ -186,26 +203,28 @@ void ShGetInfo(const ShHandle handle, Sh
         break;
     case SH_OBJECT_CODE_LENGTH:
         *params = compiler->getInfoSink().obj.size() + 1;
         break;
     case SH_ACTIVE_UNIFORMS:
         *params = compiler->getUniforms().size();
         break;
     case SH_ACTIVE_UNIFORM_MAX_LENGTH:
-        *params = getVariableMaxLength(compiler->getUniforms());
+        *params = 1 +  MAX_SYMBOL_NAME_LEN;
         break;
     case SH_ACTIVE_ATTRIBUTES:
         *params = compiler->getAttribs().size();
         break;
     case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
-        *params = getVariableMaxLength(compiler->getAttribs());
+        *params = 1 + MAX_SYMBOL_NAME_LEN;
         break;
     case SH_MAPPED_NAME_MAX_LENGTH:
-        *params = compiler->getMappedNameMaxLength();
+        // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to
+        // handle array and struct dereferences.
+        *params = 1 + MAX_SYMBOL_NAME_LEN;
         break;
     default: UNREACHABLE();
     }
 }
 
 //
 // Return any compiler log of messages for the application.
 //
--- a/gfx/angle/src/compiler/SymbolTable.cpp
+++ b/gfx/angle/src/compiler/SymbolTable.cpp
@@ -8,16 +8,18 @@
 // Symbol table for parsing.  Most functionaliy and main ideas
 // are documented in the header file.
 //
 
 #include "compiler/SymbolTable.h"
 
 #include <stdio.h>
 
+#include <algorithm>
+
 //
 // TType helper function needs a place to live.
 //
 
 //
 // Recursively generate mangled names.
 //
 void TType::buildMangledName(TString& mangledName)
@@ -66,16 +68,30 @@ int TType::getStructSize() const
 
     if (structureSize == 0)
         for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
             structureSize += ((*tl).type)->getObjectSize();
 
     return structureSize;
 }
 
+void TType::computeDeepestStructNesting()
+{
+    if (!getStruct()) {
+        return;
+    }
+
+    int maxNesting = 0;
+    for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); ++tl) {
+        maxNesting = std::max(maxNesting, ((*tl).type)->getDeepestStructNesting());
+    }
+
+    deepestStructNesting = 1 + maxNesting;
+}
+
 //
 // Dump functions.
 //
 
 void TVariable::dump(TInfoSink& infoSink) const
 {
     infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString();
     if (type.isArray()) {
--- a/gfx/angle/src/compiler/Types.h
+++ b/gfx/angle/src/compiler/Types.h
@@ -80,31 +80,32 @@ typedef TMap<TTypeList*, TTypeList*>::it
 // Base class for things that have a type.
 //
 class TType {
 public:
     POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
     TType() {}
     TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) :
             type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0),
-            maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), fieldName(0), mangled(0), typeName(0)
+            maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0)
     {
     }
     explicit TType(const TPublicType &p) :
             type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize),
-            maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), fieldName(0), mangled(0), typeName(0)
+            maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0)
     {
         if (p.userDef) {
             structure = p.userDef->getStruct();
             typeName = NewPoolTString(p.userDef->getTypeName().c_str());
+            computeDeepestStructNesting();
         }
     }
     TType(TTypeList* userDef, const TString& n, TPrecision p = EbpUndefined) :
             type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0),
-            maxArraySize(0), arrayInformationType(0), structure(userDef), structureSize(0), fieldName(0), mangled(0)
+            maxArraySize(0), arrayInformationType(0), structure(userDef), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0)
     {
         typeName = NewPoolTString(n.c_str());
     }
 
     void copyType(const TType& copyOf, TStructureMap& remapper)
     {
         type = copyOf.type;
         precision = copyOf.precision;
@@ -139,16 +140,17 @@ public:
             typeName = NewPoolTString(copyOf.typeName->c_str());
 
         mangled = 0;
         if (copyOf.mangled)
             mangled = NewPoolTString(copyOf.mangled->c_str());
 
         structureSize = copyOf.structureSize;
         maxArraySize = copyOf.maxArraySize;
+        deepestStructNesting = copyOf.deepestStructNesting;
         assert(copyOf.arrayInformationType == 0);
         arrayInformationType = 0; // arrayInformationType should not be set for builtIn symbol table level
     }
 
     TType* clone(TStructureMap& remapper)
     {
         TType *newType = new TType();
         newType->copyType(*this, remapper);
@@ -197,17 +199,17 @@ public:
     void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; }
     void setArrayInformationType(TType* t) { arrayInformationType = t; }
     TType* getArrayInformationType() const { return arrayInformationType; }
 
     bool isVector() const { return size > 1 && !matrix; }
     bool isScalar() const { return size == 1 && !matrix && !structure; }
 
     TTypeList* getStruct() const { return structure; }
-    void setStruct(TTypeList* s) { structure = s; }
+    void setStruct(TTypeList* s) { structure = s; computeDeepestStructNesting(); }
 
     const TString& getTypeName() const
     {
         assert(typeName);
         return *typeName;
     }
     void setTypeName(const TString& n)
     {
@@ -263,31 +265,47 @@ public:
         return false;
     }
 
     const char* getBasicString() const { return ::getBasicString(type); }
     const char* getPrecisionString() const { return ::getPrecisionString(precision); }
     const char* getQualifierString() const { return ::getQualifierString(qualifier); }
     TString getCompleteString() const;
 
+    // If this type is a struct, returns the deepest struct nesting of
+    // any field in the struct. For example:
+    //   struct nesting1 {
+    //     vec4 position;
+    //   };
+    //   struct nesting2 {
+    //     nesting1 field1;
+    //     vec4 field2;
+    //   };
+    // For type "nesting2", this method would return 2 -- the number
+    // of structures through which indirection must occur to reach the
+    // deepest field (nesting2.field1.position).
+    int getDeepestStructNesting() const { return deepestStructNesting; }
+
 protected:
     void buildMangledName(TString&);
     int getStructSize() const;
+    void computeDeepestStructNesting();
 
     TBasicType type      : 6;
     TPrecision precision;
     TQualifier qualifier : 7;
     int size             : 8; // size of vector or matrix, not size of array
     unsigned int matrix  : 1;
     unsigned int array   : 1;
     int arraySize;
     int maxArraySize;
     TType* arrayInformationType;
 
     TTypeList* structure;      // 0 unless this is a struct
     mutable int structureSize;
+    int deepestStructNesting;
 
     TString *fieldName;         // for structure field names
     TString *mangled;
     TString *typeName;          // for structure field type name
 };
 
 #endif // _TYPES_INCLUDED_
--- a/gfx/angle/src/compiler/glslang.y
+++ b/gfx/angle/src/compiler/glslang.y
@@ -1637,33 +1637,35 @@ type_specifier_nonarray
         TType& structure = static_cast<TVariable*>($1.symbol)->getType();
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         $$.setBasic(EbtStruct, qual, $1.line);
         $$.userDef = &structure;
     }
     ;
 
 struct_specifier
-    : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE {
+    : STRUCT IDENTIFIER LEFT_BRACE { if (context->enterStructDeclaration($2.line, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
         if (context->reservedErrorCheck($2.line, *$2.string))
             context->recover();
 
-        TType* structure = new TType($4, *$2.string);
+        TType* structure = new TType($5, *$2.string);
         TVariable* userTypeDef = new TVariable($2.string, *structure, true);
         if (! context->symbolTable.insert(*userTypeDef)) {
             context->error($2.line, "redefinition", $2.string->c_str(), "struct");
             context->recover();
         }
         $$.setBasic(EbtStruct, EvqTemporary, $1.line);
         $$.userDef = structure;
+        context->exitStructDeclaration();
     }
-    | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE {
-        TType* structure = new TType($3, TString(""));
+    | STRUCT LEFT_BRACE { if (context->enterStructDeclaration($2.line, *$2.string)) context->recover(); } struct_declaration_list RIGHT_BRACE {
+        TType* structure = new TType($4, TString(""));
         $$.setBasic(EbtStruct, EvqTemporary, $1.line);
         $$.userDef = structure;
+        context->exitStructDeclaration();
     }
     ;
 
 struct_declaration_list
     : struct_declaration {
         $$ = $1;
     }
     | struct_declaration_list struct_declaration {
@@ -1703,16 +1705,20 @@ struct_declaration
                     context->recover();
             }
             if ($1.array)
                 type->setArraySize($1.arraySize);
             if ($1.userDef) {
                 type->setStruct($1.userDef->getStruct());
                 type->setTypeName($1.userDef->getTypeName());
             }
+
+            if (context->structNestingErrorCheck($1.line, *type)) {
+                context->recover();
+            }
         }
     }
     ;
 
 struct_declarator_list
     : struct_declarator {
         $$ = NewPoolTTypeList();
         $$->push_back($1);
--- a/gfx/angle/src/compiler/glslang_tab.cpp
+++ b/gfx/angle/src/compiler/glslang_tab.cpp
@@ -322,17 +322,17 @@ typedef union YYSTYPE
             TQualifier qualifier;
             TFunction* function;
             TParameter param;
             TTypeLine typeLine;
             TTypeList* typeList;
         };
     } interm;
 }
-/* Line 187 of yacc.c.  */
+/* Line 193 of yacc.c.  */
 
 	YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 # define YYSTYPE_IS_TRIVIAL 1
 #endif
 
 
@@ -412,17 +412,17 @@ typedef short int yytype_int16;
 # else
 #  define YYSIZE_T unsigned int
 # endif
 #endif
 
 #define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
 
 #ifndef YY_
-# if YYENABLE_NLS
+# if defined YYENABLE_NLS && YYENABLE_NLS
 #  if ENABLE_NLS
 #   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
 #   define YY_(msgid) dgettext ("bison-runtime", msgid)
 #  endif
 # endif
 # ifndef YY_
 #  define YY_(msgid) msgid
 # endif
@@ -577,26 +577,26 @@ union yyalloc
       }									\
     while (YYID (0))
 
 #endif
 
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  70
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   1381
+#define YYLAST   1327
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  95
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  78
+#define YYNNTS  80
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  194
+#define YYNRULES  196
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  297
+#define YYNSTATES  299
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
 #define YYMAXUTOK   349
 
 #define YYTRANSLATE(YYX)						\
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
 
@@ -653,29 +653,29 @@ static const yytype_uint16 yyprhs[] =
      140,   142,   144,   146,   148,   152,   154,   158,   160,   164,
      166,   172,   174,   178,   180,   182,   184,   186,   188,   190,
      194,   196,   199,   202,   207,   210,   212,   214,   217,   221,
      225,   228,   234,   238,   241,   245,   248,   249,   251,   253,
      255,   257,   259,   263,   269,   276,   282,   284,   287,   292,
      298,   303,   306,   308,   311,   313,   315,   317,   320,   322,
      324,   327,   329,   331,   333,   335,   340,   342,   344,   346,
      348,   350,   352,   354,   356,   358,   360,   362,   364,   366,
-     368,   370,   372,   374,   376,   378,   380,   382,   388,   393,
-     395,   398,   402,   404,   408,   410,   415,   417,   419,   421,
-     423,   425,   427,   429,   431,   433,   436,   437,   438,   444,
-     446,   448,   451,   455,   457,   460,   462,   465,   471,   475,
-     477,   479,   484,   485,   492,   493,   502,   503,   511,   513,
-     515,   517,   518,   521,   525,   528,   531,   534,   538,   541,
-     543,   546,   548,   550,   551
+     368,   370,   372,   374,   376,   378,   380,   382,   383,   390,
+     391,   397,   399,   402,   406,   408,   412,   414,   419,   421,
+     423,   425,   427,   429,   431,   433,   435,   437,   440,   441,
+     442,   448,   450,   452,   455,   459,   461,   464,   466,   469,
+     475,   479,   481,   483,   488,   489,   496,   497,   506,   507,
+     515,   517,   519,   521,   522,   525,   529,   532,   535,   538,
+     542,   545,   547,   550,   552,   554,   555
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int16 yyrhs[] =
 {
-     169,     0,    -1,    44,    -1,    96,    -1,    47,    -1,    46,
+     171,     0,    -1,    44,    -1,    96,    -1,    47,    -1,    46,
       -1,    48,    -1,    71,   123,    72,    -1,    97,    -1,    98,
       73,    99,    74,    -1,   100,    -1,    98,    77,    49,    -1,
       98,    52,    -1,    98,    53,    -1,   123,    -1,   101,    -1,
      102,    -1,    98,    77,   102,    -1,   104,    72,    -1,   103,
       72,    -1,   105,    39,    -1,   105,    -1,   105,   121,    -1,
      104,    78,   121,    -1,   106,    71,    -1,   141,    -1,    44,
       -1,    49,    -1,    98,    -1,    52,   107,    -1,    53,   107,
       -1,   108,   107,    -1,    85,    -1,    83,    -1,    82,    -1,
@@ -693,44 +693,44 @@ static const yytype_int16 yyrhs[] =
       81,    -1,     7,   139,   140,    81,    -1,   127,    72,    -1,
      129,    -1,   128,    -1,   129,   131,    -1,   128,    78,   131,
       -1,   136,    44,    71,    -1,   138,    44,    -1,   138,    44,
       73,   124,    74,    -1,   137,   132,   130,    -1,   132,   130,
       -1,   137,   132,   133,    -1,   132,   133,    -1,    -1,    33,
       -1,    34,    -1,    35,    -1,   138,    -1,   135,    -1,   134,
       78,    44,    -1,   134,    78,    44,    73,    74,    -1,   134,
       78,    44,    73,   124,    74,    -1,   134,    78,    44,    80,
-     147,    -1,   136,    -1,   136,    44,    -1,   136,    44,    73,
+     149,    -1,   136,    -1,   136,    44,    -1,   136,    44,    73,
       74,    -1,   136,    44,    73,   124,    74,    -1,   136,    44,
-      80,   147,    -1,     3,    44,    -1,   138,    -1,   137,   138,
+      80,   149,    -1,     3,    44,    -1,   138,    -1,   137,   138,
       -1,     9,    -1,     8,    -1,    37,    -1,     3,    37,    -1,
       36,    -1,   140,    -1,   139,   140,    -1,     4,    -1,     5,
       -1,     6,    -1,   141,    -1,   141,    73,   124,    74,    -1,
       39,    -1,    11,    -1,    12,    -1,    10,    -1,    27,    -1,
       28,    -1,    29,    -1,    21,    -1,    22,    -1,    23,    -1,
       24,    -1,    25,    -1,    26,    -1,    30,    -1,    31,    -1,
       32,    -1,    41,    -1,    42,    -1,    43,    -1,   142,    -1,
-      45,    -1,    38,    44,    75,   143,    76,    -1,    38,    75,
-     143,    76,    -1,   144,    -1,   143,   144,    -1,   138,   145,
-      81,    -1,   146,    -1,   145,    78,   146,    -1,    44,    -1,
-      44,    73,   124,    74,    -1,   121,    -1,   125,    -1,   151,
-      -1,   150,    -1,   148,    -1,   157,    -1,   158,    -1,   161,
-      -1,   168,    -1,    75,    76,    -1,    -1,    -1,    75,   152,
-     156,   153,    76,    -1,   155,    -1,   150,    -1,    75,    76,
-      -1,    75,   156,    76,    -1,   149,    -1,   156,   149,    -1,
-      81,    -1,   123,    81,    -1,    18,    71,   123,    72,   159,
-      -1,   149,    16,   149,    -1,   149,    -1,   123,    -1,   136,
-      44,    80,   147,    -1,    -1,    40,    71,   162,   160,    72,
-     154,    -1,    -1,    15,   163,   149,    40,    71,   123,    72,
-      81,    -1,    -1,    17,    71,   164,   165,   167,    72,   154,
-      -1,   157,    -1,   148,    -1,   160,    -1,    -1,   166,    81,
-      -1,   166,    81,   123,    -1,    14,    81,    -1,    13,    81,
-      -1,    20,    81,    -1,    20,   123,    81,    -1,    19,    81,
-      -1,   170,    -1,   169,   170,    -1,   171,    -1,   125,    -1,
-      -1,   126,   172,   155,    -1
+      45,    -1,    -1,    38,    44,    75,   143,   145,    76,    -1,
+      -1,    38,    75,   144,   145,    76,    -1,   146,    -1,   145,
+     146,    -1,   138,   147,    81,    -1,   148,    -1,   147,    78,
+     148,    -1,    44,    -1,    44,    73,   124,    74,    -1,   121,
+      -1,   125,    -1,   153,    -1,   152,    -1,   150,    -1,   159,
+      -1,   160,    -1,   163,    -1,   170,    -1,    75,    76,    -1,
+      -1,    -1,    75,   154,   158,   155,    76,    -1,   157,    -1,
+     152,    -1,    75,    76,    -1,    75,   158,    76,    -1,   151,
+      -1,   158,   151,    -1,    81,    -1,   123,    81,    -1,    18,
+      71,   123,    72,   161,    -1,   151,    16,   151,    -1,   151,
+      -1,   123,    -1,   136,    44,    80,   149,    -1,    -1,    40,
+      71,   164,   162,    72,   156,    -1,    -1,    15,   165,   151,
+      40,    71,   123,    72,    81,    -1,    -1,    17,    71,   166,
+     167,   169,    72,   156,    -1,   159,    -1,   150,    -1,   162,
+      -1,    -1,   168,    81,    -1,   168,    81,   123,    -1,    14,
+      81,    -1,    13,    81,    -1,    20,    81,    -1,    20,   123,
+      81,    -1,    19,    81,    -1,   172,    -1,   171,   172,    -1,
+     173,    -1,   125,    -1,    -1,   126,   174,   157,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
        0,   153,   153,   188,   191,   204,   209,   214,   220,   223,
      296,   299,   408,   418,   431,   439,   538,   541,   549,   553,
      560,   564,   571,   577,   586,   594,   649,   656,   666,   669,
@@ -739,23 +739,23 @@ static const yytype_uint16 yyrline[] =
      831,   835,   839,   843,   844,   857,   858,   871,   872,   885,
      886,   903,   904,   917,   918,   919,   920,   921,   925,   928,
      939,   947,   972,   977,   984,  1020,  1023,  1030,  1038,  1059,
     1078,  1089,  1118,  1123,  1133,  1138,  1148,  1151,  1154,  1157,
     1163,  1170,  1173,  1189,  1207,  1231,  1254,  1258,  1276,  1284,
     1316,  1336,  1412,  1421,  1444,  1447,  1453,  1461,  1469,  1477,
     1487,  1494,  1497,  1500,  1506,  1509,  1524,  1528,  1532,  1536,
     1545,  1550,  1555,  1560,  1565,  1570,  1575,  1580,  1585,  1590,
-    1596,  1602,  1608,  1613,  1618,  1627,  1632,  1645,  1658,  1666,
-    1669,  1684,  1716,  1720,  1726,  1734,  1750,  1754,  1758,  1759,
-    1765,  1766,  1767,  1768,  1769,  1773,  1774,  1774,  1774,  1784,
-    1785,  1790,  1793,  1803,  1806,  1812,  1813,  1817,  1825,  1829,
-    1839,  1844,  1861,  1861,  1866,  1866,  1873,  1873,  1881,  1884,
-    1890,  1893,  1899,  1903,  1910,  1917,  1924,  1931,  1942,  1951,
-    1955,  1962,  1965,  1971,  1971
+    1596,  1602,  1608,  1613,  1618,  1627,  1632,  1645,  1645,  1659,
+    1659,  1668,  1671,  1686,  1722,  1726,  1732,  1740,  1756,  1760,
+    1764,  1765,  1771,  1772,  1773,  1774,  1775,  1779,  1780,  1780,
+    1780,  1790,  1791,  1796,  1799,  1809,  1812,  1818,  1819,  1823,
+    1831,  1835,  1845,  1850,  1867,  1867,  1872,  1872,  1879,  1879,
+    1887,  1890,  1896,  1899,  1905,  1909,  1916,  1923,  1930,  1937,
+    1948,  1957,  1961,  1968,  1971,  1977,  1977
 };
 #endif
 
 #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
@@ -789,26 +789,26 @@ static const char *const yytname[] =
   "assignment_expression", "assignment_operator", "expression",
   "constant_expression", "declaration", "function_prototype",
   "function_declarator", "function_header_with_parameters",
   "function_header", "parameter_declarator", "parameter_declaration",
   "parameter_qualifier", "parameter_type_specifier",
   "init_declarator_list", "single_declaration", "fully_specified_type",
   "type_qualifier", "type_specifier", "precision_qualifier",
   "type_specifier_no_prec", "type_specifier_nonarray", "struct_specifier",
-  "struct_declaration_list", "struct_declaration",
+  "@1", "@2", "struct_declaration_list", "struct_declaration",
   "struct_declarator_list", "struct_declarator", "initializer",
   "declaration_statement", "statement", "simple_statement",
-  "compound_statement", "@1", "@2", "statement_no_new_scope",
+  "compound_statement", "@3", "@4", "statement_no_new_scope",
   "compound_statement_no_new_scope", "statement_list",
   "expression_statement", "selection_statement",
-  "selection_rest_statement", "condition", "iteration_statement", "@3",
-  "@4", "@5", "for_init_statement", "conditionopt", "for_rest_statement",
+  "selection_rest_statement", "condition", "iteration_statement", "@5",
+  "@6", "@7", "for_init_statement", "conditionopt", "for_rest_statement",
   "jump_statement", "translation_unit", "external_declaration",
-  "function_definition", "@6", 0
+  "function_definition", "@8", 0
 };
 #endif
 
 # ifdef YYPRINT
 /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
    token YYLEX-NUM.  */
 static const yytype_uint16 yytoknum[] =
 {
@@ -836,23 +836,23 @@ static const yytype_uint8 yyr1[] =
      114,   115,   116,   117,   117,   118,   118,   119,   119,   120,
      120,   121,   121,   122,   122,   122,   122,   122,   123,   123,
      124,   125,   125,   125,   126,   127,   127,   128,   128,   129,
      130,   130,   131,   131,   131,   131,   132,   132,   132,   132,
      133,   134,   134,   134,   134,   134,   135,   135,   135,   135,
      135,   135,   136,   136,   137,   137,   137,   137,   137,   138,
      138,   139,   139,   139,   140,   140,   141,   141,   141,   141,
      141,   141,   141,   141,   141,   141,   141,   141,   141,   141,
-     141,   141,   141,   141,   141,   141,   141,   142,   142,   143,
-     143,   144,   145,   145,   146,   146,   147,   148,   149,   149,
-     150,   150,   150,   150,   150,   151,   152,   153,   151,   154,
-     154,   155,   155,   156,   156,   157,   157,   158,   159,   159,
-     160,   160,   162,   161,   163,   161,   164,   161,   165,   165,
-     166,   166,   167,   167,   168,   168,   168,   168,   168,   169,
-     169,   170,   170,   172,   171
+     141,   141,   141,   141,   141,   141,   141,   143,   142,   144,
+     142,   145,   145,   146,   147,   147,   148,   148,   149,   150,
+     151,   151,   152,   152,   152,   152,   152,   153,   154,   155,
+     153,   156,   156,   157,   157,   158,   158,   159,   159,   160,
+     161,   161,   162,   162,   164,   163,   165,   163,   166,   163,
+     167,   167,   168,   168,   169,   169,   170,   170,   170,   170,
+     170,   171,   171,   172,   172,   174,   173
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
        0,     2,     1,     1,     1,     1,     1,     3,     1,     4,
        1,     3,     2,     2,     1,     1,     1,     3,     2,     2,
        2,     1,     2,     3,     2,     1,     1,     1,     1,     2,
@@ -861,450 +861,438 @@ static const yytype_uint8 yyr2[] =
        1,     1,     1,     1,     3,     1,     3,     1,     3,     1,
        5,     1,     3,     1,     1,     1,     1,     1,     1,     3,
        1,     2,     2,     4,     2,     1,     1,     2,     3,     3,
        2,     5,     3,     2,     3,     2,     0,     1,     1,     1,
        1,     1,     3,     5,     6,     5,     1,     2,     4,     5,
        4,     2,     1,     2,     1,     1,     1,     2,     1,     1,
        2,     1,     1,     1,     1,     4,     1,     1,     1,     1,
        1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     1,     1,     1,     1,     1,     1,     5,     4,     1,
-       2,     3,     1,     3,     1,     4,     1,     1,     1,     1,
-       1,     1,     1,     1,     1,     2,     0,     0,     5,     1,
-       1,     2,     3,     1,     2,     1,     2,     5,     3,     1,
-       1,     4,     0,     6,     0,     8,     0,     7,     1,     1,
-       1,     0,     2,     3,     2,     2,     2,     3,     2,     1,
-       2,     1,     1,     0,     3
+       1,     1,     1,     1,     1,     1,     1,     0,     6,     0,
+       5,     1,     2,     3,     1,     3,     1,     4,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     2,     0,     0,
+       5,     1,     1,     2,     3,     1,     2,     1,     2,     5,
+       3,     1,     1,     4,     0,     6,     0,     8,     0,     7,
+       1,     1,     1,     0,     2,     3,     2,     2,     2,     3,
+       2,     1,     2,     1,     1,     0,     3
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
    STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
        0,     0,   111,   112,   113,     0,   105,   104,   119,   117,
      118,   123,   124,   125,   126,   127,   128,   120,   121,   122,
      129,   130,   131,   108,   106,     0,   116,   132,   133,   134,
-     136,   192,   193,     0,    76,    86,     0,    91,    96,     0,
-     102,     0,   109,   114,   135,     0,   189,   191,   107,   101,
-       0,     0,     0,    71,     0,    74,    86,     0,    87,    88,
+     136,   194,   195,     0,    76,    86,     0,    91,    96,     0,
+     102,     0,   109,   114,   135,     0,   191,   193,   107,   101,
+       0,     0,   139,    71,     0,    74,    86,     0,    87,    88,
       89,    77,     0,    86,     0,    72,    97,   103,   110,     0,
-       1,   190,     0,     0,     0,     0,   139,     0,   194,    78,
-      83,    85,    90,     0,    92,    79,     0,     0,     2,     5,
-       4,     6,    27,     0,     0,     0,    34,    33,    32,     3,
-       8,    28,    10,    15,    16,     0,     0,    21,     0,    35,
-       0,    38,    41,    42,    47,    50,    51,    52,    53,    55,
-      57,    59,    70,     0,    25,    73,     0,   144,     0,   142,
-     138,   140,     0,     0,   174,     0,     0,     0,     0,     0,
-     156,   161,   165,    35,    61,    68,     0,   147,     0,   114,
-     150,   163,   149,   148,     0,   151,   152,   153,   154,    80,
-      82,    84,     0,     0,    98,     0,   146,   100,    29,    30,
-       0,    12,    13,     0,     0,    19,    18,     0,    20,    22,
-      24,    31,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   115,   137,     0,     0,
-     141,   185,   184,     0,   176,     0,   188,   186,     0,   172,
-     155,     0,    64,    65,    66,    67,    63,     0,     0,   166,
-     162,   164,     0,    93,     0,    95,    99,     7,     0,    14,
-      26,    11,    17,    23,    36,    37,    40,    39,    45,    46,
-      43,    44,    48,    49,    54,    56,    58,     0,     0,   143,
-       0,     0,     0,   187,     0,   157,    62,    69,     0,    94,
-       9,     0,   145,     0,   179,   178,   181,     0,   170,     0,
-       0,     0,    81,    60,     0,   180,     0,     0,   169,   167,
-       0,     0,   158,     0,   182,     0,     0,     0,   160,   173,
-     159,     0,   183,   177,   168,   171,   175
+       1,   192,     0,   137,     0,     0,   196,    78,    83,    85,
+      90,     0,    92,    79,     0,     0,     2,     5,     4,     6,
+      27,     0,     0,     0,    34,    33,    32,     3,     8,    28,
+      10,    15,    16,     0,     0,    21,     0,    35,     0,    38,
+      41,    42,    47,    50,    51,    52,    53,    55,    57,    59,
+      70,     0,    25,    73,     0,     0,     0,   141,     0,     0,
+     176,     0,     0,     0,     0,     0,   158,   163,   167,    35,
+      61,    68,     0,   149,     0,   114,   152,   165,   151,   150,
+       0,   153,   154,   155,   156,    80,    82,    84,     0,     0,
+      98,     0,   148,   100,    29,    30,     0,    12,    13,     0,
+       0,    19,    18,     0,    20,    22,    24,    31,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   115,     0,   146,     0,   144,   140,   142,   187,
+     186,     0,   178,     0,   190,   188,     0,   174,   157,     0,
+      64,    65,    66,    67,    63,     0,     0,   168,   164,   166,
+       0,    93,     0,    95,    99,     7,     0,    14,    26,    11,
+      17,    23,    36,    37,    40,    39,    45,    46,    43,    44,
+      48,    49,    54,    56,    58,     0,   138,     0,     0,   143,
+       0,     0,     0,   189,     0,   159,    62,    69,     0,    94,
+       9,     0,     0,   145,     0,   181,   180,   183,     0,   172,
+       0,     0,     0,    81,    60,   147,     0,   182,     0,     0,
+     171,   169,     0,     0,   160,     0,   184,     0,     0,     0,
+     162,   175,   161,     0,   185,   179,   170,   173,   177
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,    99,   100,   101,   228,   102,   103,   104,   105,   106,
-     107,   108,   143,   110,   111,   112,   113,   114,   115,   116,
-     117,   118,   119,   120,   121,   144,   145,   217,   146,   123,
-     147,   148,    33,    34,    35,    80,    61,    62,    81,    36,
-      37,    38,    39,    40,    41,    42,   124,    44,    75,    76,
-     128,   129,   167,   150,   151,   152,   153,   211,   271,   289,
-     290,   154,   155,   156,   279,   270,   157,   254,   203,   251,
-     266,   276,   277,   158,    45,    46,    47,    54
+      -1,    97,    98,    99,   226,   100,   101,   102,   103,   104,
+     105,   106,   139,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   140,   141,   215,   142,   121,
+     143,   144,    33,    34,    35,    78,    61,    62,    79,    36,
+      37,    38,    39,    40,    41,    42,   122,    44,   124,    74,
+     126,   127,   195,   196,   163,   146,   147,   148,   149,   209,
+     272,   291,   292,   150,   151,   152,   281,   271,   153,   254,
+     201,   251,   267,   278,   279,   154,    45,    46,    47,    54
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -251
+#define YYPACT_NINF -242
 static const yytype_int16 yypact[] =
 {
-    1233,   -19,  -251,  -251,  -251,   130,  -251,  -251,  -251,  -251,
-    -251,  -251,  -251,  -251,  -251,  -251,  -251,  -251,  -251,  -251,
-    -251,  -251,  -251,  -251,  -251,   -24,  -251,  -251,  -251,  -251,
-    -251,  -251,   -62,    -6,    17,    34,   -20,  -251,    36,  1275,
-    -251,  1336,  -251,    32,  -251,  1190,  -251,  -251,  -251,  -251,
-    1336,    44,  1275,  -251,    47,  -251,    51,    78,  -251,  -251,
-    -251,  -251,  1275,   109,    81,  -251,   -50,  -251,  -251,   959,
-    -251,  -251,    56,  1275,   102,  1092,  -251,   284,  -251,  -251,
-    -251,  -251,   111,  1275,   -44,  -251,   764,   959,    87,  -251,
-    -251,  -251,  -251,   959,   959,   959,  -251,  -251,  -251,  -251,
-    -251,    37,  -251,  -251,  -251,    89,    22,  1024,    88,  -251,
-     959,   -54,    -9,  -251,   -43,    92,  -251,  -251,  -251,   105,
-     104,   -45,  -251,    91,  -251,  -251,  1134,    93,    15,  -251,
-    -251,  -251,    86,    90,  -251,    97,    98,    94,   829,    99,
-     101,  -251,  -251,     2,  -251,  -251,    31,  -251,   -62,    74,
-    -251,  -251,  -251,  -251,   367,  -251,  -251,  -251,  -251,   100,
-    -251,  -251,   894,   959,  -251,   107,  -251,  -251,  -251,  -251,
-      25,  -251,  -251,   959,  1300,  -251,  -251,   959,   103,  -251,
-    -251,  -251,   959,   959,   959,   959,   959,   959,   959,   959,
-     959,   959,   959,   959,   959,   959,  -251,  -251,   959,   102,
-    -251,  -251,  -251,   450,  -251,   959,  -251,  -251,    40,  -251,
-    -251,   450,  -251,  -251,  -251,  -251,  -251,   959,   959,  -251,
-    -251,  -251,   959,  -251,   108,  -251,  -251,  -251,   110,   113,
-    -251,   112,  -251,  -251,  -251,  -251,   -54,   -54,  -251,  -251,
-    -251,  -251,   -43,   -43,  -251,   105,   104,    72,   114,  -251,
-     138,   616,    26,  -251,   699,   450,  -251,  -251,   115,  -251,
-    -251,   959,  -251,   116,  -251,  -251,   699,   450,   113,   135,
-     121,   118,  -251,  -251,   959,  -251,   117,   123,   169,  -251,
-     106,   533,  -251,    35,   959,   533,   450,   959,  -251,  -251,
-    -251,   119,   113,  -251,  -251,  -251,  -251
+    1179,    -6,  -242,  -242,  -242,   151,  -242,  -242,  -242,  -242,
+    -242,  -242,  -242,  -242,  -242,  -242,  -242,  -242,  -242,  -242,
+    -242,  -242,  -242,  -242,  -242,   -39,  -242,  -242,  -242,  -242,
+    -242,  -242,   -69,   -37,   -32,    21,   -61,  -242,    26,  1221,
+    -242,  1282,  -242,   -58,  -242,   207,  -242,  -242,  -242,  -242,
+    1282,    22,  -242,  -242,    33,  -242,    70,    88,  -242,  -242,
+    -242,  -242,  1221,   125,    42,  -242,    -8,  -242,  -242,   961,
+    -242,  -242,    72,  -242,  1221,   286,  -242,  -242,  -242,  -242,
+     117,  1221,   -57,  -242,   766,   961,    94,  -242,  -242,  -242,
+    -242,   961,   961,   961,  -242,  -242,  -242,  -242,  -242,    14,
+    -242,  -242,  -242,    99,   -35,  1026,   101,  -242,   961,   -27,
+      46,  -242,   -21,    56,  -242,  -242,  -242,   115,   119,   -45,
+    -242,   103,  -242,  -242,  1221,   136,  1094,  -242,   102,   104,
+    -242,   111,   116,   105,   831,   118,   112,  -242,  -242,    39,
+    -242,  -242,    17,  -242,   -69,    93,  -242,  -242,  -242,  -242,
+     369,  -242,  -242,  -242,  -242,   122,  -242,  -242,   896,   961,
+    -242,   123,  -242,  -242,  -242,  -242,    10,  -242,  -242,   961,
+    1246,  -242,  -242,   961,   120,  -242,  -242,  -242,   961,   961,
+     961,   961,   961,   961,   961,   961,   961,   961,   961,   961,
+     961,   961,  -242,  1136,   126,    49,  -242,  -242,  -242,  -242,
+    -242,   452,  -242,   961,  -242,  -242,    71,  -242,  -242,   452,
+    -242,  -242,  -242,  -242,  -242,   961,   961,  -242,  -242,  -242,
+     961,  -242,   124,  -242,  -242,  -242,   128,   114,  -242,   129,
+    -242,  -242,  -242,  -242,   -27,   -27,  -242,  -242,  -242,  -242,
+     -21,   -21,  -242,   115,   119,    89,  -242,   961,   136,  -242,
+     150,   618,    11,  -242,   701,   452,  -242,  -242,   130,  -242,
+    -242,   961,   131,  -242,   137,  -242,  -242,   701,   452,   114,
+     152,   148,   145,  -242,  -242,  -242,   961,  -242,   141,   153,
+     208,  -242,   143,   535,  -242,    38,   961,   535,   452,   961,
+    -242,  -242,  -242,   146,   114,  -242,  -242,  -242,  -242
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -251,  -251,  -251,  -251,  -251,  -251,  -251,    23,  -251,  -251,
-    -251,  -251,    30,  -251,   -32,  -251,   -58,   -34,  -251,  -251,
-    -251,     4,     6,     7,  -251,   -60,   -85,  -251,   -94,   -81,
-       8,    10,  -251,  -251,  -251,   122,   148,   143,   124,  -251,
-    -251,  -238,   -22,   -35,   203,   -26,     0,  -251,   136,   -69,
-    -251,    11,  -160,   -25,  -147,  -250,  -251,  -251,  -251,   -56,
-     171,    16,   -21,  -251,  -251,   -33,  -251,  -251,  -251,  -251,
-    -251,  -251,  -251,  -251,  -251,   186,  -251,  -251
+    -242,  -242,  -242,  -242,  -242,  -242,  -242,    77,  -242,  -242,
+    -242,  -242,   -44,  -242,   -63,  -242,   -62,   -17,  -242,  -242,
+    -242,    52,    37,    51,  -242,   -66,   -83,  -242,   -92,   -73,
+       7,     8,  -242,  -242,  -242,   161,   197,   193,   176,  -242,
+    -242,  -241,   -29,   -30,   253,   -22,     0,  -242,  -242,  -242,
+     135,  -122,  -242,    12,  -138,    13,  -140,  -203,  -242,  -242,
+    -242,   -26,   209,    53,    15,  -242,  -242,    -2,  -242,  -242,
+    -242,  -242,  -242,  -242,  -242,  -242,  -242,   224,  -242,  -242
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If zero, do what YYDEFACT says.
    If YYTABLE_NINF, syntax error.  */
 #define YYTABLE_NINF -117
 static const yytype_int16 yytable[] =
 {
-      43,   170,   166,   225,    67,   165,   131,   221,    31,   122,
-      32,   186,   187,    63,   194,    68,   269,    74,    48,    53,
-      51,    85,   179,    86,    72,    49,   122,    82,   269,   162,
-      87,   288,   182,   183,    63,   288,   163,    57,    74,    43,
-      74,    43,     6,     7,   208,    43,   188,   189,    82,   195,
-      43,    52,    43,    31,    57,    32,   250,   131,    64,     6,
-       7,    65,    43,   212,   213,   214,    55,    58,    59,    60,
-      23,    24,   215,    43,   184,    43,   185,   149,   166,   229,
-      66,   224,   216,    43,    58,    59,    60,    23,    24,   171,
-     172,    74,   233,   199,   176,    56,   200,   227,   267,   109,
-     177,   247,   122,   218,   218,    69,   -75,   291,   221,   218,
-     173,   252,   219,   218,   174,    48,   109,   248,   218,    73,
-     278,   253,    77,   168,   169,    84,    43,   295,   238,   239,
-     240,   241,   256,   257,     2,     3,     4,   125,   122,   294,
-     181,   258,    58,    59,    60,   -25,   127,    69,   190,   191,
-     218,   261,   236,   237,   149,   159,   242,   243,   -26,   180,
-     268,   175,   122,   192,   193,   196,   198,   201,   204,   205,
-     209,   202,   268,   222,  -116,   206,   273,   210,   263,   280,
-     283,   226,   259,   -27,   260,   286,   287,   274,   262,   272,
-     292,   218,   109,   281,   282,   285,   244,   232,   284,   245,
-     296,   246,   166,   149,    79,   160,    83,   161,    50,   126,
-     249,   149,   234,   235,   109,   109,   109,   109,   109,   109,
-     109,   109,   109,   109,   109,    78,   264,   255,   109,   293,
-     265,    71,     0,   275,     0,     0,     0,     0,     0,     0,
+      43,   166,   162,   120,   198,    51,    63,    31,    32,    67,
+     219,   161,    53,   270,   190,    69,   158,    64,   120,    68,
+      65,   223,   175,   159,    57,   107,   270,    63,    72,     6,
+       7,    48,    80,   182,   183,    55,    52,   172,    49,    43,
+     107,    43,   206,   173,   125,    43,    56,   164,   165,   191,
+      43,    80,    31,    32,    58,    59,    60,    23,    24,   178,
+     179,   250,    43,    83,   177,    84,   167,   168,   184,   185,
+      66,   198,    85,    57,    43,   145,   162,   227,     6,     7,
+     290,    43,   225,   268,   290,   222,    82,   169,   216,   216,
+     231,   170,   120,   -75,   125,   216,   125,    73,   217,   245,
+     210,   211,   212,    58,    59,    60,    23,    24,    75,   213,
+     293,   252,   186,   187,   107,   219,   216,   234,   235,   214,
+     236,   237,   238,   239,    43,    48,    43,   248,   280,   180,
+     249,   181,   256,   257,   232,   233,   107,   107,   107,   107,
+     107,   107,   107,   107,   107,   107,   107,   258,   296,   216,
+     145,   297,   253,   123,   120,     2,     3,     4,    58,    59,
+      60,   155,   269,   125,   -25,   -26,    69,   216,   261,   240,
+     241,   171,   176,   188,   262,   269,   107,   192,   274,   189,
+     194,   120,   202,   199,   285,   200,   204,   203,   208,   207,
+     264,  -116,   216,    43,   294,   220,   282,   224,   259,   247,
+     -27,   145,   260,   107,   273,   275,   162,    70,   276,   145,
+       1,     2,     3,     4,     5,     6,     7,     8,     9,    10,
+     283,   284,   286,   289,   288,   287,   243,   298,    11,    12,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+     242,   244,   156,    23,    24,    25,    26,   230,    27,    28,
+      29,   145,    30,    77,   145,   145,    81,   157,    50,   193,
+     263,   295,   255,    76,   265,   277,   266,   145,   145,    71,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   145,     0,     0,     0,   145,   145,     1,
+       2,     3,     4,     5,     6,     7,     8,     9,    10,   128,
+     129,   130,     0,   131,   132,   133,   134,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,     0,
+       0,     0,    23,    24,    25,    26,   135,    27,    28,    29,
+      86,    30,    87,    88,    89,    90,     0,     0,    91,    92,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,    93,     0,     0,
+       0,   136,   137,     0,     0,     0,     0,   138,    94,    95,
+       0,    96,     1,     2,     3,     4,     5,     6,     7,     8,
+       9,    10,   128,   129,   130,     0,   131,   132,   133,   134,
+      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,     0,     0,     0,    23,    24,    25,    26,   135,
+      27,    28,    29,    86,    30,    87,    88,    89,    90,     0,
+       0,    91,    92,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      93,     0,     0,     0,   136,   218,     0,     0,     0,     0,
+     138,    94,    95,     0,    96,     1,     2,     3,     4,     5,
+       6,     7,     8,     9,    10,   128,   129,   130,     0,   131,
+     132,   133,   134,    11,    12,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,     0,     0,     0,    23,    24,
+      25,    26,   135,    27,    28,    29,    86,    30,    87,    88,
+      89,    90,     0,     0,    91,    92,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,   149,   109,     0,   149,   149,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   149,   149,     0,     0,
+       0,     0,     0,    93,     0,     0,     0,   136,     0,     0,
+       0,     0,     0,   138,    94,    95,     0,    96,     1,     2,
+       3,     4,     5,     6,     7,     8,     9,    10,   128,   129,
+     130,     0,   131,   132,   133,   134,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,     0,     0,
+       0,    23,    24,    25,    26,   135,    27,    28,    29,    86,
+      30,    87,    88,    89,    90,     0,     0,    91,    92,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    93,     0,     0,     0,
+      75,     0,     0,     0,     0,     0,   138,    94,    95,     0,
+      96,     1,     2,     3,     4,     5,     6,     7,     8,     9,
+      10,     0,     0,     0,     0,     0,     0,     0,     0,    11,
+      12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,     0,     0,     0,    23,    24,    25,    26,     0,    27,
+      28,    29,    86,    30,    87,    88,    89,    90,     0,     0,
+      91,    92,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    93,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   138,
+      94,    95,     0,    96,    57,     2,     3,     4,     0,     6,
+       7,     8,     9,    10,     0,     0,     0,     0,     0,     0,
+       0,     0,    11,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,     0,     0,     0,    23,    24,    25,
+      26,     0,    27,    28,    29,    86,    30,    87,    88,    89,
+      90,     0,     0,    91,    92,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,   149,     0,     0,     0,   149,   149,     1,     2,     3,
-       4,     5,     6,     7,     8,     9,    10,   132,   133,   134,
-       0,   135,   136,   137,   138,    11,    12,    13,    14,    15,
+       0,     0,    93,     0,     0,     0,     8,     9,    10,     0,
+       0,     0,     0,    94,    95,     0,    96,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,     0,
+       0,     0,     0,     0,    25,    26,     0,    27,    28,    29,
+      86,    30,    87,    88,    89,    90,     0,     0,    91,    92,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,    93,     0,     0,
+     160,     8,     9,    10,     0,     0,     0,     0,    94,    95,
+       0,    96,    11,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,     0,     0,     0,     0,     0,    25,
+      26,     0,    27,    28,    29,    86,    30,    87,    88,    89,
+      90,     0,     0,    91,    92,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    93,     0,     0,     0,     8,     9,    10,     0,
+       0,     0,   205,    94,    95,     0,    96,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,     0,
+       0,     0,     0,     0,    25,    26,     0,    27,    28,    29,
+      86,    30,    87,    88,    89,    90,     0,     0,    91,    92,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,    93,     0,     0,
+     221,     8,     9,    10,     0,     0,     0,     0,    94,    95,
+       0,    96,    11,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,     0,     0,     0,     0,     0,    25,
+      26,     0,    27,    28,    29,    86,    30,    87,    88,    89,
+      90,     0,     0,    91,    92,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    93,     0,     0,     0,     8,     9,    10,     0,
+       0,     0,     0,    94,    95,     0,    96,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,     0,
+       0,     0,     0,     0,    25,   174,     0,    27,    28,    29,
+      86,    30,    87,    88,    89,    90,     0,     0,    91,    92,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,    93,     2,     3,
+       4,     0,     0,     0,     8,     9,    10,     0,    94,    95,
+       0,    96,     0,     0,     0,    11,    12,    13,    14,    15,
       16,    17,    18,    19,    20,    21,    22,     0,     0,     0,
-      23,    24,    25,    26,   139,    27,    28,    29,    88,    30,
-      89,    90,    91,    92,     0,     0,    93,    94,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    95,     0,     0,     0,   140,
-     141,     0,     0,     0,     0,   142,    96,    97,     0,    98,
-       1,     2,     3,     4,     5,     6,     7,     8,     9,    10,
-     132,   133,   134,     0,   135,   136,   137,   138,    11,    12,
-      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-       0,     0,     0,    23,    24,    25,    26,   139,    27,    28,
-      29,    88,    30,    89,    90,    91,    92,     0,     0,    93,
-      94,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    95,     0,
-       0,     0,   140,   220,     0,     0,     0,     0,   142,    96,
-      97,     0,    98,     1,     2,     3,     4,     5,     6,     7,
-       8,     9,    10,   132,   133,   134,     0,   135,   136,   137,
-     138,    11,    12,    13,    14,    15,    16,    17,    18,    19,
-      20,    21,    22,     0,     0,     0,    23,    24,    25,    26,
-     139,    27,    28,    29,    88,    30,    89,    90,    91,    92,
-       0,     0,    93,    94,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,    95,     0,     0,     0,   140,     0,     0,     0,     0,
-       0,   142,    96,    97,     0,    98,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,   132,   133,   134,     0,
-     135,   136,   137,   138,    11,    12,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,     0,     0,     0,    23,
-      24,    25,    26,   139,    27,    28,    29,    88,    30,    89,
-      90,    91,    92,     0,     0,    93,    94,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,    95,     0,     0,     0,    77,     0,
-       0,     0,     0,     0,   142,    96,    97,     0,    98,     1,
-       2,     3,     4,     5,     6,     7,     8,     9,    10,     0,
+       0,     0,    25,    26,     0,    27,    28,    29,     0,    30,
+       2,     3,     4,     0,     0,     0,     8,     9,    10,     0,
        0,     0,     0,     0,     0,     0,     0,    11,    12,    13,
       14,    15,    16,    17,    18,    19,    20,    21,    22,     0,
-       0,     0,    23,    24,    25,    26,     0,    27,    28,    29,
-      88,    30,    89,    90,    91,    92,     0,     0,    93,    94,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,    95,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   142,    96,    97,
-       0,    98,    57,     2,     3,     4,     0,     6,     7,     8,
+     197,     0,     0,     0,    25,    26,     0,    27,    28,    29,
+       0,    30,     1,     2,     3,     4,     5,     6,     7,     8,
        9,    10,     0,     0,     0,     0,     0,     0,     0,     0,
       11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,     0,     0,     0,    23,    24,    25,    26,     0,
-      27,    28,    29,    88,    30,    89,    90,    91,    92,     0,
-       0,    93,    94,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-      95,     0,     0,     0,     8,     9,    10,     0,     0,     0,
-       0,    96,    97,     0,    98,    11,    12,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,     0,     0,     0,
-       0,     0,    25,    26,     0,    27,    28,    29,    88,    30,
-      89,    90,    91,    92,     0,     0,    93,    94,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    95,     0,     0,   164,     8,
-       9,    10,     0,     0,     0,     0,    96,    97,     0,    98,
-      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,     0,     0,     0,     0,     0,    25,    26,     0,
-      27,    28,    29,    88,    30,    89,    90,    91,    92,     0,
-       0,    93,    94,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-      95,     0,     0,     0,     8,     9,    10,     0,     0,     0,
-     207,    96,    97,     0,    98,    11,    12,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,     0,     0,     0,
-       0,     0,    25,    26,     0,    27,    28,    29,    88,    30,
-      89,    90,    91,    92,     0,     0,    93,    94,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    95,     0,     0,   223,     8,
-       9,    10,     0,     0,     0,     0,    96,    97,     0,    98,
-      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,     0,     0,     0,     0,     0,    25,    26,     0,
-      27,    28,    29,    88,    30,    89,    90,    91,    92,     0,
-       0,    93,    94,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-      95,     0,     0,     0,     8,     9,    10,     0,     0,     0,
-       0,    96,    97,     0,    98,    11,    12,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,     0,     0,     0,
-       0,     0,    25,   178,     0,    27,    28,    29,    88,    30,
-      89,    90,    91,    92,     0,     0,    93,    94,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,    95,     2,     3,     4,     0,
-       0,     0,     8,     9,    10,     0,    96,    97,     0,    98,
+      21,    22,   246,     0,     0,    23,    24,    25,    26,     0,
+      27,    28,    29,     0,    30,     2,     3,     4,     0,     0,
+       0,     8,     9,    10,     0,     0,     0,     0,     0,     0,
+       0,     0,    11,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,     0,     0,     8,     9,    10,    25,
+      26,     0,    27,    28,    29,     0,    30,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,     0,
+       0,     0,     0,     0,    25,    26,     0,    27,    28,    29,
+     228,    30,     8,     9,    10,   229,     0,     0,     0,     0,
        0,     0,     0,    11,    12,    13,    14,    15,    16,    17,
       18,    19,    20,    21,    22,     0,     0,     0,     0,     0,
-      25,    26,     0,    27,    28,    29,     0,    30,     2,     3,
-       4,     0,     0,     0,     8,     9,    10,     0,     0,     0,
-       0,     0,     0,     0,     0,    11,    12,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,     0,   130,     0,
-       0,     0,    25,    26,     0,    27,    28,    29,     0,    30,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-      70,     0,     0,     1,     2,     3,     4,     5,     6,     7,
-       8,     9,    10,     0,     0,     0,     0,     0,     0,     0,
-     197,    11,    12,    13,    14,    15,    16,    17,    18,    19,
-      20,    21,    22,     0,     0,     0,    23,    24,    25,    26,
-       0,    27,    28,    29,     0,    30,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,     0,     0,     0,     0,
-       0,     0,     0,     0,    11,    12,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,     0,     0,     0,    23,
-      24,    25,    26,     0,    27,    28,    29,     0,    30,     2,
-       3,     4,     0,     0,     0,     8,     9,    10,     0,     0,
-       0,     0,     0,     0,     0,     0,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,     0,     0,
-       8,     9,    10,    25,    26,     0,    27,    28,    29,     0,
-      30,    11,    12,    13,    14,    15,    16,    17,    18,    19,
-      20,    21,    22,     0,     0,     0,     0,     0,    25,    26,
-       0,    27,    28,    29,   230,    30,     8,     9,    10,   231,
-       0,     0,     0,     0,     0,     0,     0,    11,    12,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,     0,
-       0,     0,     0,     0,    25,    26,     0,    27,    28,    29,
-       0,    30
+      25,    26,     0,    27,    28,    29,     0,    30
 };
 
 static const yytype_int16 yycheck[] =
 {
-       0,    95,    87,   163,    39,    86,    75,   154,     0,    69,
-       0,    54,    55,    35,    59,    41,   254,    52,    37,    81,
-      44,    71,   107,    73,    50,    44,    86,    62,   266,    73,
-      80,   281,    86,    87,    56,   285,    80,     3,    73,    39,
-      75,    41,     8,     9,   138,    45,    89,    90,    83,    94,
-      50,    75,    52,    45,     3,    45,   203,   126,    78,     8,
-       9,    81,    62,    61,    62,    63,    72,    33,    34,    35,
-      36,    37,    70,    73,    83,    75,    85,    77,   163,   173,
-      44,   162,    80,    83,    33,    34,    35,    36,    37,    52,
-      53,   126,   177,    78,    72,    78,    81,    72,    72,    69,
-      78,   195,   162,    78,    78,    73,    72,    72,   255,    78,
-      73,   205,    81,    78,    77,    37,    86,   198,    78,    75,
-     267,    81,    75,    93,    94,    44,   126,   287,   186,   187,
-     188,   189,   217,   218,     4,     5,     6,    81,   198,   286,
-     110,   222,    33,    34,    35,    71,    44,    73,    56,    57,
-      78,    79,   184,   185,   154,    44,   190,   191,    71,    71,
-     254,    72,   222,    58,    60,    74,    73,    81,    71,    71,
-      71,    81,   266,    73,    71,    81,   261,    76,    40,    44,
-     274,    74,    74,    71,    74,    16,    80,    71,    74,    74,
-     284,    78,   162,    72,    76,    72,   192,   174,    81,   193,
-      81,   194,   287,   203,    56,    83,    63,    83,     5,    73,
-     199,   211,   182,   183,   184,   185,   186,   187,   188,   189,
-     190,   191,   192,   193,   194,    54,   251,   211,   198,   285,
-     251,    45,    -1,   266,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,   251,   222,    -1,   254,   255,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   266,   267,    -1,    -1,
+       0,    93,    85,    69,   126,    44,    35,     0,     0,    39,
+     150,    84,    81,   254,    59,    73,    73,    78,    84,    41,
+      81,   159,   105,    80,     3,    69,   267,    56,    50,     8,
+       9,    37,    62,    54,    55,    72,    75,    72,    44,    39,
+      84,    41,   134,    78,    74,    45,    78,    91,    92,    94,
+      50,    81,    45,    45,    33,    34,    35,    36,    37,    86,
+      87,   201,    62,    71,   108,    73,    52,    53,    89,    90,
+      44,   193,    80,     3,    74,    75,   159,   169,     8,     9,
+     283,    81,    72,    72,   287,   158,    44,    73,    78,    78,
+     173,    77,   158,    72,   124,    78,   126,    75,    81,   191,
+      61,    62,    63,    33,    34,    35,    36,    37,    75,    70,
+      72,   203,    56,    57,   158,   255,    78,   180,   181,    80,
+     182,   183,   184,   185,   124,    37,   126,    78,   268,    83,
+      81,    85,   215,   216,   178,   179,   180,   181,   182,   183,
+     184,   185,   186,   187,   188,   189,   190,   220,   288,    78,
+     150,   289,    81,    81,   220,     4,     5,     6,    33,    34,
+      35,    44,   254,   193,    71,    71,    73,    78,    79,   186,
+     187,    72,    71,    58,   247,   267,   220,    74,   261,    60,
+      44,   247,    71,    81,   276,    81,    81,    71,    76,    71,
+      40,    71,    78,   193,   286,    73,    44,    74,    74,    73,
+      71,   201,    74,   247,    74,    74,   289,     0,    71,   209,
+       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
+      72,    76,    81,    80,    16,    72,   189,    81,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+     188,   190,    81,    36,    37,    38,    39,   170,    41,    42,
+      43,   251,    45,    56,   254,   255,    63,    81,     5,   124,
+     248,   287,   209,    54,   251,   267,   251,   267,   268,    45,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,   281,    -1,    -1,    -1,   285,   286,     3,     4,     5,
-       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      -1,    17,    18,    19,    20,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    30,    31,    32,    -1,    -1,    -1,
-      36,    37,    38,    39,    40,    41,    42,    43,    44,    45,
-      46,    47,    48,    49,    -1,    -1,    52,    53,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    71,    -1,    -1,    -1,    75,
-      76,    -1,    -1,    -1,    -1,    81,    82,    83,    -1,    85,
-       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-      13,    14,    15,    -1,    17,    18,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-      -1,    -1,    -1,    36,    37,    38,    39,    40,    41,    42,
-      43,    44,    45,    46,    47,    48,    49,    -1,    -1,    52,
-      53,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    71,    -1,
-      -1,    -1,    75,    76,    -1,    -1,    -1,    -1,    81,    82,
-      83,    -1,    85,     3,     4,     5,     6,     7,     8,     9,
-      10,    11,    12,    13,    14,    15,    -1,    17,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      30,    31,    32,    -1,    -1,    -1,    36,    37,    38,    39,
-      40,    41,    42,    43,    44,    45,    46,    47,    48,    49,
-      -1,    -1,    52,    53,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    71,    -1,    -1,    -1,    75,    -1,    -1,    -1,    -1,
-      -1,    81,    82,    83,    -1,    85,     3,     4,     5,     6,
-       7,     8,     9,    10,    11,    12,    13,    14,    15,    -1,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-      27,    28,    29,    30,    31,    32,    -1,    -1,    -1,    36,
-      37,    38,    39,    40,    41,    42,    43,    44,    45,    46,
-      47,    48,    49,    -1,    -1,    52,    53,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    71,    -1,    -1,    -1,    75,    -1,
-      -1,    -1,    -1,    -1,    81,    82,    83,    -1,    85,     3,
-       4,     5,     6,     7,     8,     9,    10,    11,    12,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    21,    22,    23,
+      -1,    -1,    -1,   283,    -1,    -1,    -1,   287,   288,     3,
+       4,     5,     6,     7,     8,     9,    10,    11,    12,    13,
+      14,    15,    -1,    17,    18,    19,    20,    21,    22,    23,
       24,    25,    26,    27,    28,    29,    30,    31,    32,    -1,
-      -1,    -1,    36,    37,    38,    39,    -1,    41,    42,    43,
+      -1,    -1,    36,    37,    38,    39,    40,    41,    42,    43,
       44,    45,    46,    47,    48,    49,    -1,    -1,    52,    53,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    71,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    81,    82,    83,
-      -1,    85,     3,     4,     5,     6,    -1,     8,     9,    10,
-      11,    12,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    75,    76,    -1,    -1,    -1,    -1,    81,    82,    83,
+      -1,    85,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    13,    14,    15,    -1,    17,    18,    19,    20,
       21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    -1,    -1,    -1,    36,    37,    38,    39,    -1,
-      41,    42,    43,    44,    45,    46,    47,    48,    49,    -1,
-      -1,    52,    53,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      71,    -1,    -1,    -1,    10,    11,    12,    -1,    -1,    -1,
-      -1,    82,    83,    -1,    85,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    30,    31,    32,    -1,    -1,    -1,
-      -1,    -1,    38,    39,    -1,    41,    42,    43,    44,    45,
-      46,    47,    48,    49,    -1,    -1,    52,    53,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    71,    -1,    -1,    74,    10,
-      11,    12,    -1,    -1,    -1,    -1,    82,    83,    -1,    85,
-      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    -1,    -1,    -1,    -1,    -1,    38,    39,    -1,
-      41,    42,    43,    44,    45,    46,    47,    48,    49,    -1,
-      -1,    52,    53,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      71,    -1,    -1,    -1,    10,    11,    12,    -1,    -1,    -1,
-      81,    82,    83,    -1,    85,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    30,    31,    32,    -1,    -1,    -1,
-      -1,    -1,    38,    39,    -1,    41,    42,    43,    44,    45,
-      46,    47,    48,    49,    -1,    -1,    52,    53,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    71,    -1,    -1,    74,    10,
-      11,    12,    -1,    -1,    -1,    -1,    82,    83,    -1,    85,
-      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    -1,    -1,    -1,    -1,    -1,    38,    39,    -1,
+      31,    32,    -1,    -1,    -1,    36,    37,    38,    39,    40,
       41,    42,    43,    44,    45,    46,    47,    48,    49,    -1,
       -1,    52,    53,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      71,    -1,    -1,    -1,    10,    11,    12,    -1,    -1,    -1,
-      -1,    82,    83,    -1,    85,    21,    22,    23,    24,    25,
+      71,    -1,    -1,    -1,    75,    76,    -1,    -1,    -1,    -1,
+      81,    82,    83,    -1,    85,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    13,    14,    15,    -1,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,    31,    32,    -1,    -1,    -1,    36,    37,
+      38,    39,    40,    41,    42,    43,    44,    45,    46,    47,
+      48,    49,    -1,    -1,    52,    53,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    71,    -1,    -1,    -1,    75,    -1,    -1,
+      -1,    -1,    -1,    81,    82,    83,    -1,    85,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    -1,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    -1,    -1,
+      -1,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    -1,    -1,    52,    53,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    71,    -1,    -1,    -1,
+      75,    -1,    -1,    -1,    -1,    -1,    81,    82,    83,    -1,
+      85,     3,     4,     5,     6,     7,     8,     9,    10,    11,
+      12,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    21,
+      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+      32,    -1,    -1,    -1,    36,    37,    38,    39,    -1,    41,
+      42,    43,    44,    45,    46,    47,    48,    49,    -1,    -1,
+      52,    53,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    71,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    81,
+      82,    83,    -1,    85,     3,     4,     5,     6,    -1,     8,
+       9,    10,    11,    12,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    -1,    -1,    -1,    36,    37,    38,
+      39,    -1,    41,    42,    43,    44,    45,    46,    47,    48,
+      49,    -1,    -1,    52,    53,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    71,    -1,    -1,    -1,    10,    11,    12,    -1,
+      -1,    -1,    -1,    82,    83,    -1,    85,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    -1,
+      -1,    -1,    -1,    -1,    38,    39,    -1,    41,    42,    43,
+      44,    45,    46,    47,    48,    49,    -1,    -1,    52,    53,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    71,    -1,    -1,
+      74,    10,    11,    12,    -1,    -1,    -1,    -1,    82,    83,
+      -1,    85,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    -1,    -1,    -1,    -1,    -1,    38,
+      39,    -1,    41,    42,    43,    44,    45,    46,    47,    48,
+      49,    -1,    -1,    52,    53,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    71,    -1,    -1,    -1,    10,    11,    12,    -1,
+      -1,    -1,    81,    82,    83,    -1,    85,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    -1,
+      -1,    -1,    -1,    -1,    38,    39,    -1,    41,    42,    43,
+      44,    45,    46,    47,    48,    49,    -1,    -1,    52,    53,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    71,    -1,    -1,
+      74,    10,    11,    12,    -1,    -1,    -1,    -1,    82,    83,
+      -1,    85,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    -1,    -1,    -1,    -1,    -1,    38,
+      39,    -1,    41,    42,    43,    44,    45,    46,    47,    48,
+      49,    -1,    -1,    52,    53,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    71,    -1,    -1,    -1,    10,    11,    12,    -1,
+      -1,    -1,    -1,    82,    83,    -1,    85,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    -1,
+      -1,    -1,    -1,    -1,    38,    39,    -1,    41,    42,    43,
+      44,    45,    46,    47,    48,    49,    -1,    -1,    52,    53,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    71,     4,     5,
+       6,    -1,    -1,    -1,    10,    11,    12,    -1,    82,    83,
+      -1,    85,    -1,    -1,    -1,    21,    22,    23,    24,    25,
       26,    27,    28,    29,    30,    31,    32,    -1,    -1,    -1,
-      -1,    -1,    38,    39,    -1,    41,    42,    43,    44,    45,
-      46,    47,    48,    49,    -1,    -1,    52,    53,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    71,     4,     5,     6,    -1,
-      -1,    -1,    10,    11,    12,    -1,    82,    83,    -1,    85,
+      -1,    -1,    38,    39,    -1,    41,    42,    43,    -1,    45,
+       4,     5,     6,    -1,    -1,    -1,    10,    11,    12,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    -1,
+      76,    -1,    -1,    -1,    38,    39,    -1,    41,    42,    43,
+      -1,    45,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    76,    -1,    -1,    36,    37,    38,    39,    -1,
+      41,    42,    43,    -1,    45,     4,     5,     6,    -1,    -1,
+      -1,    10,    11,    12,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    -1,    -1,    10,    11,    12,    38,
+      39,    -1,    41,    42,    43,    -1,    45,    21,    22,    23,
+      24,    25,    26,    27,    28,    29,    30,    31,    32,    -1,
+      -1,    -1,    -1,    -1,    38,    39,    -1,    41,    42,    43,
+      44,    45,    10,    11,    12,    49,    -1,    -1,    -1,    -1,
       -1,    -1,    -1,    21,    22,    23,    24,    25,    26,    27,
       28,    29,    30,    31,    32,    -1,    -1,    -1,    -1,    -1,
-      38,    39,    -1,    41,    42,    43,    -1,    45,     4,     5,
-       6,    -1,    -1,    -1,    10,    11,    12,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    30,    31,    32,    -1,    76,    -1,
-      -1,    -1,    38,    39,    -1,    41,    42,    43,    -1,    45,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-       0,    -1,    -1,     3,     4,     5,     6,     7,     8,     9,
-      10,    11,    12,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      76,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      30,    31,    32,    -1,    -1,    -1,    36,    37,    38,    39,
-      -1,    41,    42,    43,    -1,    45,     3,     4,     5,     6,
-       7,     8,     9,    10,    11,    12,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    21,    22,    23,    24,    25,    26,
-      27,    28,    29,    30,    31,    32,    -1,    -1,    -1,    36,
-      37,    38,    39,    -1,    41,    42,    43,    -1,    45,     4,
-       5,     6,    -1,    -1,    -1,    10,    11,    12,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    -1,    -1,
-      10,    11,    12,    38,    39,    -1,    41,    42,    43,    -1,
-      45,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      30,    31,    32,    -1,    -1,    -1,    -1,    -1,    38,    39,
-      -1,    41,    42,    43,    44,    45,    10,    11,    12,    49,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    21,    22,    23,
-      24,    25,    26,    27,    28,    29,    30,    31,    32,    -1,
-      -1,    -1,    -1,    -1,    38,    39,    -1,    41,    42,    43,
-      -1,    45
+      38,    39,    -1,    41,    42,    43,    -1,    45
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
        0,     3,     4,     5,     6,     7,     8,     9,    10,    11,
       12,    21,    22,    23,    24,    25,    26,    27,    28,    29,
       30,    31,    32,    36,    37,    38,    39,    41,    42,    43,
       45,   125,   126,   127,   128,   129,   134,   135,   136,   137,
-     138,   139,   140,   141,   142,   169,   170,   171,    37,    44,
-     139,    44,    75,    81,   172,    72,    78,     3,    33,    34,
+     138,   139,   140,   141,   142,   171,   172,   173,    37,    44,
+     139,    44,    75,    81,   174,    72,    78,     3,    33,    34,
       35,   131,   132,   137,    78,    81,    44,   138,   140,    73,
-       0,   170,   140,    75,   138,   143,   144,    75,   155,   131,
-     130,   133,   138,   132,    44,    71,    73,    80,    44,    46,
-      47,    48,    49,    52,    53,    71,    82,    83,    85,    96,
-      97,    98,   100,   101,   102,   103,   104,   105,   106,   107,
-     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
-     118,   119,   120,   124,   141,    81,   143,    44,   145,   146,
-      76,   144,    13,    14,    15,    17,    18,    19,    20,    40,
-      75,    76,    81,   107,   120,   121,   123,   125,   126,   141,
-     148,   149,   150,   151,   156,   157,   158,   161,   168,    44,
-     130,   133,    73,    80,    74,   124,   121,   147,   107,   107,
-     123,    52,    53,    73,    77,    72,    72,    78,    39,   121,
-      71,   107,    86,    87,    83,    85,    54,    55,    89,    90,
-      56,    57,    58,    60,    59,    94,    74,    76,    73,    78,
-      81,    81,    81,   163,    71,    71,    81,    81,   123,    71,
-      76,   152,    61,    62,    63,    70,    80,   122,    78,    81,
-      76,   149,    73,    74,   124,   147,    74,    72,    99,   123,
-      44,    49,   102,   121,   107,   107,   109,   109,   111,   111,
-     111,   111,   112,   112,   116,   117,   118,   123,   124,   146,
-     149,   164,   123,    81,   162,   156,   121,   121,   124,    74,
-      74,    79,    74,    40,   148,   157,   165,    72,   123,   136,
-     160,   153,    74,   121,    71,   160,   166,   167,   149,   159,
-      44,    72,    76,   123,    81,    72,    16,    80,   150,   154,
-     155,    72,   123,   154,   149,   147,    81
+       0,   172,   140,    75,   144,    75,   157,   131,   130,   133,
+     138,   132,    44,    71,    73,    80,    44,    46,    47,    48,
+      49,    52,    53,    71,    82,    83,    85,    96,    97,    98,
+     100,   101,   102,   103,   104,   105,   106,   107,   108,   109,
+     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
+     120,   124,   141,    81,   143,   138,   145,   146,    13,    14,
+      15,    17,    18,    19,    20,    40,    75,    76,    81,   107,
+     120,   121,   123,   125,   126,   141,   150,   151,   152,   153,
+     158,   159,   160,   163,   170,    44,   130,   133,    73,    80,
+      74,   124,   121,   149,   107,   107,   123,    52,    53,    73,
+      77,    72,    72,    78,    39,   121,    71,   107,    86,    87,
+      83,    85,    54,    55,    89,    90,    56,    57,    58,    60,
+      59,    94,    74,   145,    44,   147,   148,    76,   146,    81,
+      81,   165,    71,    71,    81,    81,   123,    71,    76,   154,
+      61,    62,    63,    70,    80,   122,    78,    81,    76,   151,
+      73,    74,   124,   149,    74,    72,    99,   123,    44,    49,
+     102,   121,   107,   107,   109,   109,   111,   111,   111,   111,
+     112,   112,   116,   117,   118,   123,    76,    73,    78,    81,
+     151,   166,   123,    81,   164,   158,   121,   121,   124,    74,
+      74,    79,   124,   148,    40,   150,   159,   167,    72,   123,
+     136,   162,   155,    74,   121,    74,    71,   162,   168,   169,
+     151,   161,    44,    72,    76,   123,    81,    72,    16,    80,
+     152,   156,   157,    72,   123,   156,   151,   149,    81
 };
 
 #define yyerrok		(yyerrstatus = 0)
 #define yyclearin	(yychar = YYEMPTY)
 #define YYEMPTY		(-2)
 #define YYEOF		0
 
 #define YYACCEPT	goto yyacceptlab
@@ -1368,17 +1356,17 @@ while (YYID (0))
 #endif
 
 
 /* YY_LOCATION_PRINT -- Print the location on the stream.
    This macro was not mandated originally: define only if we know
    we won't break user code: when these are the locations we know.  */
 
 #ifndef YY_LOCATION_PRINT
-# if YYLTYPE_IS_TRIVIAL
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
 #  define YY_LOCATION_PRINT(File, Loc)			\
      fprintf (File, "%d.%d-%d.%d",			\
 	      (Loc).first_line, (Loc).first_column,	\
 	      (Loc).last_line,  (Loc).last_column)
 # else
 #  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 # endif
 #endif
@@ -3920,64 +3908,76 @@ yyreduce:
         TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
         (yyval.interm.type).setBasic(EbtStruct, qual, (yyvsp[(1) - (1)].lex).line);
         (yyval.interm.type).userDef = &structure;
     ;}
     break;
 
   case 137:
 
-    {
-        if (context->reservedErrorCheck((yyvsp[(2) - (5)].lex).line, *(yyvsp[(2) - (5)].lex).string))
-            context->recover();
-
-        TType* structure = new TType((yyvsp[(4) - (5)].interm.typeList), *(yyvsp[(2) - (5)].lex).string);
-        TVariable* userTypeDef = new TVariable((yyvsp[(2) - (5)].lex).string, *structure, true);
-        if (! context->symbolTable.insert(*userTypeDef)) {
-            context->error((yyvsp[(2) - (5)].lex).line, "redefinition", (yyvsp[(2) - (5)].lex).string->c_str(), "struct");
-            context->recover();
-        }
-        (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yyvsp[(1) - (5)].lex).line);
-        (yyval.interm.type).userDef = structure;
-    ;}
+    { if (context->enterStructDeclaration((yyvsp[(2) - (3)].lex).line, *(yyvsp[(2) - (3)].lex).string)) context->recover(); ;}
     break;
 
   case 138:
 
     {
-        TType* structure = new TType((yyvsp[(3) - (4)].interm.typeList), TString(""));
-        (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yyvsp[(1) - (4)].lex).line);
+        if (context->reservedErrorCheck((yyvsp[(2) - (6)].lex).line, *(yyvsp[(2) - (6)].lex).string))
+            context->recover();
+
+        TType* structure = new TType((yyvsp[(5) - (6)].interm.typeList), *(yyvsp[(2) - (6)].lex).string);
+        TVariable* userTypeDef = new TVariable((yyvsp[(2) - (6)].lex).string, *structure, true);
+        if (! context->symbolTable.insert(*userTypeDef)) {
+            context->error((yyvsp[(2) - (6)].lex).line, "redefinition", (yyvsp[(2) - (6)].lex).string->c_str(), "struct");
+            context->recover();
+        }
+        (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yyvsp[(1) - (6)].lex).line);
         (yyval.interm.type).userDef = structure;
+        context->exitStructDeclaration();
     ;}
     break;
 
   case 139:
 
+    { if (context->enterStructDeclaration((yyvsp[(2) - (2)].lex).line, *(yyvsp[(2) - (2)].lex).string)) context->recover(); ;}
+    break;
+
+  case 140:
+
+    {
+        TType* structure = new TType((yyvsp[(4) - (5)].interm.typeList), TString(""));
+        (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yyvsp[(1) - (5)].lex).line);
+        (yyval.interm.type).userDef = structure;
+        context->exitStructDeclaration();
+    ;}
+    break;
+
+  case 141:
+
     {
         (yyval.interm.typeList) = (yyvsp[(1) - (1)].interm.typeList);
     ;}
     break;
 
-  case 140:
+  case 142:
 
     {
         (yyval.interm.typeList) = (yyvsp[(1) - (2)].interm.typeList);
         for (unsigned int i = 0; i < (yyvsp[(2) - (2)].interm.typeList)->size(); ++i) {
             for (unsigned int j = 0; j < (yyval.interm.typeList)->size(); ++j) {
                 if ((*(yyval.interm.typeList))[j].type->getFieldName() == (*(yyvsp[(2) - (2)].interm.typeList))[i].type->getFieldName()) {
                     context->error((*(yyvsp[(2) - (2)].interm.typeList))[i].line, "duplicate field name in structure:", "struct", (*(yyvsp[(2) - (2)].interm.typeList))[i].type->getFieldName().c_str());
                     context->recover();
                 }
             }
             (yyval.interm.typeList)->push_back((*(yyvsp[(2) - (2)].interm.typeList))[i]);
         }
     ;}
     break;
 
-  case 141:
+  case 143:
 
     {
         (yyval.interm.typeList) = (yyvsp[(2) - (3)].interm.typeList);
 
         if (context->voidErrorCheck((yyvsp[(1) - (3)].interm.type).line, (*(yyvsp[(2) - (3)].interm.typeList))[0].type->getFieldName(), (yyvsp[(1) - (3)].interm.type))) {
             context->recover();
         }
         for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) {
@@ -3996,87 +3996,81 @@ yyreduce:
                     context->recover();
             }
             if ((yyvsp[(1) - (3)].interm.type).array)
                 type->setArraySize((yyvsp[(1) - (3)].interm.type).arraySize);
             if ((yyvsp[(1) - (3)].interm.type).userDef) {
                 type->setStruct((yyvsp[(1) - (3)].interm.type).userDef->getStruct());
                 type->setTypeName((yyvsp[(1) - (3)].interm.type).userDef->getTypeName());
             }
+
+            if (context->structNestingErrorCheck((yyvsp[(1) - (3)].interm.type).line, *type)) {
+                context->recover();
+            }
         }
     ;}
     break;
 
-  case 142:
+  case 144:
 
     {
         (yyval.interm.typeList) = NewPoolTTypeList();
         (yyval.interm.typeList)->push_back((yyvsp[(1) - (1)].interm.typeLine));
     ;}
     break;
 
-  case 143:
+  case 145:
 
     {
         (yyval.interm.typeList)->push_back((yyvsp[(3) - (3)].interm.typeLine));
     ;}
     break;
 
-  case 144:
+  case 146:
 
     {
         if (context->reservedErrorCheck((yyvsp[(1) - (1)].lex).line, *(yyvsp[(1) - (1)].lex).string))
             context->recover();
 
         (yyval.interm.typeLine).type = new TType(EbtVoid, EbpUndefined);
         (yyval.interm.typeLine).line = (yyvsp[(1) - (1)].lex).line;
         (yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (1)].lex).string);
     ;}
     break;
 
-  case 145:
+  case 147:
 
     {
         if (context->reservedErrorCheck((yyvsp[(1) - (4)].lex).line, *(yyvsp[(1) - (4)].lex).string))
             context->recover();
 
         (yyval.interm.typeLine).type = new TType(EbtVoid, EbpUndefined);
         (yyval.interm.typeLine).line = (yyvsp[(1) - (4)].lex).line;
         (yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (4)].lex).string);
 
         int size;
         if (context->arraySizeErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(3) - (4)].interm.intermTypedNode), size))
             context->recover();
         (yyval.interm.typeLine).type->setArraySize(size);
     ;}
     break;
 
-  case 146:
+  case 148:
 
     { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
     break;
 
-  case 147:
-
-    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
-    break;
-
-  case 148:
-
-    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermAggregate); ;}
-    break;
-
   case 149:
 
     { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
     break;
 
   case 150:
 
-    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermAggregate); ;}
     break;
 
   case 151:
 
     { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
     break;
 
   case 152:
@@ -4091,127 +4085,137 @@ yyreduce:
 
   case 154:
 
     { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
     break;
 
   case 155:
 
-    { (yyval.interm.intermAggregate) = 0; ;}
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
     break;
 
   case 156:
 
+    { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+    break;
+
+  case 157:
+
+    { (yyval.interm.intermAggregate) = 0; ;}
+    break;
+
+  case 158:
+
     { context->symbolTable.push(); ;}
     break;
 
-  case 157:
+  case 159:
 
     { context->symbolTable.pop(); ;}
     break;
 
-  case 158:
+  case 160:
 
     {
         if ((yyvsp[(3) - (5)].interm.intermAggregate) != 0) {
             (yyvsp[(3) - (5)].interm.intermAggregate)->setOp(EOpSequence);
             (yyvsp[(3) - (5)].interm.intermAggregate)->setEndLine((yyvsp[(5) - (5)].lex).line);
         }
         (yyval.interm.intermAggregate) = (yyvsp[(3) - (5)].interm.intermAggregate);
     ;}
     break;
 
-  case 159:
+  case 161:
 
     { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
     break;
 
-  case 160:
+  case 162:
 
     { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
     break;
 
-  case 161:
+  case 163:
 
     {
         (yyval.interm.intermNode) = 0;
     ;}
     break;
 
-  case 162:
+  case 164:
 
     {
         if ((yyvsp[(2) - (3)].interm.intermAggregate)) {
             (yyvsp[(2) - (3)].interm.intermAggregate)->setOp(EOpSequence);
             (yyvsp[(2) - (3)].interm.intermAggregate)->setEndLine((yyvsp[(3) - (3)].lex).line);
         }
         (yyval.interm.intermNode) = (yyvsp[(2) - (3)].interm.intermAggregate);
     ;}
     break;
 
-  case 163:
+  case 165:
 
     {
         (yyval.interm.intermAggregate) = context->intermediate.makeAggregate((yyvsp[(1) - (1)].interm.intermNode), 0);
     ;}
     break;
 
-  case 164:
+  case 166:
 
     {
         (yyval.interm.intermAggregate) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermAggregate), (yyvsp[(2) - (2)].interm.intermNode), 0);
     ;}
     break;
 
-  case 165:
+  case 167:
 
     { (yyval.interm.intermNode) = 0; ;}
     break;
 
-  case 166:
+  case 168:
 
     { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[(1) - (2)].interm.intermTypedNode)); ;}
     break;
 
-  case 167:
+  case 169:
 
     {
         if (context->boolErrorCheck((yyvsp[(1) - (5)].lex).line, (yyvsp[(3) - (5)].interm.intermTypedNode)))
             context->recover();
         (yyval.interm.intermNode) = context->intermediate.addSelection((yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.nodePair), (yyvsp[(1) - (5)].lex).line);
     ;}
     break;
 
-  case 168:
+  case 170:
 
     {
         (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermNode);
         (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermNode);
     ;}
     break;
 
-  case 169:
+  case 171:
 
     {
         (yyval.interm.nodePair).node1 = (yyvsp[(1) - (1)].interm.intermNode);
         (yyval.interm.nodePair).node2 = 0;
     ;}
     break;
 
-  case 170:
+  case 172:
 
     {
         (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
         if (context->boolErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode)->getLine(), (yyvsp[(1) - (1)].interm.intermTypedNode)))
             context->recover();
     ;}
     break;
 
-  case 171:
+  case 173:
 
     {
         TIntermNode* intermNode;
         if (context->structQualifierErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type)))
             context->recover();
         if (context->boolErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type)))
             context->recover();
 
@@ -4219,193 +4223,193 @@ yyreduce:
             (yyval.interm.intermTypedNode) = (yyvsp[(4) - (4)].interm.intermTypedNode);
         else {
             context->recover();
             (yyval.interm.intermTypedNode) = 0;
         }
     ;}
     break;
 
-  case 172:
+  case 174:
 
     { context->symbolTable.push(); ++context->loopNestingLevel; ;}
     break;
 
-  case 173:
+  case 175:
 
     {
         context->symbolTable.pop();
         (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[(4) - (6)].interm.intermTypedNode), 0, (yyvsp[(6) - (6)].interm.intermNode), (yyvsp[(1) - (6)].lex).line);
         --context->loopNestingLevel;
     ;}
     break;
 
-  case 174:
+  case 176:
 
     { ++context->loopNestingLevel; ;}
     break;
 
-  case 175:
+  case 177:
 
     {
         if (context->boolErrorCheck((yyvsp[(8) - (8)].lex).line, (yyvsp[(6) - (8)].interm.intermTypedNode)))
             context->recover();
 
         (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[(6) - (8)].interm.intermTypedNode), 0, (yyvsp[(3) - (8)].interm.intermNode), (yyvsp[(4) - (8)].lex).line);
         --context->loopNestingLevel;
     ;}
     break;
 
-  case 176:
+  case 178:
 
     { context->symbolTable.push(); ++context->loopNestingLevel; ;}
     break;
 
-  case 177:
+  case 179:
 
     {
         context->symbolTable.pop();
         (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[(4) - (7)].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node2), (yyvsp[(7) - (7)].interm.intermNode), (yyvsp[(1) - (7)].lex).line);
         --context->loopNestingLevel;
     ;}
     break;
 
-  case 178:
+  case 180:
 
     {
         (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
     ;}
     break;
 
-  case 179:
-
-    {
-        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
-    ;}
-    break;
-
-  case 180:
-
-    {
-        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
-    ;}
-    break;
-
   case 181:
 
     {
-        (yyval.interm.intermTypedNode) = 0;
+        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
     ;}
     break;
 
   case 182:
 
     {
+        (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+    ;}
+    break;
+
+  case 183:
+
+    {
+        (yyval.interm.intermTypedNode) = 0;
+    ;}
+    break;
+
+  case 184:
+
+    {
         (yyval.interm.nodePair).node1 = (yyvsp[(1) - (2)].interm.intermTypedNode);
         (yyval.interm.nodePair).node2 = 0;
     ;}
     break;
 
-  case 183:
+  case 185:
 
     {
         (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermTypedNode);
         (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermTypedNode);
     ;}
     break;
 
-  case 184:
+  case 186:
 
     {
         if (context->loopNestingLevel <= 0) {
             context->error((yyvsp[(1) - (2)].lex).line, "continue statement only allowed in loops", "", "");
             context->recover();
         }
         (yyval.interm.intermNode) = context->intermediate.addBranch(EOpContinue, (yyvsp[(1) - (2)].lex).line);
     ;}
     break;
 
-  case 185:
+  case 187:
 
     {
         if (context->loopNestingLevel <= 0) {
             context->error((yyvsp[(1) - (2)].lex).line, "break statement only allowed in loops", "", "");
             context->recover();
         }
         (yyval.interm.intermNode) = context->intermediate.addBranch(EOpBreak, (yyvsp[(1) - (2)].lex).line);
     ;}
     break;
 
-  case 186:
+  case 188:
 
     {
         (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[(1) - (2)].lex).line);
         if (context->currentFunctionType->getBasicType() != EbtVoid) {
             context->error((yyvsp[(1) - (2)].lex).line, "non-void function must return a value", "return", "");
             context->recover();
         }
     ;}
     break;
 
-  case 187:
+  case 189:
 
     {
         (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[(2) - (3)].interm.intermTypedNode), (yyvsp[(1) - (3)].lex).line);
         context->functionReturnsValue = true;
         if (context->currentFunctionType->getBasicType() == EbtVoid) {
             context->error((yyvsp[(1) - (3)].lex).line, "void function cannot return a value", "return", "");
             context->recover();
         } else if (*(context->currentFunctionType) != (yyvsp[(2) - (3)].interm.intermTypedNode)->getType()) {
             context->error((yyvsp[(1) - (3)].lex).line, "function return is not matching type:", "return", "");
             context->recover();
         }
     ;}
     break;
 
-  case 188:
+  case 190:
 
     {
         FRAG_ONLY("discard", (yyvsp[(1) - (2)].lex).line);
         (yyval.interm.intermNode) = context->intermediate.addBranch(EOpKill, (yyvsp[(1) - (2)].lex).line);
     ;}
     break;
 
-  case 189:
-
-    {
-        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
-        context->treeRoot = (yyval.interm.intermNode);
-    ;}
-    break;
-
-  case 190:
-
-    {
-        (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermNode), (yyvsp[(2) - (2)].interm.intermNode), 0);
-        context->treeRoot = (yyval.interm.intermNode);
-    ;}
-    break;
-
   case 191:
 
     {
         (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+        context->treeRoot = (yyval.interm.intermNode);
     ;}
     break;
 
   case 192:
 
     {
-        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+        (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermNode), (yyvsp[(2) - (2)].interm.intermNode), 0);
+        context->treeRoot = (yyval.interm.intermNode);
     ;}
     break;
 
   case 193:
 
     {
+        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+    ;}
+    break;
+
+  case 194:
+
+    {
+        (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+    ;}
+    break;
+
+  case 195:
+
+    {
         TFunction* function = (yyvsp[(1) - (1)].interm).function;
         TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName()));
         //
         // Note:  'prevDec' could be 'function' if this is the first time we've seen function
         // as it would have just been put in the symbol table.  Otherwise, we're looking up
         // an earlier occurance.
         //
         if (prevDec->isDefined()) {
@@ -4478,17 +4482,17 @@ yyreduce:
             }
         }
         context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yyvsp[(1) - (1)].interm).line);
         (yyvsp[(1) - (1)].interm).intermAggregate = paramNodes;
         context->loopNestingLevel = 0;
     ;}
     break;
 
-  case 194:
+  case 196:
 
     {
         //?? Check that all paths return a value if return type != void ?
         //   May be best done as post process phase on intermediate code
         if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
             context->error((yyvsp[(1) - (3)].interm).line, "function does not return a value:", "", (yyvsp[(1) - (3)].interm).function->getName().c_str());
             context->recover();
         }
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/preprocessor/length_limits.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// length_limits.h
+//
+
+#if !defined(__LENGTH_LIMITS_H)
+#define __LENGTH_LIMITS_H 1
+
+// These constants are factored out from the rest of the headers to
+// make it easier to reference them from the compiler sources.
+
+// These lengths do not include the NULL terminator.
+// see bug 675625: NVIDIA driver crash with lengths >= 253
+// this is only an interim fix, the real fix is name mapping, see ANGLE bug 144 / r619
+#define MAX_SYMBOL_NAME_LEN 250
+#define MAX_STRING_LEN 511
+
+#endif // !(defined(__LENGTH_LIMITS_H)
--- a/gfx/angle/src/compiler/preprocessor/scanner.h
+++ b/gfx/angle/src/compiler/preprocessor/scanner.h
@@ -43,22 +43,17 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILI
 \****************************************************************************/
 //
 // scanner.h
 //
 
 #if !defined(__SCANNER_H)
 #define __SCANNER_H 1
 
-// These lengths do not include the NULL terminator.
-// see bug 675625: NVIDIA driver crash with lengths >= 253
-// this is only an interim fix, the real fix is name mapping, see ANGLE bug 144 / r619
-#define MAX_SYMBOL_NAME_LEN 250
-#define MAX_STRING_LEN 511
-
+#include "compiler/preprocessor/length_limits.h"
 #include "compiler/preprocessor/parser.h"
 
 // Not really atom table stuff but needed first...
 
 typedef struct SourceLoc_Rec {
     unsigned short file, line;
 } SourceLoc;
 
--- a/gfx/angle/src/libGLESv2/Context.cpp
+++ b/gfx/angle/src/libGLESv2/Context.cpp
@@ -35,16 +35,19 @@ namespace
 {
     enum { CLOSING_INDEX_BUFFER_SIZE = 4096 };
 }
 
 namespace gl
 {
 Context::Context(const egl::Config *config, const gl::Context *shareContext) : mConfig(config)
 {
+    mDisplay = NULL;
+    mDevice = NULL;
+
     mFenceHandleAllocator.setBaseHandle(0);
 
     setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
     mState.depthClearValue = 1.0f;
     mState.stencilClearValue = 0;
 
     mState.cullFace = false;
@@ -229,29 +232,30 @@ Context::~Context()
         mMaskedClearSavedState->Release();
     }
 
     mResourceManager->release();
 }
 
 void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
 {
-    IDirect3DDevice9 *device = display->getDevice();
+    mDisplay = display;
+    mDevice = mDisplay->getDevice();
 
     if (!mHasBeenCurrent)
     {
-        mDeviceCaps = display->getDeviceCaps();
-
-        mVertexDataManager = new VertexDataManager(this, device);
-        mIndexDataManager = new IndexDataManager(this, device);
+        mDeviceCaps = mDisplay->getDeviceCaps();
+
+        mVertexDataManager = new VertexDataManager(this, mDevice);
+        mIndexDataManager = new IndexDataManager(this, mDevice);
         mBlit = new Blit(this);
 
         mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0);
-        mSupportsVertexTexture = display->getVertexTextureSupport();
-        mSupportsNonPower2Texture = display->getNonPower2TextureSupport();
+        mSupportsVertexTexture = mDisplay->getVertexTextureSupport();
+        mSupportsNonPower2Texture = mDisplay->getNonPower2TextureSupport();
 
         mMaxTextureDimension = std::min(std::min((int)mDeviceCaps.MaxTextureWidth, (int)mDeviceCaps.MaxTextureHeight),
                                         (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE);
         mMaxCubeTextureDimension = std::min(mMaxTextureDimension, (int)gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE);
         mMaxRenderbufferDimension = mMaxTextureDimension;
         mMaxTextureLevel = log2(mMaxTextureDimension) + 1;
         TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d",
               mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel);
@@ -263,38 +267,38 @@ void Context::makeCurrent(egl::Display *
             D3DFMT_R5G6B5,
             D3DFMT_D24S8
         };
 
         int max = 0;
         for (int i = 0; i < sizeof(renderBufferFormats) / sizeof(D3DFORMAT); ++i)
         {
             bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
-            display->getMultiSampleSupport(renderBufferFormats[i], multisampleArray);
+            mDisplay->getMultiSampleSupport(renderBufferFormats[i], multisampleArray);
             mMultiSampleSupport[renderBufferFormats[i]] = multisampleArray;
 
             for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
             {
                 if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
                 {
                     max = j;
                 }
             }
         }
 
         mMaxSupportedSamples = max;
 
-        mSupportsEventQueries = display->getEventQuerySupport();
-        mSupportsDXT1Textures = display->getDXT1TextureSupport();
-        mSupportsDXT3Textures = display->getDXT3TextureSupport();
-        mSupportsDXT5Textures = display->getDXT5TextureSupport();
-        mSupportsFloatTextures = display->getFloatTextureSupport(&mSupportsFloatLinearFilter, &mSupportsFloatRenderableTextures);
-        mSupportsHalfFloatTextures = display->getHalfFloatTextureSupport(&mSupportsHalfFloatLinearFilter, &mSupportsHalfFloatRenderableTextures);
-        mSupportsLuminanceTextures = display->getLuminanceTextureSupport();
-        mSupportsLuminanceAlphaTextures = display->getLuminanceAlphaTextureSupport();
+        mSupportsEventQueries = mDisplay->getEventQuerySupport();
+        mSupportsDXT1Textures = mDisplay->getDXT1TextureSupport();
+        mSupportsDXT3Textures = mDisplay->getDXT3TextureSupport();
+        mSupportsDXT5Textures = mDisplay->getDXT5TextureSupport();
+        mSupportsFloatTextures = mDisplay->getFloatTextureSupport(&mSupportsFloatLinearFilter, &mSupportsFloatRenderableTextures);
+        mSupportsHalfFloatTextures = mDisplay->getHalfFloatTextureSupport(&mSupportsHalfFloatLinearFilter, &mSupportsHalfFloatRenderableTextures);
+        mSupportsLuminanceTextures = mDisplay->getLuminanceTextureSupport();
+        mSupportsLuminanceAlphaTextures = mDisplay->getLuminanceAlphaTextureSupport();
 
         mSupports32bitIndices = mDeviceCaps.MaxVertexIndex >= (1 << 16);
 
         mNumCompressedTextureFormats = 0;
         if (supportsDXT1Textures())
         {
             mNumCompressedTextureFormats += 2;
         }
@@ -1615,18 +1619,16 @@ bool Context::getQueryParameterInfo(GLen
 
     return true;
 }
 
 // Applies the render target surface, depth stencil surface, viewport rectangle and
 // scissor rectangle to the Direct3D 9 device
 bool Context::applyRenderTarget(bool ignoreViewport)
 {
-    IDirect3DDevice9 *device = getDevice();
-
     Framebuffer *framebufferObject = getDrawFramebuffer();
 
     if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
     {
         return error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
     }
 
     IDirect3DSurface9 *renderTarget = NULL;
@@ -1637,17 +1639,17 @@ bool Context::applyRenderTarget(bool ign
     if (renderTargetSerial != mAppliedRenderTargetSerial)
     {
         renderTarget = framebufferObject->getRenderTarget();
 
         if (!renderTarget)
         {
             return false;   // Context must be lost
         }
-        device->SetRenderTarget(0, renderTarget);
+        mDevice->SetRenderTarget(0, renderTarget);
         mAppliedRenderTargetSerial = renderTargetSerial;
         mScissorStateDirty = true; // Scissor area must be clamped to render target's size-- this is different for different render targets.
         renderTargetChanged = true;
     }
 
     unsigned int depthbufferSerial = 0;
     unsigned int stencilbufferSerial = 0;
     if (framebufferObject->getDepthbufferType() != GL_NONE)
@@ -1672,17 +1674,17 @@ bool Context::applyRenderTarget(bool ign
         
         stencilbufferSerial = framebufferObject->getStencilbuffer()->getSerial();
     }
 
     if (depthbufferSerial != mAppliedDepthbufferSerial ||
         stencilbufferSerial != mAppliedStencilbufferSerial ||
         !mDepthStencilInitialized)
     {
-        device->SetDepthStencilSurface(depthStencil);
+        mDevice->SetDepthStencilSurface(depthStencil);
         mAppliedDepthbufferSerial = depthbufferSerial;
         mAppliedStencilbufferSerial = stencilbufferSerial;
         mDepthStencilInitialized = true;
     }
 
     if (!mRenderTargetDescInitialized || renderTargetChanged)
     {
         if (!renderTarget)
@@ -1725,37 +1727,37 @@ bool Context::applyRenderTarget(bool ign
 
     if (viewport.Width <= 0 || viewport.Height <= 0)
     {
         return false;   // Nothing to render
     }
 
     if (!mViewportInitialized || memcmp(&viewport, &mSetViewport, sizeof mSetViewport) != 0)
     {
-        device->SetViewport(&viewport);
+        mDevice->SetViewport(&viewport);
         mSetViewport = viewport;
         mViewportInitialized = true;
         mDxUniformsDirty = true;
     }
 
     if (mScissorStateDirty)
     {
         if (mState.scissorTest)
         {
             RECT rect = transformPixelRect(mState.scissorX, mState.scissorY, mState.scissorWidth, mState.scissorHeight, mRenderTargetDesc.Height);
             rect.left = clamp(rect.left, 0L, static_cast<LONG>(mRenderTargetDesc.Width));
             rect.top = clamp(rect.top, 0L, static_cast<LONG>(mRenderTargetDesc.Height));
             rect.right = clamp(rect.right, 0L, static_cast<LONG>(mRenderTargetDesc.Width));
             rect.bottom = clamp(rect.bottom, 0L, static_cast<LONG>(mRenderTargetDesc.Height));
-            device->SetScissorRect(&rect);
-            device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
+            mDevice->SetScissorRect(&rect);
+            mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
         }
         else
         {
-            device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
         }
 
         mScissorStateDirty = false;
     }
 
     if (mState.currentProgram && mDxUniformsDirty)
     {
         Program *programObject = getCurrentProgram();
@@ -1781,127 +1783,125 @@ bool Context::applyRenderTarget(bool ign
     }
 
     return true;
 }
 
 // Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device
 void Context::applyState(GLenum drawMode)
 {
-    IDirect3DDevice9 *device = getDevice();
     Program *programObject = getCurrentProgram();
 
     Framebuffer *framebufferObject = getDrawFramebuffer();
 
     GLenum adjustedFrontFace = adjustWinding(mState.frontFace);
 
     GLint frontCCW = programObject->getDxFrontCCWLocation();
     GLint ccw = (adjustedFrontFace == GL_CCW);
     programObject->setUniform1iv(frontCCW, 1, &ccw);
 
     GLint pointsOrLines = programObject->getDxPointsOrLinesLocation();
     GLint alwaysFront = !isTriangleMode(drawMode);
     programObject->setUniform1iv(pointsOrLines, 1, &alwaysFront);
 
-    egl::Display *display = getDisplay();
-    D3DADAPTER_IDENTIFIER9 *identifier = display->getAdapterIdentifier();
+    D3DADAPTER_IDENTIFIER9 *identifier = mDisplay->getAdapterIdentifier();
     bool zeroColorMaskAllowed = identifier->VendorId != 0x1002;
     // Apparently some ATI cards have a bug where a draw with a zero color
     // write mask can cause later draws to have incorrect results. Instead,
     // set a nonzero color write mask but modify the blend state so that no
     // drawing is done.
     // http://code.google.com/p/angleproject/issues/detail?id=169
 
     if (mCullStateDirty || mFrontFaceDirty)
     {
         if (mState.cullFace)
         {
-            device->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(mState.cullMode, adjustedFrontFace));
+            mDevice->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(mState.cullMode, adjustedFrontFace));
         }
         else
         {
-            device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+            mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
         }
 
         mCullStateDirty = false;
     }
 
     if (mDepthStateDirty)
     {
         if (mState.depthTest)
         {
-            device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
-            device->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc));
+            mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
+            mDevice->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc));
         }
         else
         {
-            device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
+            mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
         }
 
         mDepthStateDirty = false;
     }
 
     if (!zeroColorMaskAllowed && (mMaskStateDirty || mBlendStateDirty))
     {
         mBlendStateDirty = true;
         mMaskStateDirty = true;
     }
 
     if (mBlendStateDirty)
     {
         if (mState.blend)
         {
-            device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+            mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
 
             if (mState.sourceBlendRGB != GL_CONSTANT_ALPHA && mState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
                 mState.destBlendRGB != GL_CONSTANT_ALPHA && mState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
             {
-                device->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(mState.blendColor));
+                mDevice->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(mState.blendColor));
             }
             else
             {
-                device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(mState.blendColor.alpha),
+                mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(mState.blendColor.alpha),
                                                                         unorm<8>(mState.blendColor.alpha),
                                                                         unorm<8>(mState.blendColor.alpha),
                                                                         unorm<8>(mState.blendColor.alpha)));
             }
 
-            device->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(mState.sourceBlendRGB));
-            device->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(mState.destBlendRGB));
-            device->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(mState.blendEquationRGB));
+            mDevice->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(mState.sourceBlendRGB));
+            mDevice->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(mState.destBlendRGB));
+            mDevice->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(mState.blendEquationRGB));
 
             if (mState.sourceBlendRGB != mState.sourceBlendAlpha || 
                 mState.destBlendRGB != mState.destBlendAlpha || 
                 mState.blendEquationRGB != mState.blendEquationAlpha)
             {
-                device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
-
-                device->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(mState.sourceBlendAlpha));
-                device->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(mState.destBlendAlpha));
-                device->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(mState.blendEquationAlpha));
+                mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+
+                mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(mState.sourceBlendAlpha));
+                mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(mState.destBlendAlpha));
+                mDevice->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(mState.blendEquationAlpha));
             }
             else
             {
-                device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+                mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
             }
         }
         else
         {
-            device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
         }
 
         mBlendStateDirty = false;
     }
 
     if (mStencilStateDirty || mFrontFaceDirty)
     {
         if (mState.stencilTest && framebufferObject->hasStencil())
         {
-            device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
-            device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
+            mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+            mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
 
             // FIXME: Unsupported by D3D9
             const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
             const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
             const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
             if (mState.stencilWritemask != mState.stencilBackWritemask || 
                 mState.stencilRef != mState.stencilBackRef || 
                 mState.stencilMask != mState.stencilBackMask)
@@ -1909,105 +1909,105 @@ void Context::applyState(GLenum drawMode
                 ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL.");
                 return error(GL_INVALID_OPERATION);
             }
 
             // get the maximum size of the stencil ref
             gl::DepthStencilbuffer *stencilbuffer = framebufferObject->getStencilbuffer();
             GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1;
 
-            device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask);
-            device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, 
+            mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask);
+            mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, 
                                    es2dx::ConvertComparison(mState.stencilFunc));
 
-            device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil);
-            device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask);
-
-            device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, 
+            mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil);
+            mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask);
+
+            mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, 
                                    es2dx::ConvertStencilOp(mState.stencilFail));
-            device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, 
+            mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, 
                                    es2dx::ConvertStencilOp(mState.stencilPassDepthFail));
-            device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, 
+            mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, 
                                    es2dx::ConvertStencilOp(mState.stencilPassDepthPass));
 
-            device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilBackWritemask);
-            device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, 
+            mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilBackWritemask);
+            mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, 
                                    es2dx::ConvertComparison(mState.stencilBackFunc));
 
-            device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil);
-            device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilBackMask);
-
-            device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, 
+            mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil);
+            mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilBackMask);
+
+            mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, 
                                    es2dx::ConvertStencilOp(mState.stencilBackFail));
-            device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, 
+            mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, 
                                    es2dx::ConvertStencilOp(mState.stencilBackPassDepthFail));
-            device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, 
+            mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, 
                                    es2dx::ConvertStencilOp(mState.stencilBackPassDepthPass));
         }
         else
         {
-            device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
         }
 
         mStencilStateDirty = false;
         mFrontFaceDirty = false;
     }
 
     if (mMaskStateDirty)
     {
         int colorMask = es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, 
                                                 mState.colorMaskBlue, mState.colorMaskAlpha);
         if (colorMask == 0 && !zeroColorMaskAllowed)
         {
             // Enable green channel, but set blending so nothing will be drawn.
-            device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
-            device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
-
-            device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
-            device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
-            device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+            mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
+            mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+            mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
+            mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
+            mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
         }
         else
         {
-            device->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
+            mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
         }
-        device->SetRenderState(D3DRS_ZWRITEENABLE, mState.depthMask ? TRUE : FALSE);
+        mDevice->SetRenderState(D3DRS_ZWRITEENABLE, mState.depthMask ? TRUE : FALSE);
 
         mMaskStateDirty = false;
     }
 
     if (mPolygonOffsetStateDirty)
     {
         if (mState.polygonOffsetFill)
         {
             gl::DepthStencilbuffer *depthbuffer = framebufferObject->getDepthbuffer();
             if (depthbuffer)
             {
-                device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor));
+                mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor));
                 float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize()));
-                device->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias));
+                mDevice->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias));
             }
         }
         else
         {
-            device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
-            device->SetRenderState(D3DRS_DEPTHBIAS, 0);
+            mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
+            mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0);
         }
 
         mPolygonOffsetStateDirty = false;
     }
 
     if (mSampleStateDirty)
     {
         if (mState.sampleAlphaToCoverage)
         {
             FIXME("Sample alpha to coverage is unimplemented.");
         }
 
-        device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
+        mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
         if (mState.sampleCoverage)
         {
             unsigned int mask = 0;
             if (mState.sampleCoverageValue != 0)
             {
                 float threshold = 0.5f;
 
                 for (int i = 0; i < framebufferObject->getSamples(); ++i)
@@ -2022,77 +2022,75 @@ void Context::applyState(GLenum drawMode
                 }
             }
             
             if (mState.sampleCoverageInvert)
             {
                 mask = ~mask;
             }
 
-            device->SetRenderState(D3DRS_MULTISAMPLEMASK, mask);
+            mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, mask);
         }
         else
         {
-            device->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+            mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
         }
 
         mSampleStateDirty = false;
     }
 
     if (mDitherStateDirty)
     {
-        device->SetRenderState(D3DRS_DITHERENABLE, mState.dither ? TRUE : FALSE);
+        mDevice->SetRenderState(D3DRS_DITHERENABLE, mState.dither ? TRUE : FALSE);
 
         mDitherStateDirty = false;
     }
 }
 
 GLenum Context::applyVertexBuffer(GLint first, GLsizei count)
 {
     TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS];
 
     GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes);
     if (err != GL_NO_ERROR)
     {
         return err;
     }
 
-    return mVertexDeclarationCache.applyDeclaration(attributes, getCurrentProgram());
+    return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, getCurrentProgram());
 }
 
 // Applies the indices and element array bindings to the Direct3D 9 device
 GLenum Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
 {
-    IDirect3DDevice9 *device = getDevice();
     GLenum err = mIndexDataManager->prepareIndexData(type, count, mState.elementArrayBuffer.get(), indices, indexInfo);
 
     if (err == GL_NO_ERROR)
     {
         if (indexInfo->serial != mAppliedIBSerial)
         {
-            device->SetIndices(indexInfo->indexBuffer);
+            mDevice->SetIndices(indexInfo->indexBuffer);
             mAppliedIBSerial = indexInfo->serial;
         }
     }
 
     return err;
 }
 
 // Applies the shaders and shader constants to the Direct3D 9 device
 void Context::applyShaders()
 {
-    IDirect3DDevice9 *device = getDevice();
     Program *programObject = getCurrentProgram();
     if (programObject->getSerial() != mAppliedProgramSerial)
     {
         IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader();
         IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader();
 
-        device->SetPixelShader(pixelShader);
-        device->SetVertexShader(vertexShader);
+        mDevice->SetPixelShader(pixelShader);
+        mDevice->SetVertexShader(vertexShader);
         programObject->dirtyAllUniforms();
         mAppliedProgramSerial = programObject->getSerial();
     }
 
     programObject->applyUniforms();
 }
 
 // Applies the textures and sampler states to the Direct3D 9 device
@@ -2106,17 +2104,16 @@ void Context::applyTextures()
     }
 }
 
 // For each Direct3D 9 sampler of either the pixel or vertex stage,
 // looks up the corresponding OpenGL texture image unit and texture type,
 // and sets the texture and its addressing/filtering state (or NULL when inactive).
 void Context::applyTextures(SamplerType type)
 {
-    IDirect3DDevice9 *device = getDevice();
     Program *programObject = getCurrentProgram();
 
     int samplerCount = (type == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF;   // Range of Direct3D 9 samplers of given sampler type
     unsigned int *appliedTextureSerial = (type == SAMPLER_PIXEL) ? mAppliedTextureSerialPS : mAppliedTextureSerialVS;
     int d3dSamplerOffset = (type == SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
     int samplerRange = programObject->getUsedSamplerRange(type);
 
     for (int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
@@ -2138,55 +2135,55 @@ void Context::applyTextures(SamplerType 
                 {
                     if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyParameter())
                     {
                         GLenum wrapS = texture->getWrapS();
                         GLenum wrapT = texture->getWrapT();
                         GLenum minFilter = texture->getMinFilter();
                         GLenum magFilter = texture->getMagFilter();
 
-                        device->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS));
-                        device->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT));
-
-                        device->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter));
+                        mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS));
+                        mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT));
+
+                        mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter));
                         D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
                         es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter);
-                        device->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
-                        device->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
+                        mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
+                        mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
                     }
 
                     if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyImage())
                     {
-                        device->SetTexture(d3dSampler, d3dTexture);
+                        mDevice->SetTexture(d3dSampler, d3dTexture);
                     }
                 }
                 else
                 {
-                    device->SetTexture(d3dSampler, getIncompleteTexture(textureType)->getTexture());
+                    mDevice->SetTexture(d3dSampler, getIncompleteTexture(textureType)->getTexture());
                 }
 
                 appliedTextureSerial[samplerIndex] = texture->getSerial();
                 texture->resetDirty();
             }
         }
         else
         {
             if (appliedTextureSerial[samplerIndex] != 0)
             {
-                device->SetTexture(d3dSampler, NULL);
+                mDevice->SetTexture(d3dSampler, NULL);
                 appliedTextureSerial[samplerIndex] = 0;
             }
         }
     }
 
     for (int samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++)
     {
         if (appliedTextureSerial[samplerIndex] != 0)
         {
-            device->SetTexture(samplerIndex + d3dSamplerOffset, NULL);
+            mDevice->SetTexture(samplerIndex + d3dSamplerOffset, NULL);
             appliedTextureSerial[samplerIndex] = 0;
         }
     }
 }
 
 void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
 {
     Framebuffer *framebuffer = getReadFramebuffer();
@@ -2203,37 +2200,35 @@ void Context::readPixels(GLint x, GLint 
 
     IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget();
 
     if (!renderTarget)
     {
         return;   // Context must be lost, return silently
     }
 
-    IDirect3DDevice9 *device = getDevice();
-
     D3DSURFACE_DESC desc;
     renderTarget->GetDesc(&desc);
 
     IDirect3DSurface9 *systemSurface;
-    HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
+    HRESULT result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
 
     if (FAILED(result))
     {
         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
         return error(GL_OUT_OF_MEMORY);
     }
 
     if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
     {
         UNIMPLEMENTED();   // FIXME: Requires resolve using StretchRect into non-multisampled render target
         return error(GL_OUT_OF_MEMORY);
     }
 
-    result = device->GetRenderTargetData(renderTarget, systemSurface);
+    result = mDevice->GetRenderTargetData(renderTarget, systemSurface);
 
     if (FAILED(result))
     {
         systemSurface->Release();
 
         switch (result)
         {
           // It turns out that D3D will sometimes produce more error
@@ -2452,18 +2447,16 @@ void Context::clear(GLbitfield mask)
 {
     Framebuffer *framebufferObject = getDrawFramebuffer();
 
     if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
     {
         return error(GL_INVALID_FRAMEBUFFER_OPERATION);
     }
 
-    egl::Display *display = getDisplay();
-    IDirect3DDevice9 *device = getDevice();
     DWORD flags = 0;
 
     if (mask & GL_COLOR_BUFFER_BIT)
     {
         mask &= ~GL_COLOR_BUFFER_BIT;
 
         if (framebufferObject->getColorbufferType() != GL_NONE)
         {
@@ -2545,98 +2538,98 @@ void Context::clear(GLbitfield mask)
     if (needMaskedColorClear || needMaskedStencilClear)
     {
         // State which is altered in all paths from this point to the clear call is saved.
         // State which is altered in only some paths will be flagged dirty in the case that
         //  that path is taken.
         HRESULT hr;
         if (mMaskedClearSavedState == NULL)
         {
-            hr = device->BeginStateBlock();
+            hr = mDevice->BeginStateBlock();
             ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
 
-            device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
-            device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
-            device->SetRenderState(D3DRS_ZENABLE, FALSE);
-            device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
-            device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
-            device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
-            device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
-            device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
-            device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
-            device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
-            device->SetPixelShader(NULL);
-            device->SetVertexShader(NULL);
-            device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
-            device->SetStreamSource(0, NULL, 0, 0);
-            device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
-            device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
-            device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
-            device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
-            device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
-            device->SetRenderState(D3DRS_TEXTUREFACTOR, color);
-            device->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
-
-            hr = device->EndStateBlock(&mMaskedClearSavedState);
+            mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+            mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+            mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+            mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+            mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+            mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+            mDevice->SetPixelShader(NULL);
+            mDevice->SetVertexShader(NULL);
+            mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
+            mDevice->SetStreamSource(0, NULL, 0, 0);
+            mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+            mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+            mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+            mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+            mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+            mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+            mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+            hr = mDevice->EndStateBlock(&mMaskedClearSavedState);
             ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
         }
 
         ASSERT(mMaskedClearSavedState != NULL);
 
         if (mMaskedClearSavedState != NULL)
         {
             hr = mMaskedClearSavedState->Capture();
             ASSERT(SUCCEEDED(hr));
         }
 
-        device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
-        device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
-        device->SetRenderState(D3DRS_ZENABLE, FALSE);
-        device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
-        device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
-        device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
-        device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
-        device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+        mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+        mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+        mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+        mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+        mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+        mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+        mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+        mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
 
         if (flags & D3DCLEAR_TARGET)
         {
-            device->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, mState.colorMaskBlue, mState.colorMaskAlpha));
+            mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, mState.colorMaskBlue, mState.colorMaskAlpha));
         }
         else
         {
-            device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+            mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
         }
 
         if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL))
         {
-            device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
-            device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
-            device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
-            device->SetRenderState(D3DRS_STENCILREF, stencil);
-            device->SetRenderState(D3DRS_STENCILWRITEMASK, mState.stencilWritemask);
-            device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
-            device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
-            device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
+            mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+            mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+            mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
+            mDevice->SetRenderState(D3DRS_STENCILREF, stencil);
+            mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, mState.stencilWritemask);
+            mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
+            mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
+            mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
             mStencilStateDirty = true;
         }
         else
         {
-            device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+            mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
         }
 
-        device->SetPixelShader(NULL);
-        device->SetVertexShader(NULL);
-        device->SetFVF(D3DFVF_XYZRHW);
-        device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
-        device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
-        device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
-        device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
-        device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
-        device->SetRenderState(D3DRS_TEXTUREFACTOR, color);
-        device->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+        mDevice->SetPixelShader(NULL);
+        mDevice->SetVertexShader(NULL);
+        mDevice->SetFVF(D3DFVF_XYZRHW);
+        mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+        mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+        mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+        mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+        mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+        mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+        mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
 
         float quad[4][4];   // A quadrilateral covering the target, aligned to match the edges
         quad[0][0] = -0.5f;
         quad[0][1] = desc.Height - 0.5f;
         quad[0][2] = 0.0f;
         quad[0][3] = 1.0f;
 
         quad[1][0] = desc.Width - 0.5f;
@@ -2649,46 +2642,44 @@ void Context::clear(GLbitfield mask)
         quad[2][2] = 0.0f;
         quad[2][3] = 1.0f;
 
         quad[3][0] = desc.Width - 0.5f;
         quad[3][1] = -0.5f;
         quad[3][2] = 0.0f;
         quad[3][3] = 1.0f;
 
-        display->startScene();
-        device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4]));
+        mDisplay->startScene();
+        mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4]));
 
         if (flags & D3DCLEAR_ZBUFFER)
         {
-            device->SetRenderState(D3DRS_ZENABLE, TRUE);
-            device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
-            device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
+            mDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
+            mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
+            mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
         }
 
         if (mMaskedClearSavedState != NULL)
         {
             mMaskedClearSavedState->Apply();
         }
     }
     else if (flags)
     {
-        device->Clear(0, NULL, flags, color, depth, stencil);
+        mDevice->Clear(0, NULL, flags, color, depth, stencil);
     }
 }
 
 void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
 {
     if (!mState.currentProgram)
     {
         return error(GL_INVALID_OPERATION);
     }
 
-    egl::Display *display = getDisplay();
-    IDirect3DDevice9 *device = getDevice();
     D3DPRIMITIVETYPE primitiveType;
     int primitiveCount;
 
     if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount))
         return error(GL_INVALID_ENUM);
 
     if (primitiveCount <= 0)
     {
@@ -2713,19 +2704,19 @@ void Context::drawArrays(GLenum mode, GL
 
     if (!getCurrentProgram()->validateSamplers(false))
     {
         return error(GL_INVALID_OPERATION);
     }
 
     if (!cullSkipsDraw(mode))
     {
-        display->startScene();
+        mDisplay->startScene();
         
-        device->DrawPrimitive(primitiveType, 0, primitiveCount);
+        mDevice->DrawPrimitive(primitiveType, 0, primitiveCount);
 
         if (mode == GL_LINE_LOOP)   // Draw the last segment separately
         {
             drawClosingLine(first, first + count - 1);
         }
     }
 }
 
@@ -2736,18 +2727,16 @@ void Context::drawElements(GLenum mode, 
         return error(GL_INVALID_OPERATION);
     }
 
     if (!indices && !mState.elementArrayBuffer)
     {
         return error(GL_INVALID_OPERATION);
     }
 
-    egl::Display *display = getDisplay();
-    IDirect3DDevice9 *device = getDevice();
     D3DPRIMITIVETYPE primitiveType;
     int primitiveCount;
 
     if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount))
         return error(GL_INVALID_ENUM);
 
     if (primitiveCount <= 0)
     {
@@ -2780,113 +2769,34 @@ void Context::drawElements(GLenum mode, 
 
     if (!getCurrentProgram()->validateSamplers(false))
     {
         return error(GL_INVALID_OPERATION);
     }
 
     if (!cullSkipsDraw(mode))
     {
-        display->startScene();
-
-        device->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount);
+        mDisplay->startScene();
+
+        mDevice->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount);
 
         if (mode == GL_LINE_LOOP)   // Draw the last segment separately
         {
             drawClosingLine(count, type, indices);
         }
     }
 }
 
-void Context::finish()
+// Implements glFlush when block is false, glFinish when block is true
+void Context::sync(bool block)
 {
-    egl::Display *display = getDisplay();
-    IDirect3DDevice9 *device = getDevice();
-    IDirect3DQuery9 *occlusionQuery = NULL;
-    HRESULT result;
-
-    result = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery);
-    if (FAILED(result))
-    {
-        ERR("CreateQuery failed hr=%x\n", result);
-        if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
-        {
-            return error(GL_OUT_OF_MEMORY);
-        }
-        ASSERT(false);
-        return;
-    }
-
-    IDirect3DStateBlock9 *savedState = NULL;
-    result = device->CreateStateBlock(D3DSBT_ALL, &savedState);
-    if (FAILED(result))
-    {
-        ERR("CreateStateBlock failed hr=%x\n", result);
-        occlusionQuery->Release();
-
-        if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
-        {
-            return error(GL_OUT_OF_MEMORY);
-        }
-        ASSERT(false);
-        return;
-    }
-
-    result = occlusionQuery->Issue(D3DISSUE_BEGIN);
-    if (FAILED(result))
-    {
-        ERR("occlusionQuery->Issue(BEGIN) failed hr=%x\n", result);
-        occlusionQuery->Release();
-        savedState->Release();
-        ASSERT(false);
-        return;
-    }
-
-    // Render something outside the render target
-    device->SetPixelShader(NULL);
-    device->SetVertexShader(NULL);
-    device->SetFVF(D3DFVF_XYZRHW);
-    float data[4] = {-1.0f, -1.0f, -1.0f, 1.0f};
-    display->startScene();
-    device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, data, sizeof(data));
-
-    result = occlusionQuery->Issue(D3DISSUE_END);
-    if (FAILED(result))
-    {
-        ERR("occlusionQuery->Issue(END) failed hr=%x\n", result);
-        occlusionQuery->Release();
-        savedState->Apply();
-        savedState->Release();
-        ASSERT(false);
-        return;
-    }
-
-    while ((result = occlusionQuery->GetData(NULL, 0, D3DGETDATA_FLUSH)) == S_FALSE)
-    {
-        // Keep polling, but allow other threads to do something useful first
-        Sleep(0);
-    }
-
-    occlusionQuery->Release();
-    savedState->Apply();
-    savedState->Release();
-
-    if (result == D3DERR_DEVICELOST)
-    {
-        error(GL_OUT_OF_MEMORY);
-    }
-}
-
-void Context::flush()
-{
-    IDirect3DDevice9 *device = getDevice();
     IDirect3DQuery9 *eventQuery = NULL;
     HRESULT result;
 
-    result = device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
+    result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
     if (FAILED(result))
     {
         ERR("CreateQuery failed hr=%x\n", result);
         if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
         {
             return error(GL_OUT_OF_MEMORY);
         }
         ASSERT(false);
@@ -2897,39 +2807,49 @@ void Context::flush()
     if (FAILED(result))
     {
         ERR("eventQuery->Issue(END) failed hr=%x\n", result);
         ASSERT(false);
         eventQuery->Release();
         return;
     }
 
-    result = eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH);
+    do
+    {
+        result = eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH);
+
+        if(block && result == S_FALSE)
+        {
+            // Keep polling, but allow other threads to do something useful first
+            Sleep(0);
+        }
+    }
+    while(block && result == S_FALSE);
+
     eventQuery->Release();
 
     if (result == D3DERR_DEVICELOST)
     {
         error(GL_OUT_OF_MEMORY);
     }
 }
 
 void Context::drawClosingLine(unsigned int first, unsigned int last)
 {
-    IDirect3DDevice9 *device = getDevice();
     IDirect3DIndexBuffer9 *indexBuffer = NULL;
     bool succeeded = false;
     UINT offset;
 
     if (supports32bitIndices())
     {
         const int spaceNeeded = 2 * sizeof(unsigned int);
 
         if (!mClosingIB)
         {
-            mClosingIB = new StreamingIndexBuffer(device, CLOSING_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
+            mClosingIB = new StreamingIndexBuffer(mDevice, CLOSING_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
         }
 
         mClosingIB->reserveSpace(spaceNeeded, GL_UNSIGNED_INT);
 
         unsigned int *data = static_cast<unsigned int*>(mClosingIB->map(spaceNeeded, &offset));
         if (data)
         {
             data[0] = last;
@@ -2940,17 +2860,17 @@ void Context::drawClosingLine(unsigned i
         }
     }
     else
     {
         const int spaceNeeded = 2 * sizeof(unsigned short);
 
         if (!mClosingIB)
         {
-            mClosingIB = new StreamingIndexBuffer(device, CLOSING_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
+            mClosingIB = new StreamingIndexBuffer(mDevice, CLOSING_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
         }
 
         mClosingIB->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT);
 
         unsigned short *data = static_cast<unsigned short*>(mClosingIB->map(spaceNeeded, &offset));
         if (data)
         {
             data[0] = last;
@@ -2958,20 +2878,20 @@ void Context::drawClosingLine(unsigned i
             mClosingIB->unmap();
             offset /= 2;
             succeeded = true;
         }
     }
     
     if (succeeded)
     {
-        device->SetIndices(mClosingIB->getBuffer());
+        mDevice->SetIndices(mClosingIB->getBuffer());
         mAppliedIBSerial = mClosingIB->getSerial();
 
-        device->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, last, offset, 1);
+        mDevice->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, last, offset, 1);
     }
     else
     {
         ERR("Could not create an index buffer for closing a line loop.");
         error(GL_OUT_OF_MEMORY);
     }
 }
 
@@ -3488,35 +3408,32 @@ void Context::initExtensionString()
 
 const char *Context::getExtensionString() const
 {
     return mExtensionString.c_str();
 }
 
 void Context::initRendererString()
 {
-    egl::Display *display = getDisplay();
-    D3DADAPTER_IDENTIFIER9 *identifier = display->getAdapterIdentifier();
+    D3DADAPTER_IDENTIFIER9 *identifier = mDisplay->getAdapterIdentifier();
 
     mRendererString = "ANGLE (";
     mRendererString += identifier->Description;
     mRendererString += ")";
 }
 
 const char *Context::getRendererString() const
 {
     return mRendererString.c_str();
 }
 
 void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 
                               GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                               GLbitfield mask)
 {
-    IDirect3DDevice9 *device = getDevice();
-
     Framebuffer *readFramebuffer = getReadFramebuffer();
     Framebuffer *drawFramebuffer = getDrawFramebuffer();
 
     if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
         !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
     {
         return error(GL_INVALID_FRAMEBUFFER_OPERATION);
     }
@@ -3747,34 +3664,33 @@ void Context::blitFramebuffer(GLint srcX
             (readDSBuffer && readDSBuffer->getSamples() != 0))
         {
             return error(GL_INVALID_OPERATION);
         }
     }
 
     if (blitRenderTarget || blitDepthStencil)
     {
-        egl::Display *display = getDisplay();
-        display->endScene();
+        mDisplay->endScene();
 
         if (blitRenderTarget)
         {
-            HRESULT result = device->StretchRect(readFramebuffer->getRenderTarget(), &sourceTrimmedRect, 
+            HRESULT result = mDevice->StretchRect(readFramebuffer->getRenderTarget(), &sourceTrimmedRect, 
                                                  drawFramebuffer->getRenderTarget(), &destTrimmedRect, D3DTEXF_NONE);
 
             if (FAILED(result))
             {
                 ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result);
                 return;
             }
         }
 
         if (blitDepthStencil)
         {
-            HRESULT result = device->StretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, D3DTEXF_NONE);
+            HRESULT result = mDevice->StretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, D3DTEXF_NONE);
 
             if (FAILED(result))
             {
                 ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result);
                 return;
             }
         }
     }
@@ -3795,20 +3711,18 @@ VertexDeclarationCache::~VertexDeclarati
     {
         if (mVertexDeclCache[i].vertexDeclaration)
         {
             mVertexDeclCache[i].vertexDeclaration->Release();
         }
     }
 }
 
-GLenum VertexDeclarationCache::applyDeclaration(TranslatedAttribute attributes[], Program *program)
+GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program)
 {
-    IDirect3DDevice9 *device = getDevice();
-
     D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS + 1];
     D3DVERTEXELEMENT9 *element = &elements[0];
 
     for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
     {
         if (attributes[i].active)
         {
             if (mAppliedVBs[i].serial != attributes[i].serial ||
--- a/gfx/angle/src/libGLESv2/Context.h
+++ b/gfx/angle/src/libGLESv2/Context.h
@@ -223,17 +223,17 @@ struct State
 
 // Helper class to construct and cache vertex declarations
 class VertexDeclarationCache
 {
   public:
     VertexDeclarationCache();
     ~VertexDeclarationCache();
 
-    GLenum applyDeclaration(TranslatedAttribute attributes[], Program *program);
+    GLenum applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program);
 
     void markStateDirty();
 
   private:
     UINT mMaxLru;
 
     enum { NUM_VERTEX_DECL_CACHE_ENTRIES = 16 };
 
@@ -416,18 +416,17 @@ class Context
     bool getBooleanv(GLenum pname, GLboolean *params);
 
     bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams);
 
     void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
     void clear(GLbitfield mask);
     void drawArrays(GLenum mode, GLint first, GLsizei count);
     void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
-    void finish();
-    void flush();
+    void sync(bool block);   // flush/finish
 
 	// Draw the last segment of a line loop
     void drawClosingLine(unsigned int first, unsigned int last);
     void drawClosingLine(GLsizei count, GLenum type, const void *indices);
 
     void recordInvalidEnum();
     void recordInvalidValue();
     void recordInvalidOperation();
@@ -492,16 +491,18 @@ class Context
 
     bool cullSkipsDraw(GLenum drawMode);
     bool isTriangleMode(GLenum drawMode);
 
     void initExtensionString();
     void initRendererString();
 
     const egl::Config *const mConfig;
+    egl::Display *mDisplay;
+    IDirect3DDevice9 *mDevice;
 
     State mState;
 
     BindingPointer<Texture2D> mTexture2DZero;
     BindingPointer<TextureCubeMap> mTextureCubeMapZero;
 
     typedef stdext::hash_map<GLuint, Framebuffer*> FramebufferMap;
     FramebufferMap mFramebufferMap;
--- a/gfx/angle/src/libGLESv2/Program.cpp
+++ b/gfx/angle/src/libGLESv2/Program.cpp
@@ -54,16 +54,17 @@ bool Uniform::isArray()
 
 UniformLocation::UniformLocation(const std::string &_name, unsigned int element, unsigned int index) 
     : name(Program::undecorateUniform(_name)), element(element), index(index)
 {
 }
 
 Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
 {
+    mDevice = getDevice();
     mFragmentShader = NULL;
     mVertexShader = NULL;
 
     mPixelExecutable = NULL;
     mVertexExecutable = NULL;
     mConstantTablePS = NULL;
     mConstantTableVS = NULL;
 
@@ -1670,19 +1671,18 @@ void Program::link()
     const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
     const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
 
     ID3D10Blob *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
     ID3D10Blob *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
 
     if (vertexBinary && pixelBinary)
     {
-        IDirect3DDevice9 *device = getDevice();
-        HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
-        HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
+        HRESULT vertexResult = mDevice->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
+        HRESULT pixelResult = mDevice->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
 
         if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
         {
             return error(GL_OUT_OF_MEMORY);
         }
 
         ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
 
@@ -2046,18 +2046,16 @@ std::string Program::undecorateUniform(c
         return _name.substr(3);
     }
     
     return _name;
 }
 
 void Program::applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v)
 {
-    IDirect3DDevice9 *device = getDevice();
-
     float *vector = NULL;
     BOOL *boolVector = NULL;
 
     if (targetUniform->ps.registerCount && targetUniform->ps.registerSet == D3DXRS_FLOAT4 ||
         targetUniform->vs.registerCount && targetUniform->vs.registerSet == D3DXRS_FLOAT4)
     {
         vector = new float[4 * count];
 
@@ -2086,70 +2084,66 @@ void Program::applyUniformnbv(Uniform *t
             boolVector[i] = v[i] != GL_FALSE;
         }
     }
 
     if (targetUniform->ps.registerCount)
     {
         if (targetUniform->ps.registerSet == D3DXRS_FLOAT4)
         {
-            device->SetPixelShaderConstantF(targetUniform->ps.registerIndex, vector, targetUniform->ps.registerCount);
+            mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, vector, targetUniform->ps.registerCount);
         }
         else if (targetUniform->ps.registerSet == D3DXRS_BOOL)
         {
-            device->SetPixelShaderConstantB(targetUniform->ps.registerIndex, boolVector, targetUniform->ps.registerCount);
+            mDevice->SetPixelShaderConstantB(targetUniform->ps.registerIndex, boolVector, targetUniform->ps.registerCount);
         }
         else UNREACHABLE();
     }
 
     if (targetUniform->vs.registerCount)
     {
         if (targetUniform->vs.registerSet == D3DXRS_FLOAT4)
         {
-            device->SetVertexShaderConstantF(targetUniform->vs.registerIndex, vector, targetUniform->vs.registerCount);
+            mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, vector, targetUniform->vs.registerCount);
         }
         else if (targetUniform->vs.registerSet == D3DXRS_BOOL)
         {
-            device->SetVertexShaderConstantB(targetUniform->vs.registerIndex, boolVector, targetUniform->vs.registerCount);
+            mDevice->SetVertexShaderConstantB(targetUniform->vs.registerIndex, boolVector, targetUniform->vs.registerCount);
         }
         else UNREACHABLE();
     }
 
     delete [] vector;
     delete [] boolVector;
 }
 
 bool Program::applyUniformnfv(Uniform *targetUniform, const GLfloat *v)
 {
-    IDirect3DDevice9 *device = getDevice();
-
     if (targetUniform->ps.registerCount)
     {
-        device->SetPixelShaderConstantF(targetUniform->ps.registerIndex, v, targetUniform->ps.registerCount);
+        mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, v, targetUniform->ps.registerCount);
     }
 
     if (targetUniform->vs.registerCount)
     {
-        device->SetVertexShaderConstantF(targetUniform->vs.registerIndex, v, targetUniform->vs.registerCount);
+        mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, v, targetUniform->vs.registerCount);
     }
 
     return true;
 }
 
 bool Program::applyUniform1iv(Uniform *targetUniform, GLsizei count, const GLint *v)
 {
     D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
 
     for (int i = 0; i < count; i++)
     {
         vector[i] = D3DXVECTOR4((float)v[i], 0, 0, 0);
     }
 
-    IDirect3DDevice9 *device = getDevice();
-
     if (targetUniform->ps.registerCount)
     {
         if (targetUniform->ps.registerSet == D3DXRS_SAMPLER)
         {
             unsigned int firstIndex = targetUniform->ps.registerIndex;
 
             for (int i = 0; i < count; i++)
             {
@@ -2160,17 +2154,17 @@ bool Program::applyUniform1iv(Uniform *t
                     ASSERT(mSamplersPS[samplerIndex].active);
                     mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
                 }
             }
         }
         else
         {
             ASSERT(targetUniform->ps.registerSet == D3DXRS_FLOAT4);
-            device->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float*)vector, targetUniform->ps.registerCount);
+            mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float*)vector, targetUniform->ps.registerCount);
         }
     }
 
     if (targetUniform->vs.registerCount)
     {
         if (targetUniform->vs.registerSet == D3DXRS_SAMPLER)
         {
             unsigned int firstIndex = targetUniform->vs.registerIndex;
@@ -2184,17 +2178,17 @@ bool Program::applyUniform1iv(Uniform *t
                     ASSERT(mSamplersVS[samplerIndex].active);
                     mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
                 }
             }
         }
         else
         {
             ASSERT(targetUniform->vs.registerSet == D3DXRS_FLOAT4);
-            device->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount);
+            mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount);
         }
     }
 
     delete [] vector;
 
     return true;
 }
 
@@ -2249,28 +2243,26 @@ bool Program::applyUniform4iv(Uniform *t
 
     delete [] vector;
 
     return true;
 }
 
 void Program::applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector)
 {
-    IDirect3DDevice9 *device = getDevice();
-
     if (targetUniform->ps.registerCount)
     {
         ASSERT(targetUniform->ps.registerSet == D3DXRS_FLOAT4);
-        device->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float *)vector, targetUniform->ps.registerCount);
+        mDevice->SetPixelShaderConstantF(targetUniform->ps.registerIndex, (const float *)vector, targetUniform->ps.registerCount);
     }
 
     if (targetUniform->vs.registerCount)
     {
         ASSERT(targetUniform->vs.registerSet == D3DXRS_FLOAT4);
-        device->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount);
+        mDevice->SetVertexShaderConstantF(targetUniform->vs.registerIndex, (const float *)vector, targetUniform->vs.registerCount);
     }
 }
 
 // append a santized message to the program info log.
 // The D3D compiler includes a fake file path in some of the warning or error 
 // messages, so lets remove all occurrences of this fake file path from the log.
 void Program::appendToInfoLogSanitized(const char *message)
 {
--- a/gfx/angle/src/libGLESv2/Program.h
+++ b/gfx/angle/src/libGLESv2/Program.h
@@ -167,16 +167,17 @@ class Program
     void initializeConstantHandles(Uniform *targetUniform, Uniform::RegisterInfo *rs, ID3DXConstantTable *constantTable);
 
     void appendToInfoLogSanitized(const char *message);
     void appendToInfoLog(const char *info, ...);
     void resetInfoLog();
 
     static unsigned int issueSerial();
 
+    IDirect3DDevice9 *mDevice;
     FragmentShader *mFragmentShader;
     VertexShader *mVertexShader;
 
     std::string mPixelHLSL;
     std::string mVertexHLSL;
 
     IDirect3DPixelShader9 *mPixelExecutable;
     IDirect3DVertexShader9 *mVertexExecutable;
--- a/gfx/angle/src/libGLESv2/libGLESv2.cpp
+++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp
@@ -1946,17 +1946,17 @@ void __stdcall glFinish(void)
     EVENT("()");
 
     try
     {
         gl::Context *context = gl::getContext();
 
         if (context)
         {
-            context->finish();
+            context->sync(true);
         }
     }
     catch(std::bad_alloc&)
     {
         return error(GL_OUT_OF_MEMORY);
     }
 }
 
@@ -1965,17 +1965,17 @@ void __stdcall glFlush(void)
     EVENT("()");
 
     try
     {
         gl::Context *context = gl::getContext();
 
         if (context)
         {
-            context->flush();
+            context->sync(false);
         }
     }
     catch(std::bad_alloc&)
     {
         return error(GL_OUT_OF_MEMORY);
     }
 }
 
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -789,22 +789,20 @@ CairoImageOGL::SetData(const CairoImage:
       mLayerProgram = gl::RGBALayerProgramType;
     } else {
       mLayerProgram = gl::RGBXLayerProgramType;
     }
     return;
   }
 #endif
 
-  InitTexture(gl, tex, LOCAL_GL_RGBA, mSize);
-
   mLayerProgram =
     gl->UploadSurfaceToTexture(aData.mSurface,
                                nsIntRect(0,0, mSize.width, mSize.height),
-                               tex);
+                               tex, true);
 }
 
 void CairoImageOGL::SetTiling(bool aTiling)
 {
   if (aTiling == mTiling)
       return;
   mozilla::gl::GLContext *gl = mTexture.GetGLContext();
   gl->MakeCurrent();
--- a/image/public/imgIContainer.idl
+++ b/image/public/imgIContainer.idl
@@ -51,28 +51,33 @@ interface imgIDecoderObserver;
 #include "gfxRect.h"
 #include "gfxPattern.h"
 #include "gfxASurface.h"
 #include "nsRect.h"
 #include "nsSize.h"
 #include "limits.h"
 
 class nsIFrame;
+
+namespace mozilla {
+class TimeStamp;
+}
 %}
 
 [ptr] native gfxImageSurface(gfxImageSurface);
 [ptr] native gfxASurface(gfxASurface);
 native gfxImageFormat(gfxASurface::gfxImageFormat);
 [ptr] native gfxContext(gfxContext);
 [ref] native gfxMatrix(gfxMatrix);
 [ref] native gfxRect(gfxRect);
 native gfxGraphicsFilter(gfxPattern::GraphicsFilter);
 [ref] native nsIntRect(nsIntRect);
 [ref] native nsIntSize(nsIntSize);
 [ptr] native nsIFrame(nsIFrame);
+[ref] native TimeStamp(mozilla::TimeStamp);
 
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces, and permits users to extract subregions
  * as other imgIContainers. It also allows drawing of images on to Thebes
  * contexts.
  *
  * Internally, imgIContainer also manages animation of images.
@@ -257,16 +262,23 @@ interface imgIContainer : nsISupports
     *
     * Upon instantiation images have a lock count of zero. It is an error to
     * call this method without first having made a matching lockImage() call.
     * In other words, the lock count is not allowed to be negative.
     */
   void unlockImage();
 
   /**
+    * Indicates that this imgIContainer has been triggered to update
+    * its internal animation state. Likely this should only be called
+    * from within nsImageFrame or objects of similar type.
+    */
+  [notxpcom] void requestRefresh([const] in TimeStamp aTime);
+
+  /**
    * Animation mode Constants
    *   0 = normal
    *   1 = don't animate
    *   2 = loop once
    */
   const short kNormalAnimMode   = 0;
   const short kDontAnimMode     = 1;
   const short kLoopOnceAnimMode = 2;
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -168,20 +168,20 @@ DiscardingEnabled()
 
   return enabled;
 }
 
 namespace mozilla {
 namespace imagelib {
 
 #ifndef DEBUG
-NS_IMPL_ISUPPORTS4(RasterImage, imgIContainer, nsITimerCallback, nsIProperties,
+NS_IMPL_ISUPPORTS3(RasterImage, imgIContainer, nsIProperties,
                    nsISupportsWeakReference)
 #else
-NS_IMPL_ISUPPORTS5(RasterImage, imgIContainer, nsITimerCallback, nsIProperties,
+NS_IMPL_ISUPPORTS4(RasterImage, imgIContainer, nsIProperties,
                    imgIContainerDebug, nsISupportsWeakReference)
 #endif
 
 //******************************************************************************
 RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
   Image(aStatusTracker), // invoke superclass's constructor
   mSize(0,0),
   mFrameDecodeFlags(DECODE_FLAGS_DEFAULT),
@@ -308,16 +308,179 @@ RasterImage::Init(imgIDecoderObserver *a
   CONTAINER_ENSURE_SUCCESS(rv);
 
   // Mark us as initialized
   mInitialized = true;
 
   return NS_OK;
 }
 
+bool
+RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect)
+{
+  NS_ASSERTION(aTime <= TimeStamp::Now(),
+               "Given time appears to be in the future");
+
+  imgFrame* nextFrame = nsnull;
+  PRUint32 currentFrameIndex = mAnim->currentAnimationFrameIndex;
+  PRUint32 nextFrameIndex = mAnim->currentAnimationFrameIndex + 1;
+  PRUint32 timeout = 0;
+
+  // Figure out if we have the next full frame. This is more complicated than
+  // just checking for mFrames.Length() because decoders append their frames
+  // before they're filled in.
+  NS_ABORT_IF_FALSE(mDecoder || nextFrameIndex <= mFrames.Length(),
+                    "How did we get 2 indices too far by incrementing?");
+
+  // If we don't have a decoder, we know we've got everything we're going to
+  // get. If we do, we only display fully-downloaded frames; everything else
+  // gets delayed.
+  bool haveFullNextFrame = !mDecoder ||
+                           nextFrameIndex < mDecoder->GetCompleteFrameCount();
+
+  // If we're done decoding the next frame, go ahead and display it now and
+  // reinit with the next frame's delay time.
+  if (haveFullNextFrame) {
+    if (mFrames.Length() == nextFrameIndex) {
+      // End of Animation, unless we are looping forever
+
+      // If animation mode is "loop once", it's time to stop animating
+      if (mAnimationMode == kLoopOnceAnimMode || mLoopCount == 0) {
+        mAnimationFinished = PR_TRUE;
+        EvaluateAnimation();
+      }
+
+      // We may have used compositingFrame to build a frame, and then copied
+      // it back into mFrames[..].  If so, delete composite to save memory
+      if (mAnim->compositingFrame && mAnim->lastCompositedFrameIndex == -1) {
+        mAnim->compositingFrame = nsnull;
+      }
+
+      nextFrameIndex = 0;
+
+      if (mLoopCount > 0) {
+        mLoopCount--;
+      }
+
+      if (!mAnimating) {
+        // break out early if we are actually done animating
+        return false;
+      }
+    }
+
+    if (!(nextFrame = mFrames[nextFrameIndex])) {
+      // something wrong with the next frame, skip it
+      mAnim->currentAnimationFrameIndex = nextFrameIndex;
+      return false;
+    }
+
+    timeout = nextFrame->GetTimeout();
+
+  } else {
+    // Uh oh, the frame we want to show is currently being decoded (partial)
+    // Wait until the next refresh driver tick and try again
+    return false;
+  }
+
+  if (!(timeout > 0)) {
+    mAnimationFinished = PR_TRUE;
+    EvaluateAnimation();
+  }
+
+  imgFrame *frameToUse = nsnull;
+
+  if (nextFrameIndex == 0) {
+    frameToUse = nextFrame;
+    *aDirtyRect = mAnim->firstFrameRefreshArea;
+  } else {
+    imgFrame *curFrame = mFrames[currentFrameIndex];
+
+    if (!curFrame) {
+      return false;
+    }
+
+    // Change frame
+    if (NS_FAILED(DoComposite(aDirtyRect, curFrame,
+                              nextFrame, nextFrameIndex))) {
+      // something went wrong, move on to next
+      NS_WARNING("RasterImage::AdvanceFrame(): Compositing of frame failed");
+      nextFrame->SetCompositingFailed(PR_TRUE);
+      mAnim->currentAnimationFrameIndex = nextFrameIndex;
+      mAnim->currentAnimationFrameTime = aTime;
+      return false;
+    }
+
+    nextFrame->SetCompositingFailed(PR_FALSE);
+  }
+
+  // Set currentAnimationFrameIndex at the last possible moment
+  mAnim->currentAnimationFrameIndex = nextFrameIndex;
+  mAnim->currentAnimationFrameTime = aTime;
+
+  return true;
+}
+
+//******************************************************************************
+// [notxpcom] void requestRefresh ([const] in TimeStamp aTime);
+NS_IMETHODIMP_(void)
+RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime)
+{
+  if (!mAnimating || !ShouldAnimate()) {
+    return;
+  }
+
+  EnsureAnimExists();
+
+  // only advance the frame if the current time is greater than or
+  // equal to the current frame's end time.
+  TimeStamp currentFrameEndTime = GetCurrentImgFrameEndTime();
+  bool frameAdvanced = false;
+
+  // The dirtyRect variable will contain an accumulation of the sub-rectangles
+  // that are dirty for each frame we advance in AdvanceFrame().
+  nsIntRect dirtyRect;
+
+  while (currentFrameEndTime <= aTime) {
+    TimeStamp oldFrameEndTime = currentFrameEndTime;
+    nsIntRect frameDirtyRect;
+    bool didAdvance = AdvanceFrame(aTime, &frameDirtyRect);
+    frameAdvanced = frameAdvanced || didAdvance;
+    currentFrameEndTime = GetCurrentImgFrameEndTime();
+
+    // Accumulate the dirty area.
+    dirtyRect = dirtyRect.Union(frameDirtyRect);
+
+    // if we didn't advance a frame, and our frame end time didn't change,
+    // then we need to break out of this loop & wait for the frame(s)
+    // to finish downloading
+    if (!frameAdvanced && (currentFrameEndTime == oldFrameEndTime)) {
+      break;
+    }
+  }
+
+  if (frameAdvanced) {
+    nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
+
+    if (!observer) {
+      NS_ERROR("Refreshing image after its imgRequest is gone");
+      StopAnimation();
+      return;
+    }
+
+    // Notify listeners that our frame has actually changed, but do this only
+    // once for all frames that we've now passed (if AdvanceFrame() was called
+    // more than once).
+    #ifdef DEBUG
+      mFramesNotified++;
+    #endif
+
+    observer->FrameChanged(this, &dirtyRect);
+  }
+}
+
 //******************************************************************************
 /* [noscript] imgIContainer extractFrame(PRUint32 aWhichFrame,
  *                                       [const] in nsIntRect aRegion,
  *                                       in PRUint32 aFlags); */
 NS_IMETHODIMP
 RasterImage::ExtractFrame(PRUint32 aWhichFrame,
                           const nsIntRect &aRegion,
                           PRUint32 aFlags,
@@ -489,16 +652,37 @@ PRUint32
 RasterImage::GetCurrentImgFrameIndex() const
 {
   if (mAnim)
     return mAnim->currentAnimationFrameIndex;
 
   return 0;
 }
 
+TimeStamp
+RasterImage::GetCurrentImgFrameEndTime() const
+{
+  imgFrame* currentFrame = mFrames[mAnim->currentAnimationFrameIndex];
+  TimeStamp currentFrameTime = mAnim->currentAnimationFrameTime;
+  PRInt64 timeout = currentFrame->GetTimeout();
+
+  if (timeout < 0) {
+    // We need to return a sentinel value in this case, because our logic
+    // doesn't work correctly if we have a negative timeout value. The reason
+    // this positive infinity was chosen was because it works with the loop in
+    // RequestRefresh() above.
+    return TimeStamp() + TimeDuration::FromMilliseconds(UINT64_MAX_VAL);
+  }
+
+  TimeDuration durationOfTimeout = TimeDuration::FromMilliseconds(timeout);
+  TimeStamp currentFrameEndTime = currentFrameTime + durationOfTimeout;
+
+  return currentFrameEndTime;
+}
+
 imgFrame*
 RasterImage::GetCurrentImgFrame()
 {
   return GetImgFrame(GetCurrentImgFrameIndex());
 }
 
 imgFrame*
 RasterImage::GetCurrentDrawableImgFrame()
@@ -1133,53 +1317,41 @@ RasterImage::StartAnimation()
 {
   if (mError)
     return NS_ERROR_FAILURE;
 
   NS_ABORT_IF_FALSE(ShouldAnimate(), "Should not animate!");
 
   EnsureAnimExists();
 
-  NS_ABORT_IF_FALSE(mAnim && !mAnim->timer, "Anim must exist and not have a timer yet");
-  
-  // Default timeout to 100: the timer notify code will do the right
-  // thing, so just get that started.
-  PRInt32 timeout = 100;
-  imgFrame *currentFrame = GetCurrentImgFrame();
+  imgFrame* currentFrame = GetCurrentImgFrame();
   if (currentFrame) {
-    timeout = currentFrame->GetTimeout();
-    if (timeout < 0) { // -1 means display this frame forever
+    if (currentFrame->GetTimeout() < 0) { // -1 means display this frame forever
       mAnimationFinished = true;
       return NS_ERROR_ABORT;
     }
+
+    // We need to set the time that this initial frame was first displayed, as
+    // this is used in AdvanceFrame().
+    mAnim->currentAnimationFrameTime = TimeStamp::Now();
   }
   
-  mAnim->timer = do_CreateInstance("@mozilla.org/timer;1");
-  NS_ENSURE_TRUE(mAnim->timer, NS_ERROR_OUT_OF_MEMORY);
-  mAnim->timer->InitWithCallback(static_cast<nsITimerCallback*>(this),
-                                 timeout, nsITimer::TYPE_REPEATING_SLACK);
-  
   return NS_OK;
 }
 
 //******************************************************************************
 /* void stopAnimation (); */
 nsresult
 RasterImage::StopAnimation()
 {
   NS_ABORT_IF_FALSE(mAnimating, "Should be animating!");
 
   if (mError)
     return NS_ERROR_FAILURE;
 
-  if (mAnim->timer) {
-    mAnim->timer->Cancel();
-    mAnim->timer = nsnull;
-  }
-
   return NS_OK;
 }
 
 //******************************************************************************
 /* void resetAnimation (); */
 NS_IMETHODIMP
 RasterImage::ResetAnimation()
 {
@@ -1426,137 +1598,16 @@ nsresult
 RasterImage::SetSourceSizeHint(PRUint32 sizeHint)
 {
   if (sizeHint && StoringSourceData())
     return mSourceData.SetCapacity(sizeHint) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
   return NS_OK;
 }
 
 //******************************************************************************
-/* void notify(in nsITimer timer); */
-NS_IMETHODIMP
-RasterImage::Notify(nsITimer *timer)
-{
-#ifdef DEBUG
-  mFramesNotified++;
-#endif
-
-  // This should never happen since the timer is only set up in StartAnimation()
-  // after mAnim is checked to exist.
-  NS_ABORT_IF_FALSE(mAnim, "Need anim for Notify()");
-  NS_ABORT_IF_FALSE(timer, "Need timer for Notify()");
-  NS_ABORT_IF_FALSE(mAnim->timer == timer,
-                    "RasterImage::Notify() called with incorrect timer");
-
-  if (!mAnimating || !ShouldAnimate())
-    return NS_OK;
-
-  nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
-  if (!observer) {
-    // the imgRequest that owns us is dead, we should die now too.
-    NS_ABORT_IF_FALSE(mAnimationConsumers == 0,
-                      "If no observer, should have no consumers");
-    if (mAnimating)
-      StopAnimation();
-    return NS_OK;
-  }
-
-  if (mFrames.Length() == 0)
-    return NS_OK;
-  
-  imgFrame *nextFrame = nsnull;
-  PRInt32 previousFrameIndex = mAnim->currentAnimationFrameIndex;
-  PRUint32 nextFrameIndex = mAnim->currentAnimationFrameIndex + 1;
-  PRInt32 timeout = 0;
-
-  // Figure out if we have the next full frame. This is more complicated than
-  // just checking for mFrames.Length() because decoders append their frames
-  // before they're filled in.
-  NS_ABORT_IF_FALSE(mDecoder || nextFrameIndex <= mFrames.Length(),
-                    "How did we get 2 indicies too far by incrementing?");
-
-  // If we don't have a decoder, we know we've got everything we're going to get.
-  // If we do, we only display fully-downloaded frames; everything else gets delayed.
-  bool haveFullNextFrame = !mDecoder || nextFrameIndex < mDecoder->GetCompleteFrameCount();
-
-  // If we're done decoding the next frame, go ahead and display it now and
-  // reinit the timer with the next frame's delay time.
-  if (haveFullNextFrame) {
-    if (mFrames.Length() == nextFrameIndex) {
-      // End of Animation
-
-      // If animation mode is "loop once", it's time to stop animating
-      if (mAnimationMode == kLoopOnceAnimMode || mLoopCount == 0) {
-        mAnimationFinished = true;
-        EvaluateAnimation();
-        return NS_OK;
-      } else {
-        // We may have used compositingFrame to build a frame, and then copied
-        // it back into mFrames[..].  If so, delete composite to save memory
-        if (mAnim->compositingFrame && mAnim->lastCompositedFrameIndex == -1)
-          mAnim->compositingFrame = nsnull;
-      }
-
-      nextFrameIndex = 0;
-      if (mLoopCount > 0)
-        mLoopCount--;
-    }
-
-    if (!(nextFrame = mFrames[nextFrameIndex])) {
-      // something wrong with the next frame, skip it
-      mAnim->currentAnimationFrameIndex = nextFrameIndex;
-      mAnim->timer->SetDelay(100);
-      return NS_OK;
-    }
-    timeout = nextFrame->GetTimeout();
-
-  } else {
-    // Uh oh, the frame we want to show is currently being decoded (partial)
-    // Wait a bit and try again
-    mAnim->timer->SetDelay(100);
-    return NS_OK;
-  }
-
-  if (timeout > 0)
-    mAnim->timer->SetDelay(timeout);
-  else {
-    mAnimationFinished = true;
-    EvaluateAnimation();
-  }
-
-  nsIntRect dirtyRect;
-
-  if (nextFrameIndex == 0) {
-    dirtyRect = mAnim->firstFrameRefreshArea;
-  } else {
-    imgFrame *prevFrame = mFrames[previousFrameIndex];
-    if (!prevFrame)
-      return NS_OK;
-
-    // Change frame and announce it
-    if (NS_FAILED(DoComposite(&dirtyRect, prevFrame,
-                              nextFrame, nextFrameIndex))) {
-      // something went wrong, move on to next
-      NS_WARNING("RasterImage::Notify(): Composing Frame Failed\n");
-      nextFrame->SetCompositingFailed(true);
-      mAnim->currentAnimationFrameIndex = nextFrameIndex;
-      return NS_OK;
-    } else {
-      nextFrame->SetCompositingFailed(false);
-    }
-  }
-  // Set currentAnimationFrameIndex at the last possible moment
-  mAnim->currentAnimationFrameIndex = nextFrameIndex;
-  // Refreshes the screen
-  observer->FrameChanged(this, &dirtyRect);
-  
-  return NS_OK;
-}
-
-//******************************************************************************
 // DoComposite gets called when the timer for animation get fired and we have to
 // update the composited frame of the animation.
 nsresult
 RasterImage::DoComposite(nsIntRect* aDirtyRect,
                          imgFrame* aPrevFrame,
                          imgFrame* aNextFrame,
                          PRInt32 aNextFrameIndex)
 {
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -66,42 +66,61 @@
 #include "DiscardTracker.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
 #ifdef DEBUG
   #include "imgIContainerDebug.h"
 #endif
 
 class imgIDecoder;
+class imgIContainerObserver;
 class nsIInputStream;
 
 #define NS_RASTERIMAGE_CID \
 { /* 376ff2c1-9bf6-418a-b143-3340c00112f7 */         \
      0x376ff2c1,                                     \
      0x9bf6,                                         \
      0x418a,                                         \
     {0xb1, 0x43, 0x33, 0x40, 0xc0, 0x01, 0x12, 0xf7} \
 }
 
 /**
+ * It would be nice if we had a macro for this in prtypes.h.
+ * TODO: Place this macro in prtypes.h as PR_UINT64_MAX.
+ */
+#define UINT64_MAX_VAL PRUint64(-1)
+
+/**
  * Handles static and animated image containers.
  *
  *
  * @par A Quick Walk Through
  * The decoder initializes this class and calls AppendFrame() to add a frame.
  * Once RasterImage detects more than one frame, it starts the animation
- * with StartAnimation().
+ * with StartAnimation(). Note that the invalidation events for RasterImage are
+ * generated automatically using nsRefreshDriver.
+ *
+ * @par
+ * StartAnimation() initializes the animation helper object and sets the time
+ * the first frame was displayed to the current clock time.
  *
  * @par
- * StartAnimation() creates a timer.  The timer calls Notify when the
- * specified frame delay time is up.
+ * When the refresh driver corresponding to the imgIContainer that this image is
+ * a part of notifies the RasterImage that it's time to invalidate,
+ * RequestRefresh() is called with a given TimeStamp to advance to. As long as
+ * the timeout of the given frame (the frame's "delay") plus the time that frame
+ * was first displayed is less than or equal to the TimeStamp given,
+ * RequestRefresh() calls AdvanceFrame().
  *
  * @par
- * Notify() moves on to the next frame, sets up the new timer delay, destroys
- * the old frame, and forces a redraw via observer->FrameChanged().
+ * AdvanceFrame() is responsible for advancing a single frame of the animation.
+ * It can return true, meaning that the frame advanced, or false, meaning that
+ * the frame failed to advance (usually because the next frame hasn't been
+ * decoded yet). It is also responsible for performing the final animation stop
+ * procedure if the final frame of a non-looping animation is reached.
  *
  * @par
  * Each frame can have a different method of removing itself. These are
  * listed as imgIContainer::cDispose... constants.  Notify() calls 
  * DoComposite() to handle any special frame destruction.
  *
  * @par
  * The basic path through DoComposite() is:
@@ -146,26 +165,24 @@ class nsIInputStream;
 
 namespace mozilla {
 namespace imagelib {
 
 class imgDecodeWorker;
 class Decoder;
 
 class RasterImage : public Image
-                  , public nsITimerCallback
                   , public nsIProperties
                   , public nsSupportsWeakReference
 #ifdef DEBUG
                   , public imgIContainerDebug
 #endif
 {
 public:
   NS_DECL_ISUPPORTS
-  NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSIPROPERTIES
 #ifdef DEBUG
   NS_DECL_IMGICONTAINERDEBUG
 #endif
 
   // BEGIN NS_DECL_IMGICONTAINER (minus GetAnimationMode/SetAnimationMode)
   // ** Don't edit this chunk except to mirror changes in imgIContainer.idl **
   NS_SCRIPTABLE NS_IMETHOD GetWidth(PRInt32 *aWidth);
@@ -178,16 +195,17 @@ public:
   NS_IMETHOD CopyFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxImageSurface **_retval NS_OUTPARAM);
   NS_IMETHOD ExtractFrame(PRUint32 aWhichFrame, const nsIntRect & aRect, PRUint32 aFlags, imgIContainer **_retval NS_OUTPARAM);
   NS_IMETHOD Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix & aUserSpaceToImageSpace, const gfxRect & aFill, const nsIntRect & aSubimage, const nsIntSize & aViewportSize, PRUint32 aFlags);
   NS_IMETHOD_(nsIFrame *) GetRootLayoutFrame(void);
   NS_SCRIPTABLE NS_IMETHOD RequestDecode(void);
   NS_SCRIPTABLE NS_IMETHOD LockImage(void);
   NS_SCRIPTABLE NS_IMETHOD UnlockImage(void);
   NS_SCRIPTABLE NS_IMETHOD ResetAnimation(void);
+  NS_IMETHOD_(void) RequestRefresh(const mozilla::TimeStamp& aTime);
   // END NS_DECL_IMGICONTAINER
 
   RasterImage(imgStatusTracker* aStatusTracker = nsnull);
   virtual ~RasterImage();
 
   virtual nsresult StartAnimation();
   virtual nsresult StopAnimation();
 
@@ -329,16 +347,20 @@ public:
   const char* GetURIString() { return mURIString.get();}
 
 private:
   struct Anim
   {
     //! Area of the first frame that needs to be redrawn on subsequent loops.
     nsIntRect                  firstFrameRefreshArea;
     PRUint32                   currentAnimationFrameIndex; // 0 to numFrames-1
+
+    // the time that the animation advanced to the current frame
+    TimeStamp                  currentAnimationFrameTime;
+
     //! Track the last composited frame for Optimizations (See DoComposite code)
     PRInt32                    lastCompositedFrameIndex;
     /** For managing blending of frames
      *
      * Some animations will use the compositingFrame to composite images
      * and just hand this back to the caller when it is time to draw the frame.
      * NOTE: When clearing compositingFrame, remember to set
      *       lastCompositedFrameIndex to -1.  Code assume that if
@@ -347,49 +369,60 @@ private:
     nsAutoPtr<imgFrame>        compositingFrame;
     /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
      *
      * The Previous Frame (all frames composited up to the current) needs to be
      * stored in cases where the image specifies it wants the last frame back
      * when it's done with the current frame.
      */
     nsAutoPtr<imgFrame>        compositingPrevFrame;
-    //! Timer to animate multiframed images
-    nsCOMPtr<nsITimer>         timer;
 
     Anim() :
       firstFrameRefreshArea(),
       currentAnimationFrameIndex(0),
-      lastCompositedFrameIndex(-1)
-    {
-      ;
-    }
-    ~Anim()
-    {
-      if (timer)
-        timer->Cancel();
-    }
+      lastCompositedFrameIndex(-1) {}
+    ~Anim() {}
   };
 
   /**
+   * Advances the animation. Typically, this will advance a single frame, but it
+   * may advance multiple frames. This may happen if we have infrequently
+   * "ticking" refresh drivers (e.g. in background tabs), or extremely short-
+   * lived animation frames.
+   *
+   * @param aTime the time that the animation should advance to. This will
+   *              typically be <= TimeStamp::Now().
+   *
+   * @param [out] aDirtyRect a pointer to an nsIntRect which encapsulates the
+   *        area to be repainted after the frame is advanced.
+   *
+   * @returns true, if the frame was successfully advanced, false if it was not
+   *          able to be advanced (e.g. the frame to which we want to advance is
+   *          still decoding). Note: If false is returned, then aDirtyRect will
+   *          remain unmodified.
+   */
+  bool AdvanceFrame(mozilla::TimeStamp aTime, nsIntRect* aDirtyRect);
+
+  /**
    * Deletes and nulls out the frame in mFrames[framenum].
    *
    * Does not change the size of mFrames.
    *
    * @param framenum The index of the frame to be deleted. 
    *                 Must lie in [0, mFrames.Length() )
    */
   void DeleteImgFrame(PRUint32 framenum);
 
   imgFrame* GetImgFrameNoDecode(PRUint32 framenum);
   imgFrame* GetImgFrame(PRUint32 framenum);
   imgFrame* GetDrawableImgFrame(PRUint32 framenum);
   imgFrame* GetCurrentImgFrame();
   imgFrame* GetCurrentDrawableImgFrame();
   PRUint32 GetCurrentImgFrameIndex() const;
+  mozilla::TimeStamp GetCurrentImgFrameEndTime() const;
   
   inline void EnsureAnimExists()
   {
     if (!mAnim) {
 
       // Create the animation context
       mAnim = new Anim();
 
@@ -400,37 +433,37 @@ private:
       // data too. However, doing this is actually hard, because we're probably
       // calling ensureAnimExists mid-decode, and thus we're decoding out of
       // the source buffer. Since we're going to fix this anyway later, and
       // since we didn't kill the source data in the old world either, locking
       // is acceptable for the moment.
       LockImage();
     }
   }
-  
+
   /** Function for doing the frame compositing of animations
    *
    * @param aDirtyRect  Area that the display will need to update
    * @param aPrevFrame  Last Frame seen/processed
    * @param aNextFrame  Frame we need to incorperate/display
    * @param aNextFrameIndex Position of aNextFrame in mFrames list
    */
   nsresult DoComposite(nsIntRect* aDirtyRect,
                        imgFrame* aPrevFrame,
                        imgFrame* aNextFrame,
                        PRInt32 aNextFrameIndex);
-  
+
   /** Clears an area of <aFrame> with transparent black.
    *
    * @param aFrame Target Frame
    *
    * @note Does also clears the transparancy mask
    */
   static void ClearFrame(imgFrame* aFrame);
-  
+
   //! @overload
   static void ClearFrame(imgFrame* aFrame, nsIntRect &aRect);
   
   //! Copy one frames's image and mask into another
   static bool CopyFrameImage(imgFrame *aSrcFrame,
                                imgFrame *aDstFrame);
   
   /** Draws one frames's image to into another,
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -167,17 +167,16 @@ SVGDrawingCallback::operator()(gfxContex
   // Clip to aFillRect so that we don't paint outside.
   aContext->NewPath();
   aContext->Rectangle(aFillRect);
   aContext->Clip();
 
   gfxContextMatrixAutoSaveRestore contextMatrixRestorer(aContext);
   aContext->Multiply(gfxMatrix(aTransform).Invert());
 
-
   nsPresContext* presContext = presShell->GetPresContext();
   NS_ABORT_IF_FALSE(presContext, "pres shell w/out pres context");
 
   nsRect svgRect(presContext->DevPixelsToAppUnits(mViewport.x),
                  presContext->DevPixelsToAppUnits(mViewport.y),
                  presContext->DevPixelsToAppUnits(mViewport.width),
                  presContext->DevPixelsToAppUnits(mViewport.height));
 
@@ -326,16 +325,24 @@ VectorImage::GetWidth(PRInt32* aWidth)
     *aWidth = 0;
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 //******************************************************************************
+/* [notxpcom] void requestRefresh ([const] in TimeStamp aTime); */
+NS_IMETHODIMP_(void)
+VectorImage::RequestRefresh(const mozilla::TimeStamp& aTime)
+{
+  // TODO: Implement for b666446.
+}
+
+//******************************************************************************
 /* readonly attribute PRInt32 height; */
 NS_IMETHODIMP
 VectorImage::GetHeight(PRInt32* aHeight)
 {
   if (mError || !mIsFullyLoaded) {
     *aHeight = 0;
     return NS_ERROR_FAILURE;
   }
--- a/image/src/VectorImage.h
+++ b/image/src/VectorImage.h
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_imagelib_VectorImage_h_
 #define mozilla_imagelib_VectorImage_h_
 
 #include "Image.h"
 #include "nsIStreamListener.h"
 #include "nsWeakReference.h"
+#include "mozilla/TimeStamp.h"
 
 class imgIDecoderObserver;
 
 namespace mozilla {
 namespace imagelib {
 
 class SVGDocumentWrapper;
 class SVGRootRenderingObserver;
@@ -71,16 +72,17 @@ public:
   NS_IMETHOD CopyFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxImageSurface **_retval NS_OUTPARAM);
   NS_IMETHOD ExtractFrame(PRUint32 aWhichFrame, const nsIntRect & aRect, PRUint32 aFlags, imgIContainer **_retval NS_OUTPARAM);
   NS_IMETHOD Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix & aUserSpaceToImageSpace, const gfxRect & aFill, const nsIntRect & aSubimage, const nsIntSize & aViewportSize, PRUint32 aFlags);
   NS_IMETHOD_(nsIFrame *) GetRootLayoutFrame(void);
   NS_SCRIPTABLE NS_IMETHOD RequestDecode(void);
   NS_SCRIPTABLE NS_IMETHOD LockImage(void);
   NS_SCRIPTABLE NS_IMETHOD UnlockImage(void);
   NS_SCRIPTABLE NS_IMETHOD ResetAnimation(void);
+  NS_IMETHOD_(void) RequestRefresh(const mozilla::TimeStamp& aTime);
   // END NS_DECL_IMGICONTAINER
 
   VectorImage(imgStatusTracker* aStatusTracker = nsnull);
   virtual ~VectorImage();
 
   // Methods inherited from Image
   nsresult Init(imgIDecoderObserver* aObserver,
                 const char* aMimeType,
--- a/image/test/mochitest/Makefile.in
+++ b/image/test/mochitest/Makefile.in
@@ -88,17 +88,36 @@ include $(topsrcdir)/config/rules.mk
                 test_bug671906.html \
                 $(NULL)
 
 # Tests disabled due to intermittent orange
 # test_bug435296.html disabled - See bug 578591
 # test_bug478398.html disabled - See bug 579139
 
 _CHROME_FILES = imgutils.js \
+                animationPolling.js \
                 lime-anim-100x100.svg \
+                animation.svg \
                 test_animSVGImage.html \
+                test_animation.html \
+                animated-gif-finalframe.gif \
+                animated-gif.gif \
+                animated-gif2.gif \
+                purple.gif \
+                test_svg_animatedGIF.html \
+                test_bullet_animation.html \
+                test_background_image_anim.html \
+                filter.svg \
+                filter-final.svg \
+                test_svg_filter_animation.html \
+                test_xultree_animation.xhtml \
+                test_changeOfSource.html \
+                test_changeOfSource2.html \
+                test_undisplayed_iframe.html \
+                iframe.html \
+                ref-iframe.html \
                 $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs:: $(_CHROME_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4e80d31a727fc725326082d71ba42ccd33bf3b49
GIT binary patch
literal 72
zc${<hbh9u|)L_tHXkcW}`p@wH|9>3@AOMLlFsZlnuRQ&hfAO3xx4Jjq+w+^h?UBc{
bXPwJlo!a(}`}ilH>)(2x|2n74%3uuu*a9G=
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..001cbfb87a05e518f53707a4237a7034d2111344
GIT binary patch
literal 146
zc${<hbhEHb)L_tHSjfbn^`GJY7s>x%p!k!8fs5fkgAM}_faDpN)O-3@o_@=}c+Qqv
x-J9?2`OV+<$Ya{G&SkGoZF|Rk{FBf1Z@tfdol|CI0P1DrVqiqk+d`yXYXIPpLiGRu
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c66cc4b7344f52e312460d7424cc2cce7f6fd87d
GIT binary patch
literal 165
zc${<hbhEHb)L_tHSjfb{!1jL{!+!`+{Lk&@8WQa67~pE8XTZ$Jz`&sRlZAnc;Xi{8
zkj((n!oZ~7(!cWbTmHp!w%qF8d~eTh{<cRR)1GxMdv$8tJMQD3e6D}%eg5m5GAl?g
PBNtE`vfdsd^;!b}g%L(;
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/animation.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink">
+	<image id="anim" xlink:href="animated-gif.gif" width="40" height="40"/>
+</svg>
+
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/animationPolling.js
@@ -0,0 +1,395 @@
+var currentTest;
+var gIsImageLoaded = false;
+var gIsRefImageLoaded = false;
+
+function pollForSuccess ()
+{
+  if (!currentTest.isTestFinished) {
+    if (!currentTest.reusingReferenceImage || (currentTest.reusingReferenceImage
+        && gRefImageLoaded)) {
+      currentTest.checkImage();
+    }
+
+    setTimeout(pollForSuccess, currentTest.pollFreq);
+  }
+};
+
+function imageLoadCallback()
+{
+  gIsImageLoaded = true;
+}
+
+function referencePoller()
+{
+  currentTest.takeReferenceSnapshot();
+}
+
+function reuseImageCallback()
+{
+  gIsRefImageLoaded = true;
+}
+
+function failTest ()
+{
+  if (currentTest.isTestFinished || currentTest.closeFunc) {
+    return;
+  }
+
+  ok(false, "timing out after " + currentTest.timeout + "ms.  "
+     + "Animated image still doesn't look correct, " + "after call #"
+     + currentTest.onStopFrameCounter + " to onStopFrame");
+  currentTest.wereFailures = true;
+
+  currentTest.enableDisplay(document.getElementById(currentTest.debugElementId));
+
+  currentTest.cleanUpAndFinish();
+};
+
+/**
+ * Create a new AnimationTest object.
+ *
+ * @param pollFreq The amount of time (in ms) to wait between consecutive
+ *        snapshots if the reference image and the test image don't match.
+ * @param timeout The total amount of time (in ms) to wait before declaring the
+ *        test as failed.
+ * @param referenceElementId The id attribute of the reference image element, or
+ *        the source of the image to change to, once the reference snapshot has
+ *        been successfully taken. This latter option could be used if you don't
+ *        want the image to become invisible at any time during the test.
+ * @param imageElementId The id attribute of the test image element.
+ * @param debugElementId The id attribute of the div where links should be
+ *        appended if the test fails.
+ * @param cleanId The id attribute of the div or element to use as the 'clean'
+ *        test. This element is only enabled when we are testing to verify that
+ *        the reference image has been loaded. It can be undefined.
+ * @param srcAttr The location of the source of the image, for preloading. This
+ *        is usually not required, but it useful for preloading reference
+ *        images.
+ * @param xulTest A boolean value indicating whether or not this is a XUL test
+ *        (uses hidden=true/false rather than display: none to hide/show
+ *        elements).
+ * @param closeFunc A function that should be called when this test is finished.
+ *        If null, then cleanUpAndFinish() will be called. This can be used to
+ *        chain tests together, so they are all finished exactly once.
+ * @returns {AnimationTest}
+ */
+function AnimationTest(pollFreq, timeout, referenceElementId, imageElementId,
+                       debugElementId, cleanId, srcAttr, xulTest, closeFunc)
+{
+  // We want to test the cold loading behavior, so clear cache in case an
+  // earlier test got our image in there already.
+  clearImageCache();
+
+  this.wereFailures = false;
+  this.pollFreq = pollFreq;
+  this.timeout = timeout;
+  this.imageElementId = imageElementId;
+  this.referenceElementId = referenceElementId;
+
+  if (!document.getElementById(referenceElementId)) {
+    // In this case, we're assuming the user passed in a string that
+    // indicates the source of the image they want to change to,
+    // after the reference image has been taken.
+    this.reusingImageAsReference = true;
+  }
+
+  this.srcAttr = srcAttr;
+  this.debugElementId = debugElementId;
+  this.referenceSnapshot = ""; // value will be set in takeReferenceSnapshot()
+  this.onStopFrameCounter = 0;
+  this.isTestFinished = false;
+  this.numRefsTaken = 0;
+  this.blankWaitTime = 0;
+
+  this.cleanId = cleanId ? cleanId : '';
+  this.xulTest = xulTest ? xulTest : '';
+  this.closeFunc = closeFunc ? closeFunc : '';
+
+  if (this.srcAttr) {
+    this.myImage = new Image();
+    this.myImage.onload = imageLoadCallback;
+    this.myImage.src = this.srcAttr;
+  } else {
+    gIsImageLoaded = true;
+  }
+}
+
+AnimationTest.prototype.outputDebugInfo = function(message, id, dataUri)
+{
+  var debugElement = document.getElementById(this.debugElementId);
+  var newDataUriElement = document.createElement("a");
+  newDataUriElement.setAttribute("id", id);
+  newDataUriElement.setAttribute("href", dataUri);
+  newDataUriElement.appendChild(document.createTextNode(message));
+  debugElement.appendChild(newDataUriElement);
+  var brElement = document.createElement("br");
+  debugElement.appendChild(brElement);
+};
+
+AnimationTest.prototype.isFinished = function()
+{
+  return this.isTestFinished;
+};
+
+AnimationTest.prototype.takeCleanSnapshot = function()
+{
+  var cleanElement;
+  if (this.cleanId) {
+    cleanElement = document.getElementById(this.cleanId);
+  }
+
+  // Enable clean page comparison element
+  if (cleanElement) {
+    this.enableDisplay(cleanElement);
+  }
+
+  // Take a snapshot of the initial (clean) page
+  this.cleanSnapshot = snapshotWindow(window, false);
+
+  // Disable the clean page comparison element
+  if (cleanElement) {
+    this.disableDisplay(cleanElement);
+  }
+
+  var dataString1 = "Clean Snapshot";
+  this.outputDebugInfo(dataString1, 'cleanSnap',
+                       this.cleanSnapshot.toDataURL());
+};
+
+AnimationTest.prototype.takeBlankSnapshot = function()
+{
+  // Take a snapshot of the initial (essentially blank) page
+  this.blankSnapshot = snapshotWindow(window, false);
+
+  var dataString1 = "Initial Blank Snapshot";
+  this.outputDebugInfo(dataString1, 'blank1Snap',
+                       this.blankSnapshot.toDataURL());
+};
+
+/**
+ * Begin the AnimationTest. This will utilize the information provided in the
+ * constructor to invoke a mochitest on animated images. It will automatically
+ * fail if allowed to run past the timeout.
+ */
+AnimationTest.prototype.beginTest = function ()
+{
+  SimpleTest.waitForExplicitFinish();
+
+  currentTest = this;
+
+  this.takeReferenceSnapshot();
+
+  // In case something goes wrong, fail earlier than mochitest timeout,
+  // and with more information.
+  setTimeout(failTest, this.timeout);
+
+  if (!this.reusingImageAsReference) {
+    this.disableDisplay(document.getElementById(this.imageElementId));
+  }
+
+  this.setupPolledImage();
+  setTimeout(pollForSuccess, 10);
+};
+
+AnimationTest.prototype.setupPolledImage = function ()
+{
+  // Make sure the image is visible
+  if (!this.reusingImageAsReference) {
+    this.enableDisplay(document.getElementById(this.imageElementId));
+    var currentSnapshot = snapshotWindow(window, false);
+    var result = compareSnapshots(currentSnapshot, this.referenceSnapshot, true);
+
+    var dataString = "Snapshot #" + this.onStopFrameCounter;
+    this.outputDebugInfo(dataString, 'snap' + this.onStopFrameCounter,
+                         currentSnapshot.toDataURL());
+
+    if (result[0]) {
+      // SUCCESS!
+      ok(true, "Animated image looks correct, " + "at call #"
+         + this.onStopFrameCounter + " to onStopFrame");
+
+      this.cleanUpAndFinish();
+    }
+  } else {
+    if (!gIsRefImageLoaded) {
+      this.myImage = new Image();
+      this.myImage.onload = reuseImageCallback;
+      document.getElementById(this.imageElementId).setAttribute('src',
+        this.referenceElementId);
+    }
+  }
+}
+
+AnimationTest.prototype.checkImage = function ()
+{
+  if (this.isTestFinished) {
+    return;
+  }
+
+  this.onStopFrameCounter++;
+
+  // We need this for some tests, because we need to force the
+  // test image to be visible.
+  if (!this.reusingImageAsReference) {
+    this.enableDisplay(document.getElementById(this.imageElementId));
+  }
+
+  var currentSnapshot = snapshotWindow(window, false);
+  var result = compareSnapshots(currentSnapshot, this.referenceSnapshot, true);
+
+  var dataString = "Snapshot #" + this.onStopFrameCounter;
+  this.outputDebugInfo(dataString, 'snap' + this.onStopFrameCounter,
+                         currentSnapshot.toDataURL());
+
+  if (result[0]) {
+    // SUCCESS!
+    ok(true, "Animated image looks correct, " + "at call #"
+       + this.onStopFrameCounter + " to onStopFrame");
+
+    this.cleanUpAndFinish();
+  }
+};
+
+AnimationTest.prototype.takeReferenceSnapshot = function ()
+{
+  this.numRefsTaken++;
+
+  // Test to make sure the reference image doesn't match a clean snapshot
+  if (!this.cleanSnapshot) {
+    this.takeCleanSnapshot();
+  }
+
+  // Used later to verify that the reference div disappeared
+  if (!this.blankSnapshot) {
+    this.takeBlankSnapshot();
+  }
+
+  if (this.reusingImageAsReference) {
+    // Show reference div, & take a snapshot
+    var referenceDiv = document.getElementById(this.imageElementId);
+    this.enableDisplay(referenceDiv);
+
+    this.referenceSnapshot = snapshotWindow(window, false);
+    var snapResult = compareSnapshots(this.cleanSnapshot, this.referenceSnapshot,
+                                      false);
+    if (!snapResult[0]) {
+      if (this.blankWaitTime > 2000) {
+        // if it took longer than two seconds to load the image, we probably
+        // have a problem.
+        this.wereFailures = true;
+        ok(snapResult[0],
+           "Reference snapshot shouldn't match clean (non-image) snapshot");
+      } else {
+        this.blankWaitTime += 20;
+        // let's wait a bit and see if it clears up
+        setTimeout(referencePoller, 20);
+        return;
+      }
+    }
+
+    ok(snapResult[0],
+       "Reference snapshot shouldn't match clean (non-image) snapshot");
+
+    var dataString = "Reference Snapshot #" + this.numRefsTaken;
+    this.outputDebugInfo(dataString, 'refSnapId',
+                         this.referenceSnapshot.toDataURL());
+  } else {
+    // Make sure the animation section is hidden
+    this.disableDisplay(document.getElementById(this.imageElementId));
+
+    // Show reference div, & take a snapshot
+    var referenceDiv = document.getElementById(this.referenceElementId);
+    this.enableDisplay(referenceDiv);
+
+    this.referenceSnapshot = snapshotWindow(window, false);
+    var snapResult = compareSnapshots(this.cleanSnapshot, this.referenceSnapshot, false);
+    if (!snapResult[0]) {
+      if (this.blankWaitTime > 2000) {
+        // if it took longer than two seconds to load the image, we probably
+        // have a problem.
+        this.wereFailures = true;
+        ok(snapResult[0],
+           "Reference snapshot shouldn't match clean (non-image) snapshot");
+      } else {
+        this.blankWaitTime += 20;
+        // let's wait a bit and see if it clears up
+        setTimeout(referencePoller, 20);
+        return;
+      }
+    }
+
+    ok(snapResult[0],
+       "Reference snapshot shouldn't match clean (non-image) snapshot");
+
+    var dataString = "Reference Snapshot #" + this.numRefsTaken;
+    this.outputDebugInfo(dataString, 'refSnapId',
+                         this.referenceSnapshot.toDataURL());
+
+    // Re-hide reference div, and take another snapshot to be sure it's gone
+    this.disableDisplay(referenceDiv);
+    this.testBlankCameBack();
+  }
+};
+
+AnimationTest.prototype.enableDisplay = function(element)
+{
+  if (!element) {
+    return;
+  }
+
+  if (!this.xulTest) {
+    element.style.display = '';
+  } else {
+    element.setAttribute('hidden', 'false');
+  }
+};
+
+AnimationTest.prototype.disableDisplay = function(element)
+{
+  if (!element) {
+    return;
+  }
+
+  if (!this.xulTest) {
+    element.style.display = 'none';
+  } else {
+    element.setAttribute('hidden', 'true');
+  }
+};
+
+AnimationTest.prototype.testBlankCameBack = function()
+{
+  var blankSnapshot2 = snapshotWindow(window, false);
+  var result = compareSnapshots(this.blankSnapshot, blankSnapshot2, true);
+  ok(result[0], "Reference image should disappear when it becomes display:none");
+
+  if (!result[0]) {
+    this.wereFailures = true;
+    var dataString = "Second Blank Snapshot";
+    this.outputDebugInfo(dataString, 'blank2SnapId', result[2]);
+  }
+};
+
+AnimationTest.prototype.cleanUpAndFinish = function ()
+{
+  // On the off chance that failTest and checkImage are triggered
+  // back-to-back, use a flag to prevent multiple calls to SimpleTest.finish.
+  if (this.isTestFinished) {
+    return;
+  }
+
+  this.isTestFinished = true;
+
+  // Call our closing function, if one exists
+  if (this.closeFunc) {
+    this.closeFunc();
+    return;
+  }
+
+  if (this.wereFailures) {
+    document.getElementById(this.debugElementId).style.display = 'block';
+  }
+
+  SimpleTest.finish();
+  document.getElementById(this.debugElementId).style.display = "";
+};
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/filter-final.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<filter id="filter1" x="0%" y="0%" width="100%" height="100%">
+  <feImage xlink:href="animated-gif-finalframe.gif"/>
+</filter>
+<g>
+	<rect x="0" y="0" width="100%" height="100%" filter="url(#filter1)"/>
+</g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/filter.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+
+<filter id="filter1" x="0%" y="0%" width="100%" height="100%">
+  <feImage xlink:href="animated-gif.gif"/>
+</filter>
+<g>
+	<rect x="0" y="0" width="100%" height="100%" filter="url(#filter1)"/>
+</g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/iframe.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="gray">
+  <img src="animated-gif.gif">
+</body>
+</html>
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..79826af205d7eceb7763d8a213d3ec28844db363
GIT binary patch
literal 86
zc${<hbhEHb)L_tHSjfb{!1jL{!+!`+{K>+|#lXOz1H=p<c?Kr+p8l1m-|{b>v*lLz
k=6id7^S3?nnD(r5*{f6A-f<uQ<a7O7@AF^hlvx?90h=QxX8-^I
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/ref-iframe.html
@@ -0,0 +1,6 @@
+<html>
+<body bgcolor="gray">
+  <div id="referenceImage"
+    style="height: 40px; width: 40px; background: #2aff00"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_animation.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666446
+-->
+<head>
+  <title>Test for Bug 666446 - General Animated GIF Test</title>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+  <script type="application/javascript" src="imgutils.js"></script>
+  <script type="application/javascript" src="animationPolling.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666446">
+Mozilla Bug 666446: lots of animated gifs swamp us with paint events
+</a>
+<p id="display"></p>
+
+<div id="content">
+  <div id="referenceDiv" style="height: 40px; width: 40px;
+                                display: none; background: #2aff00"></div>
+  <div id="animatedImage">
+    <img id="animatedGif" src="animated-gif.gif" style="display: none;">
+      <div id="text-descr"></div>
+  </div>
+  <div id="debug" style="display:none">
+  </div>
+</div>
+<pre id="test">
+<script type="text/javascript;version=1.8">
+const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
+
+function main()
+{
+  var animTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceDiv',
+                                   'animatedGif', 'debug');
+  animTest.beginTest();
+}
+
+window.onload = main;
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_background_image_anim.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666446
+-->
+<head>
+  <title>Test for Bug 666446 - Animated Background Images</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+  <script type="application/javascript" src="imgutils.js"></script>
+  <script type="application/javascript" src="animationPolling.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666446">
+Mozilla Bug 666446: lots of animated gifs swamp us with paint events
+</a>
+<p id="display"></p>
+<div id="content">
+  <div id="referenceDiv" style="height: 140px; width: 140px;
+                                display: none; background: #2aff00"></div>
+  <div id="bgImage" style="height: 140px; width: 140px; background-image: url(animated-gif.gif); display: none;">
+  </div>
+</div>
+<div id="debug" style="display:none"></div>
+<pre id="test">
+<script type="text/javascript;version=1.8">
+
+/** Test for Bug 666446 nsImageLoader/RasterImage**/
+
+const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
+
+function main() {
+  var animTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceDiv',
+                                   'bgImage', 'debug');
+  animTest.beginTest();
+}
+
+window.onload = main;
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_bullet_animation.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666446
+-->
+<head>
+  <title>Test for Bug 666446 - Animated Bullets</title>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+  <script type="application/javascript" src="imgutils.js"></script>
+  <script type="application/javascript" src="animationPolling.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666446">
+Mozilla Bug 666446: lots of animated gifs swamp us with paint events
+</a>
+<p id="display"></p>
+
+<div id="content">
+  <div id="cleanDiv" style="display: none;">
+    <ul>
+      <li>Test 1</li>
+    </ul>
+  </div>
+  <div id="referenceDiv" style="display: none;">
+    <ul>
+      <li style="list-style-image: url(animated-gif-finalframe.gif);">Test 1</li>
+    </ul>
+  </div>
+  <div id="animatedImage" style="display: none;">
+      <ul>
+        <li style="list-style-image: url(animated-gif.gif);">Test 1</li>
+      </ul>
+  </div>
+  <div id="text-descr"></div>
+  <div id="debug" style="display:none">
+  </div>
+</div>
+<pre id="test">
+<script type="text/javascript;version=1.8">
+const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
+
+function main()
+{
+  var animTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceDiv',
+                                   'animatedImage', 'debug', 'cleanDiv',
+                                   'animated-gif-finalframe.gif');
+  animTest.beginTest();
+}
+
+window.onload = main;
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_changeOfSource.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666446
+-->
+<head>
+  <title>Test for Bug 666446 - Change of Source (1st Version)</title>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+  <script type="application/javascript" src="imgutils.js"></script>
+  <script type="application/javascript" src="animationPolling.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666446">
+Mozilla Bug 666446: lots of animated gifs swamp us with paint events
+</a>
+<p id="display"></p>
+
+<div id="content">
+  <div id="referenceDiv" style="height: 40px; width: 40px;
+                                display: none; background: #2aff00;">
+  </div>
+  <div id="animatedImage">
+    <img id='animatedGif' src="animated-gif.gif" style="display: none;">
+  </div>
+  <div id="text-descr"></div>
+  <div id="debug" style="display:none">
+  </div>
+</div>
+<pre id="test">
+<script type="text/javascript;version=1.8">
+const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
+
+var gAnimTest;
+var gIntervalId;
+
+function initSecondTest() {
+  document.getElementById('debug').style.display = 'none';
+  document.getElementById('referenceDiv').style.background = "#9600ff";
+  document.getElementById('animatedGif').setAttribute('src',
+                                                      'animated-gif2.gif');
+  document.getElementById('animatedGif').style.display = 'none';
+  var secondTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceDiv',
+                                     'animatedGif', 'debug', '', '', false);
+  secondTest.beginTest();
+}
+
+function main()
+{
+  gAnimTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceDiv',
+                                'animatedGif', 'debug', '', '', false,
+                                initSecondTest);
+  gAnimTest.beginTest();
+
+}
+
+window.onload = main;
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_changeOfSource2.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666446
+-->
+<head>
+  <title>Test for Bug 691792 - Change of Source (2nd Version)</title>
+  <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+  <script type="application/javascript" src="imgutils.js"></script>
+  <script type="application/javascript" src="animationPolling.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=691792">
+Mozilla Bug 691792: Change of src attribute for animated gifs no longer works as expected
+</a>
+<p id="display"></p>
+
+<div id="content">
+  <div id="animatedImage">
+    <img id='animatedGif' src="purple.gif" style="display: none;">
+  </div>
+  <div id="text-descr"></div>
+  <div id="debug" style="display:none">
+  </div>
+</div>
+<pre id="test">
+<script type="text/javascript;version=1.8">
+const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
+
+var gAnimTest;
+var gIntervalId;
+
+function main()
+{
+  gAnimTest = new AnimationTest(20, FAILURE_TIMEOUT, 'animated-gif2.gif',
+                                'animatedGif', 'debug', '', 'animated-gif2.gif',
+                                false);
+  gAnimTest.beginTest();
+}
+
+window.onload = main;
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_svg_animatedGIF.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666446
+-->
+<head>
+  <title>Test for Bug 666446 - Animated Raster Images inside of SVG Frames</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+  <script type="application/javascript" src="imgutils.js"></script>
+  <script type="application/javascript" src="animationPolling.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+
+<!--  Make sure embed element is snapped to an exact pixel. -->
+<div class="bug-header" style="height: 100px;">
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666446">
+  Mozilla Bug 666446: lots of animated gifs swamp us with paint events
+  </a>
+</div>
+
+<p id="display"></p>
+<div id="content">
+  <div id="referenceDiv" style="height: 40px; width: 40px;
+                                display: none; background: #2aff00"></div>
+    <!--
+        We use <embed> here instead of <img> because the <img> tag utilizes
+        the VectorImage class for SVG, whereas in this test, we are testing
+        RasterImage.
+     -->
+  <embed id="embeddedSVG" src="animation.svg" type="image/svg+xml" style="display: none;"/>
+</div>
+<div id="debug" style="display:none"></div>
+<pre id="test">
+<script type="text/javascript;version=1.8">
+
+/** Test for Bug 666446 nsSVGImageFrame/RasterImage**/
+
+const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
+
+function main() {
+  var animTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceDiv',
+      							   'embeddedSVG', 'debug', '', 'src');
+  animTest.beginTest();
+}
+
+window.onload = main;
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_svg_filter_animation.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666446
+-->
+<head>
+  <title>Test for Bug 666446 - Animated Images within SVG Filters</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+  <script type="application/javascript" src="imgutils.js"></script>
+  <script type="application/javascript" src="animationPolling.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666446">
+Mozilla Bug 666446: lots of animated gifs swamp us with paint events
+</a>
+<p id="display"></p>
+<div id="content">
+  <embed id="referenceImage" src="filter-final.svg" type="image/svg+xml" style="display: none;"/>
+  <embed id="embeddedSVGFilt" src="filter.svg" type="image/svg+xml" style="display: none;"/>
+</div>
+<div id="debug" style="display:none"></div>
+<pre id="test">
+<script type="text/javascript;version=1.8">
+
+/** Test for Bug 666446 nsSVGFEImageElement/RasterImage**/
+
+const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
+
+function main() {
+  var animTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceImage',
+                       'embeddedSVGFilt', 'debug', '', 'src');
+  animTest.beginTest();
+}
+
+window.onload = main;
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_undisplayed_iframe.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666446
+-->
+<head>
+<title>Test for Bug 666446 - Test for Animated Gif within IFRAME</title>
+<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+<script type="application/javascript" src="imgutils.js"></script>
+<script type="application/javascript" src="animationPolling.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666446">
+    Mozilla Bug 666446: lots of animated gifs swamp us with paint events</a>
+  <p id="display"></p>
+
+  <div id="content">
+    <div id="referenceDiv" style="display:none;">
+      <iframe id="referenceIFrame" src="ref-iframe.html" width="50%" height="100">
+        Browser does not support iframes.
+      </iframe>
+    </div>
+    <div id="animatedImage">
+      <iframe id="imageIFrame" src="iframe.html" width="50%" height="100" style="display: none;">
+        Browser does not support iframes.
+      </iframe>
+    </div>
+    <div id="debug" style="display: none"></div>
+  </div>
+  <pre id="test">
+<script type="text/javascript;version=1.8">
+const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
+
+function main()
+{
+  var animTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceDiv',
+                                   'imageIFrame', 'debug');
+  animTest.beginTest();
+}
+
+window.onload = main;
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/image/test/mochitest/test_xultree_animation.xhtml
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html
+xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+      xml:lang="en" lang="en">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=666446
+-->
+<head>
+  <title>Test for Bug 666446 - Animated Images within SVG Filters</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
+  <script type="application/javascript" src="imgutils.js"></script>
+  <script type="application/javascript" src="animationPolling.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666446">
+Mozilla Bug 666446: lots of animated gifs swamp us with paint events
+</a>
+<p id="display"></p>
+<div id="content">
+  <xul:caption label="Bug 666446 - XULTree Test" />
+  <xul:separator />
+    <br />
+    <xul:window id="main" title="Bug 666446: XUL Tree Testing" width="100" height="100">
+      <xul:tree flex="1">
+        <xul:treecols>
+          <xul:treecol id="icon" label="Icon" flex="1" />
+        </xul:treecols>
+
+        <xul:treechildren>
+          <xul:treeitem id="referenceItem" hidden="true">
+            <xul:treerow>
+              <xul:treecell src="animated-gif-finalframe.gif" width="40" height="40" />
+            </xul:treerow>
+          </xul:treeitem>
+          <xul:treeitem id="imageItem" hidden="true">
+            <xul:treerow>
+              <xul:treecell src="animated-gif.gif" width="40" height="40" />
+            </xul:treerow>
+          </xul:treeitem>
+        </xul:treechildren>
+      </xul:tree>
+    </xul:window>
+  </div>
+<div id="debug" style="display:none"></div>
+<pre id="test">
+<script type="text/javascript;version=1.8">
+
+/** Test for Bug 666446 nsSVGFEImageElement/RasterImage**/
+
+const FAILURE_TIMEOUT = 5000; // Fail early after 120 seconds (2 minutes)
+
+function main() {
+  var animTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceItem',
+                                   'imageItem', 'debug', '',
+                                   'animated-gif-finalframe.gif', true);
+  animTest.beginTest();
+}
+
+window.onload = main;
+
+</script>
+</pre>
+</body>
+</html>
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -412,21 +412,16 @@ class HashTable : private AllocPolicy
     }
 
     ~HashTable()
     {
         if (table)
             destroyTable(*this, table, tableCapacity);
     }
 
-    size_t allocatedSize() const
-    {
-        return sizeof(Entry) * tableCapacity;
-    }
-
   private:
     static HashNumber hash1(HashNumber hash0, uint32 shift) {
         return hash0 >> shift;
     }
 
     static HashNumber hash2(HashNumber hash0, uint32 log2, uint32 shift) {
         return ((hash0 << log2) >> shift) | 1;
     }
@@ -1130,19 +1125,16 @@ class HashMap
     bool empty() const                                { return impl.empty(); }
 
     /*
      * If |generation()| is the same before and after a HashMap operation,
      * pointers into the table remain valid.
      */
     unsigned generation() const                       { return impl.generation(); }
 
-    /* Number of bytes of heap data allocated by this table. */
-    size_t allocatedSize() const                      { return impl.allocatedSize(); }
-
     /* Shorthand operations: */
 
     bool has(const Lookup &l) const {
         return impl.lookup(l) != NULL;
     }
 
     /* Overwrite existing value with v. Return NULL on oom. */
     Entry *put(const Key &k, const Value &v) {
@@ -1333,19 +1325,16 @@ class HashSet
     bool empty() const                                { return impl.empty(); }
 
     /*
      * If |generation()| is the same before and after a HashSet operation,
      * pointers into the table remain valid.
      */
     unsigned generation() const                       { return impl.generation(); }
 
-    /* Number of bytes of heap data allocated by this table. */
-    size_t allocatedSize() const                      { return impl.allocatedSize(); }
-
     /* Shorthand operations: */
 
     bool has(const Lookup &l) const {
         return impl.lookup(l) != NULL;
     }
 
     /* Overwrite existing value with v. Return NULL on oom. */
     const T *put(const T &t) {
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -69,20 +69,20 @@ AlignPtr(void *orig)
     char *result = (char *) ((uintptr_t(orig) + (LIFO_ALLOC_ALIGN - 1)) & (~LIFO_ALLOC_ALIGN + 1));
     JS_ASSERT(uintptr_t(result) % LIFO_ALLOC_ALIGN == 0);
     return result;
 }
 
 /* Header for a chunk of memory wrangled by the LifoAlloc. */
 class BumpChunk
 {
-    char        *bump;
-    char        *limit;
-    BumpChunk   *next_;
-    size_t      bumpSpaceSize;
+    char        *bump;          /* start of the available data */
+    char        *limit;         /* end of the data */
+    BumpChunk   *next_;         /* the next BumpChunk */
+    size_t      bumpSpaceSize;  /* size of the data area */
 
     char *headerBase() { return reinterpret_cast<char *>(this); }
     char *bumpBase() const { return limit - bumpSpaceSize; }
 
     BumpChunk *thisDuringConstruction() { return this; }
 
     explicit BumpChunk(size_t bumpSpaceSize)
       : bump(reinterpret_cast<char *>(thisDuringConstruction()) + sizeof(BumpChunk)),
@@ -106,16 +106,20 @@ class BumpChunk
 #endif
     }
 
   public:
     BumpChunk *next() const { return next_; }
     void setNext(BumpChunk *succ) { next_ = succ; }
 
     size_t used() const { return bump - bumpBase(); }
+    size_t sizeOf(JSUsableSizeFun usf) {
+        size_t usable = usf((void*)this);
+        return usable ? usable : limit - headerBase();
+    }
 
     void resetBump() {
         setBump(headerBase() + sizeof(BumpChunk));
     }
 
     void *mark() const { return bump; }
 
     void release(void *mark) {
@@ -285,16 +289,32 @@ class LifoAlloc
         BumpChunk *it = first;
         while (it) {
             accum += it->used();
             it = it->next();
         }
         return accum;
     }
 
+    /* Get the total size of the arena chunks (including unused space), plus,
+     * if |countMe| is true, the size of the LifoAlloc itself. */
+    size_t sizeOf(JSUsableSizeFun usf, bool countMe) const {
+        size_t accum = 0;
+        if (countMe) {
+            size_t usable = usf((void*)this);
+            accum += usable ? usable : sizeof(LifoAlloc);
+        }
+        BumpChunk *it = first;
+        while (it) {
+            accum += it->sizeOf(usf);
+            it = it->next();
+        }
+        return accum;
+    }
+
     /* Doesn't perform construction; useful for lazily-initialized POD types. */
     template <typename T>
     JS_ALWAYS_INLINE
     T *newPod() {
         return static_cast<T *>(alloc(sizeof(T)));
     }
 
     JS_DECLARE_NEW_METHODS(alloc, JS_ALWAYS_INLINE)
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2873,27 +2873,18 @@ EmitPropOp(JSContext *cx, ParseNode *pn,
     }
 
     if (callContext) {
         JS_ASSERT(pn->isKind(TOK_DOT));
         JS_ASSERT(op == JSOP_GETPROP);
         op = JSOP_CALLPROP;
     } else if (op == JSOP_GETPROP && pn->isKind(TOK_DOT)) {
         if (pn2->isKind(TOK_NAME)) {
-            /*
-             * Try to optimize arguments.length into JSOP_ARGCNT. If type
-             * inference is enabled this is optimized separately.
-             */
             if (!BindNameToSlot(cx, bce, pn2))
                 return false;
-            if (!cx->typeInferenceEnabled() &&
-                pn->pn_atom == cx->runtime->atomState.lengthAtom) {
-                if (pn2->isOp(JSOP_ARGUMENTS))
-                    return Emit1(cx, bce, JSOP_ARGCNT) >= 0;
-            }
         }
     }
 
     /*
      * If the object operand is also a dotted property reference, reverse the
      * list linked via pn_expr temporarily so we can iterate over it from the
      * bottom up (reversing again as we go), to avoid excessive recursion.
      */
@@ -3061,134 +3052,61 @@ EmitNameIncDec(JSContext *cx, ParseNode 
         return false;
 
     return true;
 }
 
 static JSBool
 EmitElemOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
 {
-    ptrdiff_t top;
-    ParseNode *left, *right, *next;
-    int32_t slot;
-
-    top = bce->offset();
-    if (pn->isArity(PN_LIST)) {
-        /* Left-associative operator chain to avoid too much recursion. */
-        JS_ASSERT(pn->isOp(JSOP_GETELEM));
-        JS_ASSERT(pn->pn_count >= 3);
-        left = pn->pn_head;
-        right = pn->last();
-        next = left->pn_next;
-        JS_ASSERT(next != right);
-
+    ParseNode *left, *right;
+
+    ptrdiff_t top = bce->offset();
+
+    if (pn->isArity(PN_NAME)) {
         /*
-         * Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by
-         * one or more index expression and JSOP_GETELEM op pairs. If type
-         * inference is enabled this is optimized separately.
+         * Set left and right so pn appears to be a TOK_LB node, instead
+         * of a TOK_DOT node.  See the TOK_FOR/IN case in EmitTree, and
+         * EmitDestructuringOps nearer below.  In the destructuring case,
+         * the base expression (pn_expr) of the name may be null, which
+         * means we have to emit a JSOP_BINDNAME.
          */
-        if (left->isKind(TOK_NAME) && next->isKind(TOK_NUMBER)) {
-            if (!BindNameToSlot(cx, bce, left))
-                return false;
-            if (left->isOp(JSOP_ARGUMENTS) &&
-                JSDOUBLE_IS_INT32(next->pn_dval, &slot) &&
-                jsuint(slot) < JS_BIT(16) &&
-                !cx->typeInferenceEnabled() &&
-                (!bce->inStrictMode() ||
-                 (!bce->mutatesParameter() && !bce->callsEval()))) {
-                /*
-                 * arguments[i]() requires arguments object as "this".
-                 * Check that we never generates list for that usage.
-                 */
-                JS_ASSERT(op != JSOP_CALLELEM || next->pn_next);
-                left->pn_offset = next->pn_offset = top;
-                EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
-                left = next;
-                next = left->pn_next;
-            }
-        }
-
-        /*
-         * Check whether we generated JSOP_ARGSUB, just above, and have only
-         * one more index expression to emit.  Given arguments[0][j], we must
-         * skip the while loop altogether, falling through to emit code for j
-         * (in the subtree referenced by right), followed by the annotated op,
-         * at the bottom of this function.
-         */
-        JS_ASSERT(next != right || pn->pn_count == 3);
-        if (left == pn->pn_head) {
-            if (!EmitTree(cx, bce, left))
-                return false;
-        }
-        while (next != right) {
-            if (!EmitTree(cx, bce, next))
-                return false;
-            if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0)
-                return false;
-            if (!EmitElemOpBase(cx, bce, JSOP_GETELEM))
+        left = pn->maybeExpr();
+        if (!left) {
+            left = NullaryNode::create(bce);
+            if (!left)
                 return false;
-            next = next->pn_next;
-        }
+            left->setKind(TOK_STRING);
+            left->setOp(JSOP_BINDNAME);
+            left->pn_pos = pn->pn_pos;
+            left->pn_atom = pn->pn_atom;
+        }
+        right = NullaryNode::create(bce);
+        if (!right)
+            return false;
+        right->setKind(TOK_STRING);
+        right->setOp(IsIdentifier(pn->pn_atom) ? JSOP_QNAMEPART : JSOP_STRING);
+        right->pn_pos = pn->pn_pos;
+        right->pn_atom = pn->pn_atom;
     } else {
-        if (pn->isArity(PN_NAME)) {
-            /*
-             * Set left and right so pn appears to be a TOK_LB node, instead
-             * of a TOK_DOT node.  See the TOK_FOR/IN case in EmitTree, and
-             * EmitDestructuringOps nearer below.  In the destructuring case,
-             * the base expression (pn_expr) of the name may be null, which
-             * means we have to emit a JSOP_BINDNAME.
-             */
-            left = pn->maybeExpr();
-            if (!left) {
-                left = NullaryNode::create(bce);
-                if (!left)
-                    return false;
-                left->setKind(TOK_STRING);
-                left->setOp(JSOP_BINDNAME);
-                left->pn_pos = pn->pn_pos;
-                left->pn_atom = pn->pn_atom;
-            }
-            right = NullaryNode::create(bce);
-            if (!right)
-                return false;
-            right->setKind(TOK_STRING);
-            right->setOp(IsIdentifier(pn->pn_atom) ? JSOP_QNAMEPART : JSOP_STRING);
-            right->pn_pos = pn->pn_pos;
-            right->pn_atom = pn->pn_atom;
-        } else {
-            JS_ASSERT(pn->isArity(PN_BINARY));
-            left = pn->pn_left;
-            right = pn->pn_right;
-        }
-
-        /*
-         * Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. If type
-         * inference is enabled this is optimized separately.
-         */
-        if (op == JSOP_GETELEM &&
-            left->isKind(TOK_NAME) &&
-            right->isKind(TOK_NUMBER)) {
-            if (!BindNameToSlot(cx, bce, left))
-                return false;
-            if (left->isOp(JSOP_ARGUMENTS) &&
-                JSDOUBLE_IS_INT32(right->pn_dval, &slot) &&
-                jsuint(slot) < JS_BIT(16) &&
-                !cx->typeInferenceEnabled() &&
-                (!bce->inStrictMode() ||
-                 (!bce->mutatesParameter() && !bce->callsEval()))) {
-                left->pn_offset = right->pn_offset = top;
-                EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
-                return true;
-            }
-        }
-
-        if (!EmitTree(cx, bce, left))
+        JS_ASSERT(pn->isArity(PN_BINARY));
+        left = pn->pn_left;
+        right = pn->pn_right;
+    }
+
+    if (op == JSOP_GETELEM &&
+        left->isKind(TOK_NAME) &&
+        right->isKind(TOK_NUMBER)) {
+        if (!BindNameToSlot(cx, bce, left))
             return false;
     }
 
+    if (!EmitTree(cx, bce, left))
+        return false;
+
     /* The right side of the descendant operator is implicitly quoted. */
     JS_ASSERT(op != JSOP_DESCENDANTS || !right->isKind(TOK_STRING) ||
               right->isOp(JSOP_QNAMEPART));
     if (!EmitTree(cx, bce, right))
         return false;
     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0)
         return false;
     return EmitElemOpBase(cx, bce, op);
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -545,18 +545,16 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_THROW:
           case JSOP_EXCEPTION:
           case JSOP_DEFLOCALFUN:
           case JSOP_DEFLOCALFUN_FC:
           case JSOP_LAMBDA:
           case JSOP_LAMBDA_FC:
           case JSOP_GETFCSLOT:
           case JSOP_CALLFCSLOT:
-          case JSOP_ARGSUB:
-          case JSOP_ARGCNT:
           case JSOP_DEBUGGER:
           case JSOP_FUNCALL:
           case JSOP_FUNAPPLY:
             isInlineable = false;
             break;
 
           default:
             break;
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -611,24 +611,23 @@ JSStructuredCloneReader::checkDouble(jsd
     }
     return true;
 }
 
 class Chars {
     JSContext *cx;
     jschar *p;
   public:
-    Chars() : p(NULL) {}
+    Chars(JSContext *cx) : cx(cx), p(NULL) {}
     ~Chars() { if (p) cx->free_(p); }
 
-    bool allocate(JSContext *cx, size_t len) {
+    bool allocate(size_t len) {
         JS_ASSERT(!p);
         // We're going to null-terminate!
         p = (jschar *) cx->malloc_((len + 1) * sizeof(jschar));
-        this->cx = cx;
         if (p) {
             p[len] = jschar(0);
             return true;
         }
         return false;
     }
     jschar *get() { return p; }
     void forget() { p = NULL; }
@@ -637,18 +636,18 @@ class Chars {
 JSString *
 JSStructuredCloneReader::readString(uint32_t nchars)
 {
     if (nchars > JSString::MAX_LENGTH) {
         JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA,
                              "string length");
         return NULL;
     }
-    Chars chars;
-    if (!chars.allocate(context(), nchars) || !in.readChars(chars.get(), nchars))
+    Chars chars(context());
+    if (!chars.allocate(nchars) || !in.readChars(chars.get(), nchars))
         return NULL;
     JSString *str = js_NewString(context(), chars.get(), nchars);
     if (str)
         chars.forget();
     return str;
 }
 
 bool
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -104,21 +104,23 @@ typedef struct TypeInferenceMemoryStats
     int64 objects;
     int64 tables;
     int64 temporary;
     int64 emptyShapes;
 } TypeInferenceMemoryStats;
 
 extern JS_FRIEND_API(void)
 JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
-                               TypeInferenceMemoryStats *stats);
+                               TypeInferenceMemoryStats *stats,
+                               JSUsableSizeFun usf);
 
 extern JS_FRIEND_API(void)
 JS_GetTypeInferenceObjectStats(/*TypeObject*/ void *object,
-                               TypeInferenceMemoryStats *stats);
+                               TypeInferenceMemoryStats *stats,
+                               JSUsableSizeFun usf);
 
 extern JS_FRIEND_API(JSPrincipals *)
 JS_GetCompartmentPrincipals(JSCompartment *compartment);
 
 /* Safe to call with input obj == NULL. Returns non-NULL iff obj != NULL. */
 extern JS_FRIEND_API(JSObject *)
 JS_ObjectToInnerObject(JSContext *cx, JSObject *obj);
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -119,79 +119,16 @@ js_GetArgsValue(JSContext *cx, StackFram
     }
     argsobj = js_GetArgsObject(cx, fp);
     if (!argsobj)
         return JS_FALSE;
     vp->setObject(*argsobj);
     return JS_TRUE;
 }
 
-JSBool
-js_GetArgsProperty(JSContext *cx, StackFrame *fp, jsid id, Value *vp)
-{
-    JS_ASSERT(fp->isFunctionFrame());
-
-    if (fp->hasOverriddenArgs()) {
-        JS_ASSERT(fp->hasCallObj());
-
-        Value v;
-        if (!fp->callObj().getProperty(cx, cx->runtime->atomState.argumentsAtom, &v))
-            return false;
-
-        JSObject *obj;
-        if (v.isPrimitive()) {
-            obj = js_ValueToNonNullObject(cx, v);
-            if (!obj)
-                return false;
-        } else {
-            obj = &v.toObject();
-        }
-        return obj->getGeneric(cx, id, vp);
-    }
-
-    vp->setUndefined();
-    if (JSID_IS_INT(id)) {
-        uint32 arg = uint32(JSID_TO_INT(id));
-        ArgumentsObject *argsobj = fp->maybeArgsObj();
-        if (arg < fp->numActualArgs()) {
-            if (argsobj) {
-                const Value &v = argsobj->element(arg);
-                if (v.isMagic(JS_ARGS_HOLE))
-                    return argsobj->getGeneric(cx, id, vp);
-                if (fp->functionScript()->strictModeCode) {
-                    *vp = v;
-                    return true;
-                }
-            }
-            *vp = fp->canonicalActualArg(arg);
-        } else {
-            /*
-             * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
-             * storage between the formal parameter and arguments[k] for all
-             * fp->argc <= k && k < fp->fun->nargs.  For example, in
-             *
-             *   function f(x) { x = 42; return arguments[0]; }
-             *   f();
-             *
-             * the call to f should return undefined, not 42.  If fp->argsobj
-             * is null at this point, as it would be in the example, return
-             * undefined in *vp.
-             */
-            if (argsobj)
-                return argsobj->getGeneric(cx, id, vp);
-        }
-    } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-        ArgumentsObject *argsobj = fp->maybeArgsObj();
-        if (argsobj && argsobj->hasOverriddenLength())
-            return argsobj->getGeneric(cx, id, vp);
-        vp->setInt32(fp->numActualArgs());
-    }
-    return true;
-}
-
 js::ArgumentsObject *
 ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee)
 {
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
 
     JSObject *proto = callee.getGlobal()->getOrCreateObjectPrototype(cx);
     if (!proto)
         return NULL;
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -531,19 +531,16 @@ SetCallVar(JSContext *cx, JSObject *obj,
 extern JSBool
 SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp);
 
 } // namespace js
 
 extern JSBool
 js_GetArgsValue(JSContext *cx, js::StackFrame *fp, js::Value *vp);
 
-extern JSBool
-js_GetArgsProperty(JSContext *cx, js::StackFrame *fp, jsid id, js::Value *vp);
-
 /*
  * Get the arguments object for the given frame.  If the frame is strict mode
  * code, its current arguments will be copied into the arguments object.
  *
  * NB: Callers *must* get the arguments object before any parameters are
  *     mutated when the frame is strict mode code!  The emitter ensures this
  *     occurs for strict mode functions containing syntax which might mutate a
  *     named parameter by synthesizing an arguments access at the start of the
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -6101,26 +6101,35 @@ TypeScript::destroy()
         Foreground::delete_(nesting);
 
     Foreground::free_(this);
 }
 
 inline size_t
 TypeSet::dynamicSize()
 {
-    /* Get the amount of memory allocated from the analysis pool for this set. */
+    /*
+     * This memory is allocated within the temp pool (but accounted for
+     * elsewhere) so we can't use a JSUsableSizeFun to measure it.  We must do
+     * it analytically.
+     */
     uint32 count = baseObjectCount();
     if (count >= 2)
         return HashSetCapacity(count) * sizeof(TypeObject *);
     return 0;
 }
 
 inline size_t
 TypeObject::dynamicSize()
 {
+    /*
+     * This memory is allocated within the temp pool (but accounted for
+     * elsewhere) so we can't use a JSUsableSizeFun to measure it.  We must do
+     * it analytically.
+     */
     size_t bytes = 0;
 
     uint32 count = basePropertyCount();
     if (count >= 2)
         bytes += HashSetCapacity(count) * sizeof(TypeObject *);
 
     count = getPropertyCount();
     for (unsigned i = 0; i < count; i++) {
@@ -6128,103 +6137,139 @@ TypeObject::dynamicSize()
         if (prop)
             bytes += sizeof(Property) + prop->types.dynamicSize();
     }
 
     return bytes;
 }
 
 static void
-GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats)
-{
-    if (!script->types)
+GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats, JSUsableSizeFun usf)
+{
+    TypeScript *typeScript = script->types;
+    if (!typeScript)
         return;
 
+    size_t usable;
+
+    /* If TI is disabled, a single TypeScript is still present. */
     if (!script->compartment()->types.inferenceEnabled) {
-        stats->scripts += sizeof(TypeScript);
+        usable = usf(typeScript);
+        stats->scripts += usable ? usable : sizeof(TypeScript);
         return;
     }
 
+    usable = usf(typeScript->nesting);
+    stats->scripts += usable ? usable : sizeof(TypeScriptNesting);
+
     unsigned count = TypeScript::NumTypeSets(script);
-    stats->scripts += sizeof(TypeScript) + count * sizeof(TypeSet);
-
-    TypeResult *result = script->types->dynamicList;
+    usable = usf(typeScript);
+    stats->scripts += usable ? usable : sizeof(TypeScript) + count * sizeof(TypeSet);
+
+    TypeResult *result = typeScript->dynamicList;
     while (result) {
-        stats->scripts += sizeof(TypeResult);
+        usable = usf(result);
+        stats->scripts += usable ? usable : sizeof(TypeResult);
         result = result->next;
     }
 
-    TypeSet *typeArray = script->types->typeArray();
+    /*
+     * This counts memory that is in the temp pool but gets attributed
+     * elsewhere.  See JS_GetTypeInferenceMemoryStats for more details.
+     */
+    TypeSet *typeArray = typeScript->typeArray();
     for (unsigned i = 0; i < count; i++) {
         size_t bytes = typeArray[i].dynamicSize();
         stats->scripts += bytes;
         stats->temporary -= bytes;
     }
 }
 
 JS_FRIEND_API(void)
 JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
-                               TypeInferenceMemoryStats *stats)
+                               TypeInferenceMemoryStats *stats, JSUsableSizeFun usf)
 {
     /*
      * Note: not all data in the pool is temporary, and some will survive GCs
-     * by being copied to the replacement pool. This memory will be counted too
-     * and deducted from the amount of temporary data.
+     * by being copied to the replacement pool. This memory will be counted
+     * elsewhere and deducted from the amount of temporary data.
      */
-    stats->temporary += compartment->typeLifoAlloc.used();
+    stats->temporary += compartment->typeLifoAlloc.sizeOf(usf, /* countMe = */false);
 
     /* Pending arrays are cleared on GC along with the analysis pool. */
-    stats->temporary += sizeof(TypeCompartment::PendingWork) * compartment->types.pendingCapacity;
+    size_t usable = usf(compartment->types.pendingArray);
+    stats->temporary +=
+        usable ? usable
+               : sizeof(TypeCompartment::PendingWork) * compartment->types.pendingCapacity;
+
+    /* TypeCompartment::pendingRecompiles is non-NULL only while inference code is running. */
+    JS_ASSERT(!compartment->types.pendingRecompiles);
 
     for (gc::CellIter i(cx, compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next())
-        GetScriptMemoryStats(i.get<JSScript>(), stats);
+        GetScriptMemoryStats(i.get<JSScript>(), stats, usf);
 
     if (compartment->types.allocationSiteTable)
-        stats->tables += compartment->types.allocationSiteTable->allocatedSize();
+        stats->tables += compartment->types.allocationSiteTable->sizeOf(usf, /* countMe = */true);
 
     if (compartment->types.arrayTypeTable)
-        stats->tables += compartment->types.arrayTypeTable->allocatedSize();
+        stats->tables += compartment->types.arrayTypeTable->sizeOf(usf, /* countMe = */true);
 
     if (compartment->types.objectTypeTable) {
-        stats->tables += compartment->types.objectTypeTable->allocatedSize();
+        stats->tables += compartment->types.objectTypeTable->sizeOf(usf, /* countMe = */true);
 
         for (ObjectTypeTable::Enum e(*compartment->types.objectTypeTable);
              !e.empty();
-             e.popFront()) {
+             e.popFront())
+        {
             const ObjectTableKey &key = e.front().key;
-            stats->tables += key.nslots * (sizeof(jsid) + sizeof(Type));
+            const ObjectTableEntry &value = e.front().value;
+
+            /* key.ids and values.types have the same length. */
+            usable = usf(key.ids) + usf(value.types);
+            stats->tables += usable ? usable : key.nslots * (sizeof(jsid) + sizeof(Type));
         }
     }
 }
 
 JS_FRIEND_API(void)
-JS_GetTypeInferenceObjectStats(void *object_, TypeInferenceMemoryStats *stats)
+JS_GetTypeInferenceObjectStats(void *object_, TypeInferenceMemoryStats *stats, JSUsableSizeFun usf)
 {
     TypeObject *object = (TypeObject *) object_;
-    stats->objects += sizeof(TypeObject);
 
     if (object->singleton) {
         /*
          * Properties and associated type sets for singletons are cleared on
          * every GC. The type object is normally destroyed too, but we don't
          * charge this to 'temporary' as this is not for GC heap values.
          */
         JS_ASSERT(!object->newScript && !object->emptyShapes);
         return;
     }
 
     if (object->newScript) {
-        size_t length = 0;
-        for (TypeNewScript::Initializer *init = object->newScript->initializerList;; init++) {
-            length++;
-            if (init->kind == TypeNewScript::Initializer::DONE)
-                break;
+        /* The initializerList is tacked onto the end of the TypeNewScript. */
+        size_t usable = usf(object->newScript);
+        if (usable) {
+            stats->objects += usable;
+        } else {
+            stats->objects += sizeof(TypeNewScript);
+            for (TypeNewScript::Initializer *init = object->newScript->initializerList; ; init++) {
+                stats->objects += sizeof(TypeNewScript::Initializer);
+                if (init->kind == TypeNewScript::Initializer::DONE)
+                    break;
+            }
         }
-        stats->objects += sizeof(TypeNewScript) + (length * sizeof(TypeNewScript::Initializer));
-    }
-
-    if (object->emptyShapes)
-        stats->emptyShapes += sizeof(EmptyShape*) * gc::FINALIZE_FUNCTION_AND_OBJECT_LAST;
-
+    }
+
+    if (object->emptyShapes) {
+        size_t usable = usf(object->emptyShapes);
+        stats->emptyShapes +=
+            usable ? usable : sizeof(EmptyShape*) * gc::FINALIZE_FUNCTION_AND_OBJECT_LAST;
+    }
+
+    /*
+     * This counts memory that is in the temp pool but gets attributed
+     * elsewhere.  See JS_GetTypeInferenceMemoryStats for more details.
+     */
     size_t bytes = object->dynamicSize();
     stats->objects += bytes;
     stats->temporary -= bytes;
 }
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -1017,21 +1017,21 @@ class TypeScript
      * is not set until the script has executed at least once and SetScope
      * called, before that 'global' will be poisoned per GLOBAL_MISSING_SCOPE.
      */
     static const size_t GLOBAL_MISSING_SCOPE = 0x1;
 
     /* Global object for the script, if compileAndGo. */
     js::GlobalObject *global;
 
+  public:
+
     /* Nesting state for outer or inner function scripts. */
     TypeScriptNesting *nesting;
 
-  public:
-
     /* Dynamic types generated at points within this script. */
     TypeResult *dynamicList;
 
     TypeScript(JSFunction *fun) {
         this->function = fun;
         this->global = (js::GlobalObject *) GLOBAL_MISSING_SCOPE;
     }
 
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -4392,36 +4392,16 @@ BEGIN_CASE(JSOP_ARGUMENTS)
     } else {
         if (!js_GetArgsValue(cx, regs.fp(), &rval))
             goto error;
     }
     PUSH_COPY(rval);
 }
 END_CASE(JSOP_ARGUMENTS)
 
-BEGIN_CASE(JSOP_ARGSUB)
-{
-    jsid id = INT_TO_JSID(GET_ARGNO(regs.pc));
-    Value rval;
-    if (!js_GetArgsProperty(cx, regs.fp(), id, &rval))
-        goto error;
-    PUSH_COPY(rval);
-}
-END_CASE(JSOP_ARGSUB)
-
-BEGIN_CASE(JSOP_ARGCNT)
-{
-    jsid id = ATOM_TO_JSID(rt->atomState.lengthAtom);
-    Value rval;
-    if (!js_GetArgsProperty(cx, regs.fp(), id, &rval))
-        goto error;
-    PUSH_COPY(rval);
-}
-END_CASE(JSOP_ARGCNT)
-
 BEGIN_CASE(JSOP_GETARG)
 BEGIN_CASE(JSOP_CALLARG)
 {
     uint32 slot = GET_ARGNO(regs.pc);
     JS_ASSERT(slot < regs.fp()->numFormalArgs());
     PUSH_COPY(argv[slot]);
     if (op == JSOP_CALLARG)
         PUSH_UNDEFINED();
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -3969,27 +3969,16 @@ Decompile(SprintStack *ss, jsbytecode *p
                                 ? js_getter_str
                                 : (lastop == JSOP_SETTER)
                                 ? js_setter_str
                                 : CodeToken[lastop]
                               : "",
                               rval);
                 break;
 
-              case JSOP_ARGSUB:
-                i = (jsint) GET_ARGNO(pc);
-                todo = Sprint(&ss->sprinter, "%s[%d]",
-                              js_arguments_str, (int) i);
-                break;
-
-              case JSOP_ARGCNT:
-                todo = Sprint(&ss->sprinter, dot_format,
-                              js_arguments_str, js_length_str);
-                break;
-
               case JSOP_CALLARG:
               case JSOP_GETARG:
                 i = GET_ARGNO(pc);
                 atom = GetArgOrVarAtom(jp, i);
 #if JS_HAS_DESTRUCTURING
                 if (!atom) {
                     todo = Sprint(&ss->sprinter, "%s[%d]", js_arguments_str, i);
                     break;
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -369,228 +369,220 @@ OPDEF(JSOP_FINALLY,     135,"finally",  
  * the closure-invariant upvar values. The immediate operand indexes the upvar
  * in the function's u.i.script->upvars() array. The CALL variant computes the
  * callee and this-object in preparation for a JSOP_CALL.
  */
 OPDEF(JSOP_GETFCSLOT,   136,"getfcslot",  NULL,       3,  0,  1, 19,  JOF_UINT16|JOF_NAME|JOF_TYPESET)
 OPDEF(JSOP_CALLFCSLOT,  137,"callfcslot", NULL,       3,  0,  2, 19,  JOF_UINT16|JOF_NAME|JOF_TYPESET|JOF_CALLOP)
 
 /*
- * Bytecodes that avoid making an arguments object in most cases:
- * JSOP_ARGSUB gets arguments[i] from fp->argv, iff i is in [0, fp->argc-1].
- * JSOP_ARGCNT returns fp->argc.
- */
-OPDEF(JSOP_ARGSUB,      138,"argsub",     NULL,       3,  0,  1, 18,  JOF_QARG |JOF_NAME)
-OPDEF(JSOP_ARGCNT,      139,"argcnt",     NULL,       1,  0,  1, 18,  JOF_BYTE)
-
-/*
  * Define a local function object as a local variable.
  * The local variable's slot number is the first immediate two-byte operand.
  * The function object's atom index is the second immediate operand.
  */
-OPDEF(JSOP_DEFLOCALFUN, 140,"deflocalfun",NULL,       5,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
+OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL,       5,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
 
 /* Extended jumps. */
-OPDEF(JSOP_GOTOX,         141,"gotox",    NULL,       5,  0,  0,  0,  JOF_JUMPX)
-OPDEF(JSOP_IFEQX,         142,"ifeqx",    NULL,       5,  1,  0,  4,  JOF_JUMPX|JOF_DETECTING)
-OPDEF(JSOP_IFNEX,         143,"ifnex",    NULL,       5,  1,  0,  0,  JOF_JUMPX|JOF_PARENHEAD)
-OPDEF(JSOP_ORX,           144,"orx",      NULL,       5,  1,  0,  5,  JOF_JUMPX|JOF_DETECTING)
-OPDEF(JSOP_ANDX,          145,"andx",     NULL,       5,  1,  0,  6,  JOF_JUMPX|JOF_DETECTING)
-OPDEF(JSOP_GOSUBX,        146,"gosubx",   NULL,       5,  0,  0,  0,  JOF_JUMPX)
-OPDEF(JSOP_CASEX,         147,"casex",    NULL,       5,  2,  1,  0,  JOF_JUMPX)
-OPDEF(JSOP_DEFAULTX,      148,"defaultx", NULL,       5,  1,  0,  0,  JOF_JUMPX)
-OPDEF(JSOP_TABLESWITCHX,  149,"tableswitchx",NULL,   -1,  1,  0,  0,  JOF_TABLESWITCHX|JOF_DETECTING|JOF_PARENHEAD)
-OPDEF(JSOP_LOOKUPSWITCHX, 150,"lookupswitchx",NULL,  -1,  1,  0,  0,  JOF_LOOKUPSWITCHX|JOF_DETECTING|JOF_PARENHEAD)
+OPDEF(JSOP_GOTOX,         139,"gotox",    NULL,       5,  0,  0,  0,  JOF_JUMPX)
+OPDEF(JSOP_IFEQX,         140,"ifeqx",    NULL,       5,  1,  0,  4,  JOF_JUMPX|JOF_DETECTING)
+OPDEF(JSOP_IFNEX,         141,"ifnex",    NULL,       5,  1,  0,  0,  JOF_JUMPX|JOF_PARENHEAD)
+OPDEF(JSOP_ORX,           142,"orx",      NULL,       5,  1,  0,  5,  JOF_JUMPX|JOF_DETECTING)
+OPDEF(JSOP_ANDX,          143,"andx",     NULL,       5,  1,  0,  6,  JOF_JUMPX|JOF_DETECTING)
+OPDEF(JSOP_GOSUBX,        144,"gosubx",   NULL,       5,  0,  0,  0,  JOF_JUMPX)
+OPDEF(JSOP_CASEX,         145,"casex",    NULL,       5,  2,  1,  0,  JOF_JUMPX)
+OPDEF(JSOP_DEFAULTX,      146,"defaultx", NULL,       5,  1,  0,  0,  JOF_JUMPX)
+OPDEF(JSOP_TABLESWITCHX,  147,"tableswitchx",NULL,   -1,  1,  0,  0,  JOF_TABLESWITCHX|JOF_DETECTING|JOF_PARENHEAD)
+OPDEF(JSOP_LOOKUPSWITCHX, 148,"lookupswitchx",NULL,  -1,  1,  0,  0,  JOF_LOOKUPSWITCHX|JOF_DETECTING|JOF_PARENHEAD)
 
 /* Placeholders for a real jump opcode set during backpatch chain fixup. */
-OPDEF(JSOP_BACKPATCH,     151,"backpatch",NULL,       3,  0,  0,  0,  JOF_JUMP|JOF_BACKPATCH)
-OPDEF(JSOP_BACKPATCH_POP, 152,"backpatch_pop",NULL,   3,  1,  0,  0,  JOF_JUMP|JOF_BACKPATCH)
+OPDEF(JSOP_BACKPATCH,     149,"backpatch",NULL,       3,  0,  0,  0,  JOF_JUMP|JOF_BACKPATCH)
+OPDEF(JSOP_BACKPATCH_POP, 150,"backpatch_pop",NULL,   3,  1,  0,  0,  JOF_JUMP|JOF_BACKPATCH)
 
 /* Set pending exception from the stack, to trigger rethrow. */
-OPDEF(JSOP_THROWING,      153,"throwing", NULL,       1,  1,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_THROWING,      151,"throwing", NULL,       1,  1,  0,  0,  JOF_BYTE)
 
 /* Set and get return value pseudo-register in stack frame. */
-OPDEF(JSOP_SETRVAL,       154,"setrval",  NULL,       1,  1,  0,  2,  JOF_BYTE)
-OPDEF(JSOP_RETRVAL,       155,"retrval",  NULL,       1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_SETRVAL,       152,"setrval",  NULL,       1,  1,  0,  2,  JOF_BYTE)
+OPDEF(JSOP_RETRVAL,       153,"retrval",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 
 /* Free variable references that must either be found on the global or a ReferenceError */
-OPDEF(JSOP_GETGNAME,      156,"getgname",  NULL,       3,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME)
-OPDEF(JSOP_SETGNAME,      157,"setgname",  NULL,       3,  2,  1,  3,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME)
-OPDEF(JSOP_INCGNAME,      158,"incgname",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
-OPDEF(JSOP_DECGNAME,      159,"decgname",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
-OPDEF(JSOP_GNAMEINC,      160,"gnameinc",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
-OPDEF(JSOP_GNAMEDEC,      161,"gnamedec",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
+OPDEF(JSOP_GETGNAME,      154,"getgname",  NULL,       3,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME)
+OPDEF(JSOP_SETGNAME,      155,"setgname",  NULL,       3,  2,  1,  3,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME)
+OPDEF(JSOP_INCGNAME,      156,"incgname",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
+OPDEF(JSOP_DECGNAME,      157,"decgname",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
+OPDEF(JSOP_GNAMEINC,      158,"gnameinc",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
+OPDEF(JSOP_GNAMEDEC,      159,"gnamedec",  NULL,       4,  0,  1, 15,  JOF_ATOM|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_GNAME|JOF_DECOMPOSE)
 
 /* Regular expression literal requiring special "fork on exec" handling. */
-OPDEF(JSOP_REGEXP,        162,"regexp",   NULL,       3,  0,  1, 19,  JOF_REGEXP)
+OPDEF(JSOP_REGEXP,        160,"regexp",   NULL,       3,  0,  1, 19,  JOF_REGEXP)
 
 /* XML (ECMA-357, a.k.a. "E4X") support. */
-OPDEF(JSOP_DEFXMLNS,      163,"defxmlns",   NULL,     1,  1,  0,  0,  JOF_BYTE)
-OPDEF(JSOP_ANYNAME,       164,"anyname",    NULL,     1,  0,  1, 19,  JOF_BYTE|JOF_XMLNAME)
-OPDEF(JSOP_QNAMEPART,     165,"qnamepart",  NULL,     3,  0,  1, 19,  JOF_ATOM|JOF_XMLNAME)
-OPDEF(JSOP_QNAMECONST,    166,"qnameconst", NULL,     3,  1,  1, 19,  JOF_ATOM|JOF_XMLNAME)
-OPDEF(JSOP_QNAME,         167,"qname",      NULL,     1,  2,  1,  0,  JOF_BYTE|JOF_XMLNAME)
-OPDEF(JSOP_TOATTRNAME,    168,"toattrname", NULL,     1,  1,  1, 19,  JOF_BYTE|JOF_XMLNAME)
-OPDEF(JSOP_TOATTRVAL,     169,"toattrval",  NULL,     1,  1,  1, 19,  JOF_BYTE)
-OPDEF(JSOP_ADDATTRNAME,   170,"addattrname",NULL,     1,  2,  1, 13,  JOF_BYTE)
-OPDEF(JSOP_ADDATTRVAL,    171,"addattrval", NULL,     1,  2,  1, 13,  JOF_BYTE)
-OPDEF(JSOP_BINDXMLNAME,   172,"bindxmlname",NULL,     1,  1,  2,  3,  JOF_BYTE|JOF_SET)
-OPDEF(JSOP_SETXMLNAME,    173,"setxmlname", NULL,     1,  3,  1,  3,  JOF_BYTE|JOF_SET|JOF_DETECTING)
-OPDEF(JSOP_XMLNAME,       174,"xmlname",    NULL,     1,  1,  1, 19,  JOF_BYTE)
-OPDEF(JSOP_DESCENDANTS,   175,"descendants",NULL,     1,  2,  1, 18,  JOF_BYTE)
-OPDEF(JSOP_FILTER,        176,"filter",     NULL,     3,  1,  1,  0,  JOF_JUMP)
-OPDEF(JSOP_ENDFILTER,     177,"endfilter",  NULL,     3,  2,  1, 18,  JOF_JUMP)
-OPDEF(JSOP_TOXML,         178,"toxml",      NULL,     1,  1,  1, 19,  JOF_BYTE)
-OPDEF(JSOP_TOXMLLIST,     179,"toxmllist",  NULL,     1,  1,  1, 19,  JOF_BYTE)
-OPDEF(JSOP_XMLTAGEXPR,    180,"xmltagexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
-OPDEF(JSOP_XMLELTEXPR,    181,"xmleltexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
-OPDEF(JSOP_NOTRACE,       182,"notrace",    NULL,     3,  0,  0,  0,  JOF_UINT16)
-OPDEF(JSOP_XMLCDATA,      183,"xmlcdata",   NULL,     3,  0,  1, 19,  JOF_ATOM)
-OPDEF(JSOP_XMLCOMMENT,    184,"xmlcomment", NULL,     3,  0,  1, 19,  JOF_ATOM)
-OPDEF(JSOP_XMLPI,         185,"xmlpi",      NULL,     3,  1,  1, 19,  JOF_ATOM)
-OPDEF(JSOP_DELDESC,       186,"deldesc",    NULL,     1,  2,  1, 15,  JOF_BYTE|JOF_ELEM|JOF_DEL)
+OPDEF(JSOP_DEFXMLNS,      161,"defxmlns",   NULL,     1,  1,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_ANYNAME,       162,"anyname",    NULL,     1,  0,  1, 19,  JOF_BYTE|JOF_XMLNAME)
+OPDEF(JSOP_QNAMEPART,     163,"qnamepart",  NULL,     3,  0,  1, 19,  JOF_ATOM|JOF_XMLNAME)
+OPDEF(JSOP_QNAMECONST,    164,"qnameconst", NULL,     3,  1,  1, 19,  JOF_ATOM|JOF_XMLNAME)
+OPDEF(JSOP_QNAME,         165,"qname",      NULL,     1,  2,  1,  0,  JOF_BYTE|JOF_XMLNAME)
+OPDEF(JSOP_TOATTRNAME,    166,"toattrname", NULL,     1,  1,  1, 19,  JOF_BYTE|JOF_XMLNAME)
+OPDEF(JSOP_TOATTRVAL,     167,"toattrval",  NULL,     1,  1,  1, 19,  JOF_BYTE)
+OPDEF(JSOP_ADDATTRNAME,   168,"addattrname",NULL,     1,  2,  1, 13,  JOF_BYTE)
+OPDEF(JSOP_ADDATTRVAL,    169,"addattrval", NULL,     1,  2,  1, 13,  JOF_BYTE)
+OPDEF(JSOP_BINDXMLNAME,   170,"bindxmlname",NULL,     1,  1,  2,  3,  JOF_BYTE|JOF_SET)
+OPDEF(JSOP_SETXMLNAME,    171,"setxmlname", NULL,     1,  3,  1,  3,  JOF_BYTE|JOF_SET|JOF_DETECTING)
+OPDEF(JSOP_XMLNAME,       172,"xmlname",    NULL,     1,  1,  1, 19,  JOF_BYTE)
+OPDEF(JSOP_DESCENDANTS,   173,"descendants",NULL,     1,  2,  1, 18,  JOF_BYTE)
+OPDEF(JSOP_FILTER,        174,"filter",     NULL,     3,  1,  1,  0,  JOF_JUMP)
+OPDEF(JSOP_ENDFILTER,     175,"endfilter",  NULL,     3,  2,  1, 18,  JOF_JUMP)
+OPDEF(JSOP_TOXML,         176,"toxml",      NULL,     1,  1,  1, 19,  JOF_BYTE)
+OPDEF(JSOP_TOXMLLIST,     177,"toxmllist",  NULL,     1,  1,  1, 19,  JOF_BYTE)
+OPDEF(JSOP_XMLTAGEXPR,    178,"xmltagexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
+OPDEF(JSOP_XMLELTEXPR,    179,"xmleltexpr", NULL,     1,  1,  1,  0,  JOF_BYTE)
+OPDEF(JSOP_NOTRACE,       180,"notrace",    NULL,     3,  0,  0,  0,  JOF_UINT16)
+OPDEF(JSOP_XMLCDATA,      181,"xmlcdata",   NULL,     3,  0,  1, 19,  JOF_ATOM)
+OPDEF(JSOP_XMLCOMMENT,    182,"xmlcomment", NULL,     3,  0,  1, 19,  JOF_ATOM)
+OPDEF(JSOP_XMLPI,         183,"xmlpi",      NULL,     3,  1,  1, 19,  JOF_ATOM)
+OPDEF(JSOP_DELDESC,       184,"deldesc",    NULL,     1,  2,  1, 15,  JOF_BYTE|JOF_ELEM|JOF_DEL)
 
-OPDEF(JSOP_CALLPROP,      187,"callprop",   NULL,     3,  1,  2, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_CALLOP|JOF_TMPSLOT3)
+OPDEF(JSOP_CALLPROP,      185,"callprop",   NULL,     3,  1,  2, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_CALLOP|JOF_TMPSLOT3)
 
 /*
  * These opcodes contain a reference to the current blockChain object.
  * They are emitted directly after instructions, such as DEFFUN, that need fast access to
  * the blockChain. The special NULLBLOCKCHAIN is needed because the JOF_OBJECT
  * does not permit NULL object references, since it stores an index into a table of
  * objects.
  */
-OPDEF(JSOP_BLOCKCHAIN,    188,"blockchain",    NULL,  3,  0,  0,  0, JOF_OBJECT)
-OPDEF(JSOP_NULLBLOCKCHAIN,189,"nullblockchain",NULL,  1,  0,  0,  0, JOF_BYTE)
+OPDEF(JSOP_BLOCKCHAIN,    186,"blockchain",    NULL,  3,  0,  0,  0, JOF_OBJECT)
+OPDEF(JSOP_NULLBLOCKCHAIN,187,"nullblockchain",NULL,  1,  0,  0,  0, JOF_BYTE)
 
 /*
  * Opcode to hold 24-bit immediate integer operands.
  */
-OPDEF(JSOP_UINT24,        190,"uint24",     NULL,     4,  0,  1, 16,  JOF_UINT24)
+OPDEF(JSOP_UINT24,        188,"uint24",     NULL,     4,  0,  1, 16,  JOF_UINT24)
 
 /*
  * Opcodes to allow 24-bit atom or object indexes. Whenever an index exceeds
  * the 16-bit limit, the index-accessing bytecode must be bracketed by
  * JSOP_INDEXBASE and JSOP_RESETBASE to provide the upper bits of the index.
  * See jsemit.c, EmitIndexOp.
  */
-OPDEF(JSOP_INDEXBASE,     191,"indexbase",  NULL,     2,  0,  0,  0,  JOF_UINT8|JOF_INDEXBASE)
-OPDEF(JSOP_RESETBASE,     192,"resetbase",  NULL,     1,  0,  0,  0,  JOF_BYTE)
-OPDEF(JSOP_RESETBASE0,    193,"resetbase0", NULL,     1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_INDEXBASE,     189,"indexbase",  NULL,     2,  0,  0,  0,  JOF_UINT8|JOF_INDEXBASE)
+OPDEF(JSOP_RESETBASE,     190,"resetbase",  NULL,     1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_RESETBASE0,    191,"resetbase0", NULL,     1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Opcodes to help the decompiler deal with XML.
  */
-OPDEF(JSOP_STARTXML,      194,"startxml",    NULL,    1,  0,  0,  0,  JOF_BYTE)
-OPDEF(JSOP_STARTXMLEXPR,  195,"startxmlexpr",NULL,    1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_STARTXML,      192,"startxml",    NULL,    1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_STARTXMLEXPR,  193,"startxmlexpr",NULL,    1,  0,  0,  0,  JOF_BYTE)
 
-OPDEF(JSOP_CALLELEM,      196, "callelem",   NULL,    1,  2,  2, 18,  JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC|JOF_CALLOP)
+OPDEF(JSOP_CALLELEM,      194, "callelem",   NULL,    1,  2,  2, 18,  JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC|JOF_CALLOP)
 
 /*
  * Stop interpretation, emitted at end of script to save the threaded bytecode
  * interpreter an extra branch test on every DO_NEXT_OP (see jsinterp.c).
  */
-OPDEF(JSOP_STOP,          197,"stop",        NULL,    1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_STOP,          195,"stop",        NULL,    1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Get an extant property value, throwing ReferenceError if the identified
  * property does not exist.
  */
-OPDEF(JSOP_GETXPROP,      198,"getxprop",    NULL,    3,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
+OPDEF(JSOP_GETXPROP,      196,"getxprop",    NULL,    3,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
 
-OPDEF(JSOP_CALLXMLNAME,   199, "callxmlname",  NULL,  1,  1,  2, 19,  JOF_BYTE|JOF_CALLOP)
+OPDEF(JSOP_CALLXMLNAME,   197, "callxmlname",  NULL,  1,  1,  2, 19,  JOF_BYTE|JOF_CALLOP)
 
 /*
  * Specialized JSOP_TYPEOF to avoid reporting undefined for typeof(0, undef).
  */
-OPDEF(JSOP_TYPEOFEXPR,    200,"typeofexpr",  NULL,    1,  1,  1, 15,  JOF_BYTE|JOF_DETECTING)
+OPDEF(JSOP_TYPEOFEXPR,    198,"typeofexpr",  NULL,    1,  1,  1, 15,  JOF_BYTE|JOF_DETECTING)
 
 /*
  * Block-local scope support.
  */
-OPDEF(JSOP_ENTERBLOCK,    201,"enterblock",  NULL,    3,  0, -1,  0,  JOF_OBJECT)
-OPDEF(JSOP_LEAVEBLOCK,    202,"leaveblock",  NULL,    5, -1,  0,  0,  JOF_UINT16)
+OPDEF(JSOP_ENTERBLOCK,    199,"enterblock",  NULL,    3,  0, -1,  0,  JOF_OBJECT)
+OPDEF(JSOP_LEAVEBLOCK,    200,"leaveblock",  NULL,    5, -1,  0,  0,  JOF_UINT16)
 
 /* Jump to target if top of stack value isn't callable. */
-OPDEF(JSOP_IFCANTCALLTOP, 203,"ifcantcalltop",NULL,   3,  1,  1,  0,  JOF_JUMP|JOF_DETECTING)
+OPDEF(JSOP_IFCANTCALLTOP, 201,"ifcantcalltop",NULL,   3,  1,  1,  0,  JOF_JUMP|JOF_DETECTING)
 
 /* Throws a TypeError if the value at the top of the stack is not primitive. */
-OPDEF(JSOP_PRIMTOP,       204,"primtop",     NULL,    2,  1,  1,  0,  JOF_INT8)
+OPDEF(JSOP_PRIMTOP,       202,"primtop",     NULL,    2,  1,  1,  0,  JOF_INT8)
 
 /*
  * Generator and array comprehension support.
  */
-OPDEF(JSOP_GENERATOR,     205,"generator",   NULL,    1,  0,  0,  0,  JOF_BYTE)
-OPDEF(JSOP_YIELD,         206,"yield",       NULL,    1,  1,  1,  1,  JOF_BYTE)
-OPDEF(JSOP_ARRAYPUSH,     207,"arraypush",   NULL,    3,  1,  0,  3,  JOF_LOCAL)
+OPDEF(JSOP_GENERATOR,     203,"generator",   NULL,    1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_YIELD,         204,"yield",       NULL,    1,  1,  1,  1,  JOF_BYTE)
+OPDEF(JSOP_ARRAYPUSH,     205,"arraypush",   NULL,    3,  1,  0,  3,  JOF_LOCAL)
 
 /*
  * Get the built-in function::foo namespace and push it.
  */
-OPDEF(JSOP_GETFUNNS,      208,"getfunns",   NULL,     1,  0,  1, 19,  JOF_BYTE)
+OPDEF(JSOP_GETFUNNS,      206,"getfunns",   NULL,     1,  0,  1, 19,  JOF_BYTE)
 
 /*
  * Variant of JSOP_ENUMELEM for destructuring const (const [a, b] = ...).
  */
-OPDEF(JSOP_ENUMCONSTELEM, 209,"enumconstelem",NULL,   1,  3,  0,  3,  JOF_BYTE|JOF_SET)
+OPDEF(JSOP_ENUMCONSTELEM, 207,"enumconstelem",NULL,   1,  3,  0,  3,  JOF_BYTE|JOF_SET)
 
 /*
  * Variant of JSOP_LEAVEBLOCK has a result on the stack above the locals,
  * which must be moved down when the block pops.
  */
-OPDEF(JSOP_LEAVEBLOCKEXPR,210,"leaveblockexpr",NULL,  5, -1,  1,  3,  JOF_UINT16)
+OPDEF(JSOP_LEAVEBLOCKEXPR,208,"leaveblockexpr",NULL,  5, -1,  1,  3,  JOF_UINT16)
 \
 /*
  * Optimize atom segments 1-3.  These must be followed by JSOP_RESETBASE0 after
  * the opcode that they prefix.
  */
-OPDEF(JSOP_INDEXBASE1,    211,"indexbase1",    NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
-OPDEF(JSOP_INDEXBASE2,    212,"indexbase2",    NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
-OPDEF(JSOP_INDEXBASE3,    213,"indexbase3",    NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
+OPDEF(JSOP_INDEXBASE1,    209,"indexbase1",    NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
+OPDEF(JSOP_INDEXBASE2,    210,"indexbase2",    NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
+OPDEF(JSOP_INDEXBASE3,    211,"indexbase3",    NULL,  1,  0,  0,  0,  JOF_BYTE |JOF_INDEXBASE)
 
-OPDEF(JSOP_CALLGNAME,     214, "callgname",    NULL,  3,  0,  2, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_CALLOP|JOF_GNAME)
-OPDEF(JSOP_CALLLOCAL,     215, "calllocal",    NULL,  3,  0,  2, 19,  JOF_LOCAL|JOF_NAME|JOF_CALLOP)
-OPDEF(JSOP_CALLARG,       216, "callarg",      NULL,  3,  0,  2, 19,  JOF_QARG |JOF_NAME|JOF_CALLOP)
-OPDEF(JSOP_BINDGNAME,     217, "bindgname",    NULL,  3,  0,  1,  0,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME)
+OPDEF(JSOP_CALLGNAME,     212, "callgname",    NULL,  3,  0,  2, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_CALLOP|JOF_GNAME)
+OPDEF(JSOP_CALLLOCAL,     213, "calllocal",    NULL,  3,  0,  2, 19,  JOF_LOCAL|JOF_NAME|JOF_CALLOP)
+OPDEF(JSOP_CALLARG,       214, "callarg",      NULL,  3,  0,  2, 19,  JOF_QARG |JOF_NAME|JOF_CALLOP)
+OPDEF(JSOP_BINDGNAME,     215, "bindgname",    NULL,  3,  0,  1,  0,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME)
 
 /*
  * Opcodes to hold 8-bit and 32-bit immediate integer operands.
  */
-OPDEF(JSOP_INT8,          218, "int8",         NULL,  2,  0,  1, 16,  JOF_INT8)
-OPDEF(JSOP_INT32,         219, "int32",        NULL,  5,  0,  1, 16,  JOF_INT32)
+OPDEF(JSOP_INT8,          216, "int8",         NULL,  2,  0,  1, 16,  JOF_INT8)
+OPDEF(JSOP_INT32,         217, "int32",        NULL,  5,  0,  1, 16,  JOF_INT32)
 
 /*
  * Get the value of the 'length' property from a stacked object.
  */
-OPDEF(JSOP_LENGTH,        220, "length",       NULL,  3,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
+OPDEF(JSOP_LENGTH,        218, "length",       NULL,  3,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET)
 
 /*
  * Push a JSVAL_HOLE value onto the stack, representing an omitted property in
  * an array literal (e.g. property 0 in the array [, 1]).  This opcode is used
  * with the JSOP_NEWARRAY opcode.
  */
-OPDEF(JSOP_HOLE,          221, "hole",         NULL,  1,  0,  1,  0,  JOF_BYTE)
+OPDEF(JSOP_HOLE,          219, "hole",         NULL,  1,  0,  1,  0,  JOF_BYTE)
 
 /*
  * Variants of JSOP_{DEF{,LOCAL}FUN,LAMBDA} optimized for the flat closure case.
  */
-OPDEF(JSOP_DEFFUN_FC,     222,"deffun_fc",     NULL,  3,  0,  0,  0,  JOF_OBJECT|JOF_DECLARING)
-OPDEF(JSOP_DEFLOCALFUN_FC,223,"deflocalfun_fc",NULL,  5,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
-OPDEF(JSOP_LAMBDA_FC,     224,"lambda_fc",     NULL,  3,  0,  1, 19,  JOF_OBJECT)
+OPDEF(JSOP_DEFFUN_FC,     220,"deffun_fc",     NULL,  3,  0,  0,  0,  JOF_OBJECT|JOF_DECLARING)
+OPDEF(JSOP_DEFLOCALFUN_FC,221,"deflocalfun_fc",NULL,  5,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
+OPDEF(JSOP_LAMBDA_FC,     222,"lambda_fc",     NULL,  3,  0,  1, 19,  JOF_OBJECT)
 
 /*
  * Ensure that the value on the top of the stack is an object. The one
  * argument is an error message, defined in js.msg, that takes one parameter
  * (the decompilation of the primitive value).
  */
-OPDEF(JSOP_OBJTOP,        225,"objtop",        NULL,  3,  0,  0,  0,  JOF_UINT16)
+OPDEF(JSOP_OBJTOP,        223,"objtop",        NULL,  3,  0,  0,  0,  JOF_UINT16)
 
 /*
  * Joined function object as method optimization support.
  */
-OPDEF(JSOP_SETMETHOD,     226,"setmethod",     NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
-OPDEF(JSOP_INITMETHOD,    227,"initmethod",    NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
-OPDEF(JSOP_UNBRAND,       228,"unbrand",       NULL,  1,  1,  1,  0,  JOF_BYTE)
-OPDEF(JSOP_UNBRANDTHIS,   229,"unbrandthis",   NULL,  1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_SETMETHOD,     224,"setmethod",     NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
+OPDEF(JSOP_INITMETHOD,    225,"initmethod",    NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
+OPDEF(JSOP_UNBRAND,       226,"unbrand",       NULL,  1,  1,  1,  0,  JOF_BYTE)
+OPDEF(JSOP_UNBRANDTHIS,   227,"unbrandthis",   NULL,  1,  0,  0,  0,  JOF_BYTE)
 
-OPDEF(JSOP_SHARPINIT,     230,"sharpinit",     NULL,  3,  0,  0,  0,  JOF_UINT16|JOF_SHARPSLOT)
+OPDEF(JSOP_SHARPINIT,     228,"sharpinit",     NULL,  3,  0,  0,  0,  JOF_UINT16|JOF_SHARPSLOT)
 
 /* Pop the stack, convert to a jsid (int or string), and push back. */
-OPDEF(JSOP_TOID,          231, "toid",         NULL,  1,  1,  1,  0,  JOF_BYTE)
+OPDEF(JSOP_TOID,          229, "toid",         NULL,  1,  1,  1,  0,  JOF_BYTE)
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -15422,77 +15422,28 @@ TraceRecorder::record_JSOP_FINALLY()
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_NOP()
 {
     return ARECORD_CONTINUE;
 }
 
-JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_ARGSUB()
-{
-    StackFrame* const fp = cx->fp();
-
-    /*
-     * The arguments object or its absence in the frame is part of the typemap,
-     * so a record-time check suffices here. We don't bother tracing ARGSUB in
-     * the case of an arguments object exising, because ARGSUB and to a lesser
-     * extent ARGCNT are emitted to avoid arguments object creation.
-     */
-    if (!fp->hasArgsObj() && !fp->fun()->isHeavyweight()) {
-        uintN slot = GET_ARGNO(cx->regs().pc);
-        if (slot >= fp->numActualArgs())
-            RETURN_STOP_A("can't trace out-of-range arguments");
-
-        stack(0, get(&cx->fp()->canonicalActualArg(slot)));
-        return ARECORD_CONTINUE;
-    }
-    RETURN_STOP_A("can't trace JSOP_ARGSUB hard case");
-}
-
 JS_REQUIRES_STACK LIns*
 TraceRecorder::guardArgsLengthNotAssigned(LIns* argsobj_ins)
 {
     // The following implements JSObject::isArgsLengthOverridden on trace.
     // ARGS_LENGTH_OVERRIDDEN_BIT is set if length was overridden.
     LIns *len_ins = w.getArgsLength(argsobj_ins);
     LIns *ovr_ins = w.andi(len_ins, w.nameImmi(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
     guard(true, w.eqi0(ovr_ins), MISMATCH_EXIT);
     return len_ins;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_ARGCNT()
-{
-    StackFrame * const fp = cx->fp();
-
-    if (fp->fun()->flags & JSFUN_HEAVYWEIGHT)
-        RETURN_STOP_A("can't trace heavyweight JSOP_ARGCNT");
-
-    // argc is fixed on trace, so ideally we would simply generate LIR for
-    // constant argc. But the user can mutate arguments.length in the
-    // interpreter, so we have to check for that in the trace entry frame.
-    // We also have to check that arguments.length has not been mutated
-    // at record time, because if so we will generate incorrect constant
-    // LIR, which will assert in tryToDemote().
-    if (fp->hasArgsObj() && fp->argsObj().hasOverriddenLength())
-        RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified");
-    LIns *a_ins = getFrameObjPtr(fp->addressOfArgs());
-    if (callDepth == 0) {
-        if (MaybeBranch mbr = w.jt(w.eqp0(a_ins))) {
-            guardArgsLengthNotAssigned(a_ins);
-            w.label(mbr);
-        }
-    }
-    stack(0, w.immd(fp->numActualArgs()));
-    return ARECORD_CONTINUE;
-}
-
-JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_DefLocalFunSetSlot(uint32 slot, JSObject* obj)
 {
     JSFunction* fun = obj->getFunctionPrivate();
 
     if (fun->isNullClosure() && fun->getParent() == globalObj) {
         LIns *proto_ins = NULL;
         CHECK_STATUS_A(getFunctionPrototype(proto_ins));
 
@@ -16102,17 +16053,17 @@ TraceRecorder::record_JSOP_LENGTH()
         unsigned depth;
         StackFrame *afp = guardArguments(obj, obj_ins, &depth);
         if (!afp)
             RETURN_STOP_A("can't reach arguments object's frame");
 
         // We must both check at record time and guard at run time that
         // arguments.length has not been reassigned, redefined or deleted.
         if (obj->asArguments()->hasOverriddenLength())
-            RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified");
+            RETURN_STOP_A("can't trace arguments.length if it has been modified");
         LIns* slot_ins = guardArgsLengthNotAssigned(obj_ins);
 
         // slot_ins is the value from the slot; right-shift to get the length;
         // see ArgumentsObject.h.
         LIns* v_ins = w.i2d(w.rshiN(slot_ins, ArgumentsObject::PACKED_BITS_COUNT));
         set(&l, v_ins);
         return ARECORD_CONTINUE;
     }
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -217,17 +217,17 @@ JS_XDRFindClassById(JSXDRState *xdr, uin
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number should be XDR'ed once near the front of any file or
  * larger storage unit containing XDR'ed bytecode and other data, and checked
  * before deserialization of bytecode.  If the saved version does not match
  * the current version, abort deserialization and invalidate the file.
  */
-#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 95)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 96)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 JS_END_EXTERN_C
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -2619,33 +2619,16 @@ mjit::Compiler::generateMethod()
                                                            knownPushedType(0), true);
             finishBarrier(barrier, REJOIN_GETTER, 0);
 
             if (op == JSOP_CALLFCSLOT)
                 frame.push(UndefinedValue());
           }
           END_CASE(JSOP_CALLFCSLOT)
 
-          BEGIN_CASE(JSOP_ARGSUB)
-          {
-            prepareStubCall(Uses(0));
-            masm.move(Imm32(GET_ARGNO(PC)), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::ArgSub, REJOIN_FALLTHROUGH);
-            pushSyncedEntry(0);
-          }
-          END_CASE(JSOP_ARGSUB)
-
-          BEGIN_CASE(JSOP_ARGCNT)
-          {
-            prepareStubCall(Uses(0));
-            INLINE_STUBCALL(stubs::ArgCnt, REJOIN_FALLTHROUGH);
-            pushSyncedEntry(0);
-          }
-          END_CASE(JSOP_ARGCNT)
-
           BEGIN_CASE(JSOP_DEFLOCALFUN)
           {
             uint32 slot = GET_SLOTNO(PC);
             JSFunction *fun = script->getFunction(fullAtomIndex(&PC[SLOTNO_LEN]));
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(fun), Registers::ArgReg1);
             INLINE_STUBCALL(stubs::DefLocalFun, REJOIN_DEFLOCALFUN);
             frame.takeReg(Registers::ReturnReg);
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -1938,29 +1938,16 @@ stubs::FastInstanceOf(VMFrame &f)
         js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-2], NULL);
         THROW();
     }
 
     f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3]));
 }
 
 void JS_FASTCALL
-stubs::ArgCnt(VMFrame &f)
-{
-    JSContext *cx = f.cx;
-    JSRuntime *rt = cx->runtime;
-    StackFrame *fp = f.fp();
-
-    jsid id = ATOM_TO_JSID(rt->atomState.lengthAtom);
-    f.regs.sp++;
-    if (!js_GetArgsProperty(cx, fp, id, &f.regs.sp[-1]))
-        THROW();
-}
-
-void JS_FASTCALL
 stubs::EnterBlock(VMFrame &f, JSObject *obj)
 {
     FrameRegs &regs = f.regs;
 #ifdef DEBUG
     StackFrame *fp = f.fp();
 #endif
 
     JS_ASSERT(!f.regs.inlined());
@@ -2179,26 +2166,16 @@ stubs::Pos(VMFrame &f)
 {
     if (!ToNumber(f.cx, &f.regs.sp[-1]))
         THROW();
     if (!f.regs.sp[-1].isInt32())
         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
 }
 
 void JS_FASTCALL
-stubs::ArgSub(VMFrame &f, uint32 n)
-{
-    jsid id = INT_TO_JSID(n);
-    Value rval;
-    if (!js_GetArgsProperty(f.cx, f.fp(), id, &rval))
-        THROW();
-    f.regs.sp[0] = rval;
-}
-
-void JS_FASTCALL
 stubs::DelName(VMFrame &f, JSAtom *atom)
 {
     jsid id = ATOM_TO_JSID(atom);
     JSObject *obj, *obj2;
     JSProperty *prop;
     if (!js_FindProperty(f.cx, id, false, &obj, &obj2, &prop))
         THROW();
 
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -150,17 +150,16 @@ JSObject * JS_FASTCALL DefLocalFun_FC(VM
 void JS_FASTCALL RegExp(VMFrame &f, JSObject *regex);
 JSObject * JS_FASTCALL Lambda(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL LambdaJoinableForInit(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL LambdaJoinableForSet(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL LambdaJoinableForCall(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL LambdaJoinableForNull(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL FlatLambda(VMFrame &f, JSFunction *fun);
 void JS_FASTCALL Arguments(VMFrame &f);
-void JS_FASTCALL ArgSub(VMFrame &f, uint32 n);
 void JS_FASTCALL EnterBlock(VMFrame &f, JSObject *obj);
 void JS_FASTCALL LeaveBlock(VMFrame &f, JSObject *blockChain);
 
 JSBool JS_FASTCALL LessThan(VMFrame &f);
 JSBool JS_FASTCALL LessEqual(VMFrame &f);
 JSBool JS_FASTCALL GreaterThan(VMFrame &f);
 JSBool JS_FASTCALL GreaterEqual(VMFrame &f);
 JSBool JS_FASTCALL Equal(VMFrame &f);
@@ -188,17 +187,16 @@ void JS_FASTCALL Iter(VMFrame &f, uint32
 void JS_FASTCALL IterNext(VMFrame &f, int32 offset);
 JSBool JS_FASTCALL IterMore(VMFrame &f);
 void JS_FASTCALL EndIter(VMFrame &f);
 
 JSBool JS_FASTCALL ValueToBoolean(VMFrame &f);
 JSString * JS_FASTCALL TypeOf(VMFrame &f);
 JSBool JS_FASTCALL InstanceOf(VMFrame &f);
 void JS_FASTCALL FastInstanceOf(VMFrame &f);
-void JS_FASTCALL ArgCnt(VMFrame &f);
 void JS_FASTCALL Unbrand(VMFrame &f);
 void JS_FASTCALL UnbrandThis(VMFrame &f);
 
 /*
  * Helper for triggering recompilation should a name read miss a type barrier,
  * produce undefined or -0.
  */
 void JS_FASTCALL TypeBarrierHelper(VMFrame &f, uint32 which);
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1275,17 +1275,18 @@ CompartmentCallback(JSContext *cx, void 
     curr->mjitCodeUnused = unused;
 #endif
 #ifdef JS_TRACER
     curr->tjitCode = GetCompartmentTjitCodeSize(compartment);
     curr->tjitDataAllocatorsMain = GetCompartmentTjitDataAllocatorsMainSize(compartment);
     curr->tjitDataAllocatorsReserve = GetCompartmentTjitDataAllocatorsReserveSize(compartment);
     curr->tjitDataNonAllocators = GetCompartmentTjitDataTraceMonitorSize(compartment);
 #endif
-    JS_GetTypeInferenceMemoryStats(cx, compartment, &curr->typeInferenceMemory);
+    JS_GetTypeInferenceMemoryStats(cx, compartment, &curr->typeInferenceMemory,
+                                   moz_malloc_usable_size);
 }
 
 void
 ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
               JSGCTraceKind traceKind, size_t thingSize)
 {
     IterateData *data = static_cast<IterateData *>(vdata);
     data->currCompartmentStats->gcHeapArenaHeaders +=
@@ -1347,17 +1348,17 @@ CellCallback(JSContext *cx, void *vdata,
             curr->mjitData += script->jitDataSize(moz_malloc_usable_size);
 #endif
             break;
         }
         case JSTRACE_TYPE_OBJECT:
         {
             js::types::TypeObject *obj = static_cast<js::types::TypeObject *>(thing);
             curr->gcHeapTypeObjects += thingSize;
-            JS_GetTypeInferenceObjectStats(obj, &curr->typeInferenceMemory);
+            JS_GetTypeInferenceObjectStats(obj, &curr->typeInferenceMemory, moz_malloc_usable_size);
             break;
         }
         case JSTRACE_XML:
         {
             curr->gcHeapXML += thingSize;
             break;
         }
     }
--- a/layout/base/nsImageLoader.cpp
+++ b/layout/base/nsImageLoader.cpp
@@ -52,37 +52,35 @@
 #include "nsIFrame.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 
 #include "imgIContainer.h"
 
 #include "nsStyleContext.h"
 #include "nsGkAtoms.h"
+#include "nsLayoutUtils.h"
 
 // Paint forcing
 #include "prenv.h"
 
 NS_IMPL_ISUPPORTS2(nsImageLoader, imgIDecoderObserver, imgIContainerObserver)
 
 nsImageLoader::nsImageLoader(nsIFrame *aFrame, PRUint32 aActions,
                              nsImageLoader *aNextLoader)
   : mFrame(aFrame),
     mActions(aActions),
-    mNextLoader(aNextLoader)
+    mNextLoader(aNextLoader),
+    mRequestRegistered(false)
 {
 }
 
 nsImageLoader::~nsImageLoader()
 {
-  mFrame = nsnull;
-
-  if (mRequest) {
-    mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
-  }
+  Destroy();
 }
 
 /* static */ already_AddRefed<nsImageLoader>
 nsImageLoader::Create(nsIFrame *aFrame, imgIRequest *aRequest, 
                       PRUint32 aActions, nsImageLoader *aNextLoader)
 {
   nsRefPtr<nsImageLoader> loader =
     new nsImageLoader(aFrame, aActions, aNextLoader);
@@ -100,49 +98,66 @@ nsImageLoader::Destroy()
   mNextLoader = nsnull;
   while (list) {
     nsRefPtr<nsImageLoader> todestroy = list;
     list = todestroy->mNextLoader;
     todestroy->mNextLoader = nsnull;
     todestroy->Destroy();
   }
 
-  mFrame = nsnull;
+  if (mRequest && mFrame) {
+    nsPresContext* presContext = mFrame->PresContext();
 
-  if (mRequest) {
+    nsLayoutUtils::DeregisterImageRequest(presContext, mRequest,
+                                          &mRequestRegistered);
     mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
   }
 
+  mFrame = nsnull;
   mRequest = nsnull;
 }
 
 nsresult
 nsImageLoader::Load(imgIRequest *aImage)
 {
   NS_ASSERTION(!mRequest, "can't reuse image loaders");
   NS_ASSERTION(mFrame, "not initialized");
   NS_ASSERTION(aImage, "must have non-null image");
 
   if (!mFrame)
     return NS_ERROR_NOT_INITIALIZED;
 
   if (!aImage)
     return NS_ERROR_FAILURE;
 
+  // Deregister mRequest from the refresh driver, since it is no longer
+  // going to be managed by this nsImageLoader.
+  nsPresContext* presContext = mFrame->PresContext();
+
+  nsLayoutUtils::DeregisterImageRequest(presContext, mRequest,
+                                        &mRequestRegistered);
+
   // Make sure to clone into a temporary, then set mRequest, since
   // cloning may notify and we don't want to trigger paints from this
   // code.
   nsCOMPtr<imgIRequest> newRequest;
   nsresult rv = aImage->Clone(this, getter_AddRefs(newRequest));
   mRequest.swap(newRequest);
+
+  // Re-register mRequest with the refresh driver, but immediately deregister
+  // if it isn't animated.
+  nsLayoutUtils::RegisterImageRequest(presContext, mRequest,
+                                      &mRequestRegistered);
+
+  nsLayoutUtils::DeregisterImageRequestIfNotAnimated(presContext, mRequest,
+                                                     &mRequestRegistered);
+
   return rv;
 }
 
-                    
-
 NS_IMETHODIMP nsImageLoader::OnStartContainer(imgIRequest *aRequest,
                                               imgIContainer *aImage)
 {
   NS_ABORT_IF_FALSE(aImage, "Who's calling us then?");
 
   /* Get requested animation policy from the pres context:
    *   normal = 0
    *   one frame = 1
@@ -264,8 +279,40 @@ nsImageLoader::DoRedraw(const nsRect* aD
   }
 
 #endif
 
   if (mFrame->GetStyleVisibility()->IsVisible()) {
     mFrame->Invalidate(bounds);
   }
 }
+
+NS_IMETHODIMP
+nsImageLoader::OnStartDecode(imgIRequest *aRequest)
+{
+  // Register our image request with the refresh driver.
+  nsPresContext* presContext = mFrame->PresContext();
+  if (!presContext) {
+    return NS_OK;
+  }
+
+  if (mRequest == aRequest) {
+    nsLayoutUtils::RegisterImageRequest(presContext, mRequest,
+                                        &mRequestRegistered);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsImageLoader::OnStopDecode(imgIRequest *aRequest, nsresult status,
+                            const PRUnichar *statusArg)
+{
+  if (mRequest == aRequest) {
+    // Deregister the imgIRequest with the refresh driver if the
+    // image is not animated.
+    nsLayoutUtils::DeregisterImageRequestIfNotAnimated(mFrame->PresContext(),
+                                                       mRequest,
+                                                       &mRequestRegistered);
+  }
+
+  return NS_OK;
+}
--- a/layout/base/nsImageLoader.h
+++ b/layout/base/nsImageLoader.h
@@ -77,16 +77,20 @@ public:
   static already_AddRefed<nsImageLoader>
     Create(nsIFrame *aFrame, imgIRequest *aRequest,
            PRUint32 aActions, nsImageLoader *aNextLoader);
 
   NS_DECL_ISUPPORTS
 
   // imgIDecoderObserver (override nsStubImageDecoderObserver)
   NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
+  NS_IMETHOD OnStartDecode(imgIRequest *aRequest);
+  NS_IMETHOD OnStopDecode(imgIRequest *aRequest,
+                          nsresult status,
+                          const PRUnichar *statusArg);
   NS_IMETHOD OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame);
   NS_IMETHOD OnStopRequest(imgIRequest *aRequest, bool aLastPart);
   // Do not override OnDataAvailable since background images are not
   // displayed incrementally; they are displayed after the entire image
   // has been loaded.
   // Note: Images referenced by the <img> element are displayed
   // incrementally in nsImageFrame.cpp.
 
@@ -104,9 +108,13 @@ private:
   void DoReflow();
   /* if aDamageRect is nsnull, the whole frame is redrawn. */
   void DoRedraw(const nsRect* aDamageRect);
 
   nsIFrame *mFrame;
   nsCOMPtr<imgIRequest> mRequest;
   PRUint32 mActions;
   nsRefPtr<nsImageLoader> mNextLoader;
+
+  // This is a boolean flag indicating whether or not the current image request
+  // has been registered with the refresh driver.
+  bool mRequestRegistered;
 };
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4322,16 +4322,112 @@ void
 nsLayoutUtils::Shutdown()
 {
   if (sContentMap) {
     delete sContentMap;
     sContentMap = NULL;
   }
 }
 
+/* static */
+void
+nsLayoutUtils::RegisterImageRequest(nsPresContext* aPresContext,
+                                    imgIRequest* aRequest,
+                                    bool* aRequestRegistered)
+{
+  if (!aPresContext) {
+    return;
+  }
+
+  if (aRequestRegistered && *aRequestRegistered) {
+    // Our request is already registered with the refresh driver, so
+    // no need to register it again.
+    return;
+  }
+
+  if (aRequest) {
+    nsCOMPtr<imgIContainer> image;
+    aRequest->GetImage(getter_AddRefs(image));
+    if (image) {
+      if (!aPresContext->RefreshDriver()->AddImageRequest(aRequest)) {
+        NS_WARNING("Unable to add image request");
+        return;
+      }
+
+      if (aRequestRegistered) {
+        *aRequestRegistered = true;
+      }
+    }
+  }
+}
+
+/* static */
+void
+nsLayoutUtils::DeregisterImageRequest(nsPresContext* aPresContext,
+                                      imgIRequest* aRequest,
+                                      bool* aRequestRegistered)
+{
+  if (!aPresContext) {
+    return;
+  }
+
+  // Deregister our imgIRequest with the refresh driver to
+  // complete tear-down, but only if it has been registered
+  if (aRequestRegistered && !*aRequestRegistered) {
+    return;
+  }
+
+  if (aRequest) {
+    nsCOMPtr<imgIContainer> image;
+    aRequest->GetImage(getter_AddRefs(image));
+    if (image) {
+      aPresContext->RefreshDriver()->RemoveImageRequest(aRequest);
+
+      if (aRequestRegistered) {
+        *aRequestRegistered = false;
+      }
+    }
+  }
+}
+
+/* static */
+void
+nsLayoutUtils::DeregisterImageRequestIfNotAnimated(nsPresContext* aPresContext,
+                                                   imgIRequest* aRequest,
+                                                   bool* aRequestRegistered)
+{
+  if (!aPresContext) {
+    return;
+  }
+
+  if (aRequestRegistered && !*aRequestRegistered) {
+    // Image request isn't registered with the refresh driver - no need
+    // to try and deregister it.
+    return;
+  }
+
+  // Deregister the imgIRequest with the refresh driver if the
+  // image is not animated
+  nsCOMPtr<imgIContainer> imageContainer;
+  if (aRequest) {
+    aRequest->GetImage(getter_AddRefs(imageContainer));
+    bool animated;
+
+    if (!imageContainer) {
+      return;
+    }
+
+    nsresult rv = imageContainer->GetAnimated(&animated);
+    if (NS_SUCCEEDED(rv) && !animated) {
+      nsLayoutUtils::DeregisterImageRequest(aPresContext, aRequest,
+                                            aRequestRegistered);
+    }
+  }
+}
+
 nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName,
                                      const nsAString& aValue)
   : mContent(aContent),
     mAttrName(aAttrName),
     mValue(aValue)
 {
   NS_ASSERTION(aContent && aAttrName, "Missing stuff, prepare to crash");
 }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1449,16 +1449,73 @@ public:
 
   /**
    * Checks if CSS 3D transforms are currently enabled.
    */
   static bool Are3DTransformsEnabled();
 
   static void Shutdown();
 
+  /**
+   * Register an imgIRequest object with a refresh driver.
+   *
+   * @param aPresContext The nsPresContext whose refresh driver we want to
+   *        register with.
+   * @param aRequest A pointer to the imgIRequest object which the client wants
+   *        to register with the refresh driver.
+   * @param aRequestRegistered A pointer to a boolean value which indicates
+   *        whether the given image request is registered. If
+   *        *aRequestRegistered is true, then this request will not be
+   *        registered again. If the request is registered by this function,
+   *        then *aRequestRegistered will be set to true upon the completion of
+   *        this function.
+   *
+   */
+  static void RegisterImageRequest(nsPresContext* aPresContext,
+                                   imgIRequest* aRequest,
+                                   bool* aRequestRegistered);
+  /**
+   * Deregister an imgIRequest object from a refresh driver.
+   *
+   * @param aPresContext The nsPresContext whose refresh driver we want to
+   *        deregister from.
+   * @param aRequest A pointer to the imgIRequest object with which the client
+   *        previously registered and now wants to deregister from the refresh
+   *        driver.
+   * @param aRequestRegistered A pointer to a boolean value which indicates
+   *        whether the given image request is registered. If
+   *        *aRequestRegistered is false, then this request will not be
+   *        deregistered. If the request is deregistered by this function,
+   *        then *aRequestRegistered will be set to false upon the completion of
+   *        this function.
+   */
+  static void DeregisterImageRequest(nsPresContext* aPresContext,
+                                     imgIRequest* aRequest,
+                                     bool* aRequestRegistered);
+  /**
+   * Deregister an imgIRequest object from a refresh driver, if the
+   * imgIRequest object represents a static (i.e. not animated) image.
+   *
+   * @param aPresContext The nsPresContext whose refresh driver we want to
+   *        deregister from.
+   * @param aRequest A pointer to the imgIRequest object with which the client
+   *        previously registered and now wants to deregister from the refresh
+   *        driver.
+   * @param aRequestRegistered A pointer to a boolean value which indicates
+   *        whether the given image request is registered. If
+   *        *aRequestRegistered is false, then this request will not be
+   *        deregistered. If the request is deregistered by this function,
+   *        then *aRequestRegistered will be set to false upon the completion of
+   *        this function.
+   */
+
+  static void DeregisterImageRequestIfNotAnimated(nsPresContext* aPresContext,
+                                                  imgIRequest* aRequest,
+                                                  bool* aRequestRegistered);
+
 #ifdef DEBUG
   /**
    * Assert that there are no duplicate continuations of the same frame
    * within aFrameList.  Optimize the tests by assuming that all frames
    * in aFrameList have parent aContainer.
    */
   static void
   AssertNoDuplicateContinuations(nsIFrame* aContainer,
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -109,16 +109,17 @@ nsRefreshDriver::GetRefreshTimerType() c
 nsRefreshDriver::nsRefreshDriver(nsPresContext *aPresContext)
   : mPresContext(aPresContext),
     mFrozen(false),
     mThrottled(false),
     mTestControllingRefreshes(false),
     mTimerIsPrecise(false),
     mLastTimerInterval(0)
 {
+  mRequests.Init();
 }
 
 nsRefreshDriver::~nsRefreshDriver()
 {
   NS_ABORT_IF_FALSE(ObserverCount() == 0,
                     "observers should have unregistered");
   NS_ABORT_IF_FALSE(!mTimer, "timer should be gone");
 }
@@ -180,16 +181,39 @@ nsRefreshDriver::AddRefreshObserver(nsAR
 bool
 nsRefreshDriver::RemoveRefreshObserver(nsARefreshObserver *aObserver,
                                        mozFlushType aFlushType)
 {
   ObserverArray& array = ArrayFor(aFlushType);
   return array.RemoveElement(aObserver);
 }
 
+bool
+nsRefreshDriver::AddImageRequest(imgIRequest* aRequest)
+{
+  if (!mRequests.PutEntry(aRequest)) {
+    return false;
+  }
+
+  EnsureTimerStarted(false);
+
+  return true;
+}
+
+void
+nsRefreshDriver::RemoveImageRequest(imgIRequest* aRequest)
+{
+  mRequests.RemoveEntry(aRequest);
+}
+
+void nsRefreshDriver::ClearAllImageRequests()
+{
+  mRequests.Clear();
+}
+
 void
 nsRefreshDriver::EnsureTimerStarted(bool aAdjustingTimer)
 {
   if (mTimer || mFrozen || !mPresContext) {
     // It's already been started, or we don't want to start it now or
     // we've been disconnected.
     return;
   }
@@ -233,27 +257,34 @@ nsRefreshDriver::StopTimer()
 
 PRUint32
 nsRefreshDriver::ObserverCount() const
 {
   PRUint32 sum = 0;
   for (PRUint32 i = 0; i < ArrayLength(mObservers); ++i) {
     sum += mObservers[i].Length();
   }
+
   // Even while throttled, we need to process layout and style changes.  Style
   // changes can trigger transitions which fire events when they complete, and
   // layout changes can affect media queries on child documents, triggering
   // style changes, etc.
   sum += mStyleFlushObservers.Length();
   sum += mLayoutFlushObservers.Length();
   sum += mBeforePaintTargets.Length();
   sum += mAnimationFrameListenerDocs.Length();
   return sum;
 }
 
+PRUint32
+nsRefreshDriver::ImageRequestCount() const
+{
+  return mRequests.Count();
+}
+
 void
 nsRefreshDriver::UpdateMostRecentRefresh()
 {
   if (mTestControlling