Merge backout
authorJustin Lebar <justin.lebar@gmail.com>
Wed, 02 Nov 2011 20:11:25 -0400
changeset 79600 b8dd6f6f420756ee87938701b682bd6b85739923
parent 79599 fe4461c7654101502a633734a1a30f698f77cb7b (current diff)
parent 79598 9b291cc0cd86047392136dcd02ed6fe471986e02 (diff)
child 79606 e81e47f8e5bb0c427739284b969239da48312b64
child 79665 819d58c7adfea851f8c52b50f4592141b34b010b
push id21415
push userjlebar@mozilla.com
push dateThu, 03 Nov 2011 00:11:55 +0000
treeherdermozilla-central@b8dd6f6f4207 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone10.0a1
first release with
nightly linux32
b8dd6f6f4207 / 10.0a1 / 20111103031131 / files
nightly linux64
b8dd6f6f4207 / 10.0a1 / 20111103031131 / files
nightly mac
b8dd6f6f4207 / 10.0a1 / 20111103031131 / files
nightly win32
b8dd6f6f4207 / 10.0a1 / 20111103031131 / files
nightly win64
b8dd6f6f4207 / 10.0a1 / 20111103031131 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge backout
content/base/src/nsDocument.cpp
layout/xul/base/src/nsImageBoxFrame.cpp
toolkit/content/tests/browser/common/mockFilePicker.js
--- a/browser/base/content/aboutHome.css
+++ b/browser/base/content/aboutHome.css
@@ -364,13 +364,21 @@ body[dir=rtl] #restorePreviousSession::b
   position: absolute;
   color: rgb(150,150,150);
   font-size: .8em;
   width: 100%;
   text-align: center;
   bottom: 2%;
 }
 
+#syncLinksContainer {
+  padding-top: 1em;
+}
+
+.sync-link {
+  padding: 1em;
+}
+
 @media all and (max-height: 370px) {
   #bottomSection {
     visibility: hidden;
   }
 }
--- a/browser/base/content/aboutHome.xhtml
+++ b/browser/base/content/aboutHome.xhtml
@@ -97,11 +97,15 @@
         <button id="restorePreviousSession">&historyRestoreLastSession.label;</button>
       </div>
     </div>
 
     <div id="bottomSection">
       <div id="aboutMozilla">
         <a href="http://www.mozilla.com/about/">&abouthome.aboutMozilla;</a>
       </div>
+      <div id="syncLinksContainer">
+        <a href="javascript:void(0);" class="sync-link" id="setupSyncLink">&abouthome.syncSetup.label;</a>
+        <a href="javascript:void(0);" class="sync-link" id="pairDeviceLink">&abouthome.pairDevice.label;</a>
+      </div>
     </div>
   </body>
 </html>
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -206,16 +206,34 @@ let gSyncUI = {
   },
 
   onLoginFinish: function SUI_onLoginFinish() {
     // Clear out any login failure notifications
     let title = this._stringBundle.GetStringFromName("error.login.title");
     this.clearError(title);
   },
 
+  // Set visibility of "Setup Sync" link
+  showSetupSyncAboutHome: function SUI_showSetupSyncAboutHome(toShow) {
+    let browsers = gBrowser.browsers;
+    for (let i = 0; i < browsers.length; i++) {
+      let b = browsers[i];
+      if ("about:home" == b.currentURI.spec) {
+        b.contentDocument.getElementById("setupSyncLink").hidden = !toShow;
+      }
+    }
+  },
+
+  onSetupComplete: function SUI_onSetupComplete() {
+    // Remove "setup sync" link in about:home if it is open. 
+    this.showSetupSyncAboutHome(false);
+
+    onLoginFinish();
+  },
+
   onLoginError: function SUI_onLoginError() {
     // if login fails, any other notifications are essentially moot
     Weave.Notifications.removeAll();
 
     // if we haven't set up the client, don't show errors
     if (this._needsSetup()) {
       this.updateUI();
       return;
@@ -250,16 +268,18 @@ let gSyncUI = {
   },
 
   onLogout: function SUI_onLogout() {
     this.updateUI();
   },
 
   onStartOver: function SUI_onStartOver() {
     this.clearError();
+    // Make "setup sync" link visible in about:home if it is open. 
+    this.showSetupSyncAboutHome(true);
   },
 
   onQuotaNotice: function onQuotaNotice(subject, data) {
     let title = this._stringBundle.GetStringFromName("warning.sync.quota.label");
     let description = this._stringBundle.GetStringFromName("warning.sync.quota.description");
     let buttons = [];
     buttons.push(new Weave.NotificationButton(
       this._stringBundle.GetStringFromName("error.sync.viewQuotaButton.label"),
@@ -286,26 +306,50 @@ let gSyncUI = {
     if (this._needsSetup())
       this.openSetup();
     else
       this.doSync();
   },
 
   //XXXzpao should be part of syncCommon.js - which we might want to make a module...
   //        To be fixed in a followup (bug 583366)
-  openSetup: function SUI_openSetup() {
+
+  /**
+   * Invoke the Sync setup wizard.
+   *
+   * @param wizardType
+   *        Indicates type of wizard to launch:
+   *          null    -- regular set up wizard
+   *          "pair"  -- pair a device first
+   *          "reset" -- reset sync
+   */
+
+  openSetup: function SUI_openSetup(wizardType) {
     let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
     if (win)
       win.focus();
     else {
       window.openDialog("chrome://browser/content/syncSetup.xul",
-                        "weaveSetup", "centerscreen,chrome,resizable=no");
+                        "weaveSetup", "centerscreen,chrome,resizable=no",
+                        wizardType);
     }
   },
 
+  openAddDevice: function () {
+    if (!Weave.Utils.ensureMPUnlocked())
+      return;
+
+    let win = Services.wm.getMostRecentWindow("Sync:AddDevice");
+    if (win)
+      win.focus();
+    else
+      window.openDialog("chrome://browser/content/syncAddDevice.xul",
+                        "syncAddDevice", "centerscreen,chrome,resizable=no");
+  },
+
   openQuotaDialog: function SUI_openQuotaDialog() {
     let win = Services.wm.getMostRecentWindow("Sync:ViewQuota");
     if (win)
       win.focus();
     else
       Services.ww.activeWindow.openDialog(
         "chrome://browser/content/syncQuota.xul", "",
         "centerscreen,chrome,dialog,modal");
@@ -457,17 +501,17 @@ let gSyncUI = {
         break;
       case "weave:service:sync:delayed":
         this.onSyncDelay();
         break;
       case "weave:service:quota:remaining":
         this.onQuotaNotice();
         break;
       case "weave:service:setup-complete":
-        this.onLoginFinish();
+        this.onSetupComplete();
         break;
       case "weave:service:login:start":
         this.onActivityStart();
         break;
       case "weave:service:login:finish":
         this.onLoginFinish();
         break;
       case "weave:ui:login:error":
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2670,25 +2670,31 @@ function PageProxyClickHandler(aEvent)
  *  to the DOM for unprivileged pages.
  */
 function BrowserOnAboutPageLoad(document) {
   if (/^about:home$/i.test(document.documentURI)) {
     let ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
              getService(Components.interfaces.nsISessionStore);
     if (!ss.canRestoreLastSession)
       document.getElementById("sessionRestoreContainer").hidden = true;
+    // Sync-related links
+    if (Services.prefs.prefHasUserValue("services.sync.username")) {
+      document.getElementById("setupSyncLink").hidden = true;
+    }
   }
 }
 
 /**
  * Handle command events bubbling up from error page content
  */
 function BrowserOnClick(event) {
     // Don't trust synthetic events
-    if (!event.isTrusted || event.target.localName != "button")
+    if (!event.isTrusted ||
+        (event.target.localName != "button" &&
+         event.target.className != "sync-link"))
       return;
 
     var ot = event.originalTarget;
     var errorDoc = ot.ownerDocument;
 
     // If the event came from an ssl error page, it is probably either the "Add
     // Exception…" or "Get me out of here!" button
     if (/^about:certerror/.test(errorDoc.documentURI)) {
@@ -2808,16 +2814,26 @@ function BrowserOnClick(event) {
     else if (/^about:home$/i.test(errorDoc.documentURI)) {
       if (ot == errorDoc.getElementById("restorePreviousSession")) {
         let ss = Cc["@mozilla.org/browser/sessionstore;1"].
                  getService(Ci.nsISessionStore);
         if (ss.canRestoreLastSession)
           ss.restoreLastSession();
         errorDoc.getElementById("sessionRestoreContainer").hidden = true;
       }
+      else if (ot == errorDoc.getElementById("pairDeviceLink")) {
+        if (Services.prefs.prefHasUserValue("services.sync.username")) {
+          gSyncUI.openAddDevice();
+        } else {
+          gSyncUI.openSetup("pair");
+        }
+      }
+      else if (ot == errorDoc.getElementById("setupSyncLink")) {
+        gSyncUI.openSetup(null);
+      }
     }
 }
 
 /**
  * Re-direct the browser to a known-safe page.  This function is
  * used when, for example, the user browses to a known malware page
  * and is presented with about:blocked.  The "Get me out of here!"
  * button should take the user to the default start page so that even
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -982,26 +982,36 @@
              nowindowdrag="true"
              hidden="true">
       <vbox flex="1">
         <resizer id="inspector-top-resizer" flex="1" 
                  class="inspector-resizer"
                  dir="top" disabled="true"
                  element="inspector-tree-box"/>
         <hbox>
+#ifdef XP_MACOSX
+          <toolbarbutton id="highlighter-closebutton"
+                         oncommand="InspectorUI.closeInspectorUI(false);"
+                         tooltiptext="&inspectCloseButton.tooltiptext;"/>
+#endif
           <toolbarbutton id="inspector-inspect-toolbutton"
                          label="&inspectButton.label;"
                          accesskey="&inspectButton.accesskey;"
                          command="Inspector:Inspect"/>
           <arrowscrollbox id="inspector-breadcrumbs"
                           flex="1" orient="horizontal"
                           clicktoscroll="true"/>
           <hbox id="inspector-tools">
             <!-- registered tools go here -->
           </hbox>
+#ifndef XP_MACOSX
+          <toolbarbutton id="highlighter-closebutton"
+                         oncommand="InspectorUI.closeInspectorUI(false);"
+                         tooltiptext="&inspectCloseButton.tooltiptext;"/>
+#endif
           <resizer id="inspector-end-resizer"
                    class="inspector-resizer"
                    dir="top" disabled="true"
                    element="inspector-tree-box"/>
         </hbox>
       </vbox>
     </toolbar>
     <toolbar id="addon-bar"
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -25,24 +25,27 @@
 #highlighter-veil-rightbox {
   -moz-box-flex: 1;
 }
 
 #highlighter-veil-middlebox:-moz-locale-dir(rtl) {
   -moz-box-direction: reverse;
 }
 
-#highlighter-close-button {
-  position: absolute;
-  pointer-events: auto;
-  z-index: 1;
+.inspector-breadcrumbs-button {
+  direction: ltr;
 }
 
-.inspector-breadcrumbs-button {
-  direction: ltr;
+.inspector-resizer {
+  display: none;
+}
+
+#inspector-toolbar[treepanel-open] > vbox > #inspector-top-resizer,
+#inspector-toolbar[treepanel-open] > vbox > hbox > #inspector-end-resizer {
+  display: -moz-box;
 }
 
 /*
  * Node Infobar
  */
 
 #highlighter-nodeinfobar-container {
   position: absolute;
--- a/browser/base/content/syncProgress.js
+++ b/browser/base/content/syncProgress.js
@@ -39,34 +39,67 @@
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://services-sync/main.js");
 
 let gProgressBar;
 let gCounter = 0;
 
 function onLoad(event) {
-  Services.obs.addObserver(increaseProgressBar, "weave:engine:sync:finish", false);
-  Services.obs.addObserver(increaseProgressBar, "weave:engine:sync:error", false);
+  Services.obs.addObserver(onEngineSync, "weave:engine:sync:finish", false);
+  Services.obs.addObserver(onEngineSync, "weave:engine:sync:error", false);
+  Services.obs.addObserver(onServiceSync, "weave:service:sync:finish", false);
+  Services.obs.addObserver(onServiceSync, "weave:service:sync:error", false);
+
   gProgressBar = document.getElementById('uploadProgressBar');
 
   if (Services.prefs.getPrefType("services.sync.firstSync") != Ci.nsIPrefBranch.PREF_INVALID) {
-    gProgressBar.max = Weave.Engines.getEnabled().length;
     gProgressBar.style.display = "inline";
   }
   else {
     gProgressBar.style.display = "none";
   }
 }
 
 function onUnload(event) {
-  Services.obs.removeObserver(increaseProgressBar, "weave:engine:sync:finish");
-  Services.obs.removeObserver(increaseProgressBar, "weave:engine:sync:error");
+  cleanUpObservers();
+}
+
+function cleanUpObservers() {
+  try {
+    Services.obs.removeObserver(onEngineSync, "weave:engine:sync:finish", false);
+    Services.obs.removeObserver(onEngineSync, "weave:engine:sync:error", false);
+    Services.obs.removeObserver(onServiceSync, "weave:service:sync:finish", false);
+    Services.obs.removeObserver(onServiceSync, "weave:service:sync:error", false);
+  }
+  catch (e) {
+    // may be double called by unload & exit. Ignore.
+  }
 }
 
-function increaseProgressBar(){
+function onEngineSync(subject, topic, data) {
+  // The Clients engine syncs first. At this point we don't necessarily know
+  // yet how many engines will be enabled, so we'll ignore the Clients engine
+  // and evaluate how many engines are enabled when the first "real" engine
+  // syncs.
+  if (data == "clients") {
+    return;
+  }
+
+  if (!gCounter &&
+      Services.prefs.getPrefType("services.sync.firstSync") != Ci.nsIPrefBranch.PREF_INVALID) {
+    gProgressBar.max = Weave.Engines.getEnabled().length;
+  }
+
   gCounter += 1;
   gProgressBar.setAttribute("value", gCounter);
 }
 
+function onServiceSync(subject, topic, data) {
+  // To address the case where 0 engines are synced, we will fill the
+  // progress bar so the user knows that the sync has finished.
+  gProgressBar.setAttribute("value", gProgressBar.max);
+  cleanUpObservers();
+}
+
 function closeTab() {
   window.close();
 }
--- a/browser/base/content/test/browser_aboutHome.js
+++ b/browser/base/content/test/browser_aboutHome.js
@@ -5,16 +5,19 @@
 registerCleanupFunction(function() {
   // Ensure we don't pollute prefs for next tests.
   try {
     Services.prefs.clearUserPref("network.cookies.cookieBehavior");
   } catch (ex) {}
   try {
     Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
   } catch (ex) {}
+  try {
+    Services.prefs.clearUserPref("services.sync.username");
+  } catch (ex) {}
 });
 
 let gTests = [
 
 {
   desc: "Check that rejecting cookies does not prevent page from working",
   setup: function ()
   {
@@ -109,16 +112,126 @@ let gTests = [
     ok(snippetsElt, "Found snippets element");
     is(snippetsElt.getElementsByTagName("span").length, 1,
        "A default snippet is visible.");
 
     executeSoon(runNextTest);
   }
 },
 
+{
+  desc: "Check sync links visibility before and after Sync setup",
+  setup: function ()
+  {
+    try {
+      Services.prefs.clearUserPref("services.sync.username");
+    } catch (ex) {}
+    Services.obs.notifyObservers(null, "weave:service:ready", null);
+  },
+  run: function ()
+  {
+    let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
+    let pairLink = doc.getElementById("pairDeviceLink");
+    let setupLink = doc.getElementById("setupSyncLink");
+
+    ok(pairLink, "Found 'Pair Device' link");
+    ok(setupLink, "Found 'Set Up Sync' link");
+    ok(!pairLink.hidden, "'Pair' link is visible before setup");
+    ok(!setupLink.hidden, "'Set Up' link is visible before setup");
+
+    Services.obs.notifyObservers(null, "weave:service:setup-complete", null);
+
+    executeSoon(function () {
+      setupLink = doc.getElementById("setupSyncLink");
+      ok(setupLink.hidden, "'Set Up' link is hidden after setup");
+      ok(!pairLink.hidden, "'Pair' link is visible after setup");
+
+      executeSoon(runNextTest);
+    });
+  }
+},
+
+{
+  desc: "Check sync links visibility before and after Sync unlink",
+  setup: function ()
+  {
+    Services.prefs.setCharPref("services.sync.username", "someuser@domain.com");
+    Services.obs.notifyObservers(null, "weave:service:ready", null);
+  },
+  run: function ()
+  {
+    let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
+    let pairLink = doc.getElementById("pairDeviceLink");
+    let setupLink = doc.getElementById("setupSyncLink");
+
+    ok(!pairLink.hidden, "'Pair' link is visible before unlink");
+    ok(setupLink.hidden, "'Set Up' link is hidden before unlink");
+
+    Services.obs.notifyObservers(null, "weave:service:start-over", null);
+
+    executeSoon(function () {
+      setupLink = doc.getElementById("setupSyncLink");
+      ok(!setupLink.hidden, "'Set Up' link is visible after unlink");
+      ok(!pairLink.hidden, "'Pair' link is visible after unlink");
+      executeSoon(runNextTest);
+    });
+  }
+},
+
+{
+  desc: "Check Pair Device link opens correct dialog with Sync account ",
+  setup: function ()
+  {
+    Services.prefs.setCharPref("services.sync.username", "someuser@domain.com");
+    Services.obs.notifyObservers(null, "weave:service:ready", null);
+  },
+  run: function ()
+  {
+    expectDialogWindow("Sync:AddDevice");
+    let browser = gBrowser.selectedTab.linkedBrowser;
+    let button = browser.contentDocument.getElementById("pairDeviceLink");
+    EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow);
+  }
+},
+
+{
+  desc: "Check Pair Device link opens correct dialog without Sync account",
+  setup: function ()
+  {
+    try {
+      Services.prefs.clearUserPref("services.sync.username");
+    } catch (ex) {}
+    Services.obs.notifyObservers(null, "weave:service:ready", null);
+  },
+  run: function ()
+  {
+    expectDialogWindow("Weave:AccountSetup");
+    let browser = gBrowser.selectedTab.linkedBrowser;
+    let button = browser.contentDocument.getElementById("pairDeviceLink");
+    EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow);
+  }
+},
+
+{
+  desc: "Check Sync Setup link opens correct dialog (without Sync account)",
+  setup: function ()
+  {
+    try {
+      Services.prefs.clearUserPref("services.sync.username");
+    } catch (ex) {}
+    Services.obs.notifyObservers(null, "weave:service:ready", null);
+  },
+  run: function ()
+  {
+    expectDialogWindow("Weave:AccountSetup");
+    let browser = gBrowser.selectedTab.linkedBrowser;
+    let button = browser.contentDocument.getElementById("setupSyncLink");
+    EventUtils.sendMouseEvent({type: "click"}, button, browser.contentWindow);
+  }
+},
 ];
 
 function test()
 {
   waitForExplicitFinish();
 
   // browser-chrome test harness inits browser specifying an hardcoded page
   // and this causes nsIBrowserHandler.defaultArgs to not be evaluated since
@@ -154,16 +267,32 @@ function runNextTest()
       executeSoon(test.run);
     }, true);
   }
   else {
     finish();
   }
 }
 
+function expectDialogWindow(expectedDialog) {
+  Services.ww.registerNotification(function onWindow(subject, topic) {
+    let win = subject.QueryInterface(Components.interfaces.nsIDOMWindow);
+    win.addEventListener("load", function onLoad() {
+      win.removeEventListener("load", onLoad, false);
+      let wintype = win.document.documentElement.getAttribute("windowtype");
+      if (topic == "domwindowopened" && wintype == expectedDialog) {
+        Services.ww.unregisterNotification(onWindow);
+        // Clean up dialog.
+        win.close();
+        executeSoon(runNextTest);
+      }
+    }, false);
+  });
+}
+
 function getStorage()
 {
   let aboutHomeURI = Services.io.newURI("moz-safe-about:home", null, null);
   let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
                   getService(Components.interfaces.nsIScriptSecurityManager).
                   getCodebasePrincipal(Services.io.newURI("about:home", null, null));
   let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
             getService(Components.interfaces.nsIDOMStorageManager);
--- 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/devtools/highlighter/TreePanel.jsm
+++ b/browser/devtools/highlighter/TreePanel.jsm
@@ -226,22 +226,17 @@ TreePanel.prototype = {
       this.IUI.browser.ownerDocument.getElementById("browser-bottombox");
     treeBox = this.document.createElement("vbox");
     treeBox.id = "inspector-tree-box";
     treeBox.state = "open"; // for the registerTools API.
     treeBox.minHeight = 10;
     treeBox.flex = 1;
     toolbarParent.insertBefore(treeBox, toolbar);
 
-    let resizerTop =
-      this.IUI.browser.ownerDocument.getElementById("inspector-top-resizer");
-    let resizerEnd =
-      this.IUI.browser.ownerDocument.getElementById("inspector-end-resizer");
-    resizerTop.removeAttribute("disabled");
-    resizerEnd.removeAttribute("disabled");
+    this.IUI.toolbar.setAttribute("treepanel-open", "true");
 
     treeBox.appendChild(this.treeIFrame);
 
     let boundLoadedInitializeTreePanel = function loadedInitializeTreePanel()
     {
       this.treeIFrame.removeEventListener("load",
         boundLoadedInitializeTreePanel, true);
       this.initializeIFrame();
@@ -259,22 +254,17 @@ TreePanel.prototype = {
   },
 
   /**
    * Close the TreePanel.
    */
   close: function TP_close()
   {
     if (this.openInDock) {
-      let resizerTop = 
-        this.IUI.browser.ownerDocument.getElementById("inspector-top-resizer");
-      let resizerEnd = 
-        this.IUI.browser.ownerDocument.getElementById("inspector-end-resizer");
-      resizerTop.setAttribute("disabled", "true");
-      resizerEnd.setAttribute("disabled", "true");
+      this.IUI.toolbar.removeAttribute("treepanel-open");
 
       let treeBox = this.container;
       let treeBoxParent = treeBox.parentNode;
       treeBoxParent.removeChild(treeBox);
     } else {
       this.container.hidePopup();
     }
 
--- a/browser/devtools/highlighter/inspector.jsm
+++ b/browser/devtools/highlighter/inspector.jsm
@@ -119,30 +119,30 @@ Highlighter.prototype = {
     this._highlighting = false;
 
     this.highlighterContainer = this.chromeDoc.createElement("stack");
     this.highlighterContainer.id = "highlighter-container";
 
     this.veilContainer = this.chromeDoc.createElement("vbox");
     this.veilContainer.id = "highlighter-veil-container";
 
+    // The controlsBox will host the different interactive
+    // elements of the highlighter (buttons, toolbars, ...).
     let controlsBox = this.chromeDoc.createElement("box");
     controlsBox.id = "highlighter-controls";
     this.highlighterContainer.appendChild(this.veilContainer);
     this.highlighterContainer.appendChild(controlsBox);
 
     stack.appendChild(this.highlighterContainer);
 
     // The veil will make the whole page darker except
     // for the region of the selected box.
     this.buildVeil(this.veilContainer);
 
-    // The controlsBox will host the different interactive
-    // elements of the highlighter (buttons, toolbars, ...).
-    this.buildControls(controlsBox);
+    this.buildInfobar(controlsBox);
 
     this.browser.addEventListener("resize", this, true);
     this.browser.addEventListener("scroll", this, true);
 
     this.handleResize();
   },
 
   /**
@@ -196,30 +196,16 @@ Highlighter.prototype = {
     this.veilMiddleBox.appendChild(veilRightBox);
 
     aParent.appendChild(this.veilTopBox);
     aParent.appendChild(this.veilMiddleBox);
     aParent.appendChild(veilBottomBox);
   },
 
   /**
-   * Build the controls:
-   *
-   * <box id="highlighter-close-button"/>
-   *
-   * @param nsIDOMElement aParent
-   *        The container of the controls elements.
-   */
-  buildControls: function Highlighter_buildControls(aParent)
-  {
-    this.buildCloseButton(aParent);
-    this.buildInfobar(aParent);
-  },
-
-  /**
    * Build the node Infobar.
    *
    * <box id="highlighter-nodeinfobar-container">
    *   <box id="Highlighter-nodeinfobar-arrow-top"/>
    *   <vbox id="highlighter-nodeinfobar">
    *     <label id="highlighter-nodeinfobar-tagname"/>
    *     <label id="highlighter-nodeinfobar-id"/>
    *     <vbox id="highlighter-nodeinfobar-classes"/>
@@ -275,48 +261,23 @@ Highlighter.prototype = {
       idLabel: idLabel,
       classesBox: classesBox,
       container: container,
       barHeight: barHeight,
     };
   },
 
   /**
-   * Build the close button.
-   *
-   * @param nsIDOMElement aParent
-   *        The container of the close-button.
-   */
-  buildCloseButton: function Highlighter_buildCloseButton(aParent)
-  {
-    let closeButton = this.chromeDoc.createElement("box");
-    closeButton.id = "highlighter-close-button";
-    closeButton.appendChild(this.chromeDoc.createElement("image"));
-
-    let boundCloseEventHandler = this.IUI.closeInspectorUI.bind(this.IUI, false);
-
-    closeButton.addEventListener("click", boundCloseEventHandler, false);
-
-    aParent.appendChild(closeButton);
-
-    this.boundCloseEventHandler = boundCloseEventHandler;
-    this.closeButton = closeButton;
-  },
-
-  /**
    * Destroy the nodes.
    */
   destroy: function Highlighter_destroy()
   {
     this.browser.removeEventListener("scroll", this, true);
     this.browser.removeEventListener("resize", this, true);
-    this.closeButton.removeEventListener("click", this.boundCloseEventHandler, false);
     this.boundCloseEventHandler = null;
-    this.closeButton.parentNode.removeChild(this.closeButton);
-    this.closeButton = null;
     this._contentRect = null;
     this._highlightRect = null;
     this._highlighting = false;
     this.veilTopBox = null;
     this.veilLeftBox = null;
     this.veilMiddleBox = null;
     this.veilTransparentBox = null;
     this.veilContainer = null;
--- a/browser/devtools/highlighter/test/browser_inspector_bug_690361.js
+++ b/browser/devtools/highlighter/test/browser_inspector_bug_690361.js
@@ -77,17 +77,17 @@ function runInspectorTests()
   ok(!InspectorUI.toolbar.hidden, "toolbar is visible");
   ok(InspectorUI.inspecting, "Inspector is inspecting");
   ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
   ok(InspectorUI.highlighter, "Highlighter is up");
 
   salutation = doc.getElementById("salutation");
   InspectorUI.inspectNode(salutation);
 
-  let button = document.getElementById("highlighter-close-button");
+  let button = document.getElementById("highlighter-closebutton");
   button.click();
 }
 
 function closeInspectorTests()
 {
   Services.obs.removeObserver(closeInspectorTests,
     InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
   Services.obs.addObserver(inspectorOpenedTrap,
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -1,10 +1,11 @@
 browser.jar:
 *   content/browser/inspector.html                (highlighter/inspector.html)
     content/browser/NetworkPanel.xhtml            (webconsole/NetworkPanel.xhtml)
 *   content/browser/scratchpad.xul                (scratchpad/scratchpad.xul)
 *   content/browser/scratchpad.js                 (scratchpad/scratchpad.js)
     content/browser/csshtmltree.xhtml             (styleinspector/csshtmltree.xhtml)
+    content/browser/devtools/cssruleview.xhtml    (styleinspector/cssruleview.xhtml)
+    content/browser/devtools/styleinspector.css   (styleinspector/styleinspector.css)
     content/browser/orion.js                      (sourceeditor/orion/orion.js)
     content/browser/orion.css                     (sourceeditor/orion/orion.css)
     content/browser/orion-mozilla.css             (sourceeditor/orion/mozilla.css)
-
--- a/browser/devtools/sourceeditor/orion/mozilla.css
+++ b/browser/devtools/sourceeditor/orion/mozilla.css
@@ -1,11 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+.viewContainer {
+  font-size: inherit; /* inherit browser's default monospace font size */
+}
 
 .rulerLines {
   background: -moz-Dialog;
   color: -moz-DialogText;
   min-width: 1.4em;
   padding-left: 4px;
   padding-right: 4px;
   text-align: end;
--- a/browser/devtools/styleinspector/CssLogic.jsm
+++ b/browser/devtools/styleinspector/CssLogic.jsm
@@ -816,16 +816,46 @@ CssLogic.sheetMediaAllowed = function Cs
   } else {
     result = true;
   }
 
   return result;
 };
 
 /**
+ * Return a shortened version of a style sheet's source.
+ *
+ * @param {CSSStyleSheet} aSheet the DOM object for the style sheet.
+ */
+CssLogic.shortSource = function CssLogic_shortSource(aSheet)
+{
+    // Use a string like "inline" if there is no source href
+    if (!aSheet || !aSheet.href) {
+      return CssLogic.l10n("rule.sourceInline");
+    }
+
+    // We try, in turn, the filename, filePath, query string, whole thing
+    let url = Services.io.newURI(aSheet.href, null, null);
+    url = url.QueryInterface(Ci.nsIURL);
+    if (url.fileName) {
+      return url.fileName;
+    }
+
+    if (url.filePath) {
+      return url.filePath;
+    }
+
+    if (url.query) {
+      return url.query;
+    }
+
+    return this.domSheet.href;
+}
+
+/**
  * A safe way to access cached bits of information about a stylesheet.
  *
  * @constructor
  * @param {CssLogic} aCssLogic pointer to the CssLogic instance working with
  * this CssSheet object.
  * @param {CSSStyleSheet} aDomSheet reference to a DOM CSSStyleSheet object.
  * @param {boolean} aSystemSheet tells if the stylesheet is system-provided.
  * @param {number} aIndex tells the index/position of the stylesheet within the
@@ -880,41 +910,17 @@ CssSheet.prototype = {
    * @return {string} the shorthand source of the stylesheet.
    */
   get shortSource()
   {
     if (this._shortSource) {
       return this._shortSource;
     }
 
-    // Use a string like "inline" if there is no source href
-    if (!this.domSheet.href) {
-      this._shortSource = CssLogic.l10n("rule.sourceInline");
-      return this._shortSource;
-    }
-
-    // We try, in turn, the filename, filePath, query string, whole thing
-    let url = Services.io.newURI(this.domSheet.href, null, null);
-    url = url.QueryInterface(Ci.nsIURL);
-    if (url.fileName) {
-      this._shortSource = url.fileName;
-      return this._shortSource;
-    }
-
-    if (url.filePath) {
-      this._shortSource = url.filePath;
-      return this._shortSource;
-    }
-
-    if (url.query) {
-      this._shortSource = url.query;
-      return this._shortSource;
-    }
-
-    this._shortSource = this.domSheet.href;
+    this._shortSource = CssLogic.shortSource(this.domSheet);
     return this._shortSource;
   },
 
   /**
    * Tells if the sheet is allowed or not by the current CssLogic.sourceFilter.
    *
    * @return {boolean} true if the stylesheet is allowed by the sourceFilter, or
    * false otherwise.
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/CssRuleView.jsm
@@ -0,0 +1,1248 @@
+/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla Inspector Module.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dave Camp (dcamp@mozilla.com) (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+"use strict"
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+const FOCUS_FORWARD = Ci.nsIFocusManager.MOVEFOCUS_FORWARD;
+const FOCUS_BACKWARD = Ci.nsIFocusManager.MOVEFOCUS_BACKWARD;
+
+/**
+ * These regular expressions are adapted from firebug's css.js, and are
+ * used to parse CSSStyleDeclaration's cssText attribute.
+ */
+
+// Used to split on css line separators
+const CSS_LINE_RE = /(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g;
+
+// Used to parse a single property line.
+const CSS_PROP_RE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(?:! (important))?;?$/;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource:///modules/devtools/CssLogic.jsm");
+
+var EXPORTED_SYMBOLS = ["CssRuleView",
+                        "_ElementStyle",
+                        "_editableField"];
+
+/**
+ * Our model looks like this:
+ *
+ * ElementStyle:
+ *   Responsible for keeping track of which properties are overridden.
+ *   Maintains a list of Rule objects that apply to the element.
+ * Rule:
+ *   Manages a single style declaration or rule.
+ *   Responsible for applying changes to the properties in a rule.
+ *   Maintains a list of TextProperty objects.
+ * TextProperty:
+ *   Manages a single property from the cssText attribute of the
+ *     relevant declaration.
+ *   Maintains a list of computed properties that come from this
+ *     property declaration.
+ *   Changes to the TextProperty are sent to its related Rule for
+ *     application.
+ */
+
+/**
+ * ElementStyle maintains a list of Rule objects for a given element.
+ *
+ * @constructor
+ */
+function ElementStyle(aElement)
+{
+  this.element = aElement;
+  let doc = aElement.ownerDocument;
+
+  // To figure out how shorthand properties are interpreted by the
+  // engine, we will set properties on a dummy element and observe
+  // how their .style attribute reflects them as computed values.
+  this.dummyElement = doc.createElementNS(this.element.namespaceURI,
+                                          this.element.tagName);
+  this._populate();
+}
+// We're exporting _ElementStyle for unit tests.
+var _ElementStyle = ElementStyle;
+
+ElementStyle.prototype = {
+
+  // The element we're looking at.
+  element: null,
+
+  // Empty, unconnected element of the same type as this node, used
+  // to figure out how shorthand properties will be parsed.
+  dummyElement: null,
+
+  domUtils: Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils),
+
+  /**
+   * Refresh the list of rules to be displayed for the active element.
+   * Upon completion, this.rules[] will hold a list of Rule objects.
+   */
+  _populate: function ElementStyle_populate()
+  {
+    this.rules = [];
+
+    // Include the element's style first.
+    this.rules.push(new Rule(this, {
+      style: this.element.style,
+      selectorText: CssLogic.l10n("rule.sourceElement")
+    }));
+
+    // Get the styles that apply to the element.
+    try {
+      var domRules = this.domUtils.getCSSStyleRules(this.element);
+    } catch (ex) {
+      Services.console.logStringMessage("ElementStyle_populate error: " + ex);
+      return;
+    }
+
+    // getCSStyleRules returns ordered from least-specific to
+    // most-specific.
+    for (let i = domRules.Count() - 1; i >= 0; i--) {
+      let domRule = domRules.GetElementAt(i);
+
+      // XXX: Optionally provide access to system sheets.
+      let systemSheet = CssLogic.isSystemStyleSheet(domRule.parentStyleSheet);
+      if (systemSheet) {
+        continue;
+      }
+
+      // XXX: non-style rules.
+      if (domRule.type === Ci.nsIDOMCSSRule.STYLE_RULE) {
+        this.rules.push(new Rule(this, { domRule: domRule }));
+      }
+    }
+
+    // Mark overridden computed styles.
+    this.markOverridden();
+  },
+
+  /**
+   * Mark the properties listed in this.rules with an overridden flag
+   * if an earlier property overrides it.
+   */
+  markOverridden: function ElementStyle_markOverridden()
+  {
+    // Gather all the text properties applied by these rules, ordered
+    // from more- to less-specific.
+    let textProps = [];
+    for each (let rule in this.rules) {
+      textProps = textProps.concat(rule.textProps.slice(0).reverse());
+    }
+
+    // Gather all the computed properties applied by those text
+    // properties.
+    let computedProps = [];
+    for each (let textProp in textProps) {
+      computedProps = computedProps.concat(textProp.computed);
+    };
+
+    // Walk over the computed properties.  As we see a property name
+    // for the first time, mark that property's name as taken by this
+    // property.
+    //
+    // If we come across a property whose name is already taken, check
+    // its priority against the property that was found first:
+    //
+    //   If the new property is a higher priority, mark the old
+    //   property overridden and mark the property name as taken by
+    //   the new property.
+    //
+    //   If the new property is a lower or equal priority, mark it as
+    //   overridden.
+    //
+    // _overriddenDirty will be set on each prop, indicating whether its
+    // dirty status changed during this pass.
+    let taken = {};
+    for each (let computedProp in computedProps) {
+      let earlier = taken[computedProp.name];
+      let overridden;
+      if (earlier
+          && computedProp.priority === "important"
+          && earlier.priority !== "important") {
+        // New property is higher priority.  Mark the earlier property
+        // overridden (which will reverse its dirty state).
+        earlier._overriddenDirty = !earlier._overriddenDirty;
+        earlier.overridden = true;
+        overridden = false;
+      } else {
+        overridden = !!earlier;
+      }
+
+      computedProp._overriddenDirty = (!!computedProp.overridden != overridden);
+      computedProp.overridden = overridden;
+      if (!computedProp.overridden) {
+        taken[computedProp.name] = computedProp;
+      }
+    }
+
+    // For each TextProperty, mark it overridden if all of its
+    // computed properties are marked overridden.  Update the text
+    // property's associated editor, if any.  This will clear the
+    // _overriddenDirty state on all computed properties.
+    for each (let textProp in textProps) {
+      // _updatePropertyOverridden will return true if the
+      // overridden state has changed for the text property.
+      if (this._updatePropertyOverridden(textProp)) {
+        textProp.updateEditor();
+      }
+    }
+  },
+
+  /**
+   * Mark a given TextProperty as overridden or not depending on the
+   * state of its computed properties.  Clears the _overriddenDirty state
+   * on all computed properties.
+   *
+   * @param {TextProperty} aProp
+   *        The text property to update.
+   *
+   * @return True if the TextProperty's overridden state (or any of its
+   *         computed properties overridden state) changed.
+   */
+  _updatePropertyOverridden: function ElementStyle_updatePropertyOverridden(aProp)
+  {
+    let overridden = true;
+    let dirty = false;
+    for each (let computedProp in aProp.computed) {
+      if (!computedProp.overridden) {
+        overridden = false;
+      }
+      dirty = computedProp._overriddenDirty || dirty;
+      delete computedProp._overriddenDirty;
+    }
+
+    dirty = (!!aProp.overridden != overridden) || dirty;
+    aProp.overridden = overridden;
+    return dirty;
+  }
+}
+
+/**
+ * A single style rule or declaration.
+ *
+ * @param {ElementStyle} aElementStyle
+ *        The ElementStyle to which this rule belongs.
+ * @param {object} aOptions
+ *        The information used to construct this rule.  Properties include:
+ *          domRule: the nsIDOMCSSStyleRule to view, if any.
+ *          style: the nsIDOMCSSStyleDeclaration to view.  If omitted,
+ *            the domRule's style will be used.
+ *          selectorText: selector text to display.  If omitted, the domRule's
+ *            selectorText will be used.
+ * @constructor
+ */
+function Rule(aElementStyle, aOptions)
+{
+  this.elementStyle = aElementStyle;
+  this.domRule = aOptions.domRule || null;
+  this.style = aOptions.style || this.domRule.style;
+  this.selectorText = aOptions.selectorText || this.domRule.selectorText;
+
+  this._getTextProperties();
+}
+
+Rule.prototype = {
+  get title()
+  {
+    if (this._title) {
+      return this._title;
+    }
+    let sheet = this.domRule ? this.domRule.parentStyleSheet : null;
+    this._title = CssLogic.shortSource(sheet);
+    if (this.domRule) {
+      let line = this.elementStyle.domUtils.getRuleLine(this.domRule);
+      this._title += ":" + line;
+    }
+    return this._title;
+  },
+
+  /**
+   * Create a new TextProperty to include in the rule.
+   *
+   * @param {string} aName
+   *        The text property name (such as "background" or "border-top").
+   * @param {string} aValue
+   *        The property's value (not including priority).
+   * @param {string} aPriority
+   *        The property's priority (either "important" or an empty string).
+   */
+  createProperty: function Rule_createProperty(aName, aValue, aPriority)
+  {
+    let prop = new TextProperty(this, aName, aValue, aPriority);
+    this.textProps.push(prop);
+    this.applyProperties();
+    return prop;
+  },
+
+  /**
+   * Reapply all the properties in this rule, and update their
+   * computed styles.  Will re-mark overridden properties.
+   */
+  applyProperties: function Rule_applyProperties()
+  {
+    for each (let prop in this.textProps) {
+      if (!prop.enabled) {
+        continue;
+      }
+
+      this.style.setProperty(prop.name, prop.value, prop.priority);
+      // Refresh the property's value from the style, to reflect
+      // any changes made during parsing.
+      prop.value = this.style.getPropertyValue(prop.name);
+      prop.priority = this.style.getPropertyPriority(prop.name);
+      prop.updateComputed();
+    }
+
+    this.elementStyle.markOverridden();
+  },
+
+  /**
+   * Renames a property.
+   *
+   * @param {TextProperty} aProperty
+   *        The property to rename.
+   * @param {string} aName
+   *        The new property name (such as "background" or "border-top").
+   */
+  setPropertyName: function Rule_setPropertyName(aProperty, aName)
+  {
+    if (aName === aProperty.name) {
+      return;
+    }
+    this.style.removeProperty(aProperty.name);
+    aProperty.name = aName;
+    this.applyProperties();
+  },
+
+  /**
+   * Sets the value and priority of a property.
+   *
+   * @param {TextProperty} aProperty
+   *        The property to manipulate.
+   * @param {string} aValue
+   *        The property's value (not including priority).
+   * @param {string} aPriority
+   *        The property's priority (either "important" or an empty string).
+   */
+  setPropertyValue: function Rule_setPropertyValue(aProperty, aValue, aPriority)
+  {
+    if (aValue === aProperty.value && aPriority === aProperty.priority) {
+      return;
+    }
+    aProperty.value = aValue;
+    aProperty.priority = aPriority;
+    this.applyProperties();
+  },
+
+  /**
+   * Disables or enables given TextProperty.
+   */
+  setPropertyEnabled: function Rule_enableProperty(aProperty, aValue)
+  {
+    aProperty.enabled = !!aValue;
+    if (!aProperty.enabled) {
+      this.style.removeProperty(aProperty.name);
+    }
+    this.applyProperties();
+  },
+
+  /**
+   * Remove a given TextProperty from the rule and update the rule
+   * accordingly.
+   */
+  removeProperty: function Rule_removeProperty(aProperty)
+  {
+    this.textProps = this.textProps.filter(function(prop) prop != aProperty);
+    this.style.removeProperty(aProperty);
+    // Need to re-apply properties in case removing this TextProperty
+    // exposes another one.
+    this.applyProperties();
+  },
+
+  /**
+   * Get the list of TextProperties from the style.  Needs
+   * to parse the style's cssText.
+   */
+  _getTextProperties: function Rule_getTextProperties()
+  {
+    this.textProps = [];
+    let lines = this.style.cssText.match(CSS_LINE_RE);
+    for each (let line in lines) {
+      let matches = CSS_PROP_RE.exec(line);
+      if(!matches || !matches[2])
+        continue;
+
+      let prop = new TextProperty(this, matches[1], matches[2], matches[3] || "");
+      this.textProps.push(prop);
+    }
+  },
+}
+
+/**
+ * A single property in a rule's cssText.
+ *
+ * @param {Rule} aRule
+ *        The rule this TextProperty came from.
+ * @param {string} aName
+ *        The text property name (such as "background" or "border-top").
+ * @param {string} aValue
+ *        The property's value (not including priority).
+ * @param {string} aPriority
+ *        The property's priority (either "important" or an empty string).
+ *
+ */
+function TextProperty(aRule, aName, aValue, aPriority)
+{
+  this.rule = aRule;
+  this.name = aName;
+  this.value = aValue;
+  this.priority = aPriority;
+  this.enabled = true;
+  this.updateComputed();
+}
+
+TextProperty.prototype = {
+  /**
+   * Update the editor associated with this text property,
+   * if any.
+   */
+  updateEditor: function TextProperty_updateEditor()
+  {
+    if (this.editor) {
+      this.editor.update();
+    }
+  },
+
+  /**
+   * Update the list of computed properties for this text property.
+   */
+  updateComputed: function TextProperty_updateComputed()
+  {
+    if (!this.name) {
+      return;
+    }
+
+    // This is a bit funky.  To get the list of computed properties
+    // for this text property, we'll set the property on a dummy element
+    // and see what the computed style looks like.
+    let dummyElement = this.rule.elementStyle.dummyElement;
+    let dummyStyle = dummyElement.style;
+    dummyStyle.cssText = "";
+    dummyStyle.setProperty(this.name, this.value, this.priority);
+
+    this.computed = [];
+    for (let i = 0, n = dummyStyle.length; i < n; i++) {
+      let prop = dummyStyle.item(i);
+      this.computed.push({
+        name: prop,
+        value: dummyStyle.getPropertyValue(prop),
+        priority: dummyStyle.getPropertyPriority(prop),
+      });
+    }
+  },
+
+  setValue: function TextProperty_setValue(aValue, aPriority)
+  {
+    this.rule.setPropertyValue(this, aValue, aPriority);
+    this.updateEditor();
+  },
+
+  setName: function TextProperty_setName(aName)
+  {
+    this.rule.setPropertyName(this, aName);
+    this.updateEditor();
+  },
+
+  setEnabled: function TextProperty_setEnabled(aValue)
+  {
+    this.rule.setPropertyEnabled(this, aValue);
+    this.updateEditor();
+  },
+
+  remove: function TextProperty_remove()
+  {
+    this.rule.removeProperty(this);
+  }
+}
+
+
+/**
+ * View hierarchy mostly follows the model hierarchy.
+ *
+ * CssRuleView:
+ *   Owns an ElementStyle and creates a list of RuleEditors for its
+ *    Rules.
+ * RuleEditor:
+ *   Owns a Rule object and creates a list of TextPropertyEditors
+ *     for its TextProperties.
+ *   Manages creation of new text properties.
+ * TextPropertyEditor:
+ *   Owns a TextProperty object.
+ *   Manages changes to the TextProperty.
+ *   Can be expanded to display computed properties.
+ *   Can mark a property disabled or enabled.
+ */
+
+/**
+ * CssRuleView is a view of the style rules and declarations that
+ * apply to a given element.  After construction, the 'element'
+ * property will be available with the user interface.
+ *
+ * @param Document aDocument
+ *        The document that will contain the rule view.
+ * @constructor
+ */
+function CssRuleView(aDoc)
+{
+  this.doc = aDoc;
+
+  this.element = this.doc.createElementNS(HTML_NS, "div");
+  this.element.setAttribute("tabindex", "0");
+  this.element.classList.add("ruleview");
+}
+
+CssRuleView.prototype = {
+  // The element that we're inspecting.
+  _viewedElement: null,
+
+  /**
+   * Update the highlighted element.
+   *
+   * @param {nsIDOMElement} aElement
+   *        The node whose style rules we'll inspect.
+   */
+  highlight: function CssRuleView_highlight(aElement)
+  {
+    if (this._viewedElement === aElement) {
+      return;
+    }
+
+    this.clear();
+
+    this._viewedElement = aElement;
+    if (!this._viewedElement) {
+      return;
+    }
+
+    this._elementStyle = new ElementStyle(aElement);
+    this._createEditors();
+  },
+
+  /**
+   * Clear the rule view.
+   */
+  clear: function CssRuleView_clear()
+  {
+    while (this.element.hasChildNodes()) {
+      this.element.removeChild(this.element.lastChild);
+    }
+    this._viewedElement = null;
+    this._elementStyle = null;
+  },
+
+  /**
+   * Creates editor UI for each of the rules in _elementStyle.
+   */
+  _createEditors: function CssRuleView_createEditors()
+  {
+    for each (let rule in this._elementStyle.rules) {
+      // Don't hold a reference to this editor beyond the one held
+      // by the node.
+      let editor = new RuleEditor(this.doc, rule);
+      this.element.appendChild(editor.element);
+    }
+  },
+};
+
+/**
+ * Create a RuleEditor.
+ *
+ * @param object aDoc
+ *        The document holding this rule editor.
+ * @param Rule aRule
+ *        The Rule object we're editing.
+ * @constructor
+ */
+function RuleEditor(aDoc, aRule)
+{
+  this.doc = aDoc;
+  this.rule = aRule;
+
+  this._onNewProperty = this._onNewProperty.bind(this);
+
+  this._create();
+}
+
+RuleEditor.prototype = {
+  _create: function RuleEditor_create()
+  {
+    this.element = this.doc.createElementNS(HTML_NS, "div");
+    this.element._ruleEditor = this;
+
+    // Add the source link.
+    let source = createChild(this.element, "div", {
+      class: "ruleview-rule-source",
+      textContent: this.rule.title
+    });
+
+    let code = createChild(this.element, "div", {
+      class: "ruleview-code"
+    });
+
+    let header = createChild(code, "div", {});
+
+    let selectors = createChild(header, "span", {
+      class: "ruleview-selector",
+      textContent: this.rule.selectorText
+    });
+    appendText(header, " {");
+
+    this.propertyList = createChild(code, "ul", {
+      class: "ruleview-propertylist"
+    });
+
+    for each (let prop in this.rule.textProps) {
+      let propEditor = new TextPropertyEditor(this, prop);
+      this.propertyList.appendChild(propEditor.element);
+    }
+
+    this.closeBrace = createChild(code, "div", {
+      class: "ruleview-ruleclose",
+      tabindex: "0",
+      textContent: "}"
+    });
+
+    // We made the close brace focusable, tabbing to it
+    // or clicking on it should start the new property editor.
+    this.closeBrace.addEventListener("focus", function() {
+      this.newProperty();
+    }.bind(this), true);
+  },
+
+  /**
+   * Create a text input for a property name.  If a non-empty property
+   * name is given, we'll create a real TextProperty and add it to the
+   * rule.
+   */
+  newProperty: function RuleEditor_newProperty()
+  {
+    // While we're editing a new property, it doesn't make sense to
+    // start a second new property editor, so disable focusing the
+    // close brace for now.
+    this.closeBrace.removeAttribute("tabindex");
+
+    this.newPropItem = createChild(this.propertyList, "li", {
+      class: "ruleview-property ruleview-newproperty",
+    });
+
+    this.newPropSpan = createChild(this.newPropItem, "span", {
+      class: "ruleview-propertyname"
+    });
+
+    new InplaceEditor({
+      element: this.newPropSpan,
+      done: this._onNewProperty,
+      advanceChars: ":"
+    });
+  },
+
+  _onNewProperty: function RuleEditor_onNewProperty(aValue, aCommit)
+  {
+    // We're done, make the close brace focusable again.
+    this.closeBrace.setAttribute("tabindex", "0");
+
+    this.propertyList.removeChild(this.newPropItem);
+    delete this.newPropItem;
+    delete this.newPropSpan;
+
+    if (!aValue || !aCommit) {
+      return;
+    }
+
+    // Create an empty-valued property and start editing it.
+    let prop = this.rule.createProperty(aValue, "", "");
+    let editor = new TextPropertyEditor(this, prop);
+    this.propertyList.appendChild(editor.element);
+    editor.valueSpan.focus();
+  },
+};
+
+/**
+ * Create a TextPropertyEditor.
+ *
+ * @param {RuleEditor} aRuleEditor
+ *        The rule editor that owns this TextPropertyEditor.
+ * @param {TextProperty} aProperty
+ *        The text property to edit.
+ * @constructor
+ */
+function TextPropertyEditor(aRuleEditor, aProperty)
+{
+  this.doc = aRuleEditor.doc;
+  this.prop = aProperty;
+  this.prop.editor = this;
+
+  this._onEnableClicked = this._onEnableClicked.bind(this);
+  this._onExpandClicked = this._onExpandClicked.bind(this);
+  this._onStartEditing = this._onStartEditing.bind(this);
+  this._onNameDone = this._onNameDone.bind(this);
+  this._onValueDone = this._onValueDone.bind(this);
+
+  this._create();
+  this.update();
+}
+
+TextPropertyEditor.prototype = {
+  get editing() {
+    return !!(this.nameSpan.inplaceEditor || this.valueSpan.inplaceEditor);
+  },
+
+  /**
+   * Create the property editor's DOM.
+   */
+  _create: function TextPropertyEditor_create()
+  {
+    this.element = this.doc.createElementNS(HTML_NS, "li");
+    this.element.classList.add("ruleview-property");
+
+    // The enable checkbox will disable or enable the rule.
+    this.enable = createChild(this.element, "input", {
+      class: "ruleview-enableproperty",
+      type: "checkbox",
+      tabindex: "-1"
+    });
+    this.enable.addEventListener("click", this._onEnableClicked, true);
+
+    // Click to expand the computed properties of the text property.
+    this.expander = createChild(this.element, "span", {
+      class: "ruleview-expander"
+    });
+    this.expander.addEventListener("click", this._onExpandClicked, true);
+
+    // Property name, editable when focused.  Property name
+    // is committed when the editor is unfocused.
+    this.nameSpan = createChild(this.element, "span", {
+      class: "ruleview-propertyname",
+      tabindex: "0",
+    });
+    editableField({
+      start: this._onStartEditing,
+      element: this.nameSpan,
+      done: this._onNameDone,
+      advanceChars: ':'
+    });
+
+    appendText(this.element, ": ");
+
+    // Property value, editable when focused.  Changes to the
+    // property value are applied as they are typed, and reverted
+    // if the user presses escape.
+    this.valueSpan = createChild(this.element, "span", {
+      class: "ruleview-propertyvalue",
+      tabindex: "0",
+    });
+
+    editableField({
+      start: this._onStartEditing,
+      element: this.valueSpan,
+      done: this._onValueDone,
+      advanceChars: ';'
+    });
+
+    // Save the initial value as the last committed value,
+    // for restoring after pressing escape.
+    this.committed = { name: this.prop.name,
+                       value: this.prop.value,
+                       priority: this.prop.priority };
+
+    appendText(this.element, ";");
+
+    // Holds the viewers for the computed properties.
+    // will be populated in |_updateComputed|.
+    this.computed = createChild(this.element, "ul", {
+      class: "ruleview-computedlist",
+    });
+  },
+
+  /**
+   * Populate the span based on changes to the TextProperty.
+   */
+  update: function TextPropertyEditor_update()
+  {
+    if (this.prop.enabled) {
+      this.enable.style.removeProperty("visibility");
+      this.enable.setAttribute("checked", "");
+    } else {
+      this.enable.style.visibility = "visible";
+      this.enable.removeAttribute("checked");
+    }
+
+    if (this.prop.overridden && !this.editing) {
+      this.element.classList.add("ruleview-overridden");
+    } else {
+      this.element.classList.remove("ruleview-overridden");
+    }
+
+    this.nameSpan.textContent = this.prop.name;
+
+    // Combine the property's value and priority into one string for
+    // the value.
+    let val = this.prop.value;
+    if (this.prop.priority) {
+      val += " !" + this.prop.priority;
+    }
+    this.valueSpan.textContent = val;
+
+    // Populate the computed styles.
+    this._updateComputed();
+  },
+
+  _onStartEditing: function TextPropertyEditor_onStartEditing()
+  {
+    this.element.classList.remove("ruleview-overridden");
+  },
+
+  /**
+   * Populate the list of computed styles.
+   */
+  _updateComputed: function TextPropertyEditor_updateComputed()
+  {
+    // Clear out existing viewers.
+    while (this.computed.hasChildNodes()) {
+      this.computed.removeChild(this.computed.lastChild);
+    }
+
+    let showExpander = false;
+    for each (let computed in this.prop.computed) {
+      // Don't bother to duplicate information already
+      // shown in the text property.
+      if (computed.name === this.prop.name) {
+        continue;
+      }
+
+      showExpander = true;
+
+      let li = createChild(this.computed, "li", {
+        class: "ruleview-computed"
+      });
+
+      if (computed.overridden) {
+        li.classList.add("ruleview-overridden");
+      }
+
+      createChild(li, "span", {
+        class: "ruleview-propertyname",
+        textContent: computed.name
+      });
+      appendText(li, ": ");
+      createChild(li, "span", {
+        class: "ruleview-propertyvalue",
+        textContent: computed.value
+      });
+      appendText(li, ";");
+    }
+
+    // Show or hide the expander as needed.
+    if (showExpander) {
+      this.expander.style.visibility = "visible";
+    } else {
+      this.expander.style.visibility = "hidden";
+    }
+  },
+
+  /**
+   * Handles clicks on the disabled property.
+   */
+  _onEnableClicked: function TextPropertyEditor_onEnableClicked()
+  {
+    this.prop.setEnabled(this.enable.checked);
+  },
+
+  /**
+   * Handles clicks on the computed property expander.
+   */
+  _onExpandClicked: function TextPropertyEditor_onExpandClicked()
+  {
+    this.expander.classList.toggle("styleinspector-open");
+    this.computed.classList.toggle("styleinspector-open");
+  },
+
+  /**
+   * Called when the property name's inplace editor is closed.
+   * Ignores the change if the user pressed escape, otherwise
+   * commits it.
+   *
+   * @param {string} aValue
+   *        The value contained in the editor.
+   * @param {boolean} aCommit
+   *        True if the change should be applied.
+   */
+  _onNameDone: function TextPropertyEditor_onNameDone(aValue, aCommit)
+  {
+    if (!aCommit) {
+      return;
+    }
+    if (!aValue) {
+      this.prop.remove();
+      this.element.parentNode.removeChild(this.element);
+      return;
+    }
+    this.prop.setName(aValue);
+  },
+
+  /**
+   * Pull priority (!important) out of the value provided by a
+   * value editor.
+   *
+   * @param {string} aValue
+   *        The value from the text editor.
+   * @return an object with 'value' and 'priority' properties.
+   */
+  _parseValue: function TextPropertyEditor_parseValue(aValue)
+  {
+    let [value, priority] = aValue.split("!", 2);
+    return {
+      value: value.trim(),
+      priority: (priority ? priority.trim() : "")
+    };
+  },
+
+  /**
+   * Called when a value editor closes.  If the user pressed escape,
+   * revert to the value this property had before editing.
+   *
+   * @param {string} aValue
+   *        The value contained in the editor.
+   * @param {boolean} aCommit
+   *        True if the change should be applied.
+   */
+   _onValueDone: function PropertyEditor_onValueDone(aValue, aCommit)
+  {
+    if (aCommit) {
+      let val = this._parseValue(aValue);
+      this.prop.setValue(val.value, val.priority);
+      this.committed.value = this.prop.value;
+      this.committed.priority = this.prop.priority;
+    } else {
+      this.prop.setValue(this.committed.value, this.committed.priority);
+    }
+  },
+};
+
+/**
+ * Mark a span editable.  |editableField| will listen for the span to
+ * be focused and create an InlineEditor to handle text input.
+ * Changes will be committed when the InlineEditor's input is blurred
+ * or dropped when the user presses escape.
+ *
+ * @param {object} aOptions
+ *    Options for the editable field, including:
+ *    {Element} element:
+ *      (required) The span to be edited on focus.
+ *    {function} start:
+ *       Will be called when the inplace editor is initialized.
+ *    {function} change:
+ *       Will be called when the text input changes.  Will be called
+ *       with the current value of the text input.
+ *    {function} done:
+ *       Called when input is committed or blurred.  Called with
+ *       current value and a boolean telling the caller whether to
+ *       commit the change.
+ *    {string} advanceChars:
+ *       If any characters in advanceChars are typed, focus will advance
+ *       to the next element.
+ */
+function editableField(aOptions)
+{
+  aOptions.element.addEventListener("focus", function() {
+    new InplaceEditor(aOptions);
+  }, false);
+}
+var _editableField = editableField;
+
+function InplaceEditor(aOptions)
+{
+  this.elt = aOptions.element;
+  this.elt.inplaceEditor = this;
+
+  this.change = aOptions.change;
+  this.done = aOptions.done;
+  this.initial = aOptions.initial ? aOptions.initial : this.elt.textContent;
+  this.doc = this.elt.ownerDocument;
+
+  this._onBlur = this._onBlur.bind(this);
+  this._onKeyPress = this._onKeyPress.bind(this);
+  this._onInput = this._onInput.bind(this);
+
+  this._createInput();
+  this._autosize();
+
+  // Pull out character codes for advanceChars, listing the
+  // characters that should trigger a blur.
+  this._advanceCharCodes = {};
+  let advanceChars = aOptions.advanceChars || '';
+  for (let i = 0; i < advanceChars.length; i++) {
+    this._advanceCharCodes[advanceChars.charCodeAt(i)] = true;
+  }
+
+  // Hide the provided element and add our editor.
+  this.originalDisplay = this.elt.style.display;
+  this.elt.style.display = "none";
+  this.elt.parentNode.insertBefore(this.input, this.elt);
+
+  this.input.select();
+  this.input.focus();
+
+  this.input.addEventListener("blur", this._onBlur, false);
+  this.input.addEventListener("keypress", this._onKeyPress, false);
+  this.input.addEventListener("input", this._onInput, false);
+
+  if (aOptions.start) {
+    aOptions.start();
+  }
+}
+
+InplaceEditor.prototype = {
+  _createInput: function InplaceEditor_createEditor()
+  {
+    this.input = this.doc.createElementNS(HTML_NS, "input");
+    this.input.inplaceEditor = this;
+    this.input.classList.add("styleinspector-propertyeditor");
+    this.input.value = this.initial;
+
+    copyTextStyles(this.elt, this.input);
+  },
+
+  /**
+   * Get rid of the editor.
+   */
+  _clear: function InplaceEditor_clear()
+  {
+    this.input.removeEventListener("blur", this._onBlur, false);
+    this.input.removeEventListener("keypress", this._onKeyPress, false);
+    this.input.removeEventListener("oninput", this._onInput, false);
+    this._stopAutosize();
+
+    this.elt.parentNode.removeChild(this.input);
+    this.elt.style.display = this.originalDisplay;
+    this.input = null;
+
+    delete this.elt.inplaceEditor;
+    delete this.elt;
+  },
+
+  /**
+   * Keeps the editor close to the size of its input string.  This is pretty
+   * crappy, suggestions for improvement welcome.
+   */
+  _autosize: function InplaceEditor_autosize()
+  {
+    // Create a hidden, absolutely-positioned span to measure the text
+    // in the input.  Boo.
+
+    // We can't just measure the original element because a) we don't
+    // change the underlying element's text ourselves (we leave that
+    // up to the client), and b) without tweaking the style of the
+    // original element, it might wrap differently or something.
+    this._measurement = this.doc.createElementNS(HTML_NS, "span");
+    this.elt.parentNode.appendChild(this._measurement);
+    let style = this._measurement.style;
+    style.visibility = "hidden";
+    style.position = "absolute";
+    style.top = "0";
+    style.left = "0";
+    copyTextStyles(this.input, this._measurement);
+    this._updateSize();
+  },
+
+  /**
+   * Clean up the mess created by _autosize().
+   */
+  _stopAutosize: function InplaceEditor_stopAutosize()
+  {
+    if (!this._measurement) {
+      return;
+    }
+    this._measurement.parentNode.removeChild(this._measurement);
+    delete this._measurement;
+  },
+
+  /**
+   * Size the editor to fit its current contents.
+   */
+  _updateSize: function InplaceEditor_updateSize()
+  {
+    // Replace spaces with non-breaking spaces.  Otherwise setting
+    // the span's textContent will collapse spaces and the measurement
+    // will be wrong.
+    this._measurement.textContent = this.input.value.replace(' ', '\u00a0', 'g');
+
+    // We add a bit of padding to the end.  Should be enough to fit
+    // any letter that could be typed, otherwise we'll scroll before
+    // we get a chance to resize.  Yuck.
+    let width = this._measurement.offsetWidth + 10;
+
+    this.input.style.width = width + "px";
+  },
+
+  /**
+   * Handle loss of focus by calling the client's done handler and
+   * clearing out.
+   */
+  _onBlur: function InplaceEditor_onBlur(aEvent)
+  {
+    if (this.done) {
+      this.done(this.cancelled ? this.initial : this.input.value.trim(),
+                !this.cancelled);
+    }
+    this._clear();
+  },
+
+  _onKeyPress: function InplaceEditor_onKeyPress(aEvent)
+  {
+    let prevent = false;
+    if (aEvent.charCode in this._advanceCharCodes
+       || aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) {
+      // Focus the next element, triggering a blur which
+      // will eventually shut us down (making return roughly equal
+      // tab).
+      prevent = true;
+      moveFocus(this.input.ownerDocument.defaultView, FOCUS_FORWARD);
+    } else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE) {
+      // Cancel and blur ourselves.  |_onBlur| will call the user's
+      // done handler for us.
+      prevent = true;
+      this.cancelled = true;
+      this.input.blur();
+    } else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
+      // No need for leading spaces here.  This is particularly
+      // noticable when adding a property: it's very natural to type
+      // <name>: (which advances to the next property) then spacebar.
+      prevent = !this.input.value;
+    }
+
+    if (prevent) {
+      aEvent.preventDefault();
+    }
+  },
+
+  /**
+   * Handle changes the input text.
+   */
+  _onInput: function InplaceEditor_onInput(aEvent)
+  {
+    // Update size if we're autosizing.
+    if (this._measurement) {
+      this._updateSize();
+    }
+
+    // Call the user's change handler if available.
+    if (this.change) {
+      this.change(this.input.value.trim());
+    }
+  }
+};
+
+/**
+ * Helper functions
+ */
+
+/**
+ * Create a child element with a set of attributes.
+ *
+ * @param {Element} aParent
+ *        The parent node.
+ * @param {string} aTag
+ *        The tag name.
+ * @param {object} aAttributes
+ *        A set of attributes to set on the node.
+ */
+function createChild(aParent, aTag, aAttributes)
+{
+  let elt = aParent.ownerDocument.createElementNS(HTML_NS, aTag);
+  for (let attr in aAttributes) {
+    if (aAttributes.hasOwnProperty(attr)) {
+      if (attr === "textContent") {
+        elt.textContent = aAttributes[attr];
+      } else {
+        elt.setAttribute(attr, aAttributes[attr]);
+      }
+    }
+  }
+  aParent.appendChild(elt);
+  return elt;
+}
+
+/**
+ * Append a text node to an element.
+ */
+function appendText(aParent, aText)
+{
+  aParent.appendChild(aParent.ownerDocument.createTextNode(aText));
+}
+
+/**
+ * Copy text-related styles from one element to another.
+ */
+function copyTextStyles(aFrom, aTo)
+{
+  let win = aFrom.ownerDocument.defaultView;
+  let style = win.getComputedStyle(aFrom);
+  aTo.style.fontFamily = style.getPropertyCSSValue("font-family").cssText;
+  aTo.style.fontSize = style.getPropertyCSSValue("font-size").cssText;
+  aTo.style.fontWeight = style.getPropertyCSSValue("font-weight").cssText;
+  aTo.style.fontStyle = style.getPropertyCSSValue("font-style").cssText;
+}
+
+/**
+ * Trigger a focus change similar to pressing tab/shift-tab.
+ */
+function moveFocus(aWin, aDirection)
+{
+  let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
+  fm.moveFocus(aWin, null, aDirection, 0);
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/cssruleview.xhtml
@@ -0,0 +1,53 @@
+<!DOCTYPE html [
+  <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
+  %htmlDTD;
+  <!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/styleinspector.dtd">
+  %inspectorDTD;
+]>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is the Mozilla Inspector Module.
+   -
+   - The Initial Developer of the Original Code is The Mozilla Foundation.
+   - Portions created by the Initial Developer are Copyright (C) 2011
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Dave Camp (dcamp@mozilla.com) (original author)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+<html xmlns="http://www.w3.org/1999/xhtml"
+  xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<head>
+  <meta http-equiv="Content-Type"
+    content="application/xhtml+xml; charset=UTF-8" />
+  <link rel="stylesheet" type="text/css"
+    href="chrome://browser/content/devtools/styleinspector.css" />
+  <link rel="stylesheet" type="text/css"
+    href="chrome://browser/skin/devtools/csshtmltree.css" />
+</head>
+<body role="application" id="ruleview-body"></body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/styleinspector.css
@@ -0,0 +1,40 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Mozilla Inspector Module.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dave Camp <dcamp@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+.ruleview-computedlist:not(.styleinspector-open) {
+  display: none;
+}
--- a/browser/devtools/styleinspector/test/browser/Makefile.in
+++ b/browser/devtools/styleinspector/test/browser/Makefile.in
@@ -47,16 +47,20 @@ include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES = \
   browser_styleinspector.js \
   browser_styleinspector_webconsole.js \
   browser_bug683672.js \
   browser_styleinspector_bug_672746_default_styles.js \
   browser_styleinspector_bug_672744_search_filter.js \
   browser_bug_692400_element_style.js \
+  browser_ruleview_editor.js \
+  browser_ruleview_manipulation.js \
+  browser_ruleview_override.js \
+  browser_ruleview_ui.js \
   head.js \
   $(NULL)
 
 _BROWSER_TEST_PAGES = \
   browser_styleinspector_webconsole.htm \
   browser_bug683672.html \
   $(NULL)
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_ruleview_editor.js
@@ -0,0 +1,121 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource:///modules/devtools/CssRuleView.jsm");
+
+let doc = content.document;
+
+function expectDone(aValue, aCommit, aNext)
+{
+  return function(aDoneValue, aDoneCommit) {
+    dump("aDoneValue: " + aDoneValue + " commit: " + aDoneCommit + "\n");
+
+    is(aDoneValue, aValue, "Should get expected value");
+    is(aDoneCommit, aDoneCommit, "Should get expected commit value");
+    aNext();
+  }
+}
+
+function clearBody()
+{
+  doc.body.innerHTML = "";
+}
+
+function createSpan()
+{
+  let span = doc.createElement("span");
+  span.setAttribute("tabindex", "0");
+  span.textContent = "Edit Me!";
+  doc.body.appendChild(span);
+  return span;
+}
+
+function testReturnCommit()
+{
+  clearBody();
+  let span = createSpan();
+  _editableField({
+    element: span,
+    initial: "explicit initial",
+    start: function() {
+      is(span.inplaceEditor.input.value, "explicit initial", "Explicit initial value should be used.");
+      span.inplaceEditor.input.value = "Test Value";
+      EventUtils.sendKey("return", span.inplaceEditor.input);
+    },
+    done: expectDone("Test Value", true, testBlurCommit)
+  });
+  span.focus();
+}
+
+function testBlurCommit()
+{
+  clearBody();
+  let span = createSpan();
+  _editableField({
+    element: span,
+    start: function() {
+      is(span.inplaceEditor.input.value, "Edit Me!", "textContent of the span used.");
+      span.inplaceEditor.input.value = "Test Value";
+      span.inplaceEditor.input.blur();
+    },
+    done: expectDone("Test Value", true, testAdvanceCharCommit)
+  });
+  span.focus();
+}
+
+function testAdvanceCharCommit()
+{
+  clearBody();
+  let span = createSpan();
+  _editableField({
+    element: span,
+    advanceChars: ":",
+    start: function() {
+      let input = span.inplaceEditor.input;
+      for each (let ch in "Test:") {
+        EventUtils.sendChar(ch, input);
+      }
+    },
+    done: expectDone("Test", true, testEscapeCancel)
+  });
+  span.focus();
+}
+
+function testEscapeCancel()
+{
+  clearBody();
+  let span = createSpan();
+  _editableField({
+    element: span,
+    initial: "initial text",
+    start: function() {
+      span.inplaceEditor.input.value = "Test Value";
+      EventUtils.sendKey("escape", span.inplaceEditor.input);
+    },
+    done: expectDone("initial text", false, finishTest)
+  });
+  span.focus();
+}
+
+
+function finishTest()
+{
+  doc = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
+    doc = content.document;
+    waitForFocus(testReturnCommit, content);
+  }, true);
+
+  content.location = "data:text/html,inline editor tests";
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_ruleview_manipulation.js
@@ -0,0 +1,70 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource:///modules/devtools/CssRuleView.jsm");
+
+let doc;
+
+function simpleOverride()
+{
+  doc.body.innerHTML = '<div id="testid">Styled Node</div>';
+  let element = doc.getElementById("testid");
+  let elementStyle = new _ElementStyle(element);
+
+  let elementRule = elementStyle.rules[0];
+  let firstProp = elementRule.createProperty("background-color", "green", "");
+  let secondProp = elementRule.createProperty("background-color", "blue", "");
+  is(elementRule.textProps[0], firstProp, "Rules should be in addition order.");
+  is(elementRule.textProps[1], secondProp, "Rules should be in addition order.");
+
+  is(element.style.getPropertyValue("background-color"), "blue", "Second property should have been used.");
+
+  secondProp.remove();
+  is(element.style.getPropertyValue("background-color"), "green", "After deleting second property, first should be used.");
+
+  secondProp = elementRule.createProperty("background-color", "blue", "");
+  is(element.style.getPropertyValue("background-color"), "blue", "New property should be used.");
+
+  is(elementRule.textProps[0], firstProp, "Rules shouldn't have switched places.");
+  is(elementRule.textProps[1], secondProp, "Rules shouldn't have switched places.");
+
+  secondProp.setEnabled(false);
+  is(element.style.getPropertyValue("background-color"), "green", "After disabling second property, first value should be used");
+
+  firstProp.setEnabled(false);
+  is(element.style.getPropertyValue("background-color"), "", "After disabling both properties, value should be empty.");
+
+  secondProp.setEnabled(true);
+  is(element.style.getPropertyValue("background-color"), "blue", "Value should be set correctly after re-enabling");
+
+  firstProp.setEnabled(true);
+  is(element.style.getPropertyValue("background-color"), "blue", "Re-enabling an earlier property shouldn't make it override a later property.");
+  is(elementRule.textProps[0], firstProp, "Rules shouldn't have switched places.");
+  is(elementRule.textProps[1], secondProp, "Rules shouldn't have switched places.");
+
+  firstProp.setValue("purple", "");
+  is(element.style.getPropertyValue("background-color"), "blue", "Modifying an earlier property shouldn't override a later property.");
+
+  finishTest();
+}
+
+function finishTest()
+{
+  doc = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
+    doc = content.document;
+    waitForFocus(simpleOverride, content);
+  }, true);
+
+  content.location = "data:text/html,basic style inspector tests";
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_ruleview_override.js
@@ -0,0 +1,134 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource:///modules/devtools/CssRuleView.jsm");
+
+let doc;
+
+function simpleOverride()
+{
+  let style = '' +
+    '#testid {' +
+    '  background-color: blue;' +
+    '} ' +
+    '.testclass {' +
+    '  background-color: green;' +
+    '}';
+
+  let styleNode = addStyle(doc, style);
+  doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
+
+  let elementStyle = new _ElementStyle(doc.getElementById("testid"));
+
+  let idRule = elementStyle.rules[1];
+  let idProp = idRule.textProps[0];
+  is(idProp.name, "background-color", "First ID prop should be background-color");
+  ok(!idProp.overridden, "ID prop should not be overridden.");
+
+  let classRule = elementStyle.rules[2];
+  let classProp = classRule.textProps[0];
+  is(classProp.name, "background-color", "First class prop should be background-color");
+  ok(classProp.overridden, "Class property should be overridden.");
+
+  // Override background-color by changing the element style.
+  let elementRule = elementStyle.rules[0];
+  elementRule.createProperty("background-color", "purple", "");
+  let elementProp = elementRule.textProps[0];
+  is(classProp.name, "background-color", "First element prop should now be background-color");
+
+  ok(!elementProp.overridden, "Element style property should not be overridden");
+  ok(idProp.overridden, "ID property should be overridden");
+  ok(classProp.overridden, "Class property should be overridden");
+
+  styleNode.parentNode.removeChild(styleNode);
+
+  partialOverride();
+}
+
+function partialOverride()
+{
+  let style = '' +
+    // Margin shorthand property...
+    '.testclass {' +
+    '  margin: 2px;' +
+    '}' +
+    // ... will be partially overridden.
+    '#testid {' +
+    '  margin-left: 1px;' +
+    '}';
+
+  let styleNode = addStyle(doc, style);
+  doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
+
+  let elementStyle = new _ElementStyle(doc.getElementById("testid"));
+
+  let classRule = elementStyle.rules[2];
+  let classProp = classRule.textProps[0];
+  ok(!classProp.overridden, "Class prop shouldn't be overridden, some props are still being used.");
+  for each (let computed in classProp.computed) {
+    if (computed.name.indexOf("margin-left") == 0) {
+      ok(computed.overridden, "margin-left props should be overridden.");
+    } else {
+      ok(!computed.overridden, "Non-margin-left props should not be overridden.");
+    }
+  }
+
+  styleNode.parentNode.removeChild(styleNode);
+
+  importantOverride();
+}
+
+function importantOverride()
+{
+  let style = '' +
+    // Margin shorthand property...
+    '.testclass {' +
+    '  background-color: green !important;' +
+    '}' +
+    // ... will be partially overridden.
+    '#testid {' +
+    '  background-color: blue;' +
+    '}';
+  let styleNode = addStyle(doc, style);
+  doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
+
+  let elementStyle = new _ElementStyle(doc.getElementById("testid"));
+
+  let idRule = elementStyle.rules[1];
+  let idProp = idRule.textProps[0];
+  ok(idProp.overridden, "Not-important rule should be overridden.");
+
+  let classRule = elementStyle.rules[2];
+  let classProp = classRule.textProps[0];
+  ok(!classProp.overridden, "Important rule should not be overridden.");
+
+  styleNode.parentNode.removeChild(styleNode);
+
+  let elementRule = elementStyle.rules[0];
+  let elementProp = elementRule.createProperty("background-color", "purple", "important");
+  ok(classProp.overridden, "New important prop should override class property.");
+  ok(!elementProp.overridden, "New important prop should not be overriden.");
+
+  finishTest();
+}
+
+function finishTest()
+{
+  doc = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
+    doc = content.document;
+    waitForFocus(simpleOverride, content);
+  }, true);
+
+  content.location = "data:text/html,basic style inspector tests";
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_ruleview_ui.js
@@ -0,0 +1,180 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Cu.import("resource:///modules/devtools/CssRuleView.jsm");
+
+let doc;
+let ruleDialog;
+let ruleView;
+
+function waitForEditorFocus(aParent, aCallback)
+{
+  aParent.addEventListener("focus", function onFocus(evt) {
+    if (evt.target.inplaceEditor) {
+      aParent.removeEventListener("focus", onFocus, true);
+      let editor = evt.target.inplaceEditor;
+      executeSoon(function() {
+        aCallback(editor);
+      });
+    }
+  }, true);
+}
+
+function waitForEditorBlur(aEditor, aCallback)
+{
+  let input = aEditor.input;
+  input.addEventListener("blur", function onBlur() {
+    input.removeEventListener("blur", onBlur, false);
+    executeSoon(function() {
+      aCallback();
+    });
+  }, false);
+}
+
+function startTest()
+{
+  let style = '' +
+    '#testid {' +
+    '  background-color: blue;' +
+    '} ' +
+    '.testclass {' +
+    '  background-color: green;' +
+    '}';
+
+  let styleNode = addStyle(doc, style);
+  doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
+  let testElement = doc.getElementById("testid");
+
+  ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xhtml",
+                          "cssruleviewtest",
+                          "width=200,height=350");
+  ruleDialog.addEventListener("load", function onLoad(evt) {
+    ruleDialog.removeEventListener("load", onLoad);
+    let doc = ruleDialog.document;
+    let body = doc.getElementById("ruleview-body");
+    ruleView = new CssRuleView(doc);
+    body.appendChild(ruleView.element);
+    ruleView.highlight(testElement);
+    waitForFocus(testCancelNew, ruleDialog);
+  }, true);
+}
+
+function testCancelNew()
+{
+  // Start at the beginning: start to add a rule to the element's style
+  // declaration, but leave it empty.
+
+  let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
+  waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) {
+    is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
+    let input = aEditor.input;
+    waitForEditorBlur(aEditor, function () {
+      is(elementRuleEditor.rule.textProps.length,  0, "Should have canceled creating a new text property.");
+      ok(!elementRuleEditor.propertyList.hasChildNodes(), "Should not have any properties.");
+      testCreateNew();
+    });
+    aEditor.input.blur();
+  });
+
+  EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
+                             { },
+                             ruleDialog);
+}
+
+function testCreateNew()
+{
+  // Create a new property.
+  let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
+  waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) {
+    is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
+    let input = aEditor.input;
+    input.value = "background-color";
+
+    waitForEditorFocus(elementRuleEditor.element, function onNewValue(aEditor) {
+      is(elementRuleEditor.rule.textProps.length,  1, "Should have created a new text property.");
+      is(elementRuleEditor.propertyList.children.length, 1, "Should have created a property editor.");
+      let textProp = elementRuleEditor.rule.textProps[0];
+      is(aEditor, textProp.editor.valueSpan.inplaceEditor, "Should be editing the value span now.");
+
+      aEditor.input.value = "purple";
+      waitForEditorBlur(aEditor, function() {
+        is(textProp.value, "purple", "Text prop should have been changed.");
+        testEditProperty();
+      });
+
+      aEditor.input.blur();
+    });
+    EventUtils.sendKey("return", input);
+  });
+
+  EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
+                             { },
+                             ruleDialog);
+}
+
+function testEditProperty()
+{
+  let idRuleEditor = ruleView.element.children[1]._ruleEditor;
+  let propEditor = idRuleEditor.rule.textProps[0].editor;
+  waitForEditorFocus(propEditor.element, function onNewElement(aEditor) {
+    is(propEditor.nameSpan.inplaceEditor, aEditor, "Next focused editor should be the name editor.");
+    let input = aEditor.input;
+    waitForEditorFocus(propEditor.element, function onNewName(aEditor) {
+      input = aEditor.input;
+      is(propEditor.valueSpan.inplaceEditor, aEditor, "Focus should have moved to the value.");
+
+      waitForEditorBlur(aEditor, function() {
+        is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
+           "border-color should have been set.");
+        testDisableProperty();
+      });
+
+      for each (let ch in "red;") {
+        EventUtils.sendChar(ch, input);
+      }
+    });
+    for each (let ch in "border-color:") {
+      EventUtils.sendChar(ch, input);
+    }
+  });
+
+  EventUtils.synthesizeMouse(propEditor.nameSpan, 1, 1,
+                             { },
+                             ruleDialog);
+}
+
+function testDisableProperty()
+{
+  let idRuleEditor = ruleView.element.children[1]._ruleEditor;
+  let propEditor = idRuleEditor.rule.textProps[0].editor;
+
+  propEditor.enable.click();
+  is(idRuleEditor.rule.style.getPropertyValue("border-color"), "", "Border-color should have been unset.");
+  propEditor.enable.click();
+  is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
+     "Border-color should have been reset.");
+  finishTest();
+}
+
+function finishTest()
+{
+  ruleDialog.close();
+  ruleDialog = ruleView = null;
+  doc = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
+    doc = content.document;
+    waitForFocus(startTest, content);
+  }, true);
+
+  content.location = "data:text/html,basic style inspector tests";
+}
--- a/browser/devtools/styleinspector/test/browser/head.js
+++ b/browser/devtools/styleinspector/test/browser/head.js
@@ -145,16 +145,25 @@ function testLogEntry(aOutputNode, aMatc
  * @param string aString
  *        The string to find.
  */
 function findLogEntry(aString)
 {
   testLogEntry(outputNode, aString, "found " + aString);
 }
 
+function addStyle(aDocument, aString)
+{
+  let node = aDocument.createElement('style');
+  node.setAttribute("type", "text/css");
+  node.textContent = aString;
+  aDocument.getElementsByTagName("head")[0].appendChild(node);
+  return node;
+}
+
 function openConsole()
 {
   HUDService.activateHUDForContext(tab);
 }
 
 function closeConsole()
 {
   HUDService.deactivateHUDForContext(tab);
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -80,16 +80,22 @@ XPCOMUtils.defineLazyGetter(this, "gcli"
 });
 
 XPCOMUtils.defineLazyGetter(this, "StyleInspector", function () {
   var obj = {};
   Cu.import("resource:///modules/devtools/StyleInspector.jsm", obj);
   return obj.StyleInspector;
 });
 
+XPCOMUtils.defineLazyGetter(this, "CssRuleView", function() {
+  let tmp = {};
+  Cu.import("resource:///modules/devtools/CssRuleView.jsm", tmp);
+  return tmp.CssRuleView;
+});
+
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function () {
   var obj = {};
   Cu.import("resource://gre/modules/NetUtil.jsm", obj);
   return obj.NetUtil;
 });
 
 XPCOMUtils.defineLazyGetter(this, "PropertyPanel", function () {
   var obj = {};
@@ -4595,16 +4601,63 @@ function JSTermHelper(aJSTerm)
         styleInspector.panel.setAttribute("hudToolId", aJSTerm.hudId);
         styleInspector.open(aNode);
       });
     } else {
       aJSTerm.writeOutput(errstr + "\n", CATEGORY_OUTPUT, SEVERITY_ERROR);
     }
   };
 
+  aJSTerm.sandbox.inspectrules = function JSTH_inspectrules(aNode)
+  {
+    aJSTerm.helperEvaluated = true;
+    let doc = aJSTerm.parentNode.ownerDocument;
+    let win = doc.defaultView;
+    let panel = createElement(doc, "panel", {
+      label: "CSS Rules",
+      titlebar: "normal",
+      noautofocus: "true",
+      noautohide: "true",
+      close: "true",
+      width: 350,
+      height: (win.screen.height / 2)
+    });
+
+    let iframe = createAndAppendElement(panel, "iframe", {
+      src: "chrome://browser/content/devtools/cssruleview.xhtml",
+      flex: "1",
+    });
+
+    panel.addEventListener("load", function onLoad() {
+      panel.removeEventListener("load", onLoad, true);
+      let doc = iframe.contentDocument;
+      let view = new CssRuleView(doc);
+      let body = doc.getElementById("ruleview-body");
+      body.appendChild(view.element);
+      view.highlight(aNode);
+    }, true);
+
+    let parent = doc.getElementById("mainPopupSet");
+    parent.appendChild(panel);
+
+    panel.addEventListener("popuphidden", function onHide() {
+      panel.removeEventListener("popuphidden", onHide);
+      parent.removeChild(panel);
+    });
+
+    let footer = createElement(doc, "hbox", { align: "end" });
+    createAndAppendElement(footer, "spacer", { flex: 1});
+    createAndAppendElement(footer, "resizer", { dir: "bottomend" });
+    panel.appendChild(footer);
+
+    let anchor = win.gBrowser.selectedBrowser;
+    panel.openPopup(anchor, "end_before", 0, 0, false, false);
+
+  }
+
   /**
    * Prints aObject to the output.
    *
    * @param object aObject
    *        Object to print to the output.
    * @returns void
    */
   aJSTerm.sandbox.pprint = function JSTH_pprint(aObject)
--- a/browser/locales/en-US/chrome/browser/aboutHome.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutHome.dtd
@@ -13,8 +13,11 @@
 <!-- LOCALIZATION NOTE (abouthome.defaultSnippet1.v1):
      text in <a/> will be linked to the Firefox features page on mozilla.com
 -->
 <!ENTITY abouthome.defaultSnippet1.v1 "Thanks for choosing Firefox! To get the most out of your browser, learn more about the <a>latest features</a>.">
 <!-- LOCALIZATION NOTE (abouthome.defaultSnippet2.v1):
      text in <a/> will be linked to the featured add-ons on addons.mozilla.org
 -->
 <!ENTITY abouthome.defaultSnippet2.v1 "It's easy to customize your Firefox exactly the way you want it. <a>Choose from thousands of add-ons</a>.">
+
+<!ENTITY abouthome.syncSetup.label   "Set Up Sync">
+<!ENTITY abouthome.pairDevice.label  "Pair a Device">
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -208,19 +208,20 @@ can reach it easily. -->
   -  "Scratchpad" in your locale. You should feel free to find a close
   -  approximation to it or choose a word (or words) that means
   -  "simple discardable text editor". -->
 <!ENTITY scratchpad.label             "Scratchpad">
 <!ENTITY scratchpad.accesskey         "s">
 <!ENTITY scratchpad.keycode           "VK_F4">
 <!ENTITY scratchpad.keytext           "F4">
 
-<!ENTITY inspectPanelTitle.label      "HTML">
-<!ENTITY inspectButton.label          "Inspect">
-<!ENTITY inspectButton.accesskey      "I">
+<!ENTITY inspectPanelTitle.label        "HTML">
+<!ENTITY inspectButton.label            "Inspect">
+<!ENTITY inspectButton.accesskey        "I">
+<!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
 
 <!ENTITY getMoreDevtoolsCmd.label        "Get More Tools">
 <!ENTITY getMoreDevtoolsCmd.accesskey    "M">
 
 <!ENTITY fileMenu.label         "File"> 
 <!ENTITY fileMenu.accesskey       "F">
 <!ENTITY newNavigatorCmd.label        "New Window">
 <!ENTITY newNavigatorCmd.key        "N">
--- 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;
 }
@@ -1922,26 +1946,26 @@ panel[dimmed="true"] {
 }
 
 /* Highlighter */
 
 .highlighter-veil {
   background-color: rgba(0, 0, 0, 0.5);
 }
 
-#highlighter-close-button {
-  list-style-image: url("chrome://browser/skin/KUI-close.png");
-  top: 12px;
-  right: 12px;
-  cursor: pointer;
+#highlighter-closebutton {
+  list-style-image: url("moz-icon://stock/gtk-close?size=menu");
+  margin-top: 0;
+  margin-bottom: 0;
 }
 
-#highlighter-close-button:-moz-locale-dir(rtl)  {
-  right: auto;
-  left: 12px;
+#highlighter-closebutton > .toolbarbutton-icon {
+  /* XXX Buttons have padding in widget/ that we don't want here but can't override with good CSS, so we must
+     use evil CSS to give the impression of smaller content */
+  margin: -4px;
 }
 
 #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
   outline: 1px dashed rgba(255,255,255,0.5);
   outline-offset: -1px;
 }
 
@@ -1949,22 +1973,27 @@ panel[dimmed="true"] {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
 
 /* Highlighter toolbar */
 
 #inspector-toolbar {
   -moz-appearance: none;
-  padding: 0 3px 4px;
+  padding: 4px 3px;
   border-top: 1px solid hsla(210, 8%, 5%, .65);
   box-shadow: 0 1px 0 0 hsla(210, 16%, 76%, .2) inset;
   background-image: -moz-linear-gradient(top, hsl(210,11%,36%), hsl(210,11%,18%));
 }
 
+#inspector-toolbar[treepanel-open] {
+  padding-top: 0;
+  -moz-padding-end: 0;
+}
+
 #inspector-inspect-toolbutton,
 #inspector-tools > toolbarbutton {
   -moz-appearance: none;
   min-width: 78px;
   min-height: 22px;
   color: hsl(210,30%,85%);
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
   border: 1px solid hsla(210,8%,5%,.45);
@@ -2000,20 +2029,16 @@ panel[dimmed="true"] {
 
 /* Highlighter - toolbar resizers */
 
 .inspector-resizer {
   -moz-appearance: none;
   cursor: n-resize;
 }
 
-.inspector-resizer[disabled] {
-  visibility: hidden;
-}
-
 #inspector-top-resizer {
   background: none;
   height: 4px;
 }
 
 #inspector-end-resizer {
   width: 12px;
   height: 8px;
--- a/browser/themes/gnomestripe/browser/devtools/csshtmltree.css
+++ b/browser/themes/gnomestripe/browser/devtools/csshtmltree.css
@@ -182,9 +182,94 @@ a.link:visited {
 .userStyles {
   position: relative;
   top: 3px;
 }
 
 .userStyles,
 .userStylesLabel {
   cursor: pointer;
-}
\ No newline at end of file
+}
+
+/**
+ * CSS Rule View
+ */
+
+.ruleview {
+  background-color: #FFF;
+}
+
+.ruleview-rule-source {
+  background-color: -moz-dialog;
+  padding: 2px;
+}
+
+.ruleview-code {
+  padding: 2px;
+}
+
+.ruleview-propertylist {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+}
+
+.ruleview-enableproperty {
+  height: 10px;
+  width: 10px;
+  -moz-margin-start: 2px;
+  -moz-margin-end: 0;
+}
+
+.ruleview-expander {
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  background: url("chrome://browser/skin/devtools/arrows.png") 24px 0;
+  cursor: pointer;
+  -moz-margin-start: 2px;
+  -moz-margin-end: 5px;
+}
+
+.ruleview-expander[dir="rtl"] {
+  background-position: 16px 0;
+}
+
+.ruleview-expander.styleinspector-open {
+  background-position: 8px 0;
+}
+
+.ruleview-newproperty {
+  /* (enable checkbox width: 12px) + (expander width: 15px) */
+  -moz-margin-start: 27px;
+}
+
+.ruleview-propertyname {
+  display: inline-block;
+  padding: 1px 0;
+  cursor: text;
+  color: #0060C0;
+  text-decoration: inherit;
+}
+
+.ruleview-propertyvalue {
+  cursor: text;
+  text-decoration: inherit;
+}
+
+.ruleview-computedlist {
+  list-style: none;
+  padding: 0;
+}
+
+.ruleview-computed {
+  -moz-margin-start: 4em;
+}
+
+.ruleview-overridden {
+  text-decoration: line-through;
+}
+
+.styleinspector-propertyeditor {
+  border: 1px solid #CCC;
+  padding: 0;
+  -moz-box-shadow: 2px 2px 2px #CCC;
+}
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -2517,26 +2517,34 @@ panel[dimmed="true"] {
 
 
 /* Highlighter */
 
 .highlighter-veil {
   background-color: rgba(0, 0, 0, 0.5);
 }
 
-#highlighter-close-button {
-  list-style-image: url("chrome://browser/skin/KUI-close.png");
-  top: 12px;
-  right: 12px;
-  cursor: pointer;
-}
-
-#highlighter-close-button:-moz-locale-dir(rtl)  {
-  right: auto;
-  left: 12px;
+#highlighter-closebutton {
+  list-style-image: url("chrome://browser/skin/devtools/toolbarbutton-close.png");
+  -moz-image-region: rect(0, 16px, 16px, 0);
+  min-width: 16px;
+  width: 16px;
+  margin: 0 4px;
+}
+
+#highlighter-closebutton > .toolbarbutton-text {
+  display: none;
+}
+
+#highlighter-closebutton:hover {
+  -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+#highlighter-closebutton:active {
+  -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
   outline: 1px dashed rgba(255,255,255,0.5);
   outline-offset: -1px;
 }
 
@@ -2544,20 +2552,24 @@ panel[dimmed="true"] {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
 
 /* Highlighter toolbar */
 
 #inspector-toolbar {
   -moz-appearance: none;
-  padding: 0 3px 4px;
   border-top: 1px solid hsla(210, 8%, 5%, .65);
   box-shadow: 0 1px 0 0 hsla(210, 16%, 76%, .2) inset;
   background-image: -moz-linear-gradient(top, hsl(210,11%,36%), hsl(210,11%,18%));
+  padding: 4px 16px 4px 0; /* use -moz-padding-end: 16px when/if bug 631729 gets fixed */
+}
+
+#inspector-toolbar[treepanel-open] {
+  padding: 0 0 4px;
 }
 
 #inspector-inspect-toolbutton,
 #inspector-tools > toolbarbutton {
   -moz-appearance: none;
   min-width: 78px;
   min-height: 22px;
   color: hsl(210,30%,85%);
@@ -2595,20 +2607,16 @@ panel[dimmed="true"] {
 
 /* Highlighter - toolbar resizers */
 
 .inspector-resizer {
   -moz-appearance: none;
   cursor: n-resize;
 }
 
-.inspector-resizer[disabled] {
-  visibility: hidden;
-}
-
 #inspector-top-resizer {
   background: none;
   height: 4px;
 }
 
 #inspector-end-resizer {
   width: 12px;
   height: 8px;
--- a/browser/themes/pinstripe/browser/devtools/csshtmltree.css
+++ b/browser/themes/pinstripe/browser/devtools/csshtmltree.css
@@ -182,9 +182,94 @@ a.link:visited {
 .userStyles {
   position: relative;
   top: 3px;
 }
 
 .userStyles,
 .userStylesLabel {
   cursor: pointer;
-}
\ No newline at end of file
+}
+
+/**
+ * CSS Rule View
+ */
+
+.ruleview {
+  background-color: #FFF;
+}
+
+.ruleview-rule-source {
+  background-color: -moz-dialog;
+  padding: 2px;
+}
+
+.ruleview-code {
+  padding: 2px;
+}
+
+.ruleview-propertylist {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+}
+
+.ruleview-enableproperty {
+  height: 10px;
+  width: 10px;
+  -moz-margin-start: 2px;
+  -moz-margin-end: 0;
+}
+
+.ruleview-expander {
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  background: url("chrome://browser/skin/devtools/arrows.png") 24px 0;
+  cursor: pointer;
+  -moz-margin-start: 2px;
+  -moz-margin-end: 5px;
+}
+
+.ruleview-expander[dir="rtl"] {
+  background-position: 16px 0;
+}
+
+.ruleview-expander.styleinspector-open {
+  background-position: 8px 0;
+}
+
+.ruleview-newproperty {
+  /* (enable checkbox width: 12px) + (expander width: 15px) */
+  -moz-margin-start: 27px;
+}
+
+.ruleview-propertyname {
+  display: inline-block;
+  padding: 1px 0;
+  cursor: text;
+  color: #0060C0;
+  text-decoration: inherit;
+}
+
+.ruleview-propertyvalue {
+  cursor: text;
+  text-decoration: inherit;
+}
+
+.ruleview-computedlist {
+  list-style: none;
+  padding: 0;
+}
+
+.ruleview-computed {
+  -moz-margin-start: 4em;
+}
+
+.ruleview-overridden {
+  text-decoration: line-through;
+}
+
+.styleinspector-propertyeditor {
+  border: 1px solid #CCC;
+  padding: 0;
+  -moz-box-shadow: 2px 2px 2px #CCC;
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..887daf052a6eda0b463bd75ca65dd998449cd330
GIT binary patch
literal 1031
zc$@(T1o-=jP)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#3000BdNkl<Zc-qyL
z`%6;+6vrzxC|2N<)IIeV(`|0ri^4K3dk{pC6+J16%F13^Nf9Jj8A_#<W<vDRirxho
zK3ZkYHudh_HIt>573nYalmCEyzi@?1xZPj;#UDO+IOlt|^L6KJcihm>(3oaaUPSC3
z7!Sh0B%lFPf}o*>TJ|XV$pjD%CaORUwWDevZ2rQ<nMQMbO>~UzJ#Yr$JvG#_N6|mQ
znw*lM(;Mrc=?eul)Uszp0}zpPFqN^424sL>1}5W$U!r~sRDcJd3Y5uQ2M<}JhFbP0
z`om*%1}|z|;IlR|s(V^=tRJyN7$eui8a33iCzydnyY?M^ot!fBqHIEAu{lci<mSId
zyflb`DX2XL7r_18L-`)7&B0Hi6qF<;S)B*-j<?YSHPo_4(LWKnZXjy4Q9TKXmbY4M
zWG@DnNJM1Rx9Lf?rU-3RFE!M%XG8-|Pv<5SJ6<)lx@dyKzo>6%Vb1CHZwq0d1{9Z;
zRn+$X8T7l_B++8Ew<cO_uI5jI$Xt0v^#f|C9l<~Vh-vAWH=Q2;vi(O2j>5!u4BeM=
zAisdQ1({hlsG&Bf0Td#H!0$)HCWePc?m7NOhA?msoKH!eb*HQMSL49nL9wMx^ftQ%
zFXOL${cmT@nRk~4s10JkYcR!mj-M*ZZgfd$dk-DU+nt+tjPa?WlGP@2yoZ{Q2Ds<N
zmnseQ&B8klPVfTFXG^cfv8H0+45+l(Q{H&Iou4qcmk9oV+mSl6jx}mR7!bf`ox$YW
zx#z&P2A4RG<QzP@S#LB+tWl$8K%-n6<vQ^uR16e?%hQvr!iUz5b__3&7Pq(EVzcv&
z%c%)rpaVPa!`l4ZynT0W{YPOo*}5Yq2S@yaHEKc{n47k6rE+bQ>$D&vD_g}t5svo>
zcb;n#`2M@;OV7^+d7UJ?W5!czLVW_$qIG_(O##>DWMT2Dyc4Ih8S^HhV`BZ(sNKL?
z<<2W_0&G+<P>e&p*Z+6WhvA)An?`H0qk%WUTxIp`T9q3R(-$qNYHIbRbLVjnlHOpJ
zcoWQJW-YIvM)d|zT+iVd6PjR-vC6m5d2pxn^0oV^GiE<We3K;GQ=c)%n##A37j(^;
zJHOm$ifc#QN%Tf@2Xm~c9I+}vf5`BL9PR?R1a5$<;GE1A=2)YK+W&vZ^ahh#{_jfi
z;65M_#&S-ghFbQFrh)JcTXw9$VAUK{rV3ON#>07PsAZ4xQDWJORqJFEUleo_WsVwZ
z*)!S?a~cp25>%i@Gs45%Bwz$)6^zs>ALhn1{{Yzl!O-c}?LPnj002ovPDHLkV1g8J
B@QeTe
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -121,16 +121,17 @@ browser.jar:
   skin/classic/browser/tabview/search.png                   (tabview/search.png)
   skin/classic/browser/tabview/stack-expander.png           (tabview/stack-expander.png)
   skin/classic/browser/tabview/tabview.png                  (tabview/tabview.png)
   skin/classic/browser/tabview/tabview.css                  (tabview/tabview.css)
   skin/classic/browser/devtools/arrows.png                  (devtools/arrows.png)
   skin/classic/browser/devtools/search.png                  (devtools/search.png)
   skin/classic/browser/devtools/csshtmltree.css             (devtools/csshtmltree.css)
   skin/classic/browser/devtools/gcli.css                    (devtools/gcli.css)
+  skin/classic/browser/devtools/toolbarbutton-close.png     (devtools/toolbarbutton-close.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png              (devtools/breadcrumbs/ltr-end-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png     (devtools/breadcrumbs/ltr-end-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png             (devtools/breadcrumbs/ltr-end-selected.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-end.png                      (devtools/breadcrumbs/ltr-end.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-middle-pressed.png           (devtools/breadcrumbs/ltr-middle-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png  (devtools/breadcrumbs/ltr-middle-selected-pressed.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected.png          (devtools/breadcrumbs/ltr-middle-selected.png)
   skin/classic/browser/devtools/breadcrumbs/ltr-middle.png                   (devtools/breadcrumbs/ltr-middle.png)
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -2615,26 +2615,29 @@ panel[dimmed="true"] {
 }
 
 /* Highlighter */
 
 .highlighter-veil {
   background-color: rgba(0, 0, 0, 0.5);
 }
 
-#highlighter-close-button {
-  list-style-image: url("chrome://browser/skin/KUI-close.png");
-  top: 12px;
-  right: 12px;
-  cursor: pointer;
-}
-
-#highlighter-close-button:-moz-locale-dir(rtl)  {
-  right: auto;
-  left: 12px;
+#highlighter-closebutton {
+  list-style-image: url("chrome://browser/skin/devtools/toolbarbutton-close.png");
+  -moz-image-region: rect(0, 16px, 16px, 0);
+  min-width: 16px;
+  width: 16px;
+}
+
+#highlighter-closebutton:hover {
+  -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+#highlighter-closebutton:active {
+  -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
   outline: 1px dashed rgba(255,255,255,0.5);
   outline-offset: -1px;
 }
 
@@ -2642,22 +2645,27 @@ panel[dimmed="true"] {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
 
 /* Highlighter toolbar */
 
 #inspector-toolbar {
   -moz-appearance: none;
-  padding: 0 3px 4px;
+  padding: 4px 3px;
   border-top: 1px solid hsla(211,68%,6%,.65) !important;
   box-shadow: 0 1px 0 hsla(209,29%,72%,.25) inset;
   background-image: -moz-linear-gradient(top, hsl(209,18%,34%), hsl(210,24%,16%));
 }
 
+#inspector-toolbar[treepanel-open] {
+  padding-top: 0;
+  -moz-padding-end: 0;
+}
+
 #inspector-inspect-toolbutton,
 #inspector-tools > toolbarbutton {
   -moz-appearance: none;
   min-width: 78px;
   min-height: 22px;
   color: hsl(210,30%,85%);
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
   border: 1px solid hsla(211,68%,6%,.5);
@@ -2693,20 +2701,16 @@ panel[dimmed="true"] {
 
 /* Highlighter - toolbar resizers */
 
 .inspector-resizer {
   -moz-appearance: none;
   cursor: n-resize;
 }
 
-.inspector-resizer[disabled] {
-  visibility: hidden;
-}
-
 #inspector-top-resizer {
   background: none;
   height: 4px;
 }
 
 #inspector-end-resizer {
   width: 12px;
   height: 8px;
--- a/browser/themes/winstripe/browser/devtools/csshtmltree.css
+++ b/browser/themes/winstripe/browser/devtools/csshtmltree.css
@@ -182,9 +182,94 @@ a.link:visited {
 .userStyles {
   position: relative;
   top: 3px;
 }
 
 .userStyles,
 .userStylesLabel {
   cursor: pointer;
-}
\ No newline at end of file
+}
+
+/**
+ * CSS Rule View
+ */
+
+.ruleview {
+  background-color: #FFF;
+}
+
+.ruleview-rule-source {
+  background-color: -moz-dialog;
+  padding: 2px;
+}
+
+.ruleview-code {
+  padding: 2px;
+}
+
+.ruleview-propertylist {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+}
+
+.ruleview-enableproperty {
+  height: 10px;
+  width: 10px;
+  -moz-margin-start: 2px;
+  -moz-margin-end: 0;
+}
+
+.ruleview-expander {
+  display: inline-block;
+  width: 8px;
+  height: 8px;
+  background: url("chrome://browser/skin/devtools/arrows.png") 24px 0;
+  cursor: pointer;
+  -moz-margin-start: 2px;
+  -moz-margin-end: 5px;
+}
+
+.ruleview-expander[dir="rtl"] {
+  background-position: 16px 0;
+}
+
+.ruleview-expander.styleinspector-open {
+  background-position: 8px 0;
+}
+
+.ruleview-newproperty {
+  /* (enable checkbox width: 12px) + (expander width: 15px) */
+  -moz-margin-start: 27px;
+}
+
+.ruleview-propertyname {
+  display: inline-block;
+  padding: 1px 0;
+  cursor: text;
+  color: #0060C0;
+  text-decoration: inherit;
+}
+
+.ruleview-propertyvalue {
+  cursor: text;
+  text-decoration: inherit;
+}
+
+.ruleview-computedlist {
+  list-style: none;
+  padding: 0;
+}
+
+.ruleview-computed {
+  -moz-margin-start: 4em;
+}
+
+.ruleview-overridden {
+  text-decoration: line-through;
+}
+
+.styleinspector-propertyeditor {
+  border: 1px solid #CCC;
+  padding: 0;
+  -moz-box-shadow: 2px 2px 2px #CCC;
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4a58465b9b7ea3b3c7c14b36214524fb9b0e38b7
GIT binary patch
literal 898
zc$@)(1AY97P)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#30009?Nkl<Zc-qaD
z-%C?*7{<E^ys6=GX#TF*%%jfDG@>G?$RO%(D9DVE2wO>|IdyGXXbKuAMWsXumi@rW
zizxG=3lSo^$*@vs{TpxZ=io>?+i~PBx_CVA-uLse=lObewsj)1Carg5ulx8l>ikEo
z`ThB`CSjy(=l*>gv)qjuW-uASvcvAuAyldwlHG@8CuIRJG;-)bbn4h)nLJiwD;QXI
zVgb^ed4Z!F9MR(rht#I0ORduxSIl5w*-2RdPGw^6Zh7SQ%fnR!1Itb<0CjyvhP3AA
zOXt?Da^3BYD`qgT?4&fn^PSZ)tmf|fd~&a%LWcCpYeY?t8LySK1h|l$Enzj-?eR$0
zwr%G1W^plE(Sw0a7-0I->}l1E>J%SPL`{!bq5xynRi??w&KnY4h|1e=hurac5j8z#
zCZnt+Kw$G`xu)h`UyI03Wyjk>a-*mSQPX2)GO!5)=%A`8+|&1d`tt{jBWilg5(OCD
zQ7O08Y`<a1%hr%Aep{3``i6*_9y1taEdd(TRNIy<5>kUtnu9Vww;(Tq?TDHlGn0X}
z3$P-@a`Vg*1sJLH%V2rA45)fbN@QFOFQ{=uO^+FjvX%hnva%#tSSS%a@m4kYcqs&;
zrpF8h);0hd93E|&n3{QqsOi}Sc;NR*e_5IIsd^2=H2r<{2co9O%w&|c1UQ?SDa{21
z((ZPfW=ES_WbVs%L`{#G$-vqMSbp0eYI=47hI|#$Q(7wBdeW~#VLkZ;c@}I()byB{
z46NlTq^2(G6XvQK9cyVbPkyAS1yR#uW-|450sg+{(ee<90^F_eN|#}nM(5S=Q#Bs(
zcn~!`W+tPoCBPXq)u`sif`80k($hw<5X@j;?fwIms=C-ckErP}OBCR?-Wr|Tw@XML
zcR{zCE3f1Bl(ht?bGamtn=6fZd2(K_7xj8Y?{`E^j~NVXioXX4P%0hz%#N%g7-cO1
zPB@)XuOH5aoE*%?6*CxEc2fCMB5>U>76;VWty05QFtF^z0;K17E*^2DFCJH8C-qyl
z*5!&TW-zeqq%44U*TFp)O7_PXEIY9P{yjB&F_i2+EIaJ}4?m}M|5uu7lPWt&!KShM
Y8%Lp~>GYClRsaA107*qoM6N<$g8i4Sr2qf`
--- a/browser/themes/winstripe/browser/jar.mn
+++ b/browser/themes/winstripe/browser/jar.mn
@@ -105,16 +105,17 @@ browser.jar:
         skin/classic/browser/tabview/stack-expander.png             (tabview/stack-expander.png)
         skin/classic/browser/tabview/tabview.png                    (tabview/tabview.png)
         skin/classic/browser/tabview/tabview-inverted.png           (tabview/tabview-inverted.png)
         skin/classic/browser/tabview/tabview.css                    (tabview/tabview.css)
         skin/classic/browser/devtools/arrows.png                    (devtools/arrows.png)
         skin/classic/browser/devtools/search.png                    (devtools/search.png)
         skin/classic/browser/devtools/csshtmltree.css               (devtools/csshtmltree.css)
         skin/classic/browser/devtools/gcli.css                      (devtools/gcli.css)
+        skin/classic/browser/devtools/toolbarbutton-close.png       (devtools/toolbarbutton-close.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png              (devtools/breadcrumbs/ltr-end-pressed.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png     (devtools/breadcrumbs/ltr-end-selected-pressed.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png             (devtools/breadcrumbs/ltr-end-selected.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-end.png                      (devtools/breadcrumbs/ltr-end.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-middle-pressed.png           (devtools/breadcrumbs/ltr-middle-pressed.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png  (devtools/breadcrumbs/ltr-middle-selected-pressed.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-middle-selected.png          (devtools/breadcrumbs/ltr-middle-selected.png)
         skin/classic/browser/devtools/breadcrumbs/ltr-middle.png                   (devtools/breadcrumbs/ltr-middle.png)
@@ -256,16 +257,17 @@ browser.jar:
         skin/classic/aero/browser/tabview/stack-expander.png         (tabview/stack-expander.png)
         skin/classic/aero/browser/tabview/tabview.png                (tabview/tabview.png)
         skin/classic/aero/browser/tabview/tabview-inverted.png       (tabview/tabview-inverted.png)
         skin/classic/aero/browser/tabview/tabview.css                (tabview/tabview.css)
         skin/classic/aero/browser/devtools/arrows.png                (devtools/arrows.png)
         skin/classic/aero/browser/devtools/search.png                (devtools/search.png)
         skin/classic/aero/browser/devtools/csshtmltree.css           (devtools/csshtmltree.css)
         skin/classic/aero/browser/devtools/gcli.css                  (devtools/gcli.css)
+        skin/classic/aero/browser/devtools/toolbarbutton-close.png   (devtools/toolbarbutton-close.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-end-pressed.png              (devtools/breadcrumbs/ltr-end-pressed.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png     (devtools/breadcrumbs/ltr-end-selected-pressed.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-end-selected.png             (devtools/breadcrumbs/ltr-end-selected.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-end.png                      (devtools/breadcrumbs/ltr-end.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-middle-pressed.png           (devtools/breadcrumbs/ltr-middle-pressed.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-middle-selected-pressed.png  (devtools/breadcrumbs/ltr-middle-selected-pressed.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-middle-selected.png          (devtools/breadcrumbs/ltr-middle-selected.png)
         skin/classic/aero/browser/devtools/breadcrumbs/ltr-middle.png                   (devtools/breadcrumbs/ltr-middle.png)
--- 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/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -8354,42 +8354,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 +8448,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 +8501,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 +8602,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/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/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -55,25 +55,25 @@
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 #include "mozilla/dom/StorageChild.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 #include "mozilla/jsipc/PContextWrapperChild.h"
 #include "mozilla/net/NeckoChild.h"
+#include "mozilla/Preferences.h"
 
 #if defined(MOZ_SYDNEYAUDIO)
 #include "nsAudioStream.h"
 #endif
 #include "nsIMemoryReporter.h"
 #include "nsIObserverService.h"
 #include "nsTObserverArray.h"
 #include "nsIObserver.h"
-#include "nsIPrefService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsWeakReference.h"
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsJSEnvironment.h"
 #include "SandboxHal.h"
 
@@ -633,34 +633,24 @@ ContentChild::AddRemoteAlertObserver(con
     NS_ASSERTION(aObserver, "Adding a null observer?");
     mAlertObservers.AppendElement(new AlertObserver(aObserver, aData));
     return NS_OK;
 }
 
 bool
 ContentChild::RecvPreferenceUpdate(const PrefTuple& aPref)
 {
-    nsCOMPtr<nsIPrefServiceInternal> prefs = do_GetService("@mozilla.org/preferences-service;1");
-    if (!prefs)
-        return false;
-
-    prefs->SetPreference(&aPref);
-
+    Preferences::SetPreference(&aPref);
     return true;
 }
 
 bool
 ContentChild::RecvClearUserPreference(const nsCString& aPrefName)
 {
-    nsCOMPtr<nsIPrefServiceInternal> prefs = do_GetService("@mozilla.org/preferences-service;1");
-    if (!prefs)
-        return false;
-
-    prefs->ClearContentPref(aPrefName);
-
+    Preferences::ClearContentPref(aPrefName.get());
     return true;
 }
 
 bool
 ContentChild::RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData)
 {
     for (PRUint32 i = 0; i < mAlertObservers.Length();
          /*we mutate the array during the loop; ++i iff no mutation*/) {
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -46,17 +46,16 @@
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/Preferences.h"
 #include "nsHashPropertyBag.h"
 #include "nsIFilePicker.h"
 #include "nsIWindowWatcher.h"
 #include "nsIDOMWindow.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefBranch2.h"
-#include "nsIPrefService.h"
 #include "nsIPrefLocalizedString.h"
 #include "nsIObserverService.h"
 #include "nsContentUtils.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsChromeRegistryChrome.h"
@@ -456,17 +455,17 @@ ContentParent::IsAlive()
 {
     return mIsAlive;
 }
 
 bool
 ContentParent::RecvReadPrefsArray(InfallibleTArray<PrefTuple> *prefs)
 {
     EnsurePrefService();
-    mPrefService->MirrorPreferences(prefs);
+    Preferences::MirrorPreferences(prefs);
     return true;
 }
 
 bool
 ContentParent::RecvReadFontList(InfallibleTArray<FontListEntry>* retValue)
 {
 #ifdef ANDROID
     gfxAndroidPlatform::GetPlatform()->GetFontList(retValue);
@@ -702,43 +701,19 @@ ContentParent::Observe(nsISupports* aSub
     if (!strcmp(aTopic, "memory-pressure")) {
         unused << SendFlushMemory(nsDependentString(aData));
     }
     // listening for remotePrefs...
     else if (!strcmp(aTopic, "nsPref:changed")) {
         // We know prefs are ASCII here.
         NS_LossyConvertUTF16toASCII strData(aData);
 
-        nsCOMPtr<nsIPrefServiceInternal> prefService =
-          do_GetService("@mozilla.org/preferences-service;1");
-
-        bool prefNeedUpdate;
-        prefService->PrefHasUserValue(strData, &prefNeedUpdate);
-
-        // If the pref does not have a user value, check if it exist on the
-        // default branch or not
-        if (!prefNeedUpdate) {
-          nsCOMPtr<nsIPrefBranch> defaultBranch;
-          nsCOMPtr<nsIPrefService> prefsService = do_QueryInterface(prefService);
-          prefsService->GetDefaultBranch(nsnull, getter_AddRefs(defaultBranch));
-
-          PRInt32 prefType = nsIPrefBranch::PREF_INVALID;
-          defaultBranch->GetPrefType(strData.get(), &prefType);
-          prefNeedUpdate = (prefType != nsIPrefBranch::PREF_INVALID);
-        }
-
+        PrefTuple pref;
+        bool prefNeedUpdate = Preferences::MirrorPreference(strData.get(), &pref);
         if (prefNeedUpdate) {
-          // Pref was created, or previously existed and its value
-          // changed.
-          PrefTuple pref;
-#ifdef DEBUG
-          nsresult rv =
-#endif
-          prefService->MirrorPreference(strData, &pref);
-          NS_ASSERTION(NS_SUCCEEDED(rv), "Pref has value but can't mirror?");
           if (!SendPreferenceUpdate(pref)) {
               return NS_ERROR_NOT_AVAILABLE;
           }
         } else {
           // Pref wasn't found.  It was probably removed.
           if (!SendClearUserPreference(strData)) {
               return NS_ERROR_NOT_AVAILABLE;
           }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -236,17 +236,17 @@ private:
 
     // This is a cache of all of the memory reporters
     // registered in the child process.  To update this, one
     // can broadcast the topic "child-memory-reporter-request" using
     // the nsIObserverService.
     nsCOMArray<nsIMemoryReporter> mMemoryReporters;
 
     bool mIsAlive;
-    nsCOMPtr<nsIPrefServiceInternal> mPrefService;
+    nsCOMPtr<nsIPrefService> mPrefService;
 
     bool mSendPermissionUpdates;
 
     nsRefPtr<nsFrameMessageManager> mMessageManager;
 
     friend class CrashReporterParent;
 };
 
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.js
@@ -212,17 +212,17 @@ WifiGeoPositionProvider.prototype = {
     function encode(ap) {
       // make sure that the ssid doesn't contain any | chars.
       ap.ssid = ap.ssid.replace("|", "\\|");
       // gls service parses the | as fields
       return "&wifi=mac:"+ap.mac+"|ssid:"+ap.ssid+"|ss:"+ap.signal;
     };
 
     if (accessPoints) {
-        accessPoints.sort(sort).map(encode).join("");
+        providerUrl = providerUrl + accessPoints.sort(sort).map(encode).join("");
         // max length is 2k.  make sure we are under that
         let x = providerUrl.length - 2000;
         if (x >= 0) {
             // we need to trim
             let doomed = providerUrl.lastIndexOf("&", 2000);
             LOG("Doomed:"+doomed);
             providerUrl = providerUrl.substring(0, doomed);
         }
--- 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/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</