Merge from mozilla-central (objshrink, yay!)
authorDavid Anderson <danderson@mozilla.com>
Mon, 05 Dec 2011 16:57:50 -0800
changeset 82059 220dd5cad2ac17e53112582e5b007737ff77d586
parent 81686 cd45a4d73fed79ad4bb853cd3a3fda232ea8dbc4 (current diff)
parent 82058 fafaf614791f698e9f66902560206e37065eee39 (diff)
child 82060 08b94171c35f5614ab449ddc0da8b0e7da598bc3
push idunknown
push userunknown
push dateunknown
milestone11.0a1
Merge from mozilla-central (objshrink, yay!)
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessibilityService.h
accessible/src/base/nsCoreUtils.cpp
accessible/src/base/nsCoreUtils.h
accessible/src/base/nsRootAccessible.cpp
accessible/src/html/nsHTMLFormControlAccessible.cpp
accessible/src/html/nsHTMLFormControlAccessible.h
accessible/tests/mochitest/Makefile.in
accessible/tests/mochitest/test_elm_landmarks.html
accessible/tests/mochitest/test_elm_listbox.xul
accessible/tests/mochitest/test_elm_nsApplicationAcc.html
accessible/tests/mochitest/test_elm_plugin.html
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
browser/components/migration/src/nsBrowserProfileMigratorUtils.cpp
browser/components/migration/src/nsIEProfileMigrator.cpp
browser/components/migration/src/nsOperaProfileMigrator.cpp
browser/components/migration/src/nsOperaProfileMigrator.h
browser/components/migration/src/nsProfileMigrator.cpp
browser/components/migration/src/nsSafariProfileMigrator.cpp
browser/components/migration/src/nsSafariProfileMigrator.h
browser/components/tabview/groupitems.js
browser/components/tabview/search.js
browser/components/tabview/tabitems.js
browser/components/tabview/tabview.js
browser/components/tabview/test/Makefile.in
browser/components/tabview/ui.js
browser/devtools/highlighter/test/browser_inspector_bug_665880.js
browser/devtools/highlighter/test/browser_inspector_initialization.js
browser/devtools/highlighter/test/browser_inspector_registertools.js
browser/devtools/highlighter/test/browser_inspector_tab_switch.js
browser/devtools/highlighter/test/browser_inspector_treeSelection.js
build/mobile/devicemanagerADB.py
caps/src/nsScriptSecurityManager.cpp
config/autoconf.mk.in
configure.in
content/base/src/nsAttrAndChildArray.cpp
content/base/src/nsAttrAndChildArray.h
content/base/src/nsCSPService.cpp
content/base/src/nsEventSource.cpp
content/base/src/nsEventSource.h
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
content/base/src/nsGkAtomList.h
content/base/src/nsStyleLinkElement.cpp
content/base/src/nsTreeSanitizer.cpp
content/base/src/nsXHTMLContentSerializer.cpp
content/base/src/nsXMLContentSerializer.cpp
content/base/src/nsXMLContentSerializer.h
content/base/test/Makefile.in
content/canvas/src/CanvasUtils.cpp
content/canvas/src/CanvasUtils.h
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextValidate.cpp
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
content/canvas/test/webgl/disable-quickCheckAPI.patch
content/html/content/public/nsHTMLVideoElement.h
content/html/content/src/nsHTMLMediaElement.cpp
content/html/document/src/VideoDocument.cpp
content/html/document/src/nsHTMLDocument.cpp
content/media/nsMediaCache.cpp
content/media/nsMediaStream.cpp
content/xul/document/src/nsXULDocument.cpp
content/xul/document/src/nsXULDocument.h
content/xul/templates/src/nsRuleNetwork.cpp
content/xul/templates/src/nsRuleNetwork.h
dom/Makefile.in
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/dom-config.mk
dom/indexedDB/AsyncConnectionHelper.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBObjectStore.h
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IndexedDatabaseManager.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/locales/en-US/chrome/dom/dom.properties
dom/plugins/base/nsJSNPRuntime.cpp
dom/src/storage/nsDOMStorage.cpp
dom/workers/Events.cpp
dom/workers/Exceptions.cpp
dom/workers/File.cpp
dom/workers/RuntimeService.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerScope.cpp
dom/workers/XMLHttpRequest.cpp
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/html/nsHTMLCSSUtils.cpp
editor/libeditor/html/nsHTMLCSSUtils.h
editor/libeditor/html/nsHTMLEditRules.cpp
editor/libeditor/html/nsHTMLEditor.cpp
editor/libeditor/html/nsHTMLEditor.h
editor/libeditor/html/nsHTMLInlineTableEditor.cpp
editor/libeditor/text/nsPlaintextEditor.cpp
editor/libeditor/text/nsTextEditRules.cpp
extensions/cookie/nsCookiePermission.cpp
gfx/angle/README.mozilla
gfx/angle/angle-intrinsic-msvc2005.patch
gfx/angle/angle-limit-identifiers-to-250-chars.patch
gfx/angle/angle-renaming-debug.patch
gfx/angle/src/common/version.h
gfx/angle/src/compiler/OutputHLSL.cpp
gfx/angle/src/compiler/OutputHLSL.h
gfx/angle/src/compiler/ParseHelper.cpp
gfx/angle/src/libEGL/Display.cpp
gfx/angle/src/libGLESv2/Context.cpp
gfx/angle/src/libGLESv2/Context.h
gfx/angle/src/libGLESv2/libGLESv2.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderWGL.cpp
gfx/gl/WGLLibrary.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/src/nsScriptableRegion.cpp
image/src/RasterImage.cpp
image/test/mochitest/Makefile.in
js/jsd/jsd_val.c
js/src/configure.in
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/FoldConstants.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SemanticAnalysis.cpp
js/src/gc/Barrier.h
js/src/ion/Bailouts.cpp
js/src/ion/CodeGenerator.cpp
js/src/ion/Ion.cpp
js/src/ion/IonBuilder.cpp
js/src/ion/IonCode.h
js/src/ion/IonFrames.cpp
js/src/ion/IonFrames.h
js/src/ion/IonMacroAssembler.cpp
js/src/ion/IonMacroAssembler.h
js/src/ion/arm/CodeGenerator-arm.cpp
js/src/ion/shared/CodeGenerator-x86-shared.cpp
js/src/ion/x64/CodeGenerator-x64.cpp
js/src/ion/x86/CodeGenerator-x86.cpp
js/src/jit-test/tests/basic/bug685321.js
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi-tests/testConservativeGC.cpp
js/src/jsapi-tests/testVersion.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jscell.h
js/src/jsclass.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/jsgcmark.cpp
js/src/jsgcmark.h
js/src/jsgcstats.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsiter.cpp
js/src/jsiter.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsprobes.cpp
js/src/jspropertycache.cpp
js/src/jsproxy.cpp
js/src/jsprvtd.h
js/src/jspubtd.h
js/src/jsreflect.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jstypedarrayinlines.h
js/src/jsweakmap.cpp
js/src/jswrapper.cpp
js/src/jsxdrapi.h
js/src/jsxml.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastOps.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/LoopState.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/shell/js.cpp
js/src/shell/jsworkers.cpp
js/src/tests/js1_8_5/regress/jstests.list
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/RegExpObject-inl.h
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/src/vm/StackSpace.h
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCInlines.h
js/xpconnect/src/XPCJSID.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeInfo.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
js/xpconnect/tests/components/native/xpctest_params.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsDocumentViewer.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
layout/base/tests/test_reftests_with_caret.html
layout/build/Makefile.in
layout/build/nsLayoutModule.cpp
layout/generic/nsFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIFrame.h
layout/generic/nsSubDocumentFrame.cpp
layout/generic/nsSubDocumentFrame.h
layout/generic/nsTextFrameThebes.cpp
layout/generic/nsViewportFrame.cpp
layout/style/nsStyleTransformMatrix.cpp
layout/tables/crashtests/crashtests.list
layout/tables/nsCellMap.cpp
layout/xul/base/src/nsMenuPopupFrame.cpp
layout/xul/base/src/nsMenuPopupFrame.h
layout/xul/base/src/nsResizerFrame.cpp
layout/xul/base/src/nsTitleBarFrame.cpp
layout/xul/base/src/nsXULPopupManager.cpp
mobile/xul/installer/package-manifest.in
modules/libpref/src/init/all.js
netwerk/base/public/nsNetUtil.h
netwerk/base/src/nsSocketTransport2.cpp
netwerk/base/src/nsSocketTransportService2.cpp
netwerk/base/src/nsStandardURL.cpp
netwerk/base/src/nsURLHelper.cpp
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsDeleteDir.cpp
netwerk/cache/nsDeleteDir.h
netwerk/cache/nsDiskCacheDevice.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/nsAHttpConnection.h
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttp.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpConnection.h
netwerk/protocol/http/nsHttpConnectionInfo.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpHandler.h
netwerk/protocol/http/nsHttpPipeline.cpp
netwerk/protocol/http/nsHttpTransaction.cpp
netwerk/protocol/http/nsHttpTransaction.h
netwerk/test/TestCookie.cpp
security/manager/ssl/src/SSLServerCertVerification.cpp
security/manager/ssl/src/nsNSSCallbacks.cpp
security/manager/ssl/src/nsNSSCallbacks.h
security/manager/ssl/src/nsNSSCertificate.cpp
security/manager/ssl/src/nsNSSComponent.cpp
security/manager/ssl/src/nsNSSComponent.h
security/manager/ssl/src/nsNSSIOLayer.cpp
security/manager/ssl/src/nsNSSIOLayer.h
security/manager/ssl/src/nsSSLStatus.h
security/manager/ssl/src/nsSSLThread.cpp
security/manager/ssl/src/nsSSLThread.h
storage/src/mozStorageStatementJSHelper.cpp
storage/src/mozStorageStatementWrapper.cpp
toolkit/components/places/AsyncFaviconHelpers.cpp
toolkit/components/places/nsFaviconService.cpp
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/tests/cpp/test_IHistory.cpp
toolkit/components/places/tests/head_common.js
toolkit/components/places/tests/unit/test_favicons.js
toolkit/components/satchel/nsFormFillController.cpp
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/components/telemetry/TelemetryPing.js
toolkit/components/telemetry/tests/unit/test_TelemetryPing.js
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
toolkit/mozapps/extensions/AddonRepository.jsm
toolkit/mozapps/extensions/AddonUpdateChecker.jsm
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/extensions/content/extensions.js
toolkit/system/gnome/nsGSettingsService.cpp
toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
toolkit/xre/nsAppRunner.cpp
view/src/nsView.cpp
widget/public/nsIWidget.h
widget/src/android/nsAppShell.cpp
widget/src/android/nsAppShell.h
widget/src/cocoa/nsMacDockSupport.mm
widget/src/gtk2/nsWindow.cpp
widget/src/gtk2/nsWindow.h
widget/src/os2/nsWindow.cpp
widget/src/windows/GfxInfo.cpp
widget/src/windows/nsNativeThemeWin.cpp
widget/src/windows/nsTextStore.cpp
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindow.h
widget/src/xpwidgets/nsBaseWidget.cpp
widget/src/xpwidgets/nsBaseWidget.h
widget/src/xpwidgets/nsHTMLFormatConverter.cpp
widget/src/xpwidgets/nsPrintOptionsImpl.cpp
xpcom/base/nsStackWalk.cpp
xpcom/base/nsTraceRefcntImpl.cpp
xpinstall/Makefile.in
xpinstall/public/Makefile.in
xpinstall/public/nsIDOMInstallTriggerGlobal.h
xpinstall/public/nsIXPIDialogService.idl
xpinstall/public/nsIXPIInstallInfo.idl
xpinstall/public/nsIXPIProgressDialog.idl
xpinstall/public/nsIXPInstallManager.idl
xpinstall/public/nsPICertNotification.idl
xpinstall/public/nsSoftwareUpdateIIDs.h
xpinstall/public/xpinstall.js
xpinstall/src/CertReader.cpp
xpinstall/src/CertReader.h
xpinstall/src/Makefile.in
xpinstall/src/nsInstall.h
xpinstall/src/nsInstallTrigger.cpp
xpinstall/src/nsInstallTrigger.h
xpinstall/src/nsJSInstallTriggerGlobal.cpp
xpinstall/src/nsSoftwareUpdate.cpp
xpinstall/src/nsXPIInstallInfo.cpp
xpinstall/src/nsXPIInstallInfo.h
xpinstall/src/nsXPITriggerInfo.cpp
xpinstall/src/nsXPITriggerInfo.h
xpinstall/src/nsXPInstallManager.cpp
xpinstall/src/nsXPInstallManager.h
xpinstall/test/pre_checkin.xpi
xpinstall/test/pre_checkin_trigger.html
xpinstall/test/testXPIDialogService.js
xpinstall/tests/Makefile.in
xpinstall/tests/authRedirect.sjs
xpinstall/tests/browser_auth.js
xpinstall/tests/browser_auth2.js
xpinstall/tests/browser_auth3.js
xpinstall/tests/browser_badhash.js
xpinstall/tests/browser_badhashtype.js
xpinstall/tests/browser_bug540558.js
xpinstall/tests/browser_cancel.js
xpinstall/tests/browser_chrome.js
xpinstall/tests/browser_cookies.js
xpinstall/tests/browser_cookies2.js
xpinstall/tests/browser_cookies3.js
xpinstall/tests/browser_cookies4.js
xpinstall/tests/browser_corrupt.js
xpinstall/tests/browser_empty.js
xpinstall/tests/browser_enabled.js
xpinstall/tests/browser_enabled2.js
xpinstall/tests/browser_enabled3.js
xpinstall/tests/browser_hash.js
xpinstall/tests/browser_installchrome.js
xpinstall/tests/browser_localfile.js
xpinstall/tests/browser_localfile2.js
xpinstall/tests/browser_navigateaway.js
xpinstall/tests/browser_navigateaway2.js
xpinstall/tests/browser_offline.js
xpinstall/tests/browser_opendialog.js
xpinstall/tests/browser_signed_multiple.js
xpinstall/tests/browser_signed_naming.js
xpinstall/tests/browser_signed_tampered.js
xpinstall/tests/browser_signed_trigger.js
xpinstall/tests/browser_signed_untrusted.js
xpinstall/tests/browser_signed_url.js
xpinstall/tests/browser_softwareupdate.js
xpinstall/tests/browser_unsigned_trigger.js
xpinstall/tests/browser_unsigned_url.js
xpinstall/tests/browser_whitelist.js
xpinstall/tests/browser_whitelist2.js
xpinstall/tests/browser_whitelist3.js
xpinstall/tests/browser_whitelist4.js
xpinstall/tests/browser_whitelist5.js
xpinstall/tests/browser_whitelist6.js
xpinstall/tests/bug540558.html
xpinstall/tests/cookieRedirect.sjs
xpinstall/tests/corrupt.xpi
xpinstall/tests/empty.xpi
xpinstall/tests/enabled.html
xpinstall/tests/harness.js
xpinstall/tests/installchrome.html
xpinstall/tests/installtrigger.html
xpinstall/tests/signed-no-cn.xpi
xpinstall/tests/signed-no-o.xpi
xpinstall/tests/signed-tampered.xpi
xpinstall/tests/signed-untrusted.xpi
xpinstall/tests/signed.xpi
xpinstall/tests/signed2.xpi
xpinstall/tests/startsoftwareupdate.html
xpinstall/tests/unsigned.xpi
--- a/accessible/public/nsIAccessibleRole.idl
+++ b/accessible/public/nsIAccessibleRole.idl
@@ -783,14 +783,19 @@ interface nsIAccessibleRole : nsISupport
 
   /**
    * A note. Originally intended to be hidden until activated, but now also used
    * for things like html 'aside'.
    */
   const unsigned long ROLE_NOTE = 123;
 
   /**
+   * A figure. Used for things like HTML5 figure element.
+   */
+  const unsigned long ROLE_FIGURE = 124;
+
+  /**
    * It's not role actually. This constant is important to help ensure
    * nsRoleMap's are synchronized.
    */
-  const unsigned long ROLE_LAST_ENTRY = 124;
+  const unsigned long ROLE_LAST_ENTRY = 125;
 };
 
--- a/accessible/src/atk/nsMaiInterfaceDocument.cpp
+++ b/accessible/src/atk/nsMaiInterfaceDocument.cpp
@@ -76,34 +76,16 @@ getDocumentLocaleCB(AtkDocument *aDocume
     nsAutoString locale;
     docAccessNode->GetLanguage(locale);
     if (locale.IsEmpty()) {
       return nsnull;
     }
     return nsAccessibleWrap::ReturnString(locale);
 }
 
-const gchar *
-getDocumentTypeCB(AtkDocument *aDocument)
-{
-    nsAccessibleWrap *accWrap = GetAccessibleWrap(ATK_OBJECT(aDocument));
-    if (!accWrap)
-        return nsnull;
-
-    nsCOMPtr<nsIAccessibleDocument> accDocument;
-    accWrap->QueryInterface(NS_GET_IID(nsIAccessibleDocument),
-                            getter_AddRefs(accDocument));
-    NS_ENSURE_TRUE(accDocument, nsnull);
-
-    nsAutoString mimeType;
-    nsresult rv = accDocument->GetMimeType(mimeType);
-    NS_ENSURE_SUCCESS(rv, nsnull);
-    return nsAccessibleWrap::ReturnString(mimeType);
-}
-
 static inline GSList *
 prependToList(GSList *aList, const char *const aName, const nsAutoString &aValue)
 {
     // libspi will free these
     AtkAttribute *atkAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
     atkAttr->name = g_strdup(aName);
     atkAttr->value = g_strdup(NS_ConvertUTF16toUTF8(aValue).get());
     return g_slist_prepend(aList, atkAttr);
--- a/accessible/src/atk/nsRoleMap.h
+++ b/accessible/src/atk/nsRoleMap.h
@@ -164,11 +164,12 @@ static const PRUint32 atkRoleMap[] = {
     ATK_ROLE_IMAGE,               // nsIAccessibleRole::ROLE_IMAGE_MAP            116
     ATK_ROLE_LIST_ITEM,           // nsIAccessibleRole::ROLE_OPTION               117
     ATK_ROLE_LIST_ITEM,           // nsIAccessibleRole::ROLE_RICH_OPTION          118
     ATK_ROLE_LIST,                // nsIAccessibleRole::ROLE_LISTBOX              119
     ATK_ROLE_UNKNOWN,             // nsIAccessibleRole::ROLE_FLAT_EQUATION        120
     ATK_ROLE_TABLE_CELL,          // nsIAccessibleRole::ROLE_GRID_CELL            121
     ATK_ROLE_PANEL,               // nsIAccessibleRole::ROLE_EMBEDDED_OBJECT      122
     ATK_ROLE_SECTION,             // nsIAccessibleRole::ROLE_NOTE                 123
+    ATK_ROLE_PANEL,               // nsIAccessibleRole::ROLE_FIGURE               124
     kROLE_ATK_LAST_ENTRY          // nsIAccessibleRole::ROLE_LAST_ENTRY
 };
 
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1600,17 +1600,30 @@ nsAccessibilityService::CreateAccessible
 }
 
 already_AddRefed<nsAccessible>
 nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
                                                      nsIContent* aContent,
                                                      nsIWeakReference* aWeakShell)
 {
   // This method assumes we're in an HTML namespace.
-  nsIAtom *tag = aContent->Tag();
+  nsIAtom* tag = aContent->Tag();
+  if (tag == nsGkAtoms::figcaption) {
+    nsAccessible* accessible =
+      new nsHTMLFigcaptionAccessible(aContent, aWeakShell);
+    NS_IF_ADDREF(accessible);
+    return accessible;
+  }
+
+  if (tag == nsGkAtoms::figure) {
+    nsAccessible* accessible = new nsHTMLFigureAccessible(aContent, aWeakShell);
+    NS_IF_ADDREF(accessible);
+    return accessible;
+  }
+
   if (tag == nsGkAtoms::legend) {
     nsAccessible* accessible = new nsHTMLLegendAccessible(aContent, aWeakShell);
     NS_IF_ADDREF(accessible);
     return accessible;
   }
 
   if (tag == nsGkAtoms::option) {
     nsAccessible* accessible = new nsHTMLSelectOptionAccessible(aContent,
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -419,17 +419,18 @@ static const char kRoleNames[][20] = {
   "combobox option",     //ROLE_COMBOBOX_OPTION
   "image map",           //ROLE_IMAGE_MAP
   "listbox option",      //ROLE_OPTION
   "listbox rich option", //ROLE_RICH_OPTION
   "listbox",             //ROLE_LISTBOX
   "flat equation",       //ROLE_FLAT_EQUATION
   "gridcell",            //ROLE_GRID_CELL
   "embedded object",     //ROLE_EMBEDDED_OBJECT
-  "note"                 //ROLE_NOTE
+  "note",                //ROLE_NOTE
+  "figure"               //ROLE_FIGURE
 };
 
 /**
  * Map nsIAccessibleEvents constants to strings. Used by
  * nsIAccessibleRetrieval::getStringEventType() method.
  */
 static const char kEventTypeNames[][40] = {
   "unknown",                                 //
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -655,32 +655,16 @@ nsCoreUtils::GetFirstSensibleColumn(nsIT
   nsCOMPtr<nsITreeColumn> column;
   cols->GetFirstColumn(getter_AddRefs(column));
   if (column && IsColumnHidden(column))
     return GetNextSensibleColumn(column);
 
   return column.forget();
 }
 
-already_AddRefed<nsITreeColumn>
-nsCoreUtils::GetLastSensibleColumn(nsITreeBoxObject *aTree)
-{
-  nsCOMPtr<nsITreeColumns> cols;
-  aTree->GetColumns(getter_AddRefs(cols));
-  if (!cols)
-    return nsnull;
-
-  nsCOMPtr<nsITreeColumn> column;
-  cols->GetLastColumn(getter_AddRefs(column));
-  if (column && IsColumnHidden(column))
-    return GetPreviousSensibleColumn(column);
-
-  return column.forget();
-}
-
 PRUint32
 nsCoreUtils::GetSensibleColumnCount(nsITreeBoxObject *aTree)
 {
   PRUint32 count = 0;
 
   nsCOMPtr<nsITreeColumns> cols;
   aTree->GetColumns(getter_AddRefs(cols));
   if (!cols)
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -323,22 +323,16 @@ public:
 
   /**
    * Return first sensible column for the given tree box object.
    */
   static already_AddRefed<nsITreeColumn>
     GetFirstSensibleColumn(nsITreeBoxObject *aTree);
 
   /**
-   * Return last sensible column for the given tree box object.
-   */
-  static already_AddRefed<nsITreeColumn>
-    GetLastSensibleColumn(nsITreeBoxObject *aTree);
-
-  /**
    * Return sensible columns count for the given tree box object.
    */
   static PRUint32 GetSensibleColumnCount(nsITreeBoxObject *aTree);
 
   /**
    * Return sensible column at the given index for the given tree box object.
    */
   static already_AddRefed<nsITreeColumn>
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -391,30 +391,31 @@ nsRootAccessible::ProcessDOMEvent(nsIDOM
   nsINode* targetNode = accessible->GetNode();
 
 #ifdef MOZ_XUL
   nsRefPtr<nsXULTreeAccessible> treeAcc;
   if (targetNode->IsElement() &&
       targetNode->AsElement()->NodeInfo()->Equals(nsGkAtoms::tree,
                                                   kNameSpaceID_XUL)) {
     treeAcc = do_QueryObject(accessible);
-
-    if (eventType.EqualsLiteral("TreeViewChanged")) {
-      treeAcc->TreeViewChanged();
-      return;
-    }
+    if (treeAcc) {
+      if (eventType.EqualsLiteral("TreeViewChanged")) {
+        treeAcc->TreeViewChanged();
+        return;
+      }
 
-    if (eventType.EqualsLiteral("TreeRowCountChanged")) {
-      HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
-      return;
-    }
+      if (eventType.EqualsLiteral("TreeRowCountChanged")) {
+        HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc);
+        return;
+      }
 
-    if (eventType.EqualsLiteral("TreeInvalidated")) {
-      HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
-      return;
+      if (eventType.EqualsLiteral("TreeInvalidated")) {
+        HandleTreeInvalidatedEvent(aDOMEvent, treeAcc);
+        return;
+      }
     }
   }
 #endif
 
   if (eventType.EqualsLiteral("RadioStateChange")) {
     PRUint64 state = accessible->State();
 
     // radiogroup in prefWindow is exposed as a list,
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -788,8 +788,111 @@ nsHTMLLegendAccessible::RelationByType(P
   return rel;
 }
 
 PRUint32
 nsHTMLLegendAccessible::NativeRole()
 {
   return nsIAccessibleRole::ROLE_LABEL;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLFigureAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+nsHTMLFigureAccessible::
+  nsHTMLFigureAccessible(nsIContent* aContent, nsIWeakReference* aShell) :
+  nsHyperTextAccessibleWrap(aContent, aShell)
+{
+}
+
+nsresult
+nsHTMLFigureAccessible::GetAttributesInternal(nsIPersistentProperties* aAttributes)
+{
+  nsresult rv = nsHyperTextAccessibleWrap::GetAttributesInternal(aAttributes);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Expose figure xml-role.
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::xmlroles,
+                         NS_LITERAL_STRING("figure"));
+  return NS_OK;
+}
+
+PRUint32
+nsHTMLFigureAccessible::NativeRole()
+{
+  return nsIAccessibleRole::ROLE_FIGURE;
+}
+
+nsresult
+nsHTMLFigureAccessible::GetNameInternal(nsAString& aName)
+{
+  nsresult rv = nsHyperTextAccessibleWrap::GetNameInternal(aName);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!aName.IsEmpty())
+    return NS_OK;
+
+  nsIContent* captionContent = Caption();
+  if (captionContent) {
+    return nsTextEquivUtils::
+      AppendTextEquivFromContent(this, captionContent, &aName);
+  }
+
+  return NS_OK;
+}
+
+Relation
+nsHTMLFigureAccessible::RelationByType(PRUint32 aType)
+{
+  Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
+  if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
+    rel.AppendTarget(Caption());
+
+  return rel;
+}
+
+nsIContent*
+nsHTMLFigureAccessible::Caption() const
+{
+  for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
+       childContent = childContent->GetNextSibling()) {
+    if (childContent->NodeInfo()->Equals(nsGkAtoms::figcaption,
+                                         mContent->GetNameSpaceID())) {
+      return childContent;
+    }
+  }
+
+  return nsnull;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsHTMLFigcaptionAccessible
+////////////////////////////////////////////////////////////////////////////////
+
+nsHTMLFigcaptionAccessible::
+  nsHTMLFigcaptionAccessible(nsIContent* aContent, nsIWeakReference* aShell) :
+  nsHyperTextAccessibleWrap(aContent, aShell)
+{
+}
+
+PRUint32
+nsHTMLFigcaptionAccessible::NativeRole()
+{
+  return nsIAccessibleRole::ROLE_CAPTION;
+}
+
+Relation
+nsHTMLFigcaptionAccessible::RelationByType(PRUint32 aType)
+{
+  Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
+  if (aType != nsIAccessibleRelation::RELATION_LABEL_FOR)
+    return rel;
+
+  nsAccessible* figure = Parent();
+  if (figure &&
+      figure->GetContent()->NodeInfo()->Equals(nsGkAtoms::figure,
+                                               mContent->GetNameSpaceID())) {
+    rel.AppendTarget(figure);
+  }
+
+  return rel;
+}
--- a/accessible/src/html/nsHTMLFormControlAccessible.h
+++ b/accessible/src/html/nsHTMLFormControlAccessible.h
@@ -223,9 +223,41 @@ class nsHTMLLegendAccessible : public ns
 public:
   nsHTMLLegendAccessible(nsIContent *aContent, nsIWeakReference *aShell);
 
   // nsAccessible
   virtual PRUint32 NativeRole();
   virtual Relation RelationByType(PRUint32 aType);
 };
 
-#endif  
+/**
+ * Accessible for HTML5 figure element.
+ */
+class nsHTMLFigureAccessible : public nsHyperTextAccessibleWrap
+{
+public:
+  nsHTMLFigureAccessible(nsIContent* aContent, nsIWeakReference* aShell);
+
+  // nsAccessible
+  virtual nsresult GetAttributesInternal(nsIPersistentProperties* aAttributes);
+  virtual nsresult GetNameInternal(nsAString& aName);
+  virtual PRUint32 NativeRole();
+  virtual Relation RelationByType(PRUint32 aType);
+
+protected:
+  nsIContent* Caption() const;
+};
+
+
+/**
+ * Accessible for HTML5 figcaption element.
+ */
+class nsHTMLFigcaptionAccessible : public nsHyperTextAccessibleWrap
+{
+public:
+  nsHTMLFigcaptionAccessible(nsIContent* aContent, nsIWeakReference* aShell);
+
+  // nsAccessible
+  virtual PRUint32 NativeRole();
+  virtual Relation RelationByType(PRUint32 aType);
+};
+
+#endif
--- a/accessible/src/mac/nsRoleMap.h
+++ b/accessible/src/mac/nsRoleMap.h
@@ -161,10 +161,11 @@ static const NSString* AXRoles [] = {
   NSAccessibilityImageRole,                     // ROLE_IMAGE_MAP
   NSAccessibilityRowRole,                       // ROLE_OPTION
   NSAccessibilityRowRole,                       // ROLE_RICH_OPTION
   NSAccessibilityListRole,                      // ROLE_LISTBOX
   NSAccessibilityUnknownRole,                   // ROLE_FLAT_EQUATION
   NSAccessibilityGroupRole,                     // ROLE_GRID_CELL
   NSAccessibilityGroupRole,                     // ROLE_EMBEDDED_OBJECT
   NSAccessibilityGroupRole,                     // ROLE_NOTE
+  NSAccessibilityGroupRole,                     // ROLE_FIGURE
   @"ROLE_LAST_ENTRY"                            // ROLE_LAST_ENTRY. bogus role that will never be shown (just marks the end of this array)!
 };
--- a/accessible/src/msaa/nsRoleMap.h
+++ b/accessible/src/msaa/nsRoleMap.h
@@ -441,12 +441,15 @@ static const WindowsRoleMapItem gWindows
   { ROLE_SYSTEM_CELL, ROLE_SYSTEM_CELL },
 
   // nsIAccessibleRole::ROLE_EMBEDDED_OBJECT
   { USE_ROLE_STRING, IA2_ROLE_EMBEDDED_OBJECT },
 
   // nsIAccessibleRole::ROLE_NOTE
   { USE_ROLE_STRING, IA2_ROLE_NOTE },
 
+  // nsIAccessibleRole::ROLE_FIGURE
+  { ROLE_SYSTEM_GROUPING, ROLE_SYSTEM_GROUPING },
+
   // nsIAccessibleRole::ROLE_LAST_ENTRY
   { ROLE_WINDOWS_LAST_ENTRY, ROLE_WINDOWS_LAST_ENTRY }
 };
 
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -41,16 +41,17 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = accessible
 
 DIRS	= \
   actions \
   attributes \
   editabletext \
+  elm \
   events \
   focus \
   hyperlink \
   hypertext \
   name \
   relations \
   selectable \
   states \
@@ -89,20 +90,16 @@ include $(topsrcdir)/config/rules.mk
 		test_aria_role_equation.html \
 		test_aria_roles.html \
 		test_aria_roles.xul \
 		test_aria_token_attrs.html \
 		test_bug420863.html \
 		test_childAtPoint.html \
 		test_childAtPoint.xul \
 		test_descr.html \
-		test_elm_landmarks.html \
-		test_elm_listbox.xul \
-		test_elm_nsApplicationAcc.html \
-		test_elm_plugin.html \
 		test_nsIAccessibleDocument.html \
 		test_nsIAccessibleImage.html \
 		test_nsIAccessNode_utils.html \
 		test_nsOuterDocAccessible.html \
 		test_role_nsHyperTextAcc.html \
 		test_text_caret.html \
 		test_textboxes.html \
 		test_textboxes.xul \
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/elm/Makefile.in
@@ -0,0 +1,57 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Alexander Surkov <surkov.alexander@gmail.com> (original author)
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of 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 *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = accessible/elm
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+
+_TEST_FILES =\
+		test_figure.html \
+		test_landmarks.html \
+		test_listbox.xul \
+		test_nsApplicationAcc.html \
+		test_plugin.html \
+		$(NULL)
+
+libs:: $(_TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/elm/test_figure.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>HTML5 figure/figcaption tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../attributes.js"></script>
+  <script type="application/javascript"
+          src="../relations.js"></script>
+  <script type="application/javascript"
+          src="../name.js"></script>
+
+  <script type="application/javascript">
+
+    function doTest()
+    {
+      testRole("figure", ROLE_FIGURE);
+      testRole("figcaption", ROLE_CAPTION);
+
+      todo(false, "figure name gets extra whitespace in the end!");
+      testName("figure", "figure caption ");
+      testName("figcaption", null);
+
+      testRelation("figure", RELATION_LABELLED_BY, "figcaption");
+      testRelation("figcaption", RELATION_LABEL_FOR, "figure");
+
+      testAttrs("figure", {"xml-roles" : "figure"}, true);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+    title="Implement figure and figcaption accessibility"
+    href="https://bugzilla.mozilla.org/show_bug.cgi?id=658272">
+     Mozilla Bug 658272
+  </a><br/>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <figure id="figure">
+    <figcaption id="figcaption">figure caption</figcaption>
+  </figure>
+
+</body>
+</html>
rename from accessible/tests/mochitest/test_elm_landmarks.html
rename to accessible/tests/mochitest/elm/test_landmarks.html
--- a/accessible/tests/mochitest/test_elm_landmarks.html
+++ b/accessible/tests/mochitest/elm/test_landmarks.html
@@ -4,21 +4,21 @@
   <title>HTML landmark tests</title>
   <link rel="stylesheet" type="text/css"
         href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
-          src="common.js"></script>
+          src="../common.js"></script>
   <script type="application/javascript"
-          src="role.js"></script>
+          src="../role.js"></script>
   <script type="application/javascript"
-          src="attributes.js"></script>
+          src="../attributes.js"></script>
 
   <script type="application/javascript">
 
     function doTest()
     {
       testRole("nav", ROLE_SECTION);
       testRole("header", ROLE_HEADER);
       testRole("footer", ROLE_FOOTER);
rename from accessible/tests/mochitest/test_elm_listbox.xul
rename to accessible/tests/mochitest/elm/test_listbox.xul
--- a/accessible/tests/mochitest/test_elm_listbox.xul
+++ b/accessible/tests/mochitest/elm/test_listbox.xul
@@ -5,19 +5,19 @@
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="XUL listbox element test.">
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
 
   <script type="application/javascript"
-          src="common.js"></script>
+          src="../common.js"></script>
   <script type="application/javascript"
-          src="role.js"></script>
+          src="../role.js"></script>
 
   <script type="application/javascript">
   <![CDATA[
     function doTest()
     {
       var id = "";
       var listbox = null, acc = null;
 
rename from accessible/tests/mochitest/test_elm_nsApplicationAcc.html
rename to accessible/tests/mochitest/elm/test_nsApplicationAcc.html
--- a/accessible/tests/mochitest/test_elm_nsApplicationAcc.html
+++ b/accessible/tests/mochitest/elm/test_nsApplicationAcc.html
@@ -3,19 +3,19 @@
 <head>
   <title>application accessible name</title>
   <link rel="stylesheet" type="text/css" 
          href="chrome://mochikit/content/tests/SimpleTest/test.css" />
   <script type="application/javascript" 
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript" 
-          src="common.js"></script>
+          src="../common.js"></script>
   <script type="application/javascript" 
-          src="role.js"></script>
+          src="../role.js"></script>
 
   <script type="application/javascript">
     function doTest()
     {
         var accessible = getApplicationAccessible();
         if (!accessible) {
           SimpleTest.finish();
           return;
rename from accessible/tests/mochitest/test_elm_plugin.html
rename to accessible/tests/mochitest/elm/test_plugin.html
--- a/accessible/tests/mochitest/test_elm_plugin.html
+++ b/accessible/tests/mochitest/elm/test_plugin.html
@@ -4,21 +4,21 @@
   <title>Plugin tests</title>
   <link rel="stylesheet" type="text/css"
         href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
 
   <script type="application/javascript"
-          src="common.js"></script>
+          src="../common.js"></script>
   <script type="application/javascript"
-          src="role.js"></script>
+          src="../role.js"></script>
   <script type="application/javascript"
-          src="states.js"></script>
+          src="../states.js"></script>
 
   <script type="application/javascript">
 
     function doTest()
     {
       if (!WIN) {
         ok(true,
            "Nothing to test because accessible plugins are supported on Windows only");
--- a/accessible/tests/mochitest/role.js
+++ b/accessible/tests/mochitest/role.js
@@ -15,16 +15,17 @@ const ROLE_CHROME_WINDOW = nsIAccessible
 const ROLE_COMBOBOX = nsIAccessibleRole.ROLE_COMBOBOX;
 const ROLE_COMBOBOX_LIST = nsIAccessibleRole.ROLE_COMBOBOX_LIST;
 const ROLE_COMBOBOX_OPTION = nsIAccessibleRole.ROLE_COMBOBOX_OPTION;
 const ROLE_COLUMNHEADER = nsIAccessibleRole.ROLE_COLUMNHEADER;
 const ROLE_DIALOG = nsIAccessibleRole.ROLE_DIALOG;
 const ROLE_DOCUMENT = nsIAccessibleRole.ROLE_DOCUMENT;
 const ROLE_EMBEDDED_OBJECT = nsIAccessibleRole.ROLE_EMBEDDED_OBJECT;
 const ROLE_ENTRY = nsIAccessibleRole.ROLE_ENTRY;
+const ROLE_FIGURE = nsIAccessibleRole.ROLE_FIGURE;
 const ROLE_FOOTER = nsIAccessibleRole.ROLE_FOOTER;
 const ROLE_FLAT_EQUATION = nsIAccessibleRole.ROLE_FLAT_EQUATION;
 const ROLE_FORM = nsIAccessibleRole.ROLE_FORM;
 const ROLE_GRAPHIC = nsIAccessibleRole.ROLE_GRAPHIC;
 const ROLE_GRID_CELL = nsIAccessibleRole.ROLE_GRID_CELL;
 const ROLE_GROUPING = nsIAccessibleRole.ROLE_GROUPING;
 const ROLE_HEADER = nsIAccessibleRole.ROLE_HEADER;
 const ROLE_HEADING = nsIAccessibleRole.ROLE_HEADING;
--- a/accessible/tests/mochitest/treeupdate/test_textleaf.html
+++ b/accessible/tests/mochitest/treeupdate/test_textleaf.html
@@ -91,33 +91,33 @@
 
       this.eventSeq = [
         new invokerChecker(EVENT_REORDER, this.containerNode)
       ];
 
       this.invoke = function removeTextData_invoke()
       {
         var tree = {
-          role: ROLE_SECTION,
+          role: ROLE_PARAGRAPH,
           children: [
             {
               role: ROLE_TEXT_LEAF,
               name: "text"
             }
           ]
         };
         testAccessibleTree(this.containerNode, tree);
 
         this.textNode.data = "";
       }
 
       this.finalCheck = function removeTextData_finalCheck()
       {
         var tree = {
-          role: ROLE_SECTION,
+          role: ROLE_PARAGRAPH,
           children: []
         };
         testAccessibleTree(this.containerNode, tree);
       }
 
       this.getID = function removeTextData_finalCheck()
       {
         return "remove text data of text node inside '" + aID + "'.";
@@ -142,17 +142,18 @@
       // remove onclick attribute, text leaf shouldn't have any action
       gQueue.push(new removeOnClickAttr("div"));
 
       // set onclick attribute making span accessible, it's inserted into tree
       // and adopts text leaf accessible, text leaf should have an action
       gQueue.push(new setOnClickNRoleAttrs("span"));
 
       // text data removal of text node should remove its text accessible
-      gQueue.push(new removeTextData("container2"));
+      gQueue.push(new removeTextData("p"));
+      gQueue.push(new removeTextData("pre"));
 
       gQueue.invoke(); // SimpleTest.finish() will be called in the end
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
@@ -163,24 +164,30 @@
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=545465">
     Mozilla Bug 545465
   </a>
   <a target="_blank"
      title="Make sure accessible tree is correct when rendered text is changed"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=625652">
     Mozilla Bug 625652
   </a>
+  <a target="_blank"
+     title="Remove text accesible getting no text inside a preformatted area"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=706335">
+    Mozilla Bug 706335
+  </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <div id="container">
     <div id="div">div</div>
     <span id="span">span</span>
   </div>
 
-  <div id="container2">text</div>
+  <p id="p">text</p>
+  <pre id="pre">text</pre>
 
   <div id="eventdump"></div>
 </body>
 </html>
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -81,16 +81,17 @@ if [ ! "$LIBXUL_SDK" ]; then
   if [ "$MOZ_MEMORY" ]; then
     add_makefiles "
       memory/jemalloc/Makefile
     "
   fi
   if [ "$MOZ_WIDGET_TOOLKIT" = "android" ]; then
     add_makefiles "
       other-licenses/android/Makefile
+      other-licenses/skia-npapi/Makefile
     "
   fi
 fi
 
 if [ "$OS_ARCH" = "WINNT" ]; then
   add_makefiles "
     build/win32/Makefile
     build/win32/crashinjectdll/Makefile
@@ -110,16 +111,19 @@ fi
 
 if [ "$COMPILER_DEPEND" = "" -a "$MOZ_NATIVE_MAKEDEPEND" = "" ]; then
   add_makefiles "
     config/mkdepend/Makefile
   "
 fi
 
 if [ "$ENABLE_TESTS" ]; then
+  add_makefiles "
+    build/autoconf/test/Makefile
+  "
   if [ "$_MSC_VER" -a "$OS_TEST" != "x86_64" ]; then
     add_makefiles "
       build/win32/vmwarerecordinghelper/Makefile
     "
   fi
   if [ "$OS_ARCH" != "WINNT" -a "$OS_ARCH" != "OS2" ]; then 
     add_makefiles "
       build/unix/test/Makefile
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -198,17 +198,17 @@ pref("app.update.incompatible.mode", 0);
 
 // Symmetric (can be overridden by individual extensions) update preferences.
 // e.g.
 //  extensions.{GUID}.update.enabled
 //  extensions.{GUID}.update.url
 //  .. etc ..
 //
 pref("extensions.update.enabled", true);
-pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%");
+pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
 pref("extensions.update.interval", 86400);  // Check for updates to Extensions and 
                                             // Themes every day
 // Non-symmetric (not shared by extensions) extension-specific [update] preferences
 pref("extensions.getMoreThemesURL", "https://addons.mozilla.org/%LOCALE%/firefox/getpersonas");
 pref("extensions.dss.enabled", false);          // Dynamic Skin Switching                                               
 pref("extensions.dss.switchPending", false);    // Non-dynamic switch pending after next
                                                 // restart.
 
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -203,16 +203,17 @@ let TabView = {
 
     // ___ find the deck
     this._deck = document.getElementById("tab-view-deck");
 
     // ___ create the frame
     this._iframe = document.createElement("iframe");
     this._iframe.id = "tab-view";
     this._iframe.setAttribute("transparent", "true");
+    this._iframe.setAttribute("tooltip", "tab-view-tooltip");
     this._iframe.flex = 1;
 
     let self = this;
 
     window.addEventListener("tabviewframeinitialized", function onInit() {
       window.removeEventListener("tabviewframeinitialized", onInit, false);
 
       self._isFrameLoading = false;
@@ -230,16 +231,22 @@ let TabView = {
         self._tabCloseEventListener = null;
       }
       self._initFrameCallbacks.forEach(function (cb) cb());
       self._initFrameCallbacks = [];
     }, false);
 
     this._iframe.setAttribute("src", "chrome://browser/content/tabview.html");
     this._deck.appendChild(this._iframe);
+
+    // ___ create tooltip
+    let tooltip = document.createElement("tooltip");
+    tooltip.id = "tab-view-tooltip";
+    tooltip.setAttribute("onpopupshowing", "return TabView.fillInTooltip(document.tooltipNode);");
+    document.getElementById("mainPopupSet").appendChild(tooltip);
   },
 
   // ----------
   getContentWindow: function TabView_getContentWindow() {
     return this._window;
   },
 
   // ----------
@@ -348,18 +355,20 @@ let TabView = {
         event.preventDefault();
 
         self._initFrame(function() {
           let groupItems = self._window.GroupItems;
           let tabItem = groupItems.getNextGroupItemTab(event.shiftKey);
           if (!tabItem)
             return;
 
-          // Switch to the new tab
-          window.gBrowser.selectedTab = tabItem.tab;
+          if (gBrowser.selectedTab.pinned)
+            groupItems.updateActiveGroupItemAndTabBar(tabItem, {dontSetActiveTabInGroup: true});
+          else
+            gBrowser.selectedTab = tabItem.tab;
         });
       }
     }, true);
   },
 
   // ----------
   // Prepares the tab view for undo close tab.
   prepareUndoCloseTab: function TabView_prepareUndoCloseTab(blankTabToRemove) {
@@ -435,10 +444,34 @@ let TabView = {
 
     // enable session restore if necessary
     if (Services.prefs.getIntPref(this.PREF_STARTUP_PAGE) != 3) {
       Services.prefs.setIntPref(this.PREF_STARTUP_PAGE, 3);
 
       // show banner
       this._window.UI.notifySessionRestoreEnabled();
     }
+  },
+
+  // ----------
+  // Function: fillInTooltip
+  // Fills in the tooltip text.
+  fillInTooltip: function fillInTooltip(tipElement) {
+    let retVal = false;
+    let titleText = null;
+    let direction = tipElement.ownerDocument.dir;
+
+    while (!titleText && tipElement) {
+      if (tipElement.nodeType == Node.ELEMENT_NODE)
+        titleText = tipElement.getAttribute("title");
+      tipElement = tipElement.parentNode;
+    }
+    let tipNode = document.getElementById("tab-view-tooltip");
+    tipNode.style.direction = direction;
+
+    if (titleText) {
+      tipNode.setAttribute("label", titleText);
+      retVal = true;
+    }
+
+    return retVal;
   }
 };
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3473,20 +3473,39 @@ const BrowserSearch = {
 
     // getSubmission can return null if the engine doesn't have a URL
     // with a text/html response type.  This is unlikely (since
     // SearchService._addEngineToStore() should fail for such an engine),
     // but let's be on the safe side.
     if (!submission)
       return;
 
+    let newTab;
+    function newTabHandler(event) {
+      newTab = event.target;
+    }
+    gBrowser.tabContainer.addEventListener("TabOpen", newTabHandler);
+
     openLinkIn(submission.uri.spec,
                useNewTab ? "tab" : "current",
                { postData: submission.postData,
                  relatedToCurrent: true });
+
+    gBrowser.tabContainer.removeEventListener("TabOpen", newTabHandler);
+    if (newTab && !newTab.selected) {
+      let tabSelected = false;
+      function tabSelectHandler() {
+        tabSelected = true;
+      }
+      newTab.addEventListener("TabSelect", tabSelectHandler);
+      setTimeout(function () {
+        newTab.removeEventListener("TabSelect", tabSelectHandler);
+        Services.telemetry.getHistogramById("FX_CONTEXT_SEARCH_AND_TAB_SELECT").add(tabSelected);
+      }, 5000);
+    }
   },
 
   /**
    * Returns the search bar element if it is present in the toolbar, null otherwise.
    */
   get searchBar() {
     return document.getElementById("searchbar");
   },
@@ -7654,17 +7673,18 @@ var FeedHandler = {
 
     browserForLink.feeds.push({ href: link.href, title: link.title });
 
     // If this addition was for the current browser, update the UI. For
     // background browsers, we'll update on tab switch.
     if (browserForLink == gBrowser.selectedBrowser) {
       // Batch updates to avoid updating the UI for multiple onLinkAdded events
       // fired within 100ms of each other.
-      clearTimeout(this._updateFeedTimeout);
+      if (this._updateFeedTimeout)
+        clearTimeout(this._updateFeedTimeout);
       this._updateFeedTimeout = setTimeout(this.updateFeeds.bind(this), 100);
     }
   }
 };
 
 /**
  * Re-open a closed tab.
  * @param aIndex
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -987,17 +987,17 @@ function makePreview(row)
     newImage.controls = true;
     isAudio = true;
 
     document.getElementById("theimagecontainer").collapsed = false;
     document.getElementById("brokenimagecontainer").collapsed = true;
   }
 #endif
   else {
-    // fallback image for protocols not allowed (e.g., data: or javascript:)
+    // fallback image for protocols not allowed (e.g., javascript:)
     // or elements not [yet] handled (e.g., object, embed).
     document.getElementById("brokenimagecontainer").collapsed = false;
     document.getElementById("theimagecontainer").collapsed = true;
   }
 
   var imageSize = "";
   if (url && !isAudio) {
     if (width != physWidth || height != physHeight) {
@@ -1223,13 +1223,11 @@ function selectImage()
       return;
     }
   }
 }
 
 function checkProtocol(img)
 {
   var url = img[COL_IMAGE_ADDRESS];
-  if (/^data:/.test(url) && /^image\//.test(img[COL_IMAGE_NODE].type))
-    return true;
-  const regex = /^(https?|ftp|file|about|chrome|resource):/;
-  return regex.test(url);
+  return /^data:image\//i.test(url) ||
+    /^(https?|ftp|file|about|chrome|resource):/.test(url);
 }
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -43,18 +43,16 @@ relativesrcdir  = browser/base/content/t
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
 		test_feed_discovery.html \
 		feed_discovery.html \
 		test_bug395533.html \
 		bug395533-data.txt \
-		test_contextmenu.html \
-		subtst_contextmenu.html \
 		ctxmenu-image.png \
 		video.ogg \
 		test_offlineNotification.html \
 		offlineChild.html \
 		offlineChild.cacheManifest \
 		offlineChild.cacheManifest^headers^ \
 		offlineChild2.html \
 		offlineChild2.cacheManifest \
@@ -67,16 +65,24 @@ include $(topsrcdir)/config/rules.mk
 		bug364677-data.xml^headers^ \
 		test_offline_gzip.html \
 		gZipOfflineChild.html \
 		gZipOfflineChild.html^headers^ \
 		gZipOfflineChild.cacheManifest \
 		gZipOfflineChild.cacheManifest^headers^ \
 		$(NULL)
 
+# test_contextmenu.html is disabled on Linux due to bug 513558
+ifneq (gtk2,$(MOZ_WIDGET_TOOLKIT))
+_TEST_FILES += \
+		test_contextmenu.html \
+		subtst_contextmenu.html \
+		$(NULL)
+endif
+
 # The following tests are disabled because they are unreliable:
 #   browser_bug423833.js is bug 428712
 #   browser_sanitize-download-history.js is bug 432425
 #
 # browser_sanitizeDialog_treeView.js is disabled until the tree view is added
 # back to the clear recent history dialog (santize.xul), if it ever is (bug
 # 480169)
 
--- a/browser/base/content/test/browser_customize.js
+++ b/browser/base/content/test/browser_customize.js
@@ -1,11 +1,12 @@
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
   var frame = document.getElementById("customizeToolbarSheetIFrame");
   frame.addEventListener("load", testCustomizeFrameLoadedPre, true);
 
   document.getElementById("cmd_CustomizeToolbars").doCommand();
 }
 
 function testCustomizeFrameLoadedPre(){
   // This load listener can be called before
--- a/browser/components/build/nsBrowserCompsCID.h
+++ b/browser/components/build/nsBrowserCompsCID.h
@@ -46,19 +46,16 @@
 #ifdef XP_MACOSX
 #define NS_SAFARIPROFILEMIGRATOR_CID \
 { 0x29e3b139, 0xad19, 0x44f3, { 0xb2, 0xc2, 0xe9, 0xf1, 0x3b, 0xa2, 0xbb, 0xc6 } }
 #endif
 
 #define NS_OPERAPROFILEMIGRATOR_CID \
 { 0xf34ff792, 0x722e, 0x4490, { 0xb1, 0x95, 0x47, 0xd2, 0x42, 0xed, 0xca, 0x1c } }
 
-#define NS_SEAMONKEYPROFILEMIGRATOR_CID \
-{ 0x9a28ffa7, 0xe6ef, 0x4b52, { 0xa1, 0x27, 0x6a, 0xd9, 0x51, 0xde, 0x8e, 0x9b } }
-
 #define NS_SHELLSERVICE_CID \
 { 0x63c7b9f4, 0xcc8, 0x43f8, { 0xb6, 0x66, 0xa, 0x66, 0x16, 0x55, 0xcb, 0x73 } }
 
 #define NS_SHELLSERVICE_CONTRACTID \
   "@mozilla.org/browser/shell-service;1"
 
 #define NS_RDF_FORWARDPROXY_INFER_DATASOURCE_CID \
 { 0x7a024bcf, 0xedd5, 0x4d9a, { 0x86, 0x14, 0xd4, 0x4b, 0xe1, 0xda, 0xda, 0xd3 } }
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -181,18 +181,18 @@ var MigrationWizard = {
       if (this._autoMigrate)
         this._wiz.currentPage.next = "homePageImport";
       else if (this._bookmarks)
         this._wiz.currentPage.next = "migrating"
       else
         this._wiz.currentPage.next = "importItems";
 
       var sourceProfiles = this._migrator.sourceProfiles;
-      if (sourceProfiles && sourceProfiles.Count() == 1) {
-        var profileName = sourceProfiles.QueryElementAt(0, Components.interfaces.nsISupportsString);
+      if (sourceProfiles && sourceProfiles.length == 1) {
+        var profileName = sourceProfiles.queryElementAt(0, Ci.nsISupportsString);
         this._selectedProfile = profileName.data;
       }
       else
         this._selectedProfile = "";
     }
   },
   
   // 2 - [Profile Selection]
@@ -206,20 +206,19 @@ var MigrationWizard = {
     var profiles = document.getElementById("profiles");
     while (profiles.hasChildNodes()) 
       profiles.removeChild(profiles.firstChild);
     
     // Note that this block is still reached even if the user chose 'From File'
     // and we canceled the dialog.  When that happens, _migrator will be null.
     if (this._migrator) {
       var sourceProfiles = this._migrator.sourceProfiles;
-      var count = sourceProfiles.Count();
-      for (var i = 0; i < count; ++i) {
+      for (var i = 0; i < sourceProfiles.length; ++i) {
         var item = document.createElement("radio");
-        var str = sourceProfiles.QueryElementAt(i, Components.interfaces.nsISupportsString);
+        var str = sourceProfiles.queryElementAt(i, Ci.nsISupportsString);
         item.id = str.data;
         item.setAttribute("label", str.data);
         profiles.appendChild(item);
       }
     }
     
     profiles.selectedItem = this._selectedProfile ? document.getElementById(this._selectedProfile) : profiles.firstChild;
   },
--- a/browser/components/migration/public/nsIBrowserProfileMigrator.idl
+++ b/browser/components/migration/public/nsIBrowserProfileMigrator.idl
@@ -31,20 +31,20 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
-interface nsISupportsArray;
+interface nsIArray;
 interface nsIProfileStartup;
 
-[scriptable, uuid(f8365b4a-da55-4e47-be7a-230142360f62)]
+[scriptable, uuid(5f445759-86a8-4dd3-ab84-4fc5341d9d9d)]
 interface nsIBrowserProfileMigrator : nsISupports 
 {
   /**
    * profile items to migrate. use with migrate().
    */
   const unsigned short ALL         = 0x0000;
   const unsigned short SETTINGS    = 0x0001;
   const unsigned short COOKIES     = 0x0002;
@@ -63,17 +63,18 @@ interface nsIBrowserProfileMigrator : ns
   void migrate(in unsigned short aItems, in nsIProfileStartup aStartup, in wstring aProfile);
 
   /**
    * A bit field containing profile items that this migrator
    * offers for import. 
    * @param   aProfile the profile that we are looking for available data
    *          to import
    * @param   aDoingStartup "true" if the profile is not currently being used.
-   * @returns bit field containing profile items (see above)
+   * @return  bit field containing profile items (see above)
+   * @note    a return value of 0 represents no items rather than ALL.
    */
   unsigned short getMigrateData(in wstring aProfile, in boolean aDoingStartup);
 
   /** 
    * Whether or not there is any data that can be imported from this 
    * browser (i.e. whether or not it is installed, and there exists
    * a user profile)
    */
@@ -84,15 +85,15 @@ interface nsIBrowserProfileMigrator : ns
    * has multiple user profiles configured.
    */
   readonly attribute boolean          sourceHasMultipleProfiles;
 
   /** 
    * An enumeration of available profiles. If the import source does 
    * not support profiles, this attribute is null.
    */
-  readonly attribute nsISupportsArray sourceProfiles;
-  
+  readonly attribute nsIArray         sourceProfiles;
+
   /**
    * The import source homepage.  Returns null if not present/available
    */
   readonly attribute AUTF8String      sourceHomePageURL;
 };
--- a/browser/components/migration/src/ChromeProfileMigrator.js
+++ b/browser/components/migration/src/ChromeProfileMigrator.js
@@ -34,16 +34,17 @@
  * 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 ***** */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
+const Cr = Components.results;
 
 const LOCAL_FILE_CID = "@mozilla.org/file/local;1";
 const FILE_INPUT_STREAM_CID = "@mozilla.org/network/file-input-stream;1";
 
 const BUNDLE_MIGRATION = "chrome://browser/locale/migration/migration.properties";
 
 const MIGRATE_ALL = 0x0000;
 const MIGRATE_SETTINGS = 0x0001;
@@ -67,31 +68,31 @@ XPCOMUtils.defineLazyGetter(this, "bookm
   let strbundle =
     Services.strings.createBundle(BUNDLE_MIGRATION);
   let sourceNameChrome = strbundle.GetStringFromName("sourceNameChrome");
   return strbundle.formatStringFromName("importedBookmarksFolder",
                                         [sourceNameChrome],
                                         1);
 });
 
-/*
+/**
  * Convert Chrome time format to Date object
  *
  * @param   aTime
  *          Chrome time 
  * @return  converted Date object
  * @note    Google Chrome uses FILETIME / 10 as time.
  *          FILETIME is based on same structure of Windows.
  */
 function chromeTimeToDate(aTime)
 {
   return new Date((aTime * S100NS_PER_MS - S100NS_FROM1601TO1970 ) / 10000);
 }
 
-/*
+/**
  * Insert bookmark items into specific folder.
  *
  * @param   aFolderId
  *          id of folder where items will be inserted
  * @param   aItems
  *          bookmark items to be inserted
  */
 function insertBookmarkItems(aFolderId, aItems)
@@ -124,51 +125,64 @@ function ChromeProfileMigrator()
 }
 
 ChromeProfileMigrator.prototype = {
   _paths: {
     bookmarks : null,
     cookies : null,
     history : null,
     prefs : null,
+    userData : null,
   },
 
   _homepageURL : null,
   _replaceBookmarks : false,
+  _sourceProfile: null,
+  _profilesCache: null,
 
-  /*
+  /**
    * Notify to observers to start migration
    *
    * @param   aType
    *          notification type such as MIGRATE_BOOKMARKS
    */
-
   _notifyStart : function Chrome_notifyStart(aType)
   {
     Services.obs.notifyObservers(null, "Migration:ItemBeforeMigrate", aType);
     this._pendingCount++;
   },
 
-  /*
+  /**
+   * Notify observers that a migration error occured with an item
+   *
+   * @param   aType
+   *          notification type such as MIGRATE_BOOKMARKS
+   */
+  _notifyError : function Chrome_notifyError(aType)
+  {
+    Services.obs.notifyObservers(null, "Migration:ItemError", aType);
+  },
+
+  /**
    * Notify to observers to finish migration for item
    * If all items are finished, it sends migration end notification.
    *
    * @param   aType
    *          notification type such as MIGRATE_BOOKMARKS
    */
   _notifyCompleted : function Chrome_notifyIfCompleted(aType)
   {
     Services.obs.notifyObservers(null, "Migration:ItemAfterMigrate", aType);
     if (--this._pendingCount == 0) {
       // All items are migrated, so we have to send end notification.
       Services.obs.notifyObservers(null, "Migration:Ended", null);
     }
   },
 
-  /*
+  /**
    * Migrating bookmark items
    */
   _migrateBookmarks : function Chrome_migrateBookmarks()
   {
     this._notifyStart(MIGRATE_BOOKMARKS);
 
     try {
       PlacesUtils.bookmarks.runInBatchMode({
@@ -219,21 +233,22 @@ ChromeProfileMigrator.prototype = {
             }
 
             migrator._notifyCompleted(MIGRATE_BOOKMARKS);
           });
         }
       }, null);
     } catch (e) {
       Cu.reportError(e);
+      this._notifyError(MIGRATE_BOOKMARKS);
       this._notifyCompleted(MIGRATE_BOOKMARKS);
     }
   },
 
-  /*
+  /**
    * Migrating history
    */
   _migrateHistory : function Chrome_migrateHistory()
   {
     this._notifyStart(MIGRATE_HISTORY);
 
     try {
       PlacesUtils.history.runInBatchMode({
@@ -293,21 +308,22 @@ ChromeProfileMigrator.prototype = {
               this._self._notifyCompleted(MIGRATE_HISTORY);
             }
           });
           stmt.finalize();
         }
       }, null);
     } catch (e) {
       Cu.reportError(e);
+      this._notifyError(MIGRATE_HISTORY);
       this._notifyCompleted(MIGRATE_HISTORY);
     }
   },
 
-  /*
+  /**
    * Migrating cookies
    */
   _migrateCookies : function Chrome_migrateCookies()
   {
     this._notifyStart(MIGRATE_COOKIES);
 
     try {
       // Access sqlite3 database of Chrome's cookie
@@ -354,41 +370,44 @@ ChromeProfileMigrator.prototype = {
         handleCompletion : function(aReason) {
           this._db.asyncClose();
           this._self._notifyCompleted(MIGRATE_COOKIES);
         },
       });
       stmt.finalize();
     } catch (e) {
       Cu.reportError(e);
+      this._notifyError(MIGRATE_COOKIES);
       this._notifyCompleted(MIGRATE_COOKIES);
     }
   },
 
-  /*
+  /**
    * nsIBrowserProfileMigrator interface implementation
    */
 
-  /*
+  /**
    * Let's migrate all items
    *
    * @param   aItems
-   *          list of data items to migrate.  but this is unused.
+   *          list of data items to migrate.
    * @param   aStartup
    *          non-null if called during startup.
    * @param   aProfile
-   *          this is unused due to single profile support only
+   *          profile directory name to migrate
    */
   migrate : function Chrome_migrate(aItems, aStartup, aProfile)
   {
     if (aStartup) {
       aStartup.doStartup();
       this._replaceBookmarks = true;
     }
 
+    this._sourceProfile = aProfile;
+
     Services.obs.notifyObservers(null, "Migration:Started", null);
 
     // Reset panding count.  If this count becomes 0, "Migration:Ended"
     // notification is sent
     this._pendingCount = 1;
 
     if (aItems & MIGRATE_HISTORY)
       this._migrateHistory();
@@ -402,112 +421,174 @@ ChromeProfileMigrator.prototype = {
     if (--this._pendingCount == 0) {
       // When async imports are immeditelly completed unfortunately,
       // this will be called.
       // Usually, this notification is sent by _notifyCompleted()
       Services.obs.notifyObservers(null, "Migration:Ended", null);
     }
   },
 
-  /*
+  /**
    * return supported migration types
    *
    * @param   aProfile
-   *          this is unused due to single profile support only
+   *          directory name of the profile
    * @param   aDoingStartup
    *          non-null if called during startup.
    * @return  supported migration types
    */
   getMigrateData: function Chrome_getMigrateData(aProfile, aDoingStartup)
   {
-#ifdef XP_WIN
-    let chromepath = Services.dirsvc.get("LocalAppData", Ci.nsIFile).path +
-                     "\\Google\\Chrome\\User Data\\Default\\";
-#elifdef XP_MACOSX
-    let chromepath = Services.dirsvc.get("Home", Ci.nsIFile).path +
-                     "/Library/Application Support/Google/Chrome/Default/";
-#else
-    let chromepath = Services.dirsvc.get("Home", Ci.nsIFile).path +
-                     "/.config/google-chrome/Default/";
-#endif
+    this._sourceProfile = aProfile;
+    let chromeProfileDir = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
+    chromeProfileDir.initWithPath(this._paths.userData + aProfile);
 
     let result = 0;
+    if (!chromeProfileDir.exists() || !chromeProfileDir.isReadable())
+      return result;
 
     // bookmark and preference are JSON format
 
     try {
-      let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-      file.initWithPath(chromepath + "Bookmarks");
+      let file = chromeProfileDir.clone();
+      file.append("Bookmarks");
       if (file.exists()) {
-        this._paths.bookmarks = file.path
+        this._paths.bookmarks = file.path;
         result += MIGRATE_BOOKMARKS;
       }
     } catch (e) {
       Cu.reportError(e);
     }
 
-    if (!this._paths.prefs)
-      this._paths.prefs = chromepath + "Preferences";
+    if (!this._paths.prefs) {
+      let file = chromeProfileDir.clone();
+      file.append("Preferences");
+      this._paths.prefs = file.path;
+    }
 
     // history and cookies are SQLite database
 
     try {
-      let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-      file.initWithPath(chromepath + "History");
+      let file = chromeProfileDir.clone();
+      file.append("History");
       if (file.exists()) {
-        this._paths.history = file.path
+        this._paths.history = file.path;
         result += MIGRATE_HISTORY;
       }
     } catch (e) {
       Cu.reportError(e);
     }
 
     try {
-      let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
-      file.initWithPath(chromepath + "Cookies");
+      let file = chromeProfileDir.clone();
+      file.append("Cookies");
       if (file.exists()) {
-        this._paths.cookies = file.path
+        this._paths.cookies = file.path;
         result += MIGRATE_COOKIES;
       }
     } catch (e) {
       Cu.reportError(e);
     }
 
     return result;
   },
 
-  /*
+  /**
    * Whether we support migration of Chrome
    *
    * @return true if supported
    */
   get sourceExists()
   {
-    let result = this.getMigrateData(null, false);
-    return result != 0;
+#ifdef XP_WIN
+    this._paths.userData = Services.dirsvc.get("LocalAppData", Ci.nsIFile).path +
+                            "\\Google\\Chrome\\User Data\\";
+#elifdef XP_MACOSX
+    this._paths.userData = Services.dirsvc.get("Home", Ci.nsIFile).path +
+                            "/Library/Application Support/Google/Chrome/";
+#else
+    this._paths.userData = Services.dirsvc.get("Home", Ci.nsIFile).path +
+                            "/.config/google-chrome/";
+#endif
+    let result = 0;
+    try {
+      let userDataDir = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
+      userDataDir.initWithPath(this._paths.userData);
+      if (!userDataDir.exists() || !userDataDir.isReadable())
+        return false;
+
+      let profiles = this.sourceProfiles;
+      if (profiles.length < 1)
+        return false;
+
+      // check that we can actually get data from the first profile
+      result = this.getMigrateData(profiles.queryElementAt(0, Ci.nsISupportsString), false);
+    } catch (e) {
+      Cu.reportError(e);
+    }
+    return result > 0;
+  },
+
+  get sourceHasMultipleProfiles()
+  {
+    return this.sourceProfiles.length > 1;
   },
 
-  // Although Chrome supports multi-profiles, there is no way
-  // to get profile lists.
-  sourceHasMultipleProfiles: false,
-  sourceProfiles: null,
+  get sourceProfiles()
+  {
+    let profiles = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
+    try {
+      if (!this._profilesCache) {
+        let localState = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
+        // Local State is a JSON file that contains profile info.
+        localState.initWithPath(this._paths.userData + "Local State");
+        if (!localState.exists())
+          throw new Components.Exception("Chrome's 'Local State' file does not exist.",
+                                         Cr.NS_ERROR_FILE_NOT_FOUND);
+        if (!localState.isReadable())
+          throw new Components.Exception("Chrome's 'Local State' file could not be read.",
+                                         Cr.NS_ERROR_FILE_ACCESS_DENIED);
+        let fstream = Cc[FILE_INPUT_STREAM_CID].createInstance(Ci.nsIFileInputStream);
+        fstream.init(localState, -1, 0, 0);
+        let inputStream = NetUtil.readInputStreamToString(fstream, fstream.available(),
+                                                          { charset: "UTF-8" });
+        this._profilesCache = JSON.parse(inputStream).profile.info_cache;
+      }
 
-  /*
+      for (let index in this._profilesCache) {
+        let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+        str.data = index;
+        profiles.appendElement(str, false);
+      }
+    } catch (e) {
+      Cu.reportError("Error detecting Chrome profiles: " + e);
+      // if we weren't able to detect any profiles above, fallback to the Default profile.
+      if (profiles.length < 1) {
+        let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+        // the default profile name is "Default"
+        str.data = "Default";
+        profiles.appendElement(str, false);
+      }
+    }
+    return profiles;
+  },
+
+  /**
    * Return home page URL
    *
    * @return  home page URL
    */
   get sourceHomePageURL()
   {
     try  {
       if (this._homepageURL)
         return this._homepageURL;
 
       if (!this._paths.prefs)
-        this.getMigrateData(null, false);
+        this.getMigrateData(this._sourceProfile, false);
 
       // XXX reading and parsing JSON is synchronous.
       let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile);
       file.initWithPath(this._paths.prefs);
       let fstream = Cc[FILE_INPUT_STREAM_CID].
                     createInstance(Ci.nsIFileInputStream);
       fstream.init(file, -1, 0, 0); 
       this._homepageURL = JSON.parse(
--- a/browser/components/migration/src/nsBrowserProfileMigratorUtils.cpp
+++ b/browser/components/migration/src/nsBrowserProfileMigratorUtils.cpp
@@ -49,17 +49,16 @@
 
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsISupportsPrimitives.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsIRDFService.h"
 #include "nsIStringBundle.h"
-#include "nsISupportsArray.h"
 #include "nsXPCOMCID.h"
 
 #define MIGRATION_BUNDLE "chrome://browser/locale/migration/migration.properties"
 
 #define BOOKMARKS_FILE_NAME NS_LITERAL_STRING("bookmarks.html")
 
 void SetUnicharPref(const char* aPref, const nsAString& aValue,
                     nsIPrefBranch* aPrefs)
--- a/browser/components/migration/src/nsIEProfileMigrator.cpp
+++ b/browser/components/migration/src/nsIEProfileMigrator.cpp
@@ -60,17 +60,16 @@
 #include "prlong.h"
 #include "nsICookieManager2.h"
 #include "nsIEProfileMigrator.h"
 #include "nsIFile.h"
 #include "nsILocalFile.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsISimpleEnumerator.h"
-#include "nsISupportsArray.h"
 #include "nsIProfileMigrator.h"
 #include "nsIBrowserProfileMigrator.h"
 #include "nsIObserverService.h"
 #include "nsILocalFileWin.h"
 #include "nsAutoPtr.h"
 
 #include "prnetdb.h"
 
@@ -481,17 +480,17 @@ nsIEProfileMigrator::GetSourceExists(boo
 NS_IMETHODIMP
 nsIEProfileMigrator::GetSourceHasMultipleProfiles(bool* aResult)
 {
   *aResult = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsIEProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
+nsIEProfileMigrator::GetSourceProfiles(nsIArray** aResult)
 {
   *aResult = nsnull;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsIEProfileMigrator::GetSourceHomePageURL(nsACString& aResult)
 {
--- a/browser/components/migration/src/nsOperaProfileMigrator.cpp
+++ b/browser/components/migration/src/nsOperaProfileMigrator.cpp
@@ -165,56 +165,56 @@ nsOperaProfileMigrator::GetMigrateData(c
                           aReplace, mOperaProfile, aResult);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsOperaProfileMigrator::GetSourceExists(bool* aResult)
 {
-  nsCOMPtr<nsISupportsArray> profiles;
+  nsCOMPtr<nsIArray> profiles;
   GetSourceProfiles(getter_AddRefs(profiles));
 
   if (profiles) { 
     PRUint32 count;
-    profiles->Count(&count);
+    profiles->GetLength(&count);
     *aResult = count > 0;
   }
   else
     *aResult = false;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsOperaProfileMigrator::GetSourceHasMultipleProfiles(bool* aResult)
 {
-  nsCOMPtr<nsISupportsArray> profiles;
+  nsCOMPtr<nsIArray> profiles;
   GetSourceProfiles(getter_AddRefs(profiles));
 
 #ifdef XP_WIN
   if (profiles) {
     PRUint32 count;
-    profiles->Count(&count);
+    profiles->GetLength(&count);
     *aResult = count > 1;
   }
   else
 #endif
     *aResult = false;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsOperaProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
+nsOperaProfileMigrator::GetSourceProfiles(nsIArray** aResult)
 {
   if (!mProfiles) {
     nsresult rv;
 
-    mProfiles = do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv);
+    mProfiles = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
     if (NS_FAILED(rv)) return rv;
 
     nsCOMPtr<nsIProperties> fileLocator(do_GetService("@mozilla.org/file/directory_service;1"));
     nsCOMPtr<nsILocalFile> file;
 #ifdef XP_WIN
     fileLocator->Get(NS_WIN_APPDATA_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(file));
 
     // Opera profile lives under %APP_DATA%\Opera\<operaver>\profile 
@@ -233,47 +233,47 @@ nsOperaProfileMigrator::GetSourceProfile
 
       bool isDirectory = false;
       curr->IsDirectory(&isDirectory);
       if (isDirectory) {
         nsCOMPtr<nsISupportsString> string(do_CreateInstance("@mozilla.org/supports-string;1"));
         nsAutoString leafName;
         curr->GetLeafName(leafName);
         string->SetData(leafName);
-        mProfiles->AppendElement(string);
+        mProfiles->AppendElement(string, false);
       }
 
       e->HasMoreElements(&hasMore);
     }
 #elif defined (XP_MACOSX)
     fileLocator->Get(NS_MAC_USER_LIB_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(file));
     
     file->Append(NS_LITERAL_STRING("Preferences"));
     file->Append(OPERA_PREFERENCES_FOLDER_NAME);
     
     bool exists;
     file->Exists(&exists);
     
     if (exists) {
       nsCOMPtr<nsISupportsString> string(do_CreateInstance("@mozilla.org/supports-string;1"));
       string->SetData(OPERA_PREFERENCES_FOLDER_NAME);
-      mProfiles->AppendElement(string);
+      mProfiles->AppendElement(string, false);
     }
 #elif defined (XP_UNIX)
     fileLocator->Get(NS_UNIX_HOME_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(file));
     
     file->Append(OPERA_PREFERENCES_FOLDER_NAME);
     
     bool exists;
     file->Exists(&exists);
     
     if (exists) {
       nsCOMPtr<nsISupportsString> string(do_CreateInstance("@mozilla.org/supports-string;1"));
       string->SetData(OPERA_PREFERENCES_FOLDER_NAME);
-      mProfiles->AppendElement(string);
+      mProfiles->AppendElement(string, false);
     }
 #endif
   }
 
   *aResult = mProfiles;
   NS_IF_ADDREF(*aResult);
   return NS_OK;
 }
--- a/browser/components/migration/src/nsOperaProfileMigrator.h
+++ b/browser/components/migration/src/nsOperaProfileMigrator.h
@@ -37,19 +37,19 @@
  
 #ifndef operaprofilemigrator___h___
 #define operaprofilemigrator___h___
 
 #include "nsCOMPtr.h"
 #include "nsIBinaryInputStream.h"
 #include "nsIBrowserProfileMigrator.h"
 #include "nsIObserverService.h"
-#include "nsISupportsArray.h"
 #include "nsStringAPI.h"
 #include "nsTArray.h"
+#include "nsIMutableArray.h"
 #include "nsINavHistoryService.h"
 #include "nsIStringBundle.h"
 
 class nsICookieManager2;
 class nsILineInputStream;
 class nsILocalFile;
 class nsINIParser;
 class nsIPermissionManager;
@@ -139,17 +139,17 @@ protected:
                              nsIStringBundle* aBundle, 
                              PRInt64 aParentFolder);
 #endif // defined(XP_WIN) || (defined(XP_UNIX) && !defined(XP_MACOSX))
 
   void     GetOperaProfile(const PRUnichar* aProfile, nsILocalFile** aFile);
 
 private:
   nsCOMPtr<nsILocalFile> mOperaProfile;
-  nsCOMPtr<nsISupportsArray> mProfiles;
+  nsCOMPtr<nsIMutableArray> mProfiles;
   nsCOMPtr<nsIObserverService> mObserverService;
 };
 
 class nsOperaCookieMigrator
 {
 public:
   nsOperaCookieMigrator(nsIInputStream* aSourceStream);
   virtual ~nsOperaCookieMigrator();
--- a/browser/components/migration/src/nsProfileMigrator.cpp
+++ b/browser/components/migration/src/nsProfileMigrator.cpp
@@ -40,17 +40,17 @@
 #include "nsIBrowserProfileMigrator.h"
 #include "nsIComponentManager.h"
 #include "nsIDOMWindow.h"
 #include "nsILocalFile.h"
 #include "nsIObserverService.h"
 #include "nsIProperties.h"
 #include "nsIServiceManager.h"
 #include "nsISupportsPrimitives.h"
-#include "nsISupportsArray.h"
+#include "nsIMutableArray.h"
 #include "nsIToolkitProfile.h"
 #include "nsIToolkitProfileService.h"
 #include "nsIWindowWatcher.h"
 
 #include "nsCOMPtr.h"
 #include "nsBrowserCompsCID.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDirectoryServiceDefs.h"
@@ -122,23 +122,22 @@ nsProfileMigrator::Migrate(nsIProfileSta
   nsCOMPtr<nsISupportsCString> cstr
     (do_CreateInstance("@mozilla.org/supports-cstring;1"));
   if (!cstr) return NS_ERROR_OUT_OF_MEMORY;
   cstr->SetData(key);
 
   // By opening the Migration FE with a supplied bpm, it will automatically
   // migrate from it. 
   nsCOMPtr<nsIWindowWatcher> ww(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
-  nsCOMPtr<nsISupportsArray> params = 
-    do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID);
+  nsCOMPtr<nsIMutableArray> params = do_CreateInstance(NS_ARRAY_CONTRACTID);
   if (!ww || !params) return NS_ERROR_FAILURE;
 
-  params->AppendElement(cstr);
-  params->AppendElement(bpm);
-  params->AppendElement(aStartup);
+  params->AppendElement(cstr, false);
+  params->AppendElement(bpm, false);
+  params->AppendElement(aStartup, false);
 
   nsCOMPtr<nsIDOMWindow> migrateWizard;
   return ww->OpenWindow(nsnull, 
                         MIGRATION_WIZARD_FE_URL,
                         "_blank",
                         MIGRATION_WIZARD_FE_FEATURES,
                         params,
                         getter_AddRefs(migrateWizard));
--- a/browser/components/migration/src/nsSafariProfileMigrator.cpp
+++ b/browser/components/migration/src/nsSafariProfileMigrator.cpp
@@ -54,17 +54,16 @@
 #include "nsIProfileMigrator.h"
 #include "nsIProtocolHandler.h"
 #include "nsIRDFContainer.h"
 #include "nsIRDFDataSource.h"
 #include "nsIRDFRemoteDataSource.h"
 #include "nsIRDFService.h"
 #include "nsIServiceManager.h"
 #include "nsIStringBundle.h"
-#include "nsISupportsArray.h"
 #include "nsISupportsPrimitives.h"
 #include "nsSafariProfileMigrator.h"
 #include "nsToolkitCompsCID.h"
 #include "nsNetUtil.h"
 #include "nsTArray.h"
 
 #include <Carbon/Carbon.h>
 
@@ -197,17 +196,17 @@ NS_IMETHODIMP
 nsSafariProfileMigrator::GetSourceHasMultipleProfiles(bool* aResult)
 {
   // Safari only has one profile per-user.
   *aResult = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSafariProfileMigrator::GetSourceProfiles(nsISupportsArray** aResult)
+nsSafariProfileMigrator::GetSourceProfiles(nsIArray** aResult)
 {
   *aResult = nsnull;
   return NS_OK;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // nsSafariProfileMigrator
 
--- a/browser/components/migration/src/nsSafariProfileMigrator.h
+++ b/browser/components/migration/src/nsSafariProfileMigrator.h
@@ -36,17 +36,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef safariprofilemigrator___h___
 #define safariprofilemigrator___h___
 
 #include "nsIBrowserProfileMigrator.h"
 #include "nsIObserverService.h"
-#include "nsISupportsArray.h"
 #include "nsStringAPI.h"
 #include "nsINavHistoryService.h"
 
 #include <CoreFoundation/CoreFoundation.h>
 
 class nsIRDFDataSource;
 
 class nsSafariProfileMigrator : public nsIBrowserProfileMigrator,
--- a/browser/components/preferences/languages.js
+++ b/browser/components/preferences/languages.js
@@ -204,28 +204,30 @@ var gLanguagesDialog = {
   {
     var selectedID = this._availableLanguages.selectedItem.id;
     var preference = document.getElementById("intl.accept_languages");
     var arrayOfPrefs = preference.value.toLowerCase().split(/\s*,\s*/);
     for (var i = 0; i < arrayOfPrefs.length; ++i ){
       if (arrayOfPrefs[i] == selectedID)
         return;
     }
-      
+
     this._selectedItemID = selectedID;
-    
+
     if (preference.value == "") 
       preference.value = selectedID;
-    else
-      preference.value += "," + selectedID;
+    else {
+      arrayOfPrefs.unshift(selectedID);
+      preference.value = arrayOfPrefs.join(",");
+    }
   
     this._acceptLanguages[selectedID] = true;
     this._availableLanguages.selectedItem = null;
     
-    // Reuild the available list with the added item removed...
+    // Rebuild the available list with the added item removed...
     this._buildAvailableLanguageList(); 
     
     this._availableLanguages.setAttribute("label", this._availableLanguages.getAttribute("label2"));
   },
   
   removeLanguage: function ()
   {
     // Build the new preference value string.
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_pageinfo.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_pageinfo.js
@@ -94,9 +94,10 @@ function test() {
       gBrowser.removeCurrentTab();
       gBrowser.removeCurrentTab();
 
       finish();
     });
   });
 
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 }
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_placestitle.js
@@ -40,16 +40,17 @@
 
 function test() {
   // initialization
   let pb = Cc["@mozilla.org/privatebrowsing;1"].
            getService(Ci.nsIPrivateBrowsingService);
   let cm = Cc["@mozilla.org/cookiemanager;1"].
            getService(Ci.nsICookieManager);
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 
   const TEST_URL = "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/title.sjs";
 
   function waitForCleanup(aCallback) {
     // delete all cookies
     cm.removeAll();
     // delete all history items
     waitForClearHistory(aCallback);
--- a/browser/components/sessionstore/test/browser/browser_467409-backslashplosion.js
+++ b/browser/components/sessionstore/test/browser/browser_467409-backslashplosion.js
@@ -13,16 +13,17 @@
 //
 // 3.  [backwards compat] Use a stringified state as formdata when opening about:sessionrestore
 // 3a. Make sure there are nodes in the tree on about:sessionrestore (skipped, checking formdata is sufficient)
 // 3b. Check that there are no backslashes in the formdata
 // 3c. Check that formdata (via getBrowserState) doesn't require JSON.parse
 
 function test() {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 
   let blankState = { windows: [{ tabs: [{ entries: [{ url: "about:blank" }] }]}]};
   let crashState = { windows: [{ tabs: [{ entries: [{ url: "about:mozilla" }] }]}]};
 
   let pagedata = { url: "about:sessionrestore",
                    formdata: { "#sessionData": crashState } };
   let state = { windows: [{ tabs: [{ entries: [pagedata] }] }] };
 
--- a/browser/components/sessionstore/test/browser/browser_586147.js
+++ b/browser/components/sessionstore/test/browser/browser_586147.js
@@ -39,16 +39,17 @@ function observeOneRestore(callback) {
   Services.obs.addObserver(function() {
     Services.obs.removeObserver(arguments.callee, topic, false);
     callback();
   }, topic, false);
 };
 
 function test() {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 
   // There should be one tab when we start the test
   let [origTab] = gBrowser.visibleTabs;
   let hiddenTab = gBrowser.addTab();
 
   is(gBrowser.visibleTabs.length, 2, "should have 2 tabs before hiding");
   gBrowser.showOnlyTheseTabs([origTab]);
   is(gBrowser.visibleTabs.length, 1, "only 1 after hiding");
--- a/browser/components/sessionstore/test/browser/browser_607016.js
+++ b/browser/components/sessionstore/test/browser/browser_607016.js
@@ -47,16 +47,17 @@ function cleanup() {
   } catch (e) {}
   ss.setBrowserState(stateBackup);
   executeSoon(finish);
 }
 
 function test() {
   /** Bug 607016 - If a tab is never restored, attributes (eg. hidden) aren't updated correctly **/
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 
   // Set the pref to true so we know exactly how many tabs should be restoring at
   // any given time. This guarantees that a finishing load won't start another.
   Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true);
 
   // We have our own progress listener for this test, which we'll attach before our state is set
   let progressListener = {
     onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
--- a/browser/components/tabview/groupitems.js
+++ b/browser/components/tabview/groupitems.js
@@ -143,16 +143,17 @@ function GroupItem(listOfEls, options) {
     .html(html)
     .appendTo($container);
 
   this.$closeButton = iQ('<div>')
     .addClass('close')
     .click(function() {
       self.closeAll();
     })
+    .attr("title", tabviewString("groupItem.closeGroup"))
     .appendTo($container);
 
   // ___ Title
   this.$titleContainer = iQ('.title-container', this.$titlebar);
   this.$title = iQ('.name', this.$titlebar);
   this.$titleShield = iQ('.title-shield', this.$titlebar);
   this.setTitle(options.title);
 
@@ -193,31 +194,33 @@ function GroupItem(listOfEls, options) {
         (self.$title)[0].select();
         self._titleFocused = true;
       }
     })
     .mousedown(function(e) {
       e.stopPropagation();
     })
     .keypress(handleKeyPress)
-    .keyup(handleKeyUp);
+    .keyup(handleKeyUp)
+    .attr("title", tabviewString("groupItem.defaultName"));
 
   this.$titleShield
     .mousedown(function(e) {
       self.lastMouseDownTarget = (Utils.isLeftClick(e) ? e.target : null);
     })
     .mouseup(function(e) {
       var same = (e.target == self.lastMouseDownTarget);
       self.lastMouseDownTarget = null;
       if (!same)
         return;
 
       if (!self.isDragging)
         self.focusTitle();
-    });
+    })
+    .attr("title", tabviewString("groupItem.defaultName"));
 
   if (options.focusTitle)
     this.focusTitle();
 
   // ___ Stack Expander
   this.$expander = iQ("<div/>")
     .addClass("stackExpander")
     .appendTo($container)
@@ -899,16 +902,17 @@ GroupItem.prototype = Utils.extend(new I
       .attr("type", "button")
       .attr("data-group-id", this.id)
       .appendTo("body");
     iQ("<span/>")
       .text(tabviewString("groupItem.undoCloseGroup"))
       .appendTo(this.$undoContainer);
     let undoClose = iQ("<span/>")
       .addClass("close")
+      .attr("title", tabviewString("groupItem.discardClosedGroup"))
       .appendTo(this.$undoContainer);
 
     this.$undoContainer.css({
       left: this.bounds.left + this.bounds.width/2 - iQ(self.$undoContainer).width()/2,
       top:  this.bounds.top + this.bounds.height/2 - iQ(self.$undoContainer).height()/2,
       "-moz-transform": "scale(.1)",
       opacity: 0
     });
@@ -1138,17 +1142,17 @@ GroupItem.prototype = Utils.extend(new I
 
       // if a blank tab is selected while restoring a tab the blank tab gets
       // removed. we need to keep the group alive for the restored tab.
       if (item.isRemovedAfterRestore)
         options.dontClose = true;
 
       let closed = options.dontClose ? false : this.closeIfEmpty();
       if (closed ||
-          (this._children.length == 0 && !gBrowser.selectedTab.pinned &&
+          (this._children.length == 0 && !gBrowser._numPinnedTabs &&
            !item.isDragging)) {
         this._makeLastActiveGroupItemActive();
       } else if (!options.dontArrange) {
         this.arrange({animate: !options.immediately});
         this._unfreezeItemSize({dontArrange: true});
       }
 
       this._sendToSubscribers("childRemoved",{ groupItemId: this.id, item: item });
@@ -2225,39 +2229,41 @@ let GroupItems = {
               };
   
               new GroupItem([], Utils.extend({}, data, options));
             }
           }
         }
 
         toClose.forEach(function(groupItem) {
-          // All remaining children in to-be-closed groups are re-used by
-          // session restore. Reconnect them so that they're put into their
-          // right groups.
-          let children = groupItem.getChildren().concat();
+          // all tabs still existing in closed groups will be moved to new
+          // groups. prepare them to be reconnected later.
+          groupItem.getChildren().forEach(function (tabItem) {
+            if (tabItem.parent.hidden)
+              iQ(tabItem.container).show();
 
-          children.forEach(function (tabItem) {
-            if (tabItem.parent && tabItem.parent.hidden)
-              iQ(tabItem.container).show();
+            tabItem._reconnected = false;
 
             // sanity check the tab's groupID
             let tabData = Storage.getTabData(tabItem.tab);
-            let parentGroup = GroupItems.groupItem(tabData.groupID);
+
+            if (tabData) {
+              let parentGroup = GroupItems.groupItem(tabData.groupID);
 
-            // correct the tab's groupID if necessary
-            if (!parentGroup || -1 < toClose.indexOf(parentGroup)) {
-              tabData.groupID = activeGroupId || Object.keys(groupItemData)[0];
-              Storage.saveTab(tabItem.tab, tabData);
+              // the tab's group id could be invalid or point to a non-existing
+              // group. correct it by assigning the active group id or the first
+              // group of the just restored session.
+              if (!parentGroup || -1 < toClose.indexOf(parentGroup)) {
+                tabData.groupID = activeGroupId || Object.keys(groupItemData)[0];
+                Storage.saveTab(tabItem.tab, tabData);
+              }
             }
-
-            tabItem._reconnected = false;
-            tabItem._reconnect();
           });
 
+          // this closes the group but not its children
           groupItem.close({immediately: true});
         });
       }
 
       // set active group item
       if (activeGroupId) {
         let activeGroupItem = this.groupItem(activeGroupId);
         if (activeGroupItem)
@@ -2461,20 +2467,24 @@ let GroupItems = {
 
     let tabItems = this._activeGroupItem._children;
     gBrowser.showOnlyTheseTabs(tabItems.map(function(item) item.tab));
   },
 
   // ----------
   // Function: updateActiveGroupItemAndTabBar
   // Sets active TabItem and GroupItem, and updates tab bar appropriately.
-  updateActiveGroupItemAndTabBar: function GroupItems_updateActiveGroupItemAndTabBar(tabItem) {
+  // Parameters:
+  // tabItem - the tab item
+  // options - is passed to UI.setActive() directly
+  updateActiveGroupItemAndTabBar: 
+    function GroupItems_updateActiveGroupItemAndTabBar(tabItem, options) {
     Utils.assertThrow(tabItem && tabItem.isATabItem, "tabItem must be a TabItem");
 
-    UI.setActive(tabItem);
+    UI.setActive(tabItem, options);
     this._updateTabBar();
   },
 
   // ----------
   // Function: getNextGroupItemTab
   // Paramaters:
   //  reverse - the boolean indicates the direction to look for the next groupItem.
   // Returns the <tabItem>. If nothing is found, return null.
--- a/browser/components/tabview/search.js
+++ b/browser/components/tabview/search.js
@@ -426,23 +426,25 @@ let Search = {
     iQ("#search").hide();
     iQ("#searchshade").hide().mousedown(function Search_init_shade_mousedown(event) {
       if (event.target.id != "searchbox" && !self._blockClick)
         self.hide();
     });
 
     iQ("#searchbox").keyup(function Search_init_box_keyup() {
       self.perform();
-    });
+    })
+    .attr("title", tabviewString("button.searchTabs"));
 
     iQ("#searchbutton").mousedown(function Search_init_button_mousedown() {
       self._initiatedBy = "buttonclick";
       self.ensureShown();
       self.switchToInMode();
-    });
+    })
+    .attr("title", tabviewString("button.searchTabs"));
 
     window.addEventListener("focus", function Search_init_window_focus() {
       if (self.isEnabled()) {
         self._blockClick = true;
         setTimeout(function() {
           self._blockClick = false;
         }, 0);
       }
--- a/browser/components/tabview/tabitems.js
+++ b/browser/components/tabview/tabitems.js
@@ -143,16 +143,18 @@ function TabItem(tab, options) {
     } else {
       if (!Items.item(this).isDragging)
         self.zoomIn();
     }
   });
 
   this.droppable(true);
 
+  this.$close.attr("title", tabbrowserString("tabs.closeTab"));
+
   TabItems.register(this);
 
   // ___ reconnect to data from Storage
   if (!TabItems.reconnectingPaused())
     this._reconnect(options);
 };
 
 TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
@@ -199,17 +201,25 @@ TabItem.prototype = Utils.extend(new Ite
   //
   // Parameters:
   //   tabData - the tab data
   //   imageData - the image data
   showCachedData: function TabItem_showCachedData(tabData, imageData) {
     this._cachedImageData = imageData;
     this.$cachedThumb.attr("src", this._cachedImageData).show();
     this.$canvas.css({opacity: 0});
-    this.$tabTitle.text(tabData.title ? tabData.title : "");
+    let label = "";
+    let title;
+    if (tabData.title) {
+      label = tabData.title;
+      title = label + "\n" + tabData.url;
+    } else {
+      title = tabData.url;
+    }
+    this.$tabTitle.text(label).attr("title", title);
 
     this._sendToSubscribers("showingCachedData");
   },
 
   // ----------
   // Function: hideCachedData
   // Hides the cached data i.e. image and title and show the canvas.
   hideCachedData: function TabItem_hideCachedData() {
@@ -998,20 +1008,20 @@ let TabItems = {
 
       // ___ remove from waiting list now that we have no other
       // early returns
       this._tabsWaitingForUpdate.remove(tab);
 
       // ___ URL
       let tabUrl = tab.linkedBrowser.currentURI.spec;
       if (tabUrl != tabItem.url) {
-        let oldURL = tabItem.url;
         tabItem.url = tabUrl;
         tabItem.save();
       }
+      tabItem.$container.attr("title", label + "\n" + tabUrl);
 
       // ___ Make sure the tab is complete and ready for updating.
       if (!this.isComplete(tab) && (!options || !options.force)) {
         // If it's incomplete, stick it on the end of the queue
         this._tabsWaitingForUpdate.push(tab);
         return;
       }
 
--- a/browser/components/tabview/tabview.js
+++ b/browser/components/tabview/tabview.js
@@ -8,18 +8,23 @@ const Cr = Components.results;
 Cu.import("resource:///modules/tabview/utils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "tabviewBundle", function() {
   return Services.strings.
     createBundle("chrome://browser/locale/tabview.properties");
 });
+XPCOMUtils.defineLazyGetter(this, "tabbrowserBundle", function() {
+  return Services.strings.
+    createBundle("chrome://browser/locale/tabbrowser.properties");
+});
 
 function tabviewString(name) tabviewBundle.GetStringFromName('tabview.' + name);
+function tabbrowserString(name) tabbrowserBundle.GetStringFromName(name);
 
 XPCOMUtils.defineLazyGetter(this, "gPrefBranch", function() {
   return Services.prefs.getBranch("browser.panorama.");
 });
 
 XPCOMUtils.defineLazyGetter(this, "gPrivateBrowsing", function() {
   return Cc["@mozilla.org/privatebrowsing;1"].
            getService(Ci.nsIPrivateBrowsingService);
--- a/browser/components/tabview/test/Makefile.in
+++ b/browser/components/tabview/test/Makefile.in
@@ -82,18 +82,19 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug600645.js \
                  browser_tabview_bug600812.js \
                  browser_tabview_bug602432.js \
                  browser_tabview_bug604098.js \
                  browser_tabview_bug606657.js \
                  browser_tabview_bug606905.js \
                  browser_tabview_bug607108.js \
                  browser_tabview_bug608037.js \
+                 browser_tabview_bug608153.js \
+                 browser_tabview_bug608158.js \
                  browser_tabview_bug608184.js \
-                 browser_tabview_bug608158.js \
                  browser_tabview_bug608405.js \
                  browser_tabview_bug610208.js \
                  browser_tabview_bug610242.js \
                  browser_tabview_bug612470.js \
                  browser_tabview_bug613541.js \
                  browser_tabview_bug616729.js \
                  browser_tabview_bug616967.js \
                  browser_tabview_bug618816.js \
@@ -160,16 +161,18 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug677310.js \
                  browser_tabview_bug679853.js \
                  browser_tabview_bug681599.js \
                  browser_tabview_bug685476.js \
                  browser_tabview_bug685692.js \
                  browser_tabview_bug686654.js \
                  browser_tabview_bug697390.js \
                  browser_tabview_bug705621.js \
+                 browser_tabview_bug706430.js \
+                 browser_tabview_bug706736.js \
                  browser_tabview_click_group.js \
                  browser_tabview_dragdrop.js \
                  browser_tabview_exit_button.js \
                  browser_tabview_expander.js \
                  browser_tabview_firstrun_pref.js \
                  browser_tabview_group.js \
                  browser_tabview_launch.js \
                  browser_tabview_multiwindow_search.js \
new file mode 100644
--- /dev/null
+++ b/browser/components/tabview/test/browser_tabview_bug608153.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  let pinnedTab = gBrowser.addTab();
+  gBrowser.pinTab(pinnedTab);
+
+  registerCleanupFunction(function() {
+    gBrowser.unpinTab(pinnedTab);
+    while (gBrowser.tabs[1])
+      gBrowser.removeTab(gBrowser.tabs[1]);
+    hideTabView();
+  });
+
+  showTabView(function() {
+    let cw = TabView.getContentWindow();
+    let groupItemOne = cw.GroupItems.groupItems[0];
+    let groupItemTwo = createGroupItemWithBlankTabs(window, 250, 250, 40, 1);
+
+    is(cw.GroupItems.groupItems.length, 2, "Two group items");
+
+    hideTabView(function() {
+      gBrowser.selectedTab = pinnedTab;
+      is(cw.GroupItems.getActiveGroupItem(), groupItemTwo, "Group two is active");
+      is(gBrowser.selectedTab, pinnedTab, "Selected tab is the pinned tab");
+
+      goToNextGroup();
+      is(cw.GroupItems.getActiveGroupItem(), groupItemOne, "Group one is active");
+      is(gBrowser.selectedTab, pinnedTab, "Selected tab is the pinned tab");
+
+      finish();
+    });
+  });
+}
+
+function goToNextGroup() {
+  let utils =
+    QueryInterface(Ci.nsIInterfaceRequestor).
+      getInterface(Ci.nsIDOMWindowUtils);
+
+  const masks = Ci.nsIDOMNSEvent;
+  let mval = 0;
+  mval |= masks.CONTROL_MASK;
+
+  utils.sendKeyEvent("keypress", 0, 96, mval);
+}
--- a/browser/components/tabview/test/browser_tabview_bug705621.js
+++ b/browser/components/tabview/test/browser_tabview_bug705621.js
@@ -10,17 +10,17 @@ function test() {
     });
 
     let cw = win.TabView.getContentWindow();
 
     let groupItemOne = cw.GroupItems.groupItems[0];
     is(groupItemOne.getChildren().length, 1, "Group one has 1 tab item");
 
     let groupItemTwo = createGroupItemWithBlankTabs(win, 300, 300, 40, 1);
-    is(groupItemTwo.getChildren().length, 1, "Group two has 2 tab items");
+    is(groupItemTwo.getChildren().length, 1, "Group two has 1 tab item");
 
     whenTabViewIsHidden(function() {
       executeSoon(function() { 
         win.gBrowser.removeTab(win.gBrowser.selectedTab);
         is(cw.UI.getActiveTab(), groupItemOne.getChild(0), "TabItem in Group one is selected");
         finish();
       });
     }, win);
new file mode 100644
--- /dev/null
+++ b/browser/components/tabview/test/browser_tabview_bug706430.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let state1 = {
+  windows: [{
+    tabs: [{
+      entries: [{ url: "about:blank#1" }],
+      hidden: true,
+      extData: {"tabview-tab": '{"url":"about:blank#1","groupID":1,"bounds":{"left":120,"top":20,"width":20,"height":20}}'}
+    },{
+      entries: [{ url: "about:blank#2" }],
+      hidden: false,
+      extData: {"tabview-tab": '{"url":"about:blank#2","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'},
+    }],
+    selected: 2,
+    extData: {
+      "tabview-groups": '{"nextID":3,"activeGroupId":2, "totalNumber":2}',
+      "tabview-group":
+        '{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},"id":1},' +
+        '"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},"id":2}}'
+    }
+  }]
+};
+
+let state2 = {
+  windows: [{
+    tabs: [{entries: [{ url: "about:blank#1" }], hidden: true},
+           {entries: [{ url: "about:blank#2" }], hidden: false}],
+    selected: 2
+  }]
+};
+
+let ss = Cc["@mozilla.org/browser/sessionstore;1"]
+         .getService(Ci.nsISessionStore);
+
+function test() {
+  waitForExplicitFinish();
+
+  newWindowWithState(state1, function (win) {
+    registerCleanupFunction(function () win.close());
+
+    showTabView(function () {
+      let cw = win.TabView.getContentWindow();
+      let [group1, group2] = cw.GroupItems.groupItems;
+      let [tab1, tab2] = win.gBrowser.tabs;
+
+      checkUrl(group1.getChild(0), "about:blank#1", "tab1 is in first group");
+      checkUrl(group2.getChild(0), "about:blank#2", "tab2 is in second group");
+
+      whenWindowStateReady(win, function () {
+        let groups = cw.GroupItems.groupItems;
+        is(groups.length, 1, "one groupItem");
+        is(groups[0].getChildren().length, 2, "single groupItem has two children");
+
+        finish();
+      });
+
+      ss.setWindowState(win, JSON.stringify(state2), true);
+    }, win);
+  });
+}
+
+function checkUrl(aTabItem, aUrl, aMsg) {
+  is(aTabItem.tab.linkedBrowser.currentURI.spec, aUrl, aMsg);
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/tabview/test/browser_tabview_bug706736.js
@@ -0,0 +1,40 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  waitForExplicitFinish();
+
+  newWindowWithTabView(function(win) {
+    registerCleanupFunction(function() {
+      win.close();
+    });
+
+    let cw = win.TabView.getContentWindow();
+
+    let groupItemOne = cw.GroupItems.groupItems[0];
+    is(groupItemOne.getChildren().length, 1, "Group one has 1 tab item");
+
+    let groupItemTwo = createGroupItemWithBlankTabs(win, 300, 300, 40, 1);
+    is(groupItemTwo.getChildren().length, 1, "Group two has 1 tab items");
+
+    whenTabViewIsHidden(function() {
+      win.gBrowser.removeTab(win.gBrowser.selectedTab);
+      executeSoon(function() {
+        win.undoCloseTab();
+
+        groupItemTwo.addSubscriber("childAdded", function onChildAdded(data) {
+          groupItemTwo.removeSubscriber("childAdded", onChildAdded);
+
+          is(groupItemOne.getChildren().length, 1, "Group one still has 1 tab item");
+          is(groupItemTwo.getChildren().length, 1, "Group two still has 1 tab item");
+        });
+
+        finish();
+      });
+    }, win);
+    groupItemTwo.getChild(0).zoomIn();
+  }, function(win) {
+    let newTab = win.gBrowser.addTab();
+    win.gBrowser.pinTab(newTab);
+  });
+}
--- a/browser/components/tabview/ui.js
+++ b/browser/components/tabview/ui.js
@@ -190,17 +190,18 @@ let UI = {
 
       // ___ currentTab
       this._currentTab = gBrowser.selectedTab;
 
       // ___ exit button
       iQ("#exit-button").click(function() {
         self.exit();
         self.blurAll();
-      });
+      })
+      .attr("title", tabviewString("button.exitTabGroups"));
 
       // When you click on the background/empty part of TabView,
       // we create a new groupItem.
       iQ(gTabViewFrame.contentDocument).mousedown(function(e) {
         if (iQ(":focus").length > 0) {
           iQ(":focus").each(function(element) {
             // don't fire blur event if the same input element is clicked.
             if (e.target != element && element.nodeName == "INPUT")
@@ -460,17 +461,18 @@ let UI = {
   // options
   //  dontSetActiveTabInGroup bool for not setting active tab in group
   setActive: function UI_setActive(item, options) {
     Utils.assert(item, "item must be given");
 
     if (item.isATabItem) {
       if (item.parent)
         GroupItems.setActiveGroupItem(item.parent);
-      this._setActiveTab(item);
+      if (!options || !options.dontSetActiveTabInGroup)
+        this._setActiveTab(item);
     } else {
       GroupItems.setActiveGroupItem(item);
       if (!options || !options.dontSetActiveTabInGroup) {
         let activeTab = item.getActiveTab()
         if (activeTab)
           this._setActiveTab(activeTab);
       }
     }
--- a/browser/devtools/highlighter/inspector.jsm
+++ b/browser/devtools/highlighter/inspector.jsm
@@ -2215,17 +2215,19 @@ InspectorProgressListener.prototype = {
           GetStringFromName("confirmNavigationAway.buttonLeave"),
         accessKey: this.IUI.strings.
           GetStringFromName("confirmNavigationAway.buttonLeaveAccesskey"),
         callback: function onButtonLeave() {
           if (aRequest) {
             aRequest.resume();
             aRequest = null;
             this.IUI.closeInspectorUI();
+            return true;
           }
+          return false;
         }.bind(this),
       },
       {
         id: "inspector.confirmNavigationAway.buttonStay",
         label: this.IUI.strings.
           GetStringFromName("confirmNavigationAway.buttonStay"),
         accessKey: this.IUI.strings.
           GetStringFromName("confirmNavigationAway.buttonStayAccesskey"),
--- a/browser/devtools/highlighter/test/browser_inspector_bug_665880.js
+++ b/browser/devtools/highlighter/test/browser_inspector_bug_665880.js
@@ -1,15 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 
   let doc;
   let objectNode;
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
--- a/browser/devtools/highlighter/test/browser_inspector_bug_690361.js
+++ b/browser/devtools/highlighter/test/browser_inspector_bug_690361.js
@@ -122,16 +122,17 @@ function finishInspectorTests()
     gBrowser.removeCurrentTab();
     finish();
   });
 }
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html,basic tests for inspector";
--- a/browser/devtools/highlighter/test/browser_inspector_duplicate_ruleview.js
+++ b/browser/devtools/highlighter/test/browser_inspector_duplicate_ruleview.js
@@ -106,16 +106,17 @@ function inspectorRuleTrap()
   Services.obs.removeObserver(inspectorRuleTrap,
     InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
   is(InspectorUI.ruleView.doc.documentElement.children.length, 1, "RuleView elements.length == 1");
 }
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 
   tab1 = gBrowser.addTab();
   gBrowser.selectedTab = tab1;
   gBrowser.selectedBrowser.addEventListener("load", function(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
       true);
     waitForFocus(inspectorTabOpen1, content);
   }, true);
--- a/browser/devtools/highlighter/test/browser_inspector_infobar.js
+++ b/browser/devtools/highlighter/test/browser_inspector_infobar.js
@@ -1,14 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 
   let doc;
   let nodes;
   let cursor;
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function onload() {
     gBrowser.selectedBrowser.removeEventListener("load", onload, true);
--- a/browser/devtools/highlighter/test/browser_inspector_initialization.js
+++ b/browser/devtools/highlighter/test/browser_inspector_initialization.js
@@ -213,16 +213,17 @@ function finishInspectorTests()
 
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html,basic tests for inspector";
--- a/browser/devtools/highlighter/test/browser_inspector_registertools.js
+++ b/browser/devtools/highlighter/test/browser_inspector_registertools.js
@@ -208,16 +208,17 @@ function finishUp() {
   gBrowser.removeCurrentTab();
   InspectorUI.initTools = initToolsMethod;
   finish();
 }
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
   
   content.location = "data:text/html,registertool tests for inspector";
--- a/browser/devtools/highlighter/test/browser_inspector_ruleviewstore.js
+++ b/browser/devtools/highlighter/test/browser_inspector_ruleviewstore.js
@@ -132,16 +132,17 @@ function ruleViewOpened2()
   gBrowser.removeCurrentTab();
   InspectorUI.closeInspectorUI();
   finish();
 }
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 
   tab1 = gBrowser.addTab();
   gBrowser.selectedTab = tab1;
   gBrowser.selectedBrowser.addEventListener("load", function(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
       true);
     waitForFocus(inspectorTabOpen1, content);
   }, true);
--- a/browser/devtools/highlighter/test/browser_inspector_tab_switch.js
+++ b/browser/devtools/highlighter/test/browser_inspector_tab_switch.js
@@ -258,16 +258,17 @@ function inspectorTabUnload1(evt)
   InspectorUI.closeInspectorUI();
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
 
   tab1 = gBrowser.addTab();
   gBrowser.selectedTab = tab1;
   gBrowser.selectedBrowser.addEventListener("load", function(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
       true);
     waitForFocus(inspectorTabOpen1, content);
   }, true);
--- a/browser/devtools/highlighter/test/browser_inspector_treeSelection.js
+++ b/browser/devtools/highlighter/test/browser_inspector_treeSelection.js
@@ -100,16 +100,17 @@ function finishUp() {
   doc = h1 = null;
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html,basic tests for inspector";
--- a/browser/devtools/styleinspector/test/browser/browser_bug683672.js
+++ b/browser/devtools/styleinspector/test/browser/browser_bug683672.js
@@ -9,16 +9,17 @@ let stylePanel;
 
 const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/test/browser/browser_bug683672.html";
 
 Cu.import("resource:///modules/devtools/CssHtmlTree.jsm");
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
   addTab(TEST_URI);
   browser.addEventListener("load", tabLoaded, true);
 }
 
 function tabLoaded()
 {
   browser.removeEventListener("load", tabLoaded, true);
   doc = content.document;
--- a/browser/devtools/styleinspector/test/browser/browser_styleinspector.js
+++ b/browser/devtools/styleinspector/test/browser/browser_styleinspector.js
@@ -74,16 +74,17 @@ function finishUp()
   doc = stylePanel = null;
   gBrowser.removeCurrentTab();
   finish();
 }
 
 function test()
 {
   waitForExplicitFinish();
+  ignoreAllUncaughtExceptions();
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
     doc = content.document;
     waitForFocus(createDocument, content);
   }, true);
 
   content.location = "data:text/html,basic style inspector tests";
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_580030_errors_after_page_reload.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_580030_errors_after_page_reload.js
@@ -38,16 +38,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that errors still show up in the Web Console after a page reload.
 
 const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//browser/test-error.html";
 
 function test() {
+  expectUncaughtException();
   addTab(TEST_URI);
   browser.addEventListener("load", onLoad, true);
 }
 
 // see bug 580030: the error handler fails silently after page reload.
 // https://bugzilla.mozilla.org/show_bug.cgi?id=580030
 function onLoad(aEvent) {
   browser.removeEventListener(aEvent.type, arguments.callee, true);
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_582201_duplicate_errors.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_582201_duplicate_errors.js
@@ -39,29 +39,31 @@
  * ***** END LICENSE BLOCK ***** */
 
 // Tests that exceptions thrown by content don't show up twice in the Web
 // Console.
 
 const TEST_DUPLICATE_ERROR_URI = "http://example.com/browser/browser/devtools/webconsole/test//browser/test-duplicate-error.html";
 
 function test() {
+  expectUncaughtException();
   addTab(TEST_DUPLICATE_ERROR_URI);
   browser.addEventListener("DOMContentLoaded", testDuplicateErrors, false);
 }
 
 function testDuplicateErrors() {
   browser.removeEventListener("DOMContentLoaded", testDuplicateErrors,
                               false);
   openConsole();
 
   HUDService.getHudByWindow(content).jsterm.clearOutput();
 
   Services.console.registerListener(consoleObserver);
 
+  expectUncaughtException();
   content.location.reload();
 }
 
 var consoleObserver = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   observe: function (aMessage)
   {
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_597136_external_script_errors.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_597136_external_script_errors.js
@@ -24,16 +24,17 @@ function tabLoaded(aEvent) {
   browser.addEventListener("load", contentLoaded, true);
   content.location.reload();
 }
 
 function contentLoaded(aEvent) {
   browser.removeEventListener("load", contentLoaded, true);
 
   let button = content.document.querySelector("button");
+  expectUncaughtException();
   EventUtils.sendMouseEvent({ type: "click" }, button, content);
   executeSoon(buttonClicked);
 }
 
 function buttonClicked() {
   let outputNode = HUDService.getHudByWindow(content).outputNode;
 
   let msg = "the error from the external script was logged";
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_597756_reopen_closed_tab.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_597756_reopen_closed_tab.js
@@ -13,16 +13,17 @@ const TEST_URI = "http://example.com/bro
 let newTabIsOpen = false;
 
 function tabLoaded(aEvent) {
   gBrowser.selectedBrowser.removeEventListener(aEvent.type, arguments.callee, true);
 
   HUDService.activateHUDForContext(gBrowser.selectedTab);
 
   gBrowser.selectedBrowser.addEventListener("load", tabReloaded, true);
+  expectUncaughtException();
   content.location.reload();
 }
 
 function tabReloaded(aEvent) {
   gBrowser.selectedBrowser.removeEventListener(aEvent.type, arguments.callee, true);
 
   let hudId = HUDService.getHudIdByWindow(content);
   let HUD = HUDService.hudReferences[hudId];
@@ -38,22 +39,24 @@ function tabReloaded(aEvent) {
     }
 
     let newTab = gBrowser.addTab();
     gBrowser.removeCurrentTab();
     gBrowser.selectedTab = newTab;
 
     newTabIsOpen = true;
     gBrowser.selectedBrowser.addEventListener("load", tabLoaded, true);
+    expectUncaughtException();
     content.location = TEST_URI;
   });
 }
 
 function testEnd() {
   gBrowser.removeCurrentTab();
   executeSoon(finishTest);
 }
 
 function test() {
+  expectUncaughtException();
   addTab(TEST_URI);
   browser.addEventListener("load", tabLoaded, true);
 }
 
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_601177_log_levels.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_601177_log_levels.js
@@ -59,12 +59,13 @@ function test()
     browser.removeEventListener(aEvent.type, arguments.callee, true);
 
     openConsole();
 
     browser.addEventListener("load", function(aEvent) {
       browser.removeEventListener(aEvent.type, arguments.callee, true);
       executeSoon(onContentLoaded);
     }, true);
+    expectUncaughtException();
     content.location = TEST_URI;
   }, true);
 }
 
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_618078_network_exceptions.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_618078_network_exceptions.js
@@ -85,13 +85,14 @@ function test()
 
     let hudId = HUDService.getHudIdByWindow(content);
     hud = HUDService.hudReferences[hudId];
 
     Services.console.registerListener(TestObserver);
     registerCleanupFunction(testEnd);
 
     executeSoon(function() {
+      expectUncaughtException();
       content.location = TEST_URI;
     });
   }, true);
 }
 
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_644419_log_limits.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_644419_log_limits.js
@@ -20,16 +20,17 @@ function test() {
 
 function onLoad(aEvent) {
   browser.removeEventListener(aEvent.type, arguments.callee, true);
 
   openConsole();
 
   gHudId = HUDService.getHudIdByWindow(content);
   browser.addEventListener("load", testWebDevLimits, true);
+  expectUncaughtException();
   content.location = TEST_URI;
 }
 
 function testWebDevLimits(aEvent) {
   browser.removeEventListener(aEvent.type, arguments.callee, true);
   gOldPref = Services.prefs.getIntPref("devtools.hud.loglimit.console");
   Services.prefs.setIntPref("devtools.hud.loglimit.console", 10);
 
@@ -65,16 +66,17 @@ function testJsLimits(aEvent) {
 
   // Find the sentinel entry.
   findLogEntry("testing JS limits");
   // Fill the log with JS errors.
   let head = content.document.getElementsByTagName("head")[0];
   for (let i = 0; i < 11; i++) {
     var script = content.document.createElement("script");
     script.text = "fubar" + i + ".bogus(6);";
+    expectUncaughtException();
     head.insertBefore(script, head.firstChild);
   }
 
   executeSoon(function() {
     testLogEntry(outputNode, "fubar0 is not defined", "first message is pruned", false, true);
     findLogEntry("fubar1 is not defined");
     // Check if the sentinel entry is still there.
     findLogEntry("testing JS limits");
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_network_panel.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_network_panel.js
@@ -412,17 +412,20 @@ function testGen() {
 
   // Test a response with a content type that can't be displayed in the
   // NetworkPanel.
   httpActivity.response.header["Content-Type"] = "application/x-shockwave-flash";
 
   networkPanel = HUDService.openNetworkPanel(filterBox, httpActivity);
   networkPanel.isDoneCallback = function NP_doneCallback() {
     networkPanel.isDoneCallback = null;
-    testDriver.next();
+    try {
+      testDriver.next();
+    } catch (e if e instanceof StopIteration) {
+    }
   }
 
   yield;
 
   checkIsVisible(networkPanel, {
     requestBody: false,
     requestFormData: true,
     requestCookie: true,
@@ -473,10 +476,10 @@ function testGen() {
   if (networkPanel.document.getElementById("responseBodyUnknownTypeContent").textContent !== "")
     checkNodeContent(networkPanel, "responseBodyUnknownTypeContent", responseString);
   else
     ok(true, "Flash not installed");
 
   networkPanel.panel.hidePopup(); */
 
   // All done!
-  finishTest();
+  finish();
 }
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_view_source.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_view_source.js
@@ -2,16 +2,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that source URLs in the Web Console can be clicked to display the
 // standard View Source window.
 
 const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test//browser/test-error.html";
 
 function test() {
+  expectUncaughtException();
   addTab(TEST_URI);
   browser.addEventListener("DOMContentLoaded", testViewSource, false);
 }
 
 function testViewSource() {
   browser.removeEventListener("DOMContentLoaded", testViewSource, false);
 
   openConsole();
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -131,16 +131,20 @@
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/content_xtf.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_apps.xpt
 @BINPATH@/components/dom_base.xpt
+#ifdef MOZ_B2G_RIL
+@BINPATH@/components/dom_telephony.xpt
+@BINPATH@/components/dom_telephony_worker.xpt
+#endif
 @BINPATH@/components/dom_battery.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
@@ -353,16 +357,22 @@
 @BINPATH@/components/satchel.manifest
 @BINPATH@/components/nsFormAutoComplete.js
 @BINPATH@/components/nsFormHistory.js
 @BINPATH@/components/nsInputListAutoComplete.js
 @BINPATH@/components/contentSecurityPolicy.manifest
 @BINPATH@/components/contentSecurityPolicy.js
 @BINPATH@/components/contentAreaDropListener.manifest
 @BINPATH@/components/contentAreaDropListener.js
+#ifdef MOZ_B2G_RIL
+@BINPATH@/components/nsTelephonyWorker.manifest
+@BINPATH@/components/nsTelephonyWorker.js
+@BINPATH@/components/Telephony.manifest
+@BINPATH@/components/Telephony.js
+#endif
 @BINPATH@/components/BrowserProfileMigrators.manifest
 @BINPATH@/components/ChromeProfileMigrator.js
 #ifdef XP_MACOSX
 @BINPATH@/components/libalerts_s.dylib
 #endif
 #ifdef MOZ_ENABLE_DBUS
 @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
 #endif
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -63,16 +63,20 @@ components/nsCloseAllWindows.js
 components/nsDictionary.js
 components/nsExtensionManager.js
 components/nsInterfaceInfoToIDL.js
 components/nsScriptableIO.js
 components/nsUrlClassifierTable.js
 components/nsXmlRpcClient.js
 components/pluginGlue.js
 components/sidebar.xpt
+#ifdef MOZ_B2G_RIL
+components/dom_telephony.xpt
+components/dom_telephony_worker.xpt
+#endif
 components/WeaveCrypto.js
 components/WeaveCrypto.manifest
 components/xmlextras.xpt
 components/xpcom.xpt
 components/xpti.dat
 components/xptitemp.dat
 components/nsMicrosummaryService.js
 D3DCompiler_42.dll
@@ -225,16 +229,17 @@ extensions/testpilot@labs.mozilla.com/sk
 extensions/testpilot@labs.mozilla.com/skin/win/notification-tail-up.png
 extensions/testpilot@labs.mozilla.com/tests/test_data_store.js
 greprefs/all.js
 greprefs/security-prefs.js
 greprefs/xpinstall.js
 install.rdf
 modules/ISO8601DateUtils.jsm
 modules/JSON.jsm
+modules/SpatialNavigation.js
 modules/utils.js
 mozilla-runtime@BIN_SUFFIX@
 old-homepage-default.properties
 README.txt
 res/arrow.gif
 res/arrowd.gif
 res/broken-image.gif
 res/broken-image.png
@@ -907,16 +912,22 @@ xpicleanup@BIN_SUFFIX@
   components/nsUpdateTimerManager.js
   components/nsUrlClassifierLib.js
   components/nsUrlClassifierListManager.js
   components/nsURLFormatter.js
   components/nsWebHandlerApp.js
   components/PlacesProtocolHandler.js
   components/storage-Legacy.js
   components/storage-mozStorage.js
+#ifdef MOZ_B2G_RIL
+  components/nsTelephonyWorker.manifest
+  components/nsTelephonyWorker.js
+  components/Telephony.manifest
+  components/Telephony.js
+#endif
   components/txEXSLTRegExFunctions.js
   components/Weave.js
   components/WebContentConverter.js
   defaults/autoconfig/platform.js
   defaults/autoconfig/prefcalls.js
   defaults/pref/firefox-branding.js
   defaults/pref/firefox.js
   defaults/pref/firefox-l10n.js
@@ -1124,16 +1135,20 @@ xpicleanup@BIN_SUFFIX@
   components/content_xtf.xpt
   components/contentprefs.xpt
   components/cookie.xpt
   components/crashreporter.xpt
   components/directory.xpt
   components/docshell.xpt
   components/dom.xpt
   components/dom_base.xpt
+#ifdef MOZ_B2G_RIL
+  components/dom_telephony.xpt
+  components/dom_telephony_worker.xpt
+#endif
   components/dom_canvas.xpt
   components/dom_core.xpt
   components/dom_css.xpt
   components/dom_events.xpt
   components/dom_geolocation.xpt
   components/dom_html.xpt
   components/dom_json.xpt
   components/dom_loadsave.xpt
@@ -1293,50 +1308,51 @@ xpicleanup@BIN_SUFFIX@
   updater.app/Contents/MacOS/updater.ini
 #endif
 #ifdef XP_UNIX
   #ifndef XP_MACOSX
     chrome/icons/default/default.xpm
     components/libimgicon.so
     dictionaries/PL.aff
     dictionaries/PL.dic
+    icons/document.png
     icons/mozicon16.xpm
     icons/mozicon50.xpm
     plugins/libnullplugin.so
     readme.txt
   #endif
 #endif
 #ifndef XP_WIN
   res/fonts/mathfontSymbol.properties
 #endif
 #ifdef XP_WIN
   components/brwsrcmp.dll
   components/jsd3250.dll
   components/nsPostUpdateWin.js
   js3250.dll
   plugins/npnul32.dll
   #if _MSC_VER != 1400
-    @BINPATH@/Microsoft.VC80.CRT.manifest
-    @BINPATH@/msvcm80.dll
-    @BINPATH@/msvcp80.dll
-    @BINPATH@/msvcr80.dll
+    Microsoft.VC80.CRT.manifest
+    msvcm80.dll
+    msvcp80.dll
+    msvcr80.dll
   #endif
   #if _MSC_VER != 1500
-    @BINPATH@/Microsoft.VC90.CRT.manifest
-    @BINPATH@/msvcm90.dll
-    @BINPATH@/msvcp90.dll
-    @BINPATH@/msvcr90.dll
+    Microsoft.VC90.CRT.manifest
+    msvcm90.dll
+    msvcp90.dll
+    msvcr90.dll
   #endif
   #if _MSC_VER != 1600
-    @BINPATH@/msvcp100.dll
-    @BINPATH@/msvcr100.dll
+    msvcp100.dll
+    msvcr100.dll
   #endif
   #if _MSC_VER != 1700
-    @BINPATH@/msvcp110.dll
-    @BINPATH@/msvcr110.dll
+    msvcp110.dll
+    msvcr110.dll
   #endif
   mozcrt19.dll
   mozcpp19.dll
 #endif
 @DLL_PREFIX@xpcom_core@DLL_SUFFIX@
 components/@DLL_PREFIX@jar50@DLL_SUFFIX@
 #ifdef XP_WIN
   components/xpinstal.dll
--- a/browser/locales/en-US/chrome/browser/migration/migration.dtd
+++ b/browser/locales/en-US/chrome/browser/migration/migration.dtd
@@ -4,18 +4,16 @@
 <!ENTITY importFrom.label               "Import Options, Bookmarks, History, Passwords and other data from:">
 <!ENTITY importFromUnix.label           "Import Preferences, Bookmarks, History, Passwords and other data from:">
 <!ENTITY importFromBookmarks.label      "Import Bookmarks from:">
 
 <!ENTITY importFromIE.label             "Microsoft Internet Explorer">
 <!ENTITY importFromIE.accesskey         "M">
 <!ENTITY importFromNothing.label        "Don't import anything">
 <!ENTITY importFromNothing.accesskey    "D">
-<!ENTITY importFromSeamonkey.label      "Netscape 6, 7 or Mozilla 1.x">
-<!ENTITY importFromSeamonkey.accesskey  "N">
 <!ENTITY importFromOpera.label          "Opera">
 <!ENTITY importFromOpera.accesskey      "O">
 <!ENTITY importFromSafari.label         "Safari">
 <!ENTITY importFromSafari.accesskey     "S">
 <!ENTITY importFromChrome.label         "Chrome">
 <!ENTITY importFromChrome.accesskey     "C">
 <!ENTITY importFromHTMLFile.label       "From an HTML File">
 <!ENTITY importFromHTMLFile.accesskey   "F">
--- a/browser/locales/en-US/chrome/browser/migration/migration.properties
+++ b/browser/locales/en-US/chrome/browser/migration/migration.properties
@@ -1,62 +1,53 @@
 profileName_format=%S %S
 
 # Browser Specific
 sourceNameIE=Internet Explorer
-sourceNameSeamonkey=Netscape 6/7/Mozilla
 sourceNameOpera=Opera
 sourceNameSafari=Safari
 sourceNameChrome=Google Chrome
 
 importedBookmarksFolder=From %S
 importedSearchURLsFolder=Keyword Searches (From %S)
 importedSearchURLsTitle=Search on %S
 importedSearchUrlDesc=Type "%S <search query>" in the Location Bar to perform a search on %S.
 
-importedSeamonkeyBookmarksTitle=From Netscape 6/7/Mozilla
 importedSafariBookmarks=From Safari
 importedOperaHotlistTitle=From Opera
 importedOperaSearchUrls=Keyword Searches (From Opera)
 
 # Import Sources
 1_ie=Internet Options
 1_opera=Preferences
-1_seamonkey=Preferences
 1_safari=Preferences
 1_chrome=Preferences
 
 2_ie=Cookies
 2_opera=Cookies
-2_seamonkey=Cookies
 2_safari=Cookies
 2_chrome=Cookies
 
 4_ie=Browsing History
 4_opera=Browsing History
-4_seamonkey=Browsing History
 4_safari=Browsing History
 4_chrome=Browsing History
 
 8_ie=Saved Form History
 8_opera=Saved Form History
-8_seamonkey=Saved Form History
 8_safari=Saved Form History
 8_chrome=Saved Form History
 
 16_ie=Saved Passwords
 16_opera=Saved Passwords
-16_seamonkey=Saved Passwords
 16_safari=Saved Passwords
 16_chrome=Saved Passwords
 
 32_ie=Favorites
 32_opera=Bookmarks
-32_seamonkey=Bookmarks
 32_safari=Bookmarks
 32_chrome=Bookmarks
 
 64_ie=Other Data
 64_opera=Other Data
-64_seamonkey=Other Data
 64_safari=Other Data
 64_chrome=Other Data
 
--- a/browser/locales/en-US/chrome/browser/tabview.properties
+++ b/browser/locales/en-US/chrome/browser/tabview.properties
@@ -1,4 +1,8 @@
-tabview.groupItem.defaultName=Name this tab group…
+tabview.button.searchTabs=Search tab groups
+tabview.button.exitTabGroups=Exit tab groups
+tabview.groupItem.defaultName=Name this tab group
+tabview.groupItem.closeGroup=Close group
 tabview.groupItem.undoCloseGroup=Undo Close Group
+tabview.groupItem.discardClosedGroup=Discard closed group
 tabview.search.otherWindowTabs=Tabs from other windows
 tabview.notification.sessionStore=Tabs and groups will automatically be restored the next time you start %S.
--- a/browser/makefiles.sh
+++ b/browser/makefiles.sh
@@ -64,18 +64,20 @@ browser/components/sessionstore/Makefile
 browser/components/sessionstore/src/Makefile
 browser/components/sidebar/src/Makefile
 browser/components/shell/Makefile
 browser/components/shell/public/Makefile
 browser/components/shell/src/Makefile
 browser/components/tabview/Makefile
 browser/devtools/Makefile
 browser/devtools/highlighter/Makefile
+browser/devtools/scratchpad/Makefile
 browser/devtools/shared/Makefile
 browser/devtools/sourceeditor/Makefile
+browser/devtools/styleeditor/Makefile
 browser/devtools/styleinspector/Makefile
 browser/devtools/webconsole/Makefile
 browser/fuel/Makefile
 browser/fuel/public/Makefile
 browser/fuel/src/Makefile
 browser/installer/Makefile
 browser/locales/Makefile
 browser/themes/Makefile
@@ -135,16 +137,17 @@ if [ "$ENABLE_TESTS" ]; then
     browser/components/privatebrowsing/test/Makefile
     browser/components/privatebrowsing/test/browser/Makefile
     browser/components/tabview/test/Makefile
     browser/components/test/browser/Makefile
     browser/devtools/highlighter/test/Makefile
     browser/devtools/scratchpad/test/Makefile
     browser/devtools/shared/test/Makefile
     browser/devtools/sourceeditor/test/Makefile
+    browser/devtools/styleeditor/test/Makefile
     browser/devtools/styleinspector/test/browser/Makefile
     browser/devtools/webconsole/test/browser/Makefile
     browser/fuel/test/Makefile
   "
   if [ "$MOZ_SAFE_BROWSING" ]; then
     add_makefiles "
       browser/components/safebrowsing/content/test/Makefile
     "
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -1,23 +1,25 @@
 import subprocess
 from devicemanager import DeviceManager, DMError
 import re
 import os
 import sys
+import tempfile
 
 class DeviceManagerADB(DeviceManager):
 
   def __init__(self, host = None, port = 20701, retrylimit = 5, packageName = None):
     self.host = host
     self.port = port
     self.retrylimit = retrylimit
     self.retries = 0
     self._sock = None
     self.useRunAs = False
+    self.useZip = False
     self.packageName = None
     if packageName == None:
       if os.getenv('USER'):
         packageName = 'org.mozilla.fennec_' + os.getenv('USER')
       else:
         packageName = 'org.mozilla.fennec_'
     self.Init(packageName)
 
@@ -26,16 +28,20 @@ class DeviceManagerADB(DeviceManager):
     # successful initialization even if, for example, adb is not installed.
     try:
       self.verifyADB()
       self.verifyRunAs(packageName)
     except:
       self.useRunAs = False
       self.packageName = None
     try:
+      self.verifyZip()
+    except:
+      self.useZip = False
+    try:
       # a test to see if we have root privs
       files = self.listFiles("/data/data")
       if (len(files) == 1):
         if (files[0].find("Permission denied") != -1):
           print "NOT running as root"
           raise Exception("not running as root")
     except:
       try:
@@ -98,41 +104,51 @@ class DeviceManagerADB(DeviceManager):
   # push localDir from host to remoteDir on the device
   # external function
   # returns:
   #  success: remoteDir
   #  failure: None
   def pushDir(self, localDir, remoteDir):
     # adb "push" accepts a directory as an argument, but if the directory
     # contains symbolic links, the links are pushed, rather than the linked
-    # files; we push file-by-file to get around this limitation
+    # files; we either zip/unzip or push file-by-file to get around this 
+    # limitation
     try:
-      if (not self.dirExists(remoteDir)):
-        self.mkDirs(remoteDir+"/x")
-      for root, dirs, files in os.walk(localDir, followlinks='true'):
-        relRoot = os.path.relpath(root, localDir)
-        for file in files:
-          localFile = os.path.join(root, file)
-          remoteFile = remoteDir + "/"
-          if (relRoot!="."):
-            remoteFile = remoteFile + relRoot + "/"
-          remoteFile = remoteFile + file
-          self.pushFile(localFile, remoteFile)
-        for dir in dirs:
-          targetDir = remoteDir + "/"
-          if (relRoot!="."):
-            targetDir = targetDir + relRoot + "/"
-          targetDir = targetDir + dir
-          if (not self.dirExists(targetDir)):
-            self.mkDir(targetDir)
+      if (self.useZip):
+        localZip = tempfile.mktemp()+".zip"
+        remoteZip = remoteDir + "/adbdmtmp.zip"
+        subprocess.check_output(["zip", "-r", localZip, '.'], cwd=localDir)
+        self.pushFile(localZip, remoteZip)
+        os.remove(localZip)
+        self.checkCmdAs(["shell", "unzip", "-o", remoteZip, "-d", remoteDir])
+        self.checkCmdAs(["shell", "rm", remoteZip])
+      else:
+        if (not self.dirExists(remoteDir)):
+          self.mkDirs(remoteDir+"/x")
+        for root, dirs, files in os.walk(localDir, followlinks='true'):
+          relRoot = os.path.relpath(root, localDir)
+          for file in files:
+            localFile = os.path.join(root, file)
+            remoteFile = remoteDir + "/"
+            if (relRoot!="."):
+              remoteFile = remoteFile + relRoot + "/"
+            remoteFile = remoteFile + file
+            self.pushFile(localFile, remoteFile)
+          for dir in dirs:
+            targetDir = remoteDir + "/"
+            if (relRoot!="."):
+              targetDir = targetDir + relRoot + "/"
+            targetDir = targetDir + dir
+            if (not self.dirExists(targetDir)):
+              self.mkDir(targetDir)
       self.checkCmdAs(["shell", "chmod", "777", remoteDir])
-      return True
+      return remoteDir
     except:
       print "pushing " + localDir + " to " + remoteDir + " failed"
-      return False
+      return None
 
   # external function
   # returns:
   #  success: True
   #  failure: False
   def dirExists(self, dirname):
     return self.isDir(dirname)
 
@@ -236,21 +252,35 @@ class DeviceManagerADB(DeviceManager):
   # external function
   # returns:
   #  success: output filename
   #  failure: None
   def launchProcess(self, cmd, outputFile = "process.txt", cwd = '', env = '', failIfRunning=False):
     acmd = ["shell", "am","start"]
     cmd = ' '.join(cmd).strip()
     i = cmd.find(" ")
+    # SUT identifies the URL by looking for :\\ -- another strategy to consider
+    re_url = re.compile('^[http|file|chrome|about].*')
+    last = cmd.rfind(" ")
+    uri = ""
+    args = ""
+    if re_url.match(cmd[last:].strip()):
+      args = cmd[i:last].strip()
+      uri = cmd[last:].strip()
+    else:
+      args = cmd[i:].strip()
     acmd.append("-n")
     acmd.append(cmd[0:i] + "/.App")
     acmd.append("--es")
-    acmd.append("args")
-    acmd.append(cmd[i:])
+    if args != "":
+      acmd.append("args")
+      acmd.append(args)
+    if uri != "":
+      acmd.append("-d")
+      acmd.append(''.join(['\'',uri, '\'']));
     print acmd
     self.checkCmd(acmd)
     return outputFile;
 
   # external function
   # returns:
   #  success: output from testagent
   #  failure: None
@@ -573,8 +603,30 @@ class DeviceManagerADB(DeviceManager):
       self.checkCmd(["shell", "run-as", packageName, "cp", self.tmpDir + "/tmpfile", devroot + "/sanity"])
       if (self.fileExists(devroot + "/sanity/tmpfile")):
         print "will execute commands via run-as " + packageName
         self.packageName = packageName
         self.useRunAs = True
       self.checkCmd(["shell", "rm", devroot + "/tmp/tmpfile"])
       self.checkCmd(["shell", "run-as", packageName, "rm", "-r", devroot + "/sanity"])
       
+  def isUnzipAvailable(self):
+    data = self.runCmd(["shell", "unzip"]).stdout.read()
+    if (re.search('Usage', data)):
+      return True
+    else:
+      return False
+
+  def isLocalZipAvailable(self):
+    try:
+      subprocess.check_call(["zip", "-?"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    except:
+      return False
+    return True
+
+  def verifyZip(self):
+    # If "zip" can be run locally, and "unzip" can be run remotely, then pushDir
+    # can use these to push just one file per directory -- a significant
+    # optimization for large directories.
+    self.useZip = False
+    if (self.isUnzipAvailable() and self.isLocalZipAvailable()):
+      print "will use zip to push directories"
+      self.useZip = True
--- a/build/pgo/server-locations.txt
+++ b/build/pgo/server-locations.txt
@@ -183,8 +183,12 @@ https://www.bank1.com:443           priv
 https://www.bank2.com:443           privileged,cert=escapeattack2
 
 #
 # CONNECT for redirproxy results in a 302 redirect to
 # test1.example.com
 #
 https://redirproxy.example.com:443          privileged,redir=test1.example.com
 
+# Host used for IndexedDB Quota testing
+http://bug704464-1.example.com:80        privileged
+http://bug704464-2.example.com:80        privileged
+http://bug704464-3.example.com:80        privileged
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -1733,17 +1733,17 @@ nsScriptSecurityManager::CheckFunctionAc
         GetFunctionObjectPrincipal(aCx, (JSObject *)aFunObj, nsnull, &rv);
 
     // If subject is null, get a principal from the function object's scope.
     if (NS_SUCCEEDED(rv) && !subject)
     {
 #ifdef DEBUG
         {
             JS_ASSERT(JS_ObjectIsFunction(aCx, (JSObject *)aFunObj));
-            JSFunction *fun = (JSFunction *)JS_GetPrivate(aCx, (JSObject *)aFunObj);
+            JSFunction *fun = JS_GetObjectFunction((JSObject *)aFunObj);
             JSScript *script = JS_GetFunctionScript(aCx, fun);
 
             NS_ASSERTION(!script, "Null principal for non-native function!");
         }
 #endif
 
         subject = doGetObjectPrincipal((JSObject*)aFunObj);
     }
@@ -2214,17 +2214,17 @@ nsScriptSecurityManager::GetFunctionObje
     {
         // Protect against pseudo-functions (like SJOWs).
         nsIPrincipal *result = doGetObjectPrincipal(obj);
         if (!result)
             *rv = NS_ERROR_FAILURE;
         return result;
     }
 
-    JSFunction *fun = (JSFunction *)JS_GetPrivate(cx, obj);
+    JSFunction *fun = JS_GetObjectFunction(obj);
     JSScript *script = JS_GetFunctionScript(cx, fun);
 
     if (!script)
     {
         // A native function: skip it in order to find its scripted caller.
         return nsnull;
     }
 
@@ -2238,17 +2238,17 @@ nsScriptSecurityManager::GetFunctionObje
         // principal we want is in the frame's script, not in the
         // function's script. The function's script is where the
         // eval-calling code came from, not where the eval or new
         // Script object came from, and we want the principal of
         // the eval function object or new Script object.
 
         script = frameScript;
     }
-    else if (JS_GetFunctionObject(fun) != obj)
+    else if (!js::IsOriginalScriptFunction(fun))
     {
         // Here, obj is a cloned function object.  In this case, the
         // clone's prototype may have been precompiled from brutally
         // shared chrome, or else it is a lambda or nested function.
         // The general case here is a function compiled against a
         // different scope than the one it is parented by at runtime,
         // hence the creation of a clone to carry the correct scope
         // chain linkage.
@@ -2280,17 +2280,17 @@ nsScriptSecurityManager::GetFramePrincip
         return GetScriptPrincipal(cx, script, rv);
     }
 
     nsIPrincipal* result = GetFunctionObjectPrincipal(cx, obj, fp, rv);
 
 #ifdef DEBUG
     if (NS_SUCCEEDED(*rv) && !result)
     {
-        JSFunction *fun = (JSFunction *)JS_GetPrivate(cx, obj);
+        JSFunction *fun = JS_GetObjectFunction(obj);
         JSScript *script = JS_GetFunctionScript(cx, fun);
 
         NS_ASSERTION(!script, "Null principal for non-native function!");
     }
 #endif
 
     return result;
 }
@@ -2427,17 +2427,17 @@ nsScriptSecurityManager::doGetObjectPrin
         aObj = js::GetObjectParent(aObj);
 
         if (!aObj)
             return nsnull;
 
         jsClass = js::GetObjectClass(aObj);
 
         if (jsClass == &js::CallClass) {
-            aObj = js::GetObjectParent(aObj);
+            aObj = js::GetObjectParentMaybeScope(aObj);
 
             if (!aObj)
                 return nsnull;
 
             jsClass = js::GetObjectClass(aObj);
         }
     }
 
@@ -2479,17 +2479,17 @@ nsScriptSecurityManager::doGetObjectPrin
                 result = objPrin->GetPrincipal();
 
                 if (result) {
                     break;
                 }
             }
         }
 
-        aObj = js::GetObjectParent(aObj);
+        aObj = js::GetObjectParentMaybeScope(aObj);
 
         if (!aObj)
             break;
 
         jsClass = js::GetObjectClass(aObj);
     } while (1);
 
 #ifdef DEBUG
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -124,17 +124,16 @@ DEHYDRA_PATH    = @DEHYDRA_PATH@
 NS_TRACE_MALLOC = @NS_TRACE_MALLOC@
 USE_ELF_DYNSTR_GC = @USE_ELF_DYNSTR_GC@
 USE_ELF_HACK = @USE_ELF_HACK@
 STDCXX_COMPAT = @STDCXX_COMPAT@
 MOZ_LIBSTDCXX_TARGET_VERSION=@MOZ_LIBSTDCXX_TARGET_VERSION@
 MOZ_LIBSTDCXX_HOST_VERSION=@MOZ_LIBSTDCXX_HOST_VERSION@
 INCREMENTAL_LINKER = @INCREMENTAL_LINKER@
 MACOSX_DEPLOYMENT_TARGET = @MACOSX_DEPLOYMENT_TARGET@
-MOZ_MAIL_NEWS	= @MOZ_MAIL_NEWS@
 ENABLE_TESTS	= @ENABLE_TESTS@
 IBMBIDI = @IBMBIDI@
 MOZ_UNIVERSALCHARDET = @MOZ_UNIVERSALCHARDET@
 ACCESSIBILITY = @ACCESSIBILITY@
 MOZ_BRANDING_DIRECTORY = @MOZ_BRANDING_DIRECTORY@
 XPCOM_USE_LEA = @XPCOM_USE_LEA@
 MOZ_INSTALLER	= @MOZ_INSTALLER@
 MOZ_UPDATER	= @MOZ_UPDATER@
@@ -284,16 +283,18 @@ MOZ_ENABLE_GNOME_COMPONENT = @MOZ_ENABLE
 
 MOZ_ENABLE_GIO = @MOZ_ENABLE_GIO@
 MOZ_GIO_CFLAGS = @MOZ_GIO_CFLAGS@
 MOZ_GIO_LIBS = @MOZ_GIO_LIBS@
 
 MOZ_NATIVE_NSPR = @MOZ_NATIVE_NSPR@
 MOZ_NATIVE_NSS = @MOZ_NATIVE_NSS@
 
+MOZ_B2G_RIL = @MOZ_B2G_RIL@
+
 BUILD_CTYPES = @BUILD_CTYPES@
 
 COMPILE_ENVIRONMENT = @COMPILE_ENVIRONMENT@
 CROSS_COMPILE   = @CROSS_COMPILE@
 
 WCHAR_CFLAGS	= @WCHAR_CFLAGS@
 
 OS_CPPFLAGS	= @CPPFLAGS@
--- a/configure.in
+++ b/configure.in
@@ -4359,17 +4359,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.13.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.13.2, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -n "$MOZ_NATIVE_NSS"; then
    NSS_LIBS="$NSS_LIBS -lcrmf"
 else
    NSS_CFLAGS='-I$(LIBXUL_DIST)/include/nss'
    NSS_DEP_LIBS="\
         \$(LIBXUL_DIST)/lib/\$(LIB_PREFIX)crmf.\$(LIB_SUFFIX) \
@@ -4976,16 +4976,17 @@ cairo-android)
 
 cairo-gonk)
     AC_DEFINE(MOZ_WIDGET_GONK)
     MOZ_WIDGET_TOOLKIT=gonk
     TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
     TK_LIBS='$(MOZ_CAIRO_LIBS)'
     MOZ_WEBGL=1
     MOZ_PDF_PRINTING=1
+    MOZ_B2G_RIL=1
     ;;
 
 esac
 
 AC_SUBST(MOZ_PDF_PRINTING)
 if test "$MOZ_PDF_PRINTING"; then
    PDF_SURFACE_FEATURE="#define CAIRO_HAS_PDF_SURFACE 1"
    AC_DEFINE(MOZ_PDF_PRINTING)
@@ -7569,16 +7570,28 @@ dnl ====================================
 dnl = Support for Quantify (Windows)
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(quantify,
 [  --enable-quantify       Enable Quantify support (Windows only) ],
     MOZ_QUANTIFY=1,
     MOZ_QUANTIFY= )
 
 dnl ========================================================
+dnl = Enable Radio Interface for B2G (Gonk usually)
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(b2g-ril,
+[  --enable-b2g-ril      Set compile flags necessary for testing B2G Radio Interface Layer via network sockets ],
+    MOZ_B2G_RIL=1,
+    MOZ_B2G_RIL= )
+if test -n "$MOZ_B2G_RIL"; then
+   AC_DEFINE(MOZ_B2G_RIL)
+fi
+AC_SUBST(MOZ_B2G_RIL)
+
+dnl ========================================================
 dnl = Support for demangling undefined symbols
 dnl ========================================================
 if test -z "$SKIP_LIBRARY_CHECKS"; then
     AC_LANG_SAVE
     AC_LANG_CPLUSPLUS
     AC_CHECK_FUNCS(__cxa_demangle, HAVE_DEMANGLE=1, HAVE_DEMANGLE=)
     AC_LANG_RESTORE
 fi
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/700512-worker.js
@@ -0,0 +1,7 @@
+onmessage = function(event) {
+  var blob = event.data;
+
+  blob.mozSlice(1, 5);
+
+  postMessage("done");
+}
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/700512.html
@@ -0,0 +1,16 @@
+<html class="reftest-wait">
+  <script type="text/javascript">
+    var worker = new Worker("700512-worker.js");
+
+    var bb = new MozBlobBuilder();
+
+    bb.append("foo");
+    bb.append("bar");
+
+    worker.onmessage = function() {
+      document.documentElement.removeAttribute("class");
+    }
+
+    worker.postMessage(bb.getBlob());
+  </script>
+</html>
--- a/content/base/crashtests/crashtests.list
+++ b/content/base/crashtests/crashtests.list
@@ -95,9 +95,10 @@ load 658845-1.svg
 load 667336-1.html
 load 679459.html
 load 679689-1.html
 load 682463.html
 load 693212.xhtml
 load 698974-1.html
 load 700090-1.html
 load 700090-2.html
+load 700512.html
 load xhr_html_nullresponse.html
--- a/content/base/public/nsIFrameLoader.idl
+++ b/content/base/public/nsIFrameLoader.idl
@@ -136,17 +136,17 @@ interface nsIContentViewManager : nsISup
                          [retval, array, size_is(aLength)] out nsIContentView aResult);
 
   /**
    * The root content view.
    */
   readonly attribute nsIContentView rootContentView;
 };
 
-[scriptable, uuid(12905a29-4246-475a-81d4-fc389197df02)]
+[scriptable, uuid(efc0b731-45dc-4189-8ffa-d3eeeb850977)]
 interface nsIFrameLoader : nsISupports
 {
   /**
    * Get the docshell from the frame loader.
    */
   readonly attribute nsIDocShell docShell;
 
   /**
@@ -253,16 +253,23 @@ interface nsIFrameLoader : nsISupports
 
   /**
    * With this event mode, it's the application's responsability to 
    * convert and forward events to the content process
    */
   const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001;
 
   attribute unsigned long eventMode;
+
+  /**
+   * If false, then the subdocument is not clipped to its CSS viewport, and the
+   * subdocument's viewport scrollbar(s) are not rendered.
+   * Defaults to true.
+   */
+  attribute boolean clipSubdocument;
 };
 
 native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
 
 [scriptable, uuid(5879040e-83e9-40e3-b2bb-5ddf43b76e47)]
 interface nsIFrameLoaderOwner : nsISupports
 {
   /**
--- a/content/base/src/nsAttrAndChildArray.cpp
+++ b/content/base/src/nsAttrAndChildArray.cpp
@@ -362,41 +362,16 @@ nsAttrAndChildArray::AttrAt(PRUint32 aPo
   if (aPos < mapped) {
     return mImpl->mMappedAttrs->AttrAt(aPos);
   }
 
   return &ATTRS(mImpl)[aPos - mapped].mValue;
 }
 
 nsresult
-nsAttrAndChildArray::SetAttr(nsIAtom* aLocalName, const nsAString& aValue)
-{
-  PRUint32 i, slotCount = AttrSlotCount();
-  for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
-    if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
-      ATTRS(mImpl)[i].mValue.SetTo(aValue);
-
-      return NS_OK;
-    }
-  }
-
-  NS_ENSURE_TRUE(slotCount < ATTRCHILD_ARRAY_MAX_ATTR_COUNT,
-                 NS_ERROR_FAILURE);
-
-  if (i == slotCount && !AddAttrSlot()) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  new (&ATTRS(mImpl)[i].mName) nsAttrName(aLocalName);
-  new (&ATTRS(mImpl)[i].mValue) nsAttrValue(aValue);
-
-  return NS_OK;
-}
-
-nsresult
 nsAttrAndChildArray::SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
 {
   PRUint32 i, slotCount = AttrSlotCount();
   for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
     if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
       ATTRS(mImpl)[i].mValue.Reset();
       ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
 
--- a/content/base/src/nsAttrAndChildArray.h
+++ b/content/base/src/nsAttrAndChildArray.h
@@ -98,17 +98,16 @@ public:
   // Like RemoveChildAt but hands the reference to the child being
   // removed back to the caller instead of just releasing it.
   already_AddRefed<nsIContent> TakeChildAt(PRUint32 aPos);
   PRInt32 IndexOfChild(nsINode* aPossibleChild) const;
 
   PRUint32 AttrCount() const;
   const nsAttrValue* GetAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID = kNameSpaceID_None) const;
   const nsAttrValue* AttrAt(PRUint32 aPos) const;
-  nsresult SetAttr(nsIAtom* aLocalName, const nsAString& aValue);
   nsresult SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
   nsresult SetAndTakeAttr(nsINodeInfo* aName, nsAttrValue& aValue);
 
   // Remove the attr at position aPos.  The value of the attr is placed in
   // aValue; any value that was already in aValue is destroyed.
   nsresult RemoveAttrAt(PRUint32 aPos, nsAttrValue& aValue);
 
   // Returns attribute name at given position, *not* out-of-bounds safe
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -138,24 +138,22 @@ public:
     if (base_win) {
       base_win->Destroy();
     }
     return NS_OK;
   }
   nsRefPtr<nsIDocShell> mDocShell;
 };
 
-static void InvalidateFrame(nsIFrame* aFrame)
+static void InvalidateFrame(nsIFrame* aFrame, PRUint32 aFlags)
 {
+  if (!aFrame)
+    return;
   nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size());
-  // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
-  // semantics the same for both in-process and out-of-process
-  // <browser>.  This is just a transform of the layer subtree in
-  // both.
-  aFrame->InvalidateWithFlags(rect, nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
+  aFrame->InvalidateWithFlags(rect, aFlags);
 }
 
 NS_IMPL_ISUPPORTS1(nsContentView, nsIContentView)
 
 bool
 nsContentView::IsRoot() const
 {
   return mScrollId == FrameMetrics::ROOT_SCROLL_ID;
@@ -184,18 +182,21 @@ nsContentView::Update(const ViewConfig& 
   }
 
   if (RenderFrameParent* rfp = mFrameLoader->GetCurrentRemoteFrame()) {
     rfp->ContentViewScaleChanged(this);
   }
 
   // XXX could be clever here and compute a smaller invalidation
   // rect
-  nsIFrame* frame = mFrameLoader->GetPrimaryFrameOfOwningContent();
-  InvalidateFrame(frame);
+  // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
+  // semantics the same for both in-process and out-of-process
+  // <browser>.  This is just a transform of the layer subtree in
+  // both.
+  InvalidateFrame(mFrameLoader->GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentView::ScrollTo(float aXpx, float aYpx)
 {
   ViewConfig config(mConfig);
   config.mScrollOffset = nsPoint(nsPresContext::CSSPixelsToAppUnits(aXpx),
@@ -323,16 +324,17 @@ nsFrameLoader::nsFrameLoader(Element* aO
   , mNeedsAsyncDestroy(false)
   , mInSwap(false)
   , mInShow(false)
   , mHideCalled(false)
   , mNetworkCreated(aNetworkCreated)
   , mDelayRemoteDialogs(false)
   , mRemoteBrowserShown(false)
   , mRemoteFrame(false)
+  , mClipSubdocument(true)
   , mCurrentRemoteFrame(nsnull)
   , mRemoteBrowser(nsnull)
   , mRenderMode(RENDER_MODE_DEFAULT)
   , mEventMode(EVENT_MODE_NORMAL_DISPATCH)
 {
 }
 
 nsFrameLoader*
@@ -1688,17 +1690,21 @@ nsFrameLoader::GetRenderMode(PRUint32* a
 NS_IMETHODIMP
 nsFrameLoader::SetRenderMode(PRUint32 aRenderMode)
 {
   if (aRenderMode == mRenderMode) {
     return NS_OK;
   }
 
   mRenderMode = aRenderMode;
-  InvalidateFrame(GetPrimaryFrameOfOwningContent());
+  // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
+  // semantics the same for both in-process and out-of-process
+  // <browser>.  This is just a transform of the layer subtree in
+  // both.
+  InvalidateFrame(GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFrameLoader::GetEventMode(PRUint32* aEventMode)
 {
   *aEventMode = mEventMode;
   return NS_OK;
@@ -1706,16 +1712,48 @@ nsFrameLoader::GetEventMode(PRUint32* aE
 
 NS_IMETHODIMP
 nsFrameLoader::SetEventMode(PRUint32 aEventMode)
 {
   mEventMode = aEventMode;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::GetClipSubdocument(bool* aResult)
+{
+  *aResult = mClipSubdocument;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFrameLoader::SetClipSubdocument(bool aClip)
+{
+  mClipSubdocument = aClip;
+  nsIFrame* frame = GetPrimaryFrameOfOwningContent();
+  if (frame) {
+    InvalidateFrame(frame, 0);
+    frame->PresContext()->PresShell()->
+      FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
+    nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
+    if (subdocFrame) {
+      nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
+      if (subdocRootFrame) {
+        nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
+          GetRootScrollFrame();
+        if (subdocRootScrollFrame) {
+          frame->PresContext()->PresShell()->
+            FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
+        }
+      }
+    }
+  }
+  return NS_OK;
+}
+
 nsIntSize
 nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
 {
   nsSize docSizeAppUnits;
   nsPresContext* presContext = aIFrame->PresContext();
   nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = 
     do_QueryInterface(aIFrame->GetContent());
   if (frameElem) {
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -282,16 +282,18 @@ public:
   {
     mCurrentRemoteFrame = aFrame;
   }
   nsFrameMessageManager* GetFrameMessageManager() { return mMessageManager; }
 
   mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
   void SetOwnerContent(mozilla::dom::Element* aContent);
 
+  bool ShouldClipSubdocument() { return mClipSubdocument; }
+
 private:
 
   bool ShouldUseRemoteProcess();
 
   /**
    * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
    * initialize mDocShell.
    */
@@ -333,17 +335,19 @@ private:
   bool mHideCalled : 1;
   // True when the object is created for an element which the parser has
   // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
   // it may lose the flag.
   bool mNetworkCreated : 1;
 
   bool mDelayRemoteDialogs : 1;
   bool mRemoteBrowserShown : 1;
-  bool mRemoteFrame;
+  bool mRemoteFrame : 1;
+  bool mClipSubdocument : 1;
+
   // XXX leaking
   nsCOMPtr<nsIObserver> mChildHost;
   RenderFrameParent* mCurrentRemoteFrame;
   TabParent* mRemoteBrowser;
 
   // See nsIFrameLoader.idl.  Short story, if !(mRenderMode &
   // RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in
   // favor of what content tells.
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -589,16 +589,19 @@ 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")
+#ifdef MOZ_MEDIA
+GK_ATOM(muted, "muted")
+#endif
 GK_ATOM(name, "name")
 GK_ATOM(_namespace, "namespace")
 GK_ATOM(namespaceAlias, "namespace-alias")
 GK_ATOM(namespaceUri, "namespace-uri")
 GK_ATOM(NaN, "NaN")
 GK_ATOM(nav, "nav")
 GK_ATOM(negate, "negate")
 GK_ATOM(never, "never")
--- a/content/base/src/nsStyleLinkElement.cpp
+++ b/content/base/src/nsStyleLinkElement.cpp
@@ -174,21 +174,21 @@ PRUint32 nsStyleLinkElement::ParseLinkTy
   PRUint32 linkMask = 0;
   nsAString::const_iterator start, done;
   aTypes.BeginReading(start);
   aTypes.EndReading(done);
   if (start == done)
     return linkMask;
 
   nsAString::const_iterator current(start);
-  bool inString = !nsCRT::IsAsciiSpace(*current);
+  bool inString = !nsContentUtils::IsHTMLWhitespace(*current);
   nsAutoString subString;
   
   while (current != done) {
-    if (nsCRT::IsAsciiSpace(*current)) {
+    if (nsContentUtils::IsHTMLWhitespace(*current)) {
       if (inString) {
         ToLowerCase(Substring(start, current), subString);
         linkMask |= ToLinkMask(subString);
         inString = false;
       }
     }
     else {
       if (!inString) {
--- a/content/base/src/nsTreeSanitizer.cpp
+++ b/content/base/src/nsTreeSanitizer.cpp
@@ -248,16 +248,19 @@ nsIAtom** const kAttributesHTML[] = {
   &nsGkAtoms::low,
   &nsGkAtoms::max,
   &nsGkAtoms::maxlength,
   &nsGkAtoms::media,
   &nsGkAtoms::method,
   &nsGkAtoms::min,
   &nsGkAtoms::mozdonotsend,
   &nsGkAtoms::multiple,
+#ifdef MOZ_MEDIA
+  &nsGkAtoms::muted,
+#endif
   &nsGkAtoms::name,
   &nsGkAtoms::nohref,
   &nsGkAtoms::noshade,
   &nsGkAtoms::novalidate,
   &nsGkAtoms::nowrap,
   &nsGkAtoms::open,
   &nsGkAtoms::optimum,
   &nsGkAtoms::pattern,
--- a/content/base/src/nsXHTMLContentSerializer.cpp
+++ b/content/base/src/nsXHTMLContentSerializer.cpp
@@ -738,17 +738,17 @@ nsXHTMLContentSerializer::IsShorthandAtt
   if ((aAttrName == nsGkAtoms::selected) &&
       (aElementName == nsGkAtoms::option)) {
     return true;
   }
 
 #ifdef MOZ_MEDIA
   // autoplay and controls
   if ((aElementName == nsGkAtoms::video || aElementName == nsGkAtoms::audio) &&
-    (aAttrName == nsGkAtoms::autoplay ||
+    (aAttrName == nsGkAtoms::autoplay || aAttrName == nsGkAtoms::muted ||
      aAttrName == nsGkAtoms::controls)) {
     return true;
   }
 #endif
 
   return false;
 }
 
--- a/content/base/src/nsXMLContentSerializer.cpp
+++ b/content/base/src/nsXMLContentSerializer.cpp
@@ -1147,31 +1147,16 @@ nsXMLContentSerializer::CheckElementEnd(
                                         bool & aForceFormat,
                                         nsAString& aStr)
 {
   // We don't output a separate end tag for empty element
   aForceFormat = false;
   return aContent->GetChildCount() > 0;
 }
 
-void
-nsXMLContentSerializer::AppendToString(const PRUnichar* aStr,
-                                       PRInt32 aLength,
-                                       nsAString& aOutputStr)
-{
-  if (mBodyOnly && !mInBody) {
-    return;
-  }
-  PRInt32 length = (aLength == -1) ? nsCRT::strlen(aStr) : aLength;
-
-  mColPos += length;
-
-  aOutputStr.Append(aStr, length);
-}
-
 void 
 nsXMLContentSerializer::AppendToString(const PRUnichar aChar,
                                        nsAString& aOutputStr)
 {
   if (mBodyOnly && !mInBody) {
     return;
   }
   mColPos += 1;
--- a/content/base/src/nsXMLContentSerializer.h
+++ b/content/base/src/nsXMLContentSerializer.h
@@ -98,23 +98,16 @@ class nsXMLContentSerializer : public ns
   NS_IMETHOD Flush(nsAString& aStr) { return NS_OK; }
 
   NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                  nsAString& aStr);
 
  protected:
 
   /**
-   * Appends a PRUnichar string and increments the column position
-   */
-  void AppendToString(const PRUnichar* aStr,
-                      PRInt32 aLength,
-                      nsAString& aOutputStr);
-
-  /**
    * Appends a PRUnichar character and increments the column position
    */
   void AppendToString(const PRUnichar aChar,
                       nsAString& aOutputStr);
 
   /**
    * Appends a nsAString string and increments the column position
    */
--- a/content/canvas/src/CanvasUtils.cpp
+++ b/content/canvas/src/CanvasUtils.cpp
@@ -96,44 +96,16 @@ DoDrawImageSecurityCheck(nsHTMLCanvasEle
     if (NS_SUCCEEDED(rv) && subsumes) {
         // This canvas has access to that image anyway
         return;
     }
 
     aCanvasElement->SetWriteOnly();
 }
 
-void
-LogMessage (const nsCString& errorString)
-{
-    nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
-    if (!console)
-        return;
-
-    console->LogStringMessage(NS_ConvertUTF8toUTF16(errorString).get());
-    fprintf(stderr, "%s\n", errorString.get());
-}
-
-void
-LogMessagef (const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    char buf[256];
-
-    nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
-    if (console) {
-        PR_vsnprintf(buf, 256, fmt, ap);
-        console->LogStringMessage(NS_ConvertUTF8toUTF16(nsDependentCString(buf)).get());
-        fprintf(stderr, "%s\n", buf);
-    }
-
-    va_end(ap);
-}
-
 bool
 CoerceDouble(jsval v, double* d)
 {
     if (JSVAL_IS_DOUBLE(v)) {
         *d = JSVAL_TO_DOUBLE(v);
     } else if (JSVAL_IS_INT(v)) {
         *d = double(JSVAL_TO_INT(v));
     } else if (JSVAL_IS_VOID(v)) {
--- a/content/canvas/src/CanvasUtils.h
+++ b/content/canvas/src/CanvasUtils.h
@@ -72,19 +72,16 @@ inline bool CheckSaneSubrectSize(PRInt32
 // Flag aCanvasElement as write-only if drawing an image with aPrincipal
 // onto it would make it such.
 
 void DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
                               nsIPrincipal *aPrincipal,
                               bool forceWriteOnly,
                               bool CORSUsed);
 
-void LogMessage (const nsCString& errorString);
-void LogMessagef (const char *fmt, ...);
-
 // Make a double out of |v|, treating undefined values as 0.0 (for
 // the sake of sparse arrays).  Return true iff coercion
 // succeeded.
 bool CoerceDouble(jsval v, double* d);
 
 // Return true iff the conversion succeeded, false otherwise.  *rv is
 // the value to return to script if this returns false.
 bool JSValToMatrix(JSContext* cx, const jsval& val,
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -231,23 +231,16 @@ WebGLContext::WebGLContext()
     mActiveTexture = 0;
     mWebGLError = LOCAL_GL_NO_ERROR;
     mPixelStoreFlipY = false;
     mPixelStorePremultiplyAlpha = false;
     mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
 
     mShaderValidation = true;
 
-    mMapBuffers.Init();
-    mMapTextures.Init();
-    mMapPrograms.Init();
-    mMapShaders.Init();
-    mMapFramebuffers.Init();
-    mMapRenderbuffers.Init();
-
     mBlackTexturesAreInitialized = false;
     mFakeBlackStatus = DoNotNeedFakeBlack;
 
     mVertexAttrib0Vector[0] = 0;
     mVertexAttrib0Vector[1] = 0;
     mVertexAttrib0Vector[2] = 0;
     mVertexAttrib0Vector[3] = 1;
     mFakeVertexAttrib0BufferObjectVector[0] = 0;
@@ -309,107 +302,48 @@ WebGLContext::WebGLContext()
 WebGLContext::~WebGLContext()
 {
     DestroyResourcesAndContext();
     WebGLMemoryReporter::RemoveWebGLContext(this);
     TerminateRobustnessTimer();
     mContextRestorer = nsnull;
 }
 
-static PLDHashOperator
-DeleteTextureFunction(const PRUint32& aKey, WebGLTexture *aValue, void *aData)
-{
-    gl::GLContext *gl = (gl::GLContext *) aData;
-    NS_ASSERTION(!aValue->Deleted(), "Texture is still in mMapTextures, but is deleted?");
-    GLuint name = aValue->GLName();
-    gl->fDeleteTextures(1, &name);
-    aValue->Delete();
-    return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-DeleteBufferFunction(const PRUint32& aKey, WebGLBuffer *aValue, void *aData)
-{
-    gl::GLContext *gl = (gl::GLContext *) aData;
-    NS_ASSERTION(!aValue->Deleted(), "Buffer is still in mMapBuffers, but is deleted?");
-    GLuint name = aValue->GLName();
-    gl->fDeleteBuffers(1, &name);
-    aValue->Delete();
-    return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-DeleteFramebufferFunction(const PRUint32& aKey, WebGLFramebuffer *aValue, void *aData)
-{
-    gl::GLContext *gl = (gl::GLContext *) aData;
-    NS_ASSERTION(!aValue->Deleted(), "Framebuffer is still in mMapFramebuffers, but is deleted?");
-    GLuint name = aValue->GLName();
-    gl->fDeleteFramebuffers(1, &name);
-    aValue->Delete();
-    return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-DeleteRenderbufferFunction(const PRUint32& aKey, WebGLRenderbuffer *aValue, void *aData)
-{
-    gl::GLContext *gl = (gl::GLContext *) aData;
-    NS_ASSERTION(!aValue->Deleted(), "Renderbuffer is still in mMapRenderbuffers, but is deleted?");
-    GLuint name = aValue->GLName();
-    gl->fDeleteRenderbuffers(1, &name);
-    aValue->Delete();
-    return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-DeleteProgramFunction(const PRUint32& aKey, WebGLProgram *aValue, void *aData)
-{
-    gl::GLContext *gl = (gl::GLContext *) aData;
-    NS_ASSERTION(!aValue->Deleted(), "Program is still in mMapPrograms, but is deleted?");
-    GLuint name = aValue->GLName();
-    gl->fDeleteProgram(name);
-    aValue->Delete();
-    return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-DeleteShaderFunction(const PRUint32& aKey, WebGLShader *aValue, void *aData)
-{
-    gl::GLContext *gl = (gl::GLContext *) aData;
-    NS_ASSERTION(!aValue->Deleted(), "Shader is still in mMapShaders, but is deleted?");
-    GLuint name = aValue->GLName();
-    gl->fDeleteShader(name);
-    aValue->Delete();
-    return PL_DHASH_NEXT;
-}
-
 void
 WebGLContext::DestroyResourcesAndContext()
 {
     if (!gl)
         return;
 
     gl->MakeCurrent();
 
-    mMapTextures.EnumerateRead(DeleteTextureFunction, gl);
-    mMapTextures.Clear();
+    mBound2DTextures.Clear();
+    mBoundCubeMapTextures.Clear();
+    mBoundArrayBuffer = nsnull;
+    mBoundElementArrayBuffer = nsnull;
+    mCurrentProgram = nsnull;
+    mBoundFramebuffer = nsnull;
+    mBoundRenderbuffer = nsnull;
 
-    mMapBuffers.EnumerateRead(DeleteBufferFunction, gl);
-    mMapBuffers.Clear();
-
-    mMapPrograms.EnumerateRead(DeleteProgramFunction, gl);
-    mMapPrograms.Clear();
+    mAttribBuffers.Clear();
 
-    mMapShaders.EnumerateRead(DeleteShaderFunction, gl);
-    mMapShaders.Clear();
-
-    mMapFramebuffers.EnumerateRead(DeleteFramebufferFunction, gl);
-    mMapFramebuffers.Clear();
-
-    mMapRenderbuffers.EnumerateRead(DeleteRenderbufferFunction, gl);
-    mMapRenderbuffers.Clear();
+    while (mTextures.Length())
+        mTextures.Last()->DeleteOnce();
+    while (mBuffers.Length())
+        mBuffers.Last()->DeleteOnce();
+    while (mRenderbuffers.Length())
+        mRenderbuffers.Last()->DeleteOnce();
+    while (mFramebuffers.Length())
+        mFramebuffers.Last()->DeleteOnce();
+    while (mShaders.Length())
+        mShaders.Last()->DeleteOnce();
+    while (mPrograms.Length())
+        mPrograms.Last()->DeleteOnce();
+    while (mUniformLocations.Length())
+        mUniformLocations.Last()->DeleteOnce();
 
     if (mBlackTexturesAreInitialized) {
         gl->fDeleteTextures(1, &mBlackTexture2D);
         gl->fDeleteTextures(1, &mBlackTextureCubeMap);
         mBlackTexturesAreInitialized = false;
     }
 
     if (mFakeVertexAttrib0BufferObject) {
@@ -1157,19 +1091,31 @@ WebGLContext::Notify(nsITimer* timer)
 }
 
 void
 WebGLContext::MaybeRestoreContext()
 {
     if (mContextLost || mAllowRestore)
         return;
 
-    gl->MakeCurrent();
-    GLContext::ContextResetARB resetStatus = 
-        (GLContext::ContextResetARB) gl->fGetGraphicsResetStatus();
+    GLContext::ContextResetARB resetStatus = GLContext::CONTEXT_NO_ERROR;
+    if (mHasRobustness) {
+        gl->MakeCurrent();
+        resetStatus = (GLContext::ContextResetARB) gl->fGetGraphicsResetStatus();
+    // This call is safe as it does not actually interact with GL, so the
+    // context does not have to be current.
+    } else if (gl->GetContextType() == GLContext::ContextTypeEGL) {
+        // Simulate a ARB_robustness guilty context loss for when we
+        // get an EGL_CONTEXT_LOST error. It may not actually be guilty,
+        // but we can't make any distinction, so we must assume the worst
+        // case.
+        if (!gl->MakeCurrent(true) && gl->IsContextLost()) {
+            resetStatus = GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB;
+        }
+    }
     
     if (resetStatus != GLContext::CONTEXT_NO_ERROR) {
         // It's already lost, but clean up after it and signal to JS that it is
         // lost.
         ForceLoseContext();
     }
 
     switch (resetStatus) {
@@ -1253,101 +1199,93 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebGLBuffer)
 NS_IMPL_RELEASE(WebGLBuffer)
 
 DOMCI_DATA(WebGLBuffer, WebGLBuffer)
 
 NS_INTERFACE_MAP_BEGIN(WebGLBuffer)
-  NS_INTERFACE_MAP_ENTRY(WebGLBuffer)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLBuffer)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLBuffer)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebGLTexture)
 NS_IMPL_RELEASE(WebGLTexture)
 
 DOMCI_DATA(WebGLTexture, WebGLTexture)
 
 NS_INTERFACE_MAP_BEGIN(WebGLTexture)
-  NS_INTERFACE_MAP_ENTRY(WebGLTexture)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLTexture)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLTexture)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebGLProgram)
 NS_IMPL_RELEASE(WebGLProgram)
 
 DOMCI_DATA(WebGLProgram, WebGLProgram)
 
 NS_INTERFACE_MAP_BEGIN(WebGLProgram)
-  NS_INTERFACE_MAP_ENTRY(WebGLProgram)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLProgram)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLProgram)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebGLShader)
 NS_IMPL_RELEASE(WebGLShader)
 
 DOMCI_DATA(WebGLShader, WebGLShader)
 
 NS_INTERFACE_MAP_BEGIN(WebGLShader)
-  NS_INTERFACE_MAP_ENTRY(WebGLShader)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLShader)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLShader)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebGLFramebuffer)
 NS_IMPL_RELEASE(WebGLFramebuffer)
 
 DOMCI_DATA(WebGLFramebuffer, WebGLFramebuffer)
 
 NS_INTERFACE_MAP_BEGIN(WebGLFramebuffer)
-  NS_INTERFACE_MAP_ENTRY(WebGLFramebuffer)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLFramebuffer)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLFramebuffer)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebGLRenderbuffer)
 NS_IMPL_RELEASE(WebGLRenderbuffer)
 
 DOMCI_DATA(WebGLRenderbuffer, WebGLRenderbuffer)
 
 NS_INTERFACE_MAP_BEGIN(WebGLRenderbuffer)
-  NS_INTERFACE_MAP_ENTRY(WebGLRenderbuffer)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLRenderbuffer)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLRenderbuffer)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebGLUniformLocation)
 NS_IMPL_RELEASE(WebGLUniformLocation)
 
 DOMCI_DATA(WebGLUniformLocation, WebGLUniformLocation)
 
 NS_INTERFACE_MAP_BEGIN(WebGLUniformLocation)
-  NS_INTERFACE_MAP_ENTRY(WebGLUniformLocation)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLUniformLocation)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLUniformLocation)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebGLActiveInfo)
 NS_IMPL_RELEASE(WebGLActiveInfo)
 
 DOMCI_DATA(WebGLActiveInfo, WebGLActiveInfo)
 
 NS_INTERFACE_MAP_BEGIN(WebGLActiveInfo)
-  NS_INTERFACE_MAP_ENTRY(WebGLActiveInfo)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLActiveInfo)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLActiveInfo)
 NS_INTERFACE_MAP_END
 
 #define NAME_NOT_SUPPORTED(base) \
 NS_IMETHODIMP base::GetName(WebGLuint *aName) \
 { return NS_ERROR_NOT_IMPLEMENTED; } \
@@ -1362,30 +1300,27 @@ NAME_NOT_SUPPORTED(WebGLFramebuffer)
 NAME_NOT_SUPPORTED(WebGLRenderbuffer)
 
 NS_IMPL_ADDREF(WebGLExtension)
 NS_IMPL_RELEASE(WebGLExtension)
 
 DOMCI_DATA(WebGLExtension, WebGLExtension)
 
 NS_INTERFACE_MAP_BEGIN(WebGLExtension)
-  NS_INTERFACE_MAP_ENTRY(WebGLExtension)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLExtension)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtension)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebGLExtensionStandardDerivatives)
 NS_IMPL_RELEASE(WebGLExtensionStandardDerivatives)
 
 DOMCI_DATA(WebGLExtensionStandardDerivatives, WebGLExtensionStandardDerivatives)
 
 NS_INTERFACE_MAP_BEGIN(WebGLExtensionStandardDerivatives)
-  //NS_INTERFACE_MAP_ENTRY(WebGLExtensionStandardDerivatives)
-  //NS_INTERFACE_MAP_ENTRY(WebGLExtension)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionStandardDerivatives)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionStandardDerivatives)
 NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
 
 NS_IMPL_ADDREF(WebGLExtensionLoseContext)
 NS_IMPL_RELEASE(WebGLExtensionLoseContext)
 
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -52,16 +52,17 @@
 
 #include "nsIDOMWebGLRenderingContext.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsHTMLCanvasElement.h"
 #include "nsWeakReference.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsIMemoryReporter.h"
+#include "nsContentUtils.h"
 
 #include "GLContextProvider.h"
 #include "Layers.h"
 
 #include "CheckedInt.h"
 
 /* 
  * Minimum value constants defined in 6.2 State Tables of OpenGL ES - 2.0.25
@@ -89,18 +90,18 @@ namespace mozilla {
 class WebGLTexture;
 class WebGLBuffer;
 class WebGLProgram;
 class WebGLShader;
 class WebGLFramebuffer;
 class WebGLRenderbuffer;
 class WebGLUniformLocation;
 class WebGLExtension;
+class WebGLVertexAttribData;
 
-template<int PreallocatedOwnersCapacity> class WebGLZeroingObject;
 class WebGLContextBoundObject;
 
 enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack };
 
 struct VertexAttrib0Status {
     enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
 };
 
@@ -119,196 +120,324 @@ struct WebGLTexelPremultiplicationOp {
 
 int GetWebGLTexelFormat(GLenum format, GLenum type);
 
 inline bool is_pot_assuming_nonnegative(WebGLsizei x)
 {
     return (x & (x-1)) == 0;
 }
 
-class WebGLObjectBaseRefPtr
+/* Each WebGL object class WebGLFoo wants to:
+ *  - inherit WebGLRefCountedObject<WebGLFoo>
+ *  - implement a Delete() method
+ *  - have its destructor call DeleteOnce()
+ * 
+ * This base class provides two features to WebGL object types:
+ * 1. support for OpenGL object reference counting
+ * 2. support for OpenGL deletion statuses
+ *
+ ***** 1. OpenGL object reference counting *****
+ *
+ * WebGL objects such as WebGLTexture's really have two different refcounts:
+ * the XPCOM refcount, that is directly exposed to JavaScript, and the OpenGL
+ * refcount.
+ *
+ * For example, when in JavaScript one does: var newname = existingTexture;
+ * that increments the XPCOM refcount, but doesn't affect the OpenGL refcount.
+ * When one attaches the texture to a framebuffer object, that does increment
+ * its OpenGL refcount (and also its XPCOM refcount, to prevent the regular
+ * XPCOM refcounting mechanism from destroying objects prematurely).
+ *
+ * The actual OpenGL refcount is opaque to us (it's internal to the OpenGL
+ * implementation) but is affects the WebGL semantics that we have to implement:
+ * for example, a WebGLTexture that is attached to a WebGLFramebuffer must not
+ * be actually deleted, even if deleteTexture has been called on it, and even
+ * if JavaScript doesn't have references to it anymore. We can't just rely on
+ * OpenGL to keep alive the underlying OpenGL texture for us, for a variety of
+ * reasons, most importantly: we'd need to know when OpenGL objects are actually
+ * deleted, and OpenGL doesn't notify us about that, so we would have to query
+ * status very often with glIsXxx calls which isn't practical.
+ *
+ * This means that we have to keep track of the OpenGL refcount ourselves,
+ * in addition to the XPCOM refcount.
+ *
+ * This class implements such a refcount, see the mWebGLRefCnt
+ * member. In order to avoid name clashes (with regular XPCOM refcounting)
+ * in the derived class, we prefix members with 'WebGL', whence the names
+ * WebGLAddRef, WebGLRelease, etc.
+ *
+ * In practice, WebGLAddRef and WebGLRelease are only called from the
+ * WebGLRefPtr class.
+ *
+ ***** 2. OpenGL deletion statuses *****
+ *
+ * In OpenGL, an object can go through 3 different deletion statuses during its
+ * lifetime, which correspond to the 3 enum values for DeletionStatus in this class:
+ *  - the Default status, which it has from its creation to when the
+ *    suitable glDeleteXxx function is called on it;
+ *  - the DeleteRequested status, which is has from when the suitable glDeleteXxx
+ *    function is called on it to when it is no longer referenced by other OpenGL
+ *    objects. For example, a texture that is attached to a non-current FBO
+ *    will enter that status when glDeleteTexture is called on it. For objects
+ *    with that status, GL_DELETE_STATUS queries return true, but glIsXxx
+ *    functions still return true.
+ *  - the Deleted status, which is the status of objects on which the
+ *    suitable glDeleteXxx function has been called, and that are not referenced
+ *    by other OpenGL objects.
+ *
+ * This state is stored in the mDeletionStatus member of this class.
+ *
+ * When the GL refcount hits zero, if the status is DeleteRequested then we call
+ * the Delete() method on the derived class and the status becomes Deleted. This is
+ * what the MaybeDelete() function does.
+ * 
+ * The DeleteOnce() function implemented here is a helper to ensure that we don't
+ * call Delete() twice on the same object. Since the derived class' destructor
+ * needs to call DeleteOnce() which calls Delete(), we can't allow either to be
+ * virtual. Strictly speaking, we could let them be virtual if the derived class
+ * were final, but that would be impossible to enforce and would lead to strange
+ * bugs if it were subclassed.
+ *
+ * This WebGLRefCountedObject class takes the Derived type
+ * as template parameter, as a means to allow DeleteOnce to call Delete()
+ * on the Derived class, without either method being virtual. This is a common
+ * C++ pattern known as the "curiously recursive template pattern (CRTP)".
+ */
+template<typename Derived>
+class WebGLRefCountedObject
 {
-protected:
-    template<int PreallocatedOwnersCapacity>
-    friend class WebGLZeroingObject;
+public:
+    enum DeletionStatus { Default, DeleteRequested, Deleted };
 
-    WebGLObjectBaseRefPtr()
-        : mRawPtr(0)
-    {
+    WebGLRefCountedObject()
+      : mDeletionStatus(Default)
+    { }
+
+    ~WebGLRefCountedObject() {
+        NS_ABORT_IF_FALSE(mWebGLRefCnt == 0, "destroying WebGL object still referenced by other WebGL objects");
+        NS_ABORT_IF_FALSE(mDeletionStatus == Deleted, "Derived class destructor must call DeleteOnce()");
     }
 
-    WebGLObjectBaseRefPtr(nsISupports *rawPtr)
-        : mRawPtr(rawPtr)
-    {
+    // called by WebGLRefPtr
+    void WebGLAddRef() {
+        ++mWebGLRefCnt;
+    }
+
+    // called by WebGLRefPtr
+    void WebGLRelease() {
+        NS_ABORT_IF_FALSE(mWebGLRefCnt > 0, "releasing WebGL object with WebGL refcnt already zero");
+        --mWebGLRefCnt;
+        MaybeDelete();
+    }
+
+    // this is the function that WebGL.deleteXxx() functions want to call
+    void RequestDelete() {
+        if (mDeletionStatus == Default)
+            mDeletionStatus = DeleteRequested;
+        MaybeDelete();
     }
 
-    void Zero() {
-        if (mRawPtr) {
-            // Note: RemoveRefOwner isn't called here, because
-            // the entire owner array will be cleared.
-            mRawPtr->Release();
-            mRawPtr = 0;
+    bool IsDeleted() const {
+        return mDeletionStatus == Deleted;
+    }
+
+    bool IsDeleteRequested() const {
+        return mDeletionStatus != Default;
+    }
+
+    void DeleteOnce() {
+        if (mDeletionStatus != Deleted) {
+            static_cast<Derived*>(this)->Delete();
+            mDeletionStatus = Deleted;
+        }
+    }
+
+private:
+    void MaybeDelete() {
+        if (mWebGLRefCnt == 0 &&
+            mDeletionStatus == DeleteRequested)
+        {
+            DeleteOnce();
         }
     }
 
 protected:
-    nsISupports *mRawPtr;
+    nsAutoRefCnt mWebGLRefCnt;
+    DeletionStatus mDeletionStatus;
 };
 
-template <class T>
-class WebGLObjectRefPtr
-    : public WebGLObjectBaseRefPtr
+/* This WebGLRefPtr class is meant to be used for references between WebGL objects.
+ * For example, a WebGLProgram holds WebGLRefPtr's to the WebGLShader's attached
+ * to it.
+ *
+ * Why the need for a separate refptr class? The only special thing that WebGLRefPtr
+ * does is that it increments and decrements the WebGL refcount of
+ * WebGLRefCountedObject's, in addition to incrementing and decrementing the
+ * usual XPCOM refcount.
+ *
+ * This means that by using a WebGLRefPtr instead of a nsRefPtr, you ensure that
+ * the WebGL refcount is incremented, which means that the object will be kept
+ * alive by this reference even if the matching webgl.deleteXxx() function is
+ * called on it.
+ */
+template<typename T>
+class WebGLRefPtr
 {
 public:
-    typedef T element_type;
-
-    WebGLObjectRefPtr()
+    WebGLRefPtr()
+        : mRawPtr(0)
     { }
 
-    WebGLObjectRefPtr(const WebGLObjectRefPtr<T>& aSmartPtr)
-        : WebGLObjectBaseRefPtr(aSmartPtr.mRawPtr)
+    WebGLRefPtr(const WebGLRefPtr<T>& aSmartPtr)
+        : mRawPtr(aSmartPtr.mRawPtr)
     {
-        if (mRawPtr) {
-            RawPtr()->AddRef();
-            RawPtr()->AddRefOwner(this);
-        }
+        AddRefOnPtr(mRawPtr);
     }
 
-    WebGLObjectRefPtr(T *aRawPtr)
-        : WebGLObjectBaseRefPtr(aRawPtr)
+    WebGLRefPtr(T *aRawPtr)
+        : mRawPtr(aRawPtr)
     {
-        if (mRawPtr) {
-            RawPtr()->AddRef();
-            RawPtr()->AddRefOwner(this);
-        }
+        AddRefOnPtr(mRawPtr);
     }
 
-    WebGLObjectRefPtr(const already_AddRefed<T>& aSmartPtr)
-        : WebGLObjectBaseRefPtr(aSmartPtr.mRawPtr)
-          // construct from |dont_AddRef(expr)|
-    {
-        if (mRawPtr) {
-            RawPtr()->AddRef();
-            RawPtr()->AddRefOwner(this);
-        }
+    ~WebGLRefPtr() {
+        ReleasePtr(mRawPtr);
     }
 
-    ~WebGLObjectRefPtr() {
-        if (mRawPtr) {
-            RawPtr()->RemoveRefOwner(this);
-            RawPtr()->Release();
-        }
-    }
-
-    WebGLObjectRefPtr<T>&
-    operator=(const WebGLObjectRefPtr<T>& rhs)
+    WebGLRefPtr<T>&
+    operator=(const WebGLRefPtr<T>& rhs)
     {
-        assign_with_AddRef(static_cast<T*>(rhs.mRawPtr));
+        assign_with_AddRef(rhs.mRawPtr);
         return *this;
     }
 
-    WebGLObjectRefPtr<T>&
+    WebGLRefPtr<T>&
     operator=(T* rhs)
     {
         assign_with_AddRef(rhs);
         return *this;
     }
 
-    WebGLObjectRefPtr<T>&
-    operator=(const already_AddRefed<T>& rhs)
-    {
-        assign_assuming_AddRef(static_cast<T*>(rhs.mRawPtr));
-        return *this;
-    }
-
     T* get() const {
-        return const_cast<T*>(static_cast<T*>(mRawPtr));
+        return static_cast<T*>(mRawPtr);
     }
 
     operator T*() const {
         return get();
     }
 
     T* operator->() const {
-        NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL WebGLObjectRefPtr with operator->()!");
+        NS_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a NULL WebGLRefPtr with operator->()!");
         return get();
     }
 
     T& operator*() const {
-        NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL WebGLObjectRefPtr with operator*()!");
+        NS_ABORT_IF_FALSE(mRawPtr != 0, "You can't dereference a NULL WebGLRefPtr with operator*()!");
         return *get();
     }
 
 private:
-    T* RawPtr() { return static_cast<T*>(mRawPtr); }
+
+    static void AddRefOnPtr(T* rawPtr) {
+        if (rawPtr) {
+            rawPtr->WebGLAddRef();
+            rawPtr->AddRef();
+        }
+    }
+
+    static void ReleasePtr(T* rawPtr) {
+        if (rawPtr) {
+            rawPtr->WebGLRelease(); // must be done first before Release(), as Release() might actually destroy the object
+            rawPtr->Release();
+        }
+    }
 
     void assign_with_AddRef(T* rawPtr) {
-        if (rawPtr) {
-            rawPtr->AddRef();
-            rawPtr->AddRefOwner(this);
-        }
-
+        AddRefOnPtr(rawPtr);
         assign_assuming_AddRef(rawPtr);
     }
 
     void assign_assuming_AddRef(T* newPtr) {
-        T* oldPtr = RawPtr();
+        T* oldPtr = mRawPtr;
         mRawPtr = newPtr;
-        if (oldPtr) {
-            oldPtr->RemoveRefOwner(this);
-            oldPtr->Release();
-        }
+        ReleasePtr(oldPtr);
     }
+
+protected:
+    T *mRawPtr;
 };
 
-class WebGLBuffer;
+typedef PRUint64 WebGLMonotonicHandle;
 
-struct WebGLVertexAttribData {
-    // note that these initial values are what GL initializes vertex attribs to
-    WebGLVertexAttribData()
-        : buf(0), stride(0), size(4), byteOffset(0),
-          type(LOCAL_GL_FLOAT), enabled(false), normalized(false)
-    { }
+/* WebGLFastArray offers a fast array for the use case where all what one needs is to append
+ * and remove elements. Removal is fast because the array is always kept sorted with respect
+ * to "monotonic handles". Appending an element returns such a "monotonic handle" which the
+ * user needs to keep for future use for when it will want to remove the element.
+ */
+template<typename ElementType>
+class WebGLFastArray
+{
+    struct Entry {
+        ElementType mElement;
+        WebGLMonotonicHandle mMonotonicHandle;
 
-    WebGLObjectRefPtr<WebGLBuffer> buf;
-    WebGLuint stride;
-    WebGLuint size;
-    GLuint byteOffset;
-    GLenum type;
-    bool enabled;
-    bool normalized;
+        Entry(ElementType elem, WebGLMonotonicHandle monotonicHandle)
+            : mElement(elem), mMonotonicHandle(monotonicHandle)
+        {}
 
-    GLuint componentSize() const {
-        switch(type) {
-            case LOCAL_GL_BYTE:
-                return sizeof(GLbyte);
-                break;
-            case LOCAL_GL_UNSIGNED_BYTE:
-                return sizeof(GLubyte);
-                break;
-            case LOCAL_GL_SHORT:
-                return sizeof(GLshort);
-                break;
-            case LOCAL_GL_UNSIGNED_SHORT:
-                return sizeof(GLushort);
-                break;
-            // XXX case LOCAL_GL_FIXED:
-            case LOCAL_GL_FLOAT:
-                return sizeof(GLfloat);
-                break;
-            default:
-                NS_ERROR("Should never get here!");
-                return 0;
-        }
+        struct Comparator {
+            bool Equals(const Entry& a, const Entry& b) const {
+                return a.mMonotonicHandle == b.mMonotonicHandle;
+            }
+            bool LessThan(const Entry& a, const Entry& b) const {
+                return a.mMonotonicHandle < b.mMonotonicHandle;
+            }
+        };
+    };
+
+public:
+    WebGLFastArray()
+        : mCurrentMonotonicHandle(0) // CheckedInt already does it, this is just defensive coding
+    {}
+
+    ElementType operator[](size_t index) const {
+        return mArray[index].mElement;
     }
 
-    GLuint actualStride() const {
-        if (stride) return stride;
-        return size * componentSize();
+    size_t Length() const {
+        return mArray.Length();
+    }
+
+    ElementType Last() const {
+        return operator[](Length() - 1);
+    }
+
+    WebGLMonotonicHandle AppendElement(ElementType elem)
+    {
+        WebGLMonotonicHandle monotonicHandle = NextMonotonicHandle();
+        mArray.AppendElement(Entry(elem, monotonicHandle));
+        return monotonicHandle;
     }
+
+    void RemoveElement(WebGLMonotonicHandle monotonicHandle)
+    {
+        mArray.RemoveElementSorted(Entry(ElementType(), monotonicHandle),
+                                   typename Entry::Comparator());
+    }
+
+private:
+    WebGLMonotonicHandle NextMonotonicHandle() {
+        ++mCurrentMonotonicHandle;
+        if (!mCurrentMonotonicHandle.valid())
+            NS_RUNTIMEABORT("ran out of monotonic ids!");
+        return mCurrentMonotonicHandle.value();
+    }
+
+    nsTArray<Entry> mArray;
+    CheckedInt<WebGLMonotonicHandle> mCurrentMonotonicHandle;
 };
 
 struct WebGLContextOptions {
     // these are defaults
     WebGLContextOptions()
         : alpha(true), depth(true), stencil(false),
           premultipliedAlpha(true), antialias(true),
           preserveDrawingBuffer(false)
@@ -444,17 +573,17 @@ public:
     
     bool MinCapabilityMode() const {
         return mMinCapability;
     }
 
     // Sets up the GL_ARB_robustness timer if it isn't already, so that if the
     // driver gets restarted, the context may get reset with it.
     void SetupRobustnessTimer() {
-        if (mContextLost || !mHasRobustness)
+        if (mContextLost || (!mHasRobustness && gl->GetContextType() != gl::GLContext::ContextTypeEGL))
             return;
 
         // If the timer was already running, don't restart it here. Instead,
         // wait until the previous call is done, then fire it one more time.
         // This is an optimization to prevent unnecessary cross-communication
         // between threads.
         if (mRobustnessTimerRunning) {
             mDrawSinceRobustnessTimerSet = true;
@@ -514,16 +643,19 @@ protected:
     bool mInvalidated;
     bool mResetLayer;
     bool mVerbose;
     bool mOptionsFrozen;
     bool mMinCapability;
     bool mDisableExtensions;
     bool mHasRobustness;
 
+    template<typename WebGLObjectType>
+    void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
+
     WebGLuint mActiveTexture;
     WebGLenum mWebGLError;
 
     // whether shader validation is supported
     bool mShaderValidation;
 
     // some GL constants
     PRInt32 mGLMaxVertexAttribs;
@@ -674,42 +806,36 @@ protected:
 
     void MaybeRestoreContext();
     void ForceLoseContext();
     void ForceRestoreContext();
 
     // the buffers bound to the current program's attribs
     nsTArray<WebGLVertexAttribData> mAttribBuffers;
 
-    // the textures bound to any sampler uniforms
-    nsTArray<WebGLObjectRefPtr<WebGLTexture> > mUniformTextures;
-
-    // textures bound to 
-    nsTArray<WebGLObjectRefPtr<WebGLTexture> > mBound2DTextures;
-    nsTArray<WebGLObjectRefPtr<WebGLTexture> > mBoundCubeMapTextures;
+    nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
+    nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
 
-    WebGLObjectRefPtr<WebGLBuffer> mBoundArrayBuffer;
-    WebGLObjectRefPtr<WebGLBuffer> mBoundElementArrayBuffer;
-    // note nsRefPtr -- this stays alive even after being deleted,
-    // and is only explicitly removed from the current state via
-    // a call to UseProgram.
-    nsRefPtr<WebGLProgram> mCurrentProgram;
+    WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer;
+    WebGLRefPtr<WebGLBuffer> mBoundElementArrayBuffer;
+
+    WebGLRefPtr<WebGLProgram> mCurrentProgram;
 
     PRUint32 mMaxFramebufferColorAttachments;
 
-    nsRefPtr<WebGLFramebuffer> mBoundFramebuffer;
-    nsRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
+    WebGLRefPtr<WebGLFramebuffer> mBoundFramebuffer;
+    WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
 
-    // lookup tables for GL name -> object wrapper
-    nsRefPtrHashtable<nsUint32HashKey, WebGLTexture> mMapTextures;
-    nsRefPtrHashtable<nsUint32HashKey, WebGLBuffer> mMapBuffers;
-    nsRefPtrHashtable<nsUint32HashKey, WebGLProgram> mMapPrograms;
-    nsRefPtrHashtable<nsUint32HashKey, WebGLShader> mMapShaders;
-    nsRefPtrHashtable<nsUint32HashKey, WebGLFramebuffer> mMapFramebuffers;
-    nsRefPtrHashtable<nsUint32HashKey, WebGLRenderbuffer> mMapRenderbuffers;
+    WebGLFastArray<WebGLTexture*> mTextures;
+    WebGLFastArray<WebGLBuffer*> mBuffers;
+    WebGLFastArray<WebGLProgram*> mPrograms;
+    WebGLFastArray<WebGLShader*> mShaders;
+    WebGLFastArray<WebGLRenderbuffer*> mRenderbuffers;
+    WebGLFastArray<WebGLFramebuffer*> mFramebuffers;
+    WebGLFastArray<WebGLUniformLocation*> mUniformLocations;
 
     // PixelStore parameters
     PRUint32 mPixelStorePackAlignment, mPixelStoreUnpackAlignment, mPixelStoreColorspaceConversion;
     bool mPixelStoreFlipY, mPixelStorePremultiplyAlpha;
 
     FakeBlackStatus mFakeBlackStatus;
 
     WebGLuint mBlackTexture2D, mBlackTextureCubeMap;
@@ -744,55 +870,21 @@ public:
     // console logging helpers
     static void LogMessage(const char *fmt, ...);
     static void LogMessage(const char *fmt, va_list ap);
     void LogMessageIfVerbose(const char *fmt, ...);
     void LogMessageIfVerbose(const char *fmt, va_list ap);
 
     friend class WebGLTexture;
     friend class WebGLFramebuffer;
+    friend class WebGLRenderbuffer;
     friend class WebGLProgram;
-};
-
-// this class is a mixin for the named type wrappers, and is used
-// by WebGLObjectRefPtr to tell the object who holds references, so that
-// we can zero them out appropriately when the object is deleted, because
-// it will be unbound in the GL.
-//
-// PreallocatedOwnersCapacity is the preallocated capacity for the array of refptrs to owners.
-// Having some minimal preallocated capacity is an important optimization, see bug 522193. In this
-// bug, a benchmark was using WebGLBuffer with a number of owners oscillating between 0 and 2.
-// At this time mRefOwners was a nsTArray, and the too frequent reallocations were slowing us down.
-template<int PreallocatedOwnersCapacity>
-class WebGLZeroingObject
-{
-public:
-    WebGLZeroingObject()
-    { }
-
-    void AddRefOwner(WebGLObjectBaseRefPtr *owner) {
-        mRefOwners.AppendElement(owner);
-    }
-
-    void RemoveRefOwner(WebGLObjectBaseRefPtr *owner) {
-        mRefOwners.RemoveElement(owner);
-    }
-
-    void ZeroOwners() {
-        WebGLObjectBaseRefPtr **owners = mRefOwners.Elements();
-        
-        for (PRUint32 i = 0; i < mRefOwners.Length(); i++) {
-            owners[i]->Zero();
-        }
-
-        mRefOwners.Clear();
-    }
-
-protected:
-    nsAutoTArray<WebGLObjectBaseRefPtr *, PreallocatedOwnersCapacity> mRefOwners;
+    friend class WebGLBuffer;
+    friend class WebGLShader;
+    friend class WebGLUniformLocation;
 };
 
 // this class is a mixin for GL objects that have dimensions
 // that we need to track.
 class WebGLRectangleObject
 {
 protected:
     WebGLRectangleObject()
@@ -845,52 +937,95 @@ public:
             mContextGeneration == other->Generation();
     }
 
 protected:
     WebGLContext *mContext;
     PRUint32 mContextGeneration;
 };
 
-#define WEBGLBUFFER_PRIVATE_IID \
-    {0xd69f22e9, 0x6f98, 0x48bd, {0xb6, 0x94, 0x34, 0x17, 0xed, 0x06, 0x11, 0xab}}
-class WebGLBuffer :
-    public nsIWebGLBuffer,
-    public WebGLZeroingObject<8>, // almost never has more than 8 owners
-    public WebGLContextBoundObject
+struct WebGLVertexAttribData {
+    // note that these initial values are what GL initializes vertex attribs to
+    WebGLVertexAttribData()
+        : buf(0), stride(0), size(4), byteOffset(0),
+          type(LOCAL_GL_FLOAT), enabled(false), normalized(false)
+    { }
+
+    WebGLRefPtr<WebGLBuffer> buf;
+    WebGLuint stride;
+    WebGLuint size;
+    GLuint byteOffset;
+    GLenum type;
+    bool enabled;
+    bool normalized;
+
+    GLuint componentSize() const {
+        switch(type) {
+            case LOCAL_GL_BYTE:
+                return sizeof(GLbyte);
+                break;
+            case LOCAL_GL_UNSIGNED_BYTE:
+                return sizeof(GLubyte);
+                break;
+            case LOCAL_GL_SHORT:
+                return sizeof(GLshort);
+                break;
+            case LOCAL_GL_UNSIGNED_SHORT:
+                return sizeof(GLushort);
+                break;
+            // XXX case LOCAL_GL_FIXED:
+            case LOCAL_GL_FLOAT:
+                return sizeof(GLfloat);
+                break;
+            default:
+                NS_ERROR("Should never get here!");
+                return 0;
+        }
+    }
+
+    GLuint actualStride() const {
+        if (stride) return stride;
+        return size * componentSize();
+    }
+};
+
+class WebGLBuffer
+    : public nsIWebGLBuffer
+    , public WebGLRefCountedObject<WebGLBuffer>
+    , public WebGLContextBoundObject
 {
 public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLBUFFER_PRIVATE_IID)
-
-    WebGLBuffer(WebGLContext *context, WebGLuint name) :
-        WebGLContextBoundObject(context),
-        mName(name), mDeleted(false), mHasEverBeenBound(false),
-        mByteLength(0), mTarget(LOCAL_GL_NONE), mData(nsnull)
-    {}
+    WebGLBuffer(WebGLContext *context)
+        : WebGLContextBoundObject(context)
+        , mHasEverBeenBound(false)
+        , mByteLength(0)
+        , mTarget(LOCAL_GL_NONE)
+        , mData(nsnull)
+    {
+        mContext->MakeContextCurrent();
+        mContext->gl->fGenBuffers(1, &mGLName);
+        mMonotonicHandle = mContext->mBuffers.AppendElement(this);
+    }
 
     ~WebGLBuffer() {
-        Delete();
+        DeleteOnce();
     }
 
     void Delete() {
-        if (mDeleted)
-            return;
-        ZeroOwners();
-
+        mContext->MakeContextCurrent();
+        mContext->gl->fDeleteBuffers(1, &mGLName);
         free(mData);
         mData = nsnull;
-
-        mDeleted = true;
         mByteLength = 0;
+        mContext->mBuffers.RemoveElement(mMonotonicHandle);
     }
 
-    bool Deleted() const { return mDeleted; }
     bool HasEverBeenBound() { return mHasEverBeenBound; }
     void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
-    GLuint GLName() const { return mName; }
+    GLuint GLName() const { return mGLName; }
     GLuint ByteLength() const { return mByteLength; }
     GLenum Target() const { return mTarget; }
     const void *Data() const { return mData; }
 
     void SetByteLength(GLuint byteLength) { mByteLength = byteLength; }
     void SetTarget(GLenum target) { mTarget = target; }
 
     // element array buffers are the only buffers for which we need to keep a copy of the data.
@@ -964,80 +1099,83 @@ public:
         mHasCachedMaxUshortElement = true;
         mCachedMaxUshortElement = FindMaxElementInSubArray<GLshort>(mByteLength>>1, 0);
         return mCachedMaxUshortElement;
       }
     }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLBUFFER
+
 protected:
-    WebGLuint mName;
-    bool mDeleted;
+
+    WebGLuint mGLName;
     bool mHasEverBeenBound;
     GLuint mByteLength;
     GLenum mTarget;
+    WebGLMonotonicHandle mMonotonicHandle;
 
     PRUint8 mCachedMaxUbyteElement;
     bool mHasCachedMaxUbyteElement;
     PRUint16 mCachedMaxUshortElement;
     bool mHasCachedMaxUshortElement;
 
     void* mData; // in the case of an Element Array Buffer, we keep a copy.
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLBuffer, WEBGLBUFFER_PRIVATE_IID)
-
-#define WEBGLTEXTURE_PRIVATE_IID \
-    {0x4c19f189, 0x1f86, 0x4e61, {0x96, 0x21, 0x0a, 0x11, 0xda, 0x28, 0x10, 0xdd}}
-class WebGLTexture :
-    public nsIWebGLTexture,
-    public WebGLZeroingObject<8>, // almost never has more than 8 owners
-    public WebGLContextBoundObject
+class WebGLTexture
+    : public nsIWebGLTexture
+    , public WebGLRefCountedObject<WebGLTexture>
+    , public WebGLContextBoundObject
 {
 public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLTEXTURE_PRIVATE_IID)
+    WebGLTexture(WebGLContext *context)
+        : WebGLContextBoundObject(context)
+        , mHasEverBeenBound(false)
+        , mTarget(0)
+        , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
+        , mMagFilter(LOCAL_GL_LINEAR)
+        , mWrapS(LOCAL_GL_REPEAT)
+        , mWrapT(LOCAL_GL_REPEAT)
+        , mFacesCount(0)
+        , mMaxLevelWithCustomImages(0)
+        , mHaveGeneratedMipmap(false)
+        , mFakeBlackStatus(DoNotNeedFakeBlack)
+    {
+        mContext->MakeContextCurrent();
+        mContext->gl->fGenTextures(1, &mGLName);
+        mMonotonicHandle = mContext->mTextures.AppendElement(this);
+    }
 
-    WebGLTexture(WebGLContext *context, WebGLuint name) :
-        WebGLContextBoundObject(context),
-        mDeleted(false), mHasEverBeenBound(false), mName(name),
-        mTarget(0),
-        mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR),
-        mMagFilter(LOCAL_GL_LINEAR),
-        mWrapS(LOCAL_GL_REPEAT),
-        mWrapT(LOCAL_GL_REPEAT),
-        mFacesCount(0),
-        mMaxLevelWithCustomImages(0),
-        mHaveGeneratedMipmap(false),
-        mFakeBlackStatus(DoNotNeedFakeBlack)
-    {
+    ~WebGLTexture() {
+        DeleteOnce();
     }
 
     void Delete() {
-        if (mDeleted)
-            return;
-        ZeroOwners();
-        mDeleted = true;
+        mImageInfos.Clear();
+        mContext->MakeContextCurrent();
+        mContext->gl->fDeleteTextures(1, &mGLName);
+        mContext->mTextures.RemoveElement(mMonotonicHandle);
     }
 
-    bool Deleted() { return mDeleted; }
     bool HasEverBeenBound() { return mHasEverBeenBound; }
     void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
-    WebGLuint GLName() { return mName; }
+    WebGLuint GLName() { return mGLName; }
+    GLenum Target() const { return mTarget; }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLTEXTURE
 
 protected:
+
     friend class WebGLContext;
     friend class WebGLFramebuffer;
 
-    bool mDeleted;
     bool mHasEverBeenBound;
-    WebGLuint mName;
+    WebGLuint mGLName;
 
     // we store information about the various images that are part of
     // this texture (cubemap faces, mipmap levels)
 
 public:
 
     struct ImageInfo {
         ImageInfo() : mWidth(0), mHeight(0), mFormat(0), mType(0), mIsDefined(false) {}
@@ -1093,16 +1231,18 @@ public:
                ImageInfoAt(level, face).mIsDefined;
     }
 
     static size_t FaceForTarget(WebGLenum target) {
         return target == LOCAL_GL_TEXTURE_2D ? 0 : target - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
     }
 
     PRInt64 MemoryUsage() const {
+        if (IsDeleted())
+            return 0;
         PRInt64 result = 0;
         for(size_t face = 0; face < mFacesCount; face++) {
             if (mHaveGeneratedMipmap) {
                 // Each mipmap level is 1/4 the size of the previous level
                 // 1 + x + x^2 + ... = 1/(1-x)
                 // for x = 1/4, we get 1/(1-1/4) = 4/3
                 result += ImageInfoAt(0, face).MemoryUsage() * 4 / 3;
             } else {
@@ -1119,16 +1259,18 @@ protected:
     WebGLenum mMinFilter, mMagFilter, mWrapS, mWrapT;
 
     size_t mFacesCount, mMaxLevelWithCustomImages;
     nsTArray<ImageInfo> mImageInfos;
 
     bool mHaveGeneratedMipmap;
     FakeBlackStatus mFakeBlackStatus;
 
+    WebGLMonotonicHandle mMonotonicHandle;
+
     void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) {
         mMaxLevelWithCustomImages = NS_MAX(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages);
         mImageInfos.EnsureLengthAtLeast((mMaxLevelWithCustomImages + 1) * mFacesCount);
     }
 
     bool CheckFloatTextureFilterParams() const {
         // Without OES_texture_float_linear, only NEAREST and NEAREST_MIMPAMP_NEAREST are supported
         return (mMagFilter == LOCAL_GL_NEAREST) &&
@@ -1181,17 +1323,17 @@ public:
             mContext->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
             // very important to return here before modifying texture state! This was the place when I lost a whole day figuring
             // very strange 'invalid write' crashes.
             return;
         }
 
         mTarget = aTarget;
 
-        mContext->gl->fBindTexture(mTarget, mName);
+        mContext->gl->fBindTexture(mTarget, mGLName);
 
         if (firstTimeThisTextureIsBound) {
             mFacesCount = (mTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
             EnsureMaxLevelWithCustomImagesAtLeast(0);
             SetDontKnowIfNeedFakeBlack();
 
             // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
             // present in GLES 2, but is present in GL and it seems as if for cube maps
@@ -1419,71 +1561,47 @@ public:
             if (mFakeBlackStatus == DontKnowIfNeedFakeBlack)
                 mFakeBlackStatus = DoNotNeedFakeBlack;
         }
 
         return mFakeBlackStatus == DoNeedFakeBlack;
     }
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLTexture, WEBGLTEXTURE_PRIVATE_IID)
-
-#define WEBGLSHADER_PRIVATE_IID \
-    {0x48cce975, 0xd459, 0x4689, {0x83, 0x82, 0x37, 0x82, 0x6e, 0xac, 0xe0, 0xa7}}
-class WebGLShader :
-    public nsIWebGLShader,
-    public WebGLZeroingObject<8>, // almost never has more than 8 owners
-    public WebGLContextBoundObject
+class WebGLShader
+    : public nsIWebGLShader
+    , public WebGLRefCountedObject<WebGLShader>
+    , public WebGLContextBoundObject
 {
 public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLSHADER_PRIVATE_IID)
-
-    WebGLShader(WebGLContext *context, WebGLuint name, WebGLenum stype) :
-        WebGLContextBoundObject(context),
-        mName(name), mDeleted(false), mType(stype),
-        mNeedsTranslation(true), mAttachCount(0),
-        mDeletePending(false)
-    { }
-
-    void DetachedFromProgram() {
-        DecrementAttachCount();
-        if (mDeletePending && AttachCount() <= 0) {
-            DeleteWhenNotAttached();
-        }
+    WebGLShader(WebGLContext *context, WebGLenum stype)
+        : WebGLContextBoundObject(context)
+        , mType(stype)
+        , mNeedsTranslation(true)
+    {
+        mContext->MakeContextCurrent();
+        mGLName = mContext->gl->fCreateShader(mType);
+        mMonotonicHandle = mContext->mShaders.AppendElement(this);
     }
 
-    void DeleteWhenNotAttached() {
-        if (mDeleted)
-            return;
-
-        if (AttachCount() > 0) {
-            mDeletePending = true;
-            return;
-        }
-
-        Delete();
+    ~WebGLShader() {
+        DeleteOnce();
     }
 
     void Delete() {
-        if (mDeleted)
-            return;
-
-        ZeroOwners();
-        mDeleted = true;
-        mDeletePending = false;
+        mSource.Truncate();
+        mTranslationLog.Truncate();
+        mContext->MakeContextCurrent();
+        mContext->gl->fDeleteShader(mGLName);
+        mContext->mShaders.RemoveElement(mMonotonicHandle);
     }
 
-    bool Deleted() { return mDeleted; }
-    WebGLuint GLName() { return mName; }
+    WebGLuint GLName() { return mGLName; }
     WebGLenum ShaderType() { return mType; }
 
-    PRInt32 AttachCount() { return mAttachCount; }
-    void IncrementAttachCount() { mAttachCount++; }
-    void DecrementAttachCount() { mAttachCount--; }
-
     void SetSource(const nsAString& src) {
         // XXX do some quick gzip here maybe -- getting this will be very rare
         mSource.Assign(src);
     }
 
     const nsString& Source() const { return mSource; }
 
     void SetNeedsTranslation() { mNeedsTranslation = true; }
@@ -1497,120 +1615,93 @@ public:
     void SetTranslationFailure(const nsCString& msg) {
         mTranslationLog.Assign(msg); 
     }
 
     const nsCString& TranslationLog() const { return mTranslationLog; }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLSHADER
+
 protected:
-    WebGLuint mName;
-    bool mDeleted;
+
+    WebGLuint mGLName;
     WebGLenum mType;
     nsString mSource;
     nsCString mTranslationLog;
     bool mNeedsTranslation;
-    PRInt32 mAttachCount;
-    bool mDeletePending;
+    WebGLMonotonicHandle mMonotonicHandle;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLShader, WEBGLSHADER_PRIVATE_IID)
-
-#define WEBGLPROGRAM_PRIVATE_IID \
-    {0xb3084a5b, 0xa5b4, 0x4ee0, {0xa0, 0xf0, 0xfb, 0xdd, 0x64, 0xaf, 0x8e, 0x82}}
-class WebGLProgram :
-    public nsIWebGLProgram,
-    public WebGLZeroingObject<8>, // can actually have many more owners (WebGLUniformLocations),
-                                  // but that shouldn't be performance-critical as references to the uniformlocations are stored
-                                  // in mMapUniformLocations, limiting the churning
-    public WebGLContextBoundObject
+class WebGLProgram
+    : public nsIWebGLProgram
+    , public WebGLRefCountedObject<WebGLProgram>
+    , public WebGLContextBoundObject
 {
 public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLPROGRAM_PRIVATE_IID)
-
-    WebGLProgram(WebGLContext *context, WebGLuint name) :
-        WebGLContextBoundObject(context),
-        mName(name), mDeleted(false), mDeletePending(false),
-        mLinkStatus(false), mGeneration(0),
-        mUniformMaxNameLength(0), mAttribMaxNameLength(0),
-        mUniformCount(0), mAttribCount(0)
+    WebGLProgram(WebGLContext *context)
+        : WebGLContextBoundObject(context)
+        , mLinkStatus(false)
+        , mGeneration(0)
+        , mUniformMaxNameLength(0)
+        , mAttribMaxNameLength(0)
+        , mUniformCount(0)
+        , mAttribCount(0)
     {
-        mMapUniformLocations.Init();
+        mContext->MakeContextCurrent();
+        mGLName = mContext->gl->fCreateProgram();
+        mMonotonicHandle = mContext->mPrograms.AppendElement(this);
     }
 
-    void DeleteWhenNotCurrent() {
-        if (mDeleted)
-            return;
-
-        if (mContext->mCurrentProgram == this) {
-            mDeletePending = true;
-            return;
-        }
-
-        Delete();
+    ~WebGLProgram() {
+        DeleteOnce();
     }
 
     void Delete() {
-        if (mDeleted)
-            return;
-
         DetachShaders();
-        ZeroOwners();
-        mDeleted = true;
-        mDeletePending = false;
+        mContext->MakeContextCurrent();
+        mContext->gl->fDeleteProgram(mGLName);
+        mContext->mPrograms.RemoveElement(mMonotonicHandle);
     }
 
     void DetachShaders() {
-        for (PRUint32 i = 0; i < mAttachedShaders.Length(); ++i) {
-            WebGLShader* shader = mAttachedShaders[i];
-            if (shader)
-                shader->DetachedFromProgram();
-        }
         mAttachedShaders.Clear();
     }
 
-    void NoLongerCurrent() {
-        if (mDeletePending) {
-            DetachShaders();
-            DeleteWhenNotCurrent();
-        }
-    }
-
-    bool Deleted() { return mDeleted; }
-    void SetDeletePending() { mDeletePending = true; }
-    void ClearDeletePending() { mDeletePending = false; }
-    bool HasDeletePending() { return mDeletePending; }
-
-    WebGLuint GLName() { return mName; }
-    const nsTArray<nsRefPtr<WebGLShader> >& AttachedShaders() const { return mAttachedShaders; }
+    WebGLuint GLName() { return mGLName; }
+    const nsTArray<WebGLRefPtr<WebGLShader> >& AttachedShaders() const { return mAttachedShaders; }
     bool LinkStatus() { return mLinkStatus; }
     PRUint32 Generation() const { return mGeneration.value(); }
     void SetLinkStatus(bool val) { mLinkStatus = val; }
 
     bool ContainsShader(WebGLShader *shader) {
         return mAttachedShaders.Contains(shader);
     }
 
     // return true if the shader wasn't already attached
     bool AttachShader(WebGLShader *shader) {
         if (ContainsShader(shader))
             return false;
         mAttachedShaders.AppendElement(shader);
-        shader->IncrementAttachCount();
+
+        mContext->MakeContextCurrent();
+        mContext->gl->fAttachShader(GLName(), shader->GLName());
+
         return true;
     }
 
     // return true if the shader was found and removed
     bool DetachShader(WebGLShader *shader) {
-        if (mAttachedShaders.RemoveElement(shader)) {
-            shader->DetachedFromProgram();
-            return true;
-        }
-        return false;
+        if (!mAttachedShaders.RemoveElement(shader))
+            return false;
+
+        mContext->MakeContextCurrent();
+        mContext->gl->fDetachShader(GLName(), shader->GLName());
+
+        return true;
     }
 
     bool HasAttachedShaderOfType(GLenum shaderType) {
         for (PRUint32 i = 0; i < mAttachedShaders.Length(); ++i) {
             if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType) {
                 return true;
             }
         }
@@ -1623,84 +1714,83 @@ public:
             HasAttachedShaderOfType(LOCAL_GL_FRAGMENT_SHADER);
     }
 
     bool NextGeneration()
     {
         if (!(mGeneration+1).valid())
             return false; // must exit without changing mGeneration
         ++mGeneration;
-        mMapUniformLocations.Clear();
         return true;
     }
-    
-
-    already_AddRefed<WebGLUniformLocation> GetUniformLocationObject(GLint glLocation);
 
     /* Called only after LinkProgram */
     bool UpdateInfo(gl::GLContext *gl);
 
     /* Getters for cached program info */
     WebGLint UniformMaxNameLength() const { return mUniformMaxNameLength; }
     WebGLint AttribMaxNameLength() const { return mAttribMaxNameLength; }
     WebGLint UniformCount() const { return mUniformCount; }
     WebGLint AttribCount() const { return mAttribCount; }
     bool IsAttribInUse(unsigned i) const { return mAttribsInUse[i]; }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLPROGRAM
+
 protected:
-    WebGLuint mName;
-    bool mDeleted;
-    bool mDeletePending;
+
+    WebGLuint mGLName;
     bool mLinkStatus;
     // attached shaders of the program object
-    nsTArray<nsRefPtr<WebGLShader> > mAttachedShaders;
+    nsTArray<WebGLRefPtr<WebGLShader> > mAttachedShaders;
     CheckedUint32 mGeneration;
 
     // post-link data
-    nsRefPtrHashtable<nsUint32HashKey, WebGLUniformLocation> mMapUniformLocations;
+
     GLint mUniformMaxNameLength;
     GLint mAttribMaxNameLength;
     GLint mUniformCount;
     GLint mAttribCount;
     std::vector<bool> mAttribsInUse;
+    WebGLMonotonicHandle mMonotonicHandle;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLProgram, WEBGLPROGRAM_PRIVATE_IID)
-
-#define WEBGLRENDERBUFFER_PRIVATE_IID \
-    {0x3cbc2067, 0x5831, 0x4e3f, {0xac, 0x52, 0x7e, 0xf4, 0x5c, 0x04, 0xff, 0xae}}
-class WebGLRenderbuffer :
-    public nsIWebGLRenderbuffer,
-    public WebGLZeroingObject<8>, // almost never has more than 8 owners
-    public WebGLRectangleObject,
-    public WebGLContextBoundObject
+class WebGLRenderbuffer
+    : public nsIWebGLRenderbuffer
+    , public WebGLRefCountedObject<WebGLRenderbuffer>
+    , public WebGLRectangleObject
+    , public WebGLContextBoundObject
 {
 public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLRENDERBUFFER_PRIVATE_IID)
+    WebGLRenderbuffer(WebGLContext *context)
+        : WebGLContextBoundObject(context)
+        , mInternalFormat(0)
+        , mInternalFormatForGL(0)
+        , mHasEverBeenBound(false)
+        , mInitialized(false)
+    {
 
-    WebGLRenderbuffer(WebGLContext *context, WebGLuint name, WebGLuint secondBufferName = 0) :
-        WebGLContextBoundObject(context),
-        mName(name),
-        mInternalFormat(0),
-        mInternalFormatForGL(0),
-        mDeleted(false), mHasEverBeenBound(false), mInitialized(false)
-    { }
+        mContext->MakeContextCurrent();
+        mContext->gl->fGenRenderbuffers(1, &mGLName);
+        mMonotonicHandle = mContext->mRenderbuffers.AppendElement(this);
+    }
+
+    ~WebGLRenderbuffer() {
+        DeleteOnce();
+    }
 
     void Delete() {
-        if (mDeleted)
-            return;
-        ZeroOwners();
-        mDeleted = true;
+        mContext->MakeContextCurrent();
+        mContext->gl->fDeleteRenderbuffers(1, &mGLName);
+        mContext->mRenderbuffers.RemoveElement(mMonotonicHandle);
     }
-    bool Deleted() const { return mDeleted; }
+
     bool HasEverBeenBound() { return mHasEverBeenBound; }
     void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
-    WebGLuint GLName() const { return mName; }
+    WebGLuint GLName() const { return mGLName; }
 
     bool Initialized() const { return mInitialized; }
     void SetInitialized(bool aInitialized) { mInitialized = aInitialized; }
 
     WebGLenum InternalFormat() const { return mInternalFormat; }
     void SetInternalFormat(WebGLenum aInternalFormat) { mInternalFormat = aInternalFormat; }
     
     WebGLenum InternalFormatForGL() const { return mInternalFormatForGL; }
@@ -1728,53 +1818,57 @@ public:
         NS_ABORT();
         return 0;
     }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLRENDERBUFFER
 
 protected:
-    WebGLuint mName;
+
+    WebGLuint mGLName;
     WebGLenum mInternalFormat;
     WebGLenum mInternalFormatForGL;
-
-    bool mDeleted;
+    WebGLMonotonicHandle mMonotonicHandle;
     bool mHasEverBeenBound;
     bool mInitialized;
 
     friend class WebGLFramebuffer;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLRenderbuffer, WEBGLRENDERBUFFER_PRIVATE_IID)
-
 class WebGLFramebufferAttachment
     : public WebGLRectangleObject
 {
     // deleting a texture or renderbuffer immediately detaches it
-    WebGLObjectRefPtr<WebGLTexture> mTexturePtr;
-    WebGLObjectRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
+    WebGLRefPtr<WebGLTexture> mTexturePtr;
+    WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
     WebGLenum mAttachmentPoint;
     WebGLint mTextureLevel;
     WebGLenum mTextureCubeMapFace;
 
 public:
     WebGLFramebufferAttachment(WebGLenum aAttachmentPoint)
         : mAttachmentPoint(aAttachmentPoint)
     {}
 
-    bool IsNull() const {
-        return !mTexturePtr && !mRenderbufferPtr;
+    bool IsDefined() const {
+        return Texture() || Renderbuffer();
+    }
+
+    bool IsDeleteRequested() const {
+        return Texture() ? Texture()->IsDeleteRequested()
+             : Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
+             : false;
     }
 
     bool HasAlpha() const {
         WebGLenum format = 0;
-        if (mTexturePtr)
+        if (Texture() && Texture()->HasImageInfoAt(0,0))
             format = mTexturePtr->ImageInfoAt(0,0).mFormat;
-        if (mRenderbufferPtr)
+        else if (Renderbuffer())
             format = mRenderbufferPtr->InternalFormat();
         return format == LOCAL_GL_RGBA ||
                format == LOCAL_GL_LUMINANCE_ALPHA ||
                format == LOCAL_GL_ALPHA ||
                format == LOCAL_GL_RGBA4 ||
                format == LOCAL_GL_RGB5_A1;
     }
 
@@ -1831,48 +1925,60 @@ public:
         }
 
         return false; // no attachment at all, so no incompatibility
     }
 
     bool HasUninitializedRenderbuffer() const {
         return mRenderbufferPtr && !mRenderbufferPtr->Initialized();
     }
+
+    void Reset() {
+        mTexturePtr = nsnull;
+        mRenderbufferPtr = nsnull;
+    }
 };
 
-#define WEBGLFRAMEBUFFER_PRIVATE_IID \
-    {0x0052a16f, 0x4bc9, 0x4a55, {0x9d, 0xa3, 0x54, 0x95, 0xaa, 0x4e, 0x80, 0xb9}}
-class WebGLFramebuffer :
-    public nsIWebGLFramebuffer,
-    public WebGLZeroingObject<8>, // almost never has more than 8 owners
-    public WebGLContextBoundObject
+class WebGLFramebuffer
+    : public nsIWebGLFramebuffer
+    , public WebGLRefCountedObject<WebGLFramebuffer>
+    , public WebGLContextBoundObject
 {
 public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLFRAMEBUFFER_PRIVATE_IID)
+    WebGLFramebuffer(WebGLContext *context)
+        : WebGLContextBoundObject(context)
+        , mHasEverBeenBound(false)
+        , mColorAttachment(LOCAL_GL_COLOR_ATTACHMENT0)
+        , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
+        , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
+        , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+    {
+        mContext->MakeContextCurrent();
+        mContext->gl->fGenFramebuffers(1, &mGLName);
+        mMonotonicHandle = mContext->mFramebuffers.AppendElement(this);
+    }
 
-    WebGLFramebuffer(WebGLContext *context, WebGLuint name) :
-        WebGLContextBoundObject(context),
-        mName(name), mDeleted(false), mHasEverBeenBound(false),
-        mColorAttachment(LOCAL_GL_COLOR_ATTACHMENT0),
-        mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT),
-        mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT),
-        mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
-    { }
+    ~WebGLFramebuffer() {
+        DeleteOnce();
+    }
 
     void Delete() {
-        if (mDeleted)
-            return;
-        ZeroOwners();
-        mDeleted = true;
+        mColorAttachment.Reset();
+        mDepthAttachment.Reset();
+        mStencilAttachment.Reset();
+        mDepthStencilAttachment.Reset();
+        mContext->MakeContextCurrent();
+        mContext->gl->fDeleteFramebuffers(1, &mGLName);
+        mContext->mFramebuffers.RemoveElement(mMonotonicHandle);
     }
-    bool Deleted() { return mDeleted; }
+
     bool HasEverBeenBound() { return mHasEverBeenBound; }
     void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
-    WebGLuint GLName() { return mName; }
-    
+    WebGLuint GLName() { return mGLName; }
+
     WebGLsizei width() { return mColorAttachment.width(); }
     WebGLsizei height() { return mColorAttachment.height(); }
 
     nsresult FramebufferRenderbuffer(WebGLenum target,
                                      WebGLenum attachment,
                                      WebGLenum rbtarget,
                                      nsIWebGLRenderbuffer *rbobj)
     {
@@ -2001,33 +2107,33 @@ public:
         if (mColorAttachment.IsIncompatibleWithAttachmentPoint() ||
             mDepthAttachment.IsIncompatibleWithAttachmentPoint() ||
             mStencilAttachment.IsIncompatibleWithAttachmentPoint() ||
             mDepthStencilAttachment.IsIncompatibleWithAttachmentPoint())
         {
             // some attachment is incompatible with its attachment point
             return true;
         }
-        
-        if (int(mDepthAttachment.IsNull()) +
-            int(mStencilAttachment.IsNull()) +
-            int(mDepthStencilAttachment.IsNull()) <= 1)
+
+        if (int(mDepthAttachment.IsDefined()) +
+            int(mStencilAttachment.IsDefined()) +
+            int(mDepthStencilAttachment.IsDefined()) >= 2)
         {
             // has at least two among Depth, Stencil, DepthStencil
             return true;
         }
-        
-        if (!mDepthAttachment.IsNull() && !mDepthAttachment.HasSameDimensionsAs(mColorAttachment))
+
+        if (mDepthAttachment.IsDefined() && !mDepthAttachment.HasSameDimensionsAs(mColorAttachment))
             return true;
-        if (!mStencilAttachment.IsNull() && !mStencilAttachment.HasSameDimensionsAs(mColorAttachment))
+        if (mStencilAttachment.IsDefined() && !mStencilAttachment.HasSameDimensionsAs(mColorAttachment))
             return true;
-        if (!mDepthStencilAttachment.IsNull() && !mDepthStencilAttachment.HasSameDimensionsAs(mColorAttachment))
+        if (mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.HasSameDimensionsAs(mColorAttachment))
             return true;
-        
-        else return false;
+
+        return false;
     }
 
     const WebGLFramebufferAttachment& ColorAttachment() const {
         return mColorAttachment;
     }
 
     const WebGLFramebufferAttachment& DepthAttachment() const {
         return mDepthAttachment;
@@ -2048,16 +2154,38 @@ public:
             return mDepthAttachment;
         if (attachment == LOCAL_GL_STENCIL_ATTACHMENT)
             return mStencilAttachment;
 
         NS_ASSERTION(attachment == LOCAL_GL_COLOR_ATTACHMENT0, "bad attachment!");
         return mColorAttachment;
     }
 
+    void DetachTexture(const WebGLTexture *tex) {
+        if (mColorAttachment.Texture() == tex)
+            FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_TEXTURE_2D, nsnull, 0);
+        if (mDepthAttachment.Texture() == tex)
+            FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nsnull, 0);
+        if (mStencilAttachment.Texture() == tex)
+            FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nsnull, 0);
+        if (mDepthStencilAttachment.Texture() == tex)
+            FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nsnull, 0);
+    }
+
+    void DetachRenderbuffer(const WebGLRenderbuffer *rb) {
+        if (mColorAttachment.Renderbuffer() == rb)
+            FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER, nsnull);
+        if (mDepthAttachment.Renderbuffer() == rb)
+            FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nsnull);
+        if (mStencilAttachment.Renderbuffer() == rb)
+            FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nsnull);
+        if (mDepthStencilAttachment.Renderbuffer() == rb)
+            FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nsnull);
+    }
+
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLFRAMEBUFFER
 
 protected:
 
     // protected because WebGLContext should only call InitializeRenderbuffers
     void InitializeRenderbuffers()
     {
@@ -2094,120 +2222,102 @@ protected:
 
         if (mStencilAttachment.HasUninitializedRenderbuffer())
             mStencilAttachment.Renderbuffer()->SetInitialized(true);
 
         if (mDepthStencilAttachment.HasUninitializedRenderbuffer())
             mDepthStencilAttachment.Renderbuffer()->SetInitialized(true);
     }
 
-    WebGLuint mName;
-    bool mDeleted;
+    WebGLuint mGLName;
     bool mHasEverBeenBound;
 
     // we only store pointers to attached renderbuffers, not to attached textures, because
     // we will only need to initialize renderbuffers. Textures are already initialized.
     WebGLFramebufferAttachment mColorAttachment,
                                mDepthAttachment,
                                mStencilAttachment,
                                mDepthStencilAttachment;
+
+    WebGLMonotonicHandle mMonotonicHandle;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLFramebuffer, WEBGLFRAMEBUFFER_PRIVATE_IID)
-
-#define WEBGLUNIFORMLOCATION_PRIVATE_IID \
-    {0x01a8a614, 0xb109, 0x42f1, {0xb4, 0x40, 0x8d, 0x8b, 0x87, 0x0b, 0x43, 0xa7}}
-class WebGLUniformLocation :
-    public nsIWebGLUniformLocation,
-    public WebGLZeroingObject<2>, // never saw a WebGLUniformLocation have more than 2 owners, and since these
-                                  // are small objects and there are many of them, it's worth saving some memory
-                                  // by using a small value such as 2 here.
-    public WebGLContextBoundObject
+class WebGLUniformLocation
+    : public nsIWebGLUniformLocation
+    , public WebGLContextBoundObject
+    , public WebGLRefCountedObject<WebGLUniformLocation>
 {
 public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLUNIFORMLOCATION_PRIVATE_IID)
+    WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location)
+        : WebGLContextBoundObject(context)
+        , mProgram(program)
+        , mProgramGeneration(program->Generation())
+        , mLocation(location)
+    {
+        mMonotonicHandle = mContext->mUniformLocations.AppendElement(this);
+    }
 
-    WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location) :
-        WebGLContextBoundObject(context), mProgram(program), mProgramGeneration(program->Generation()),
-        mLocation(location) { }
+    ~WebGLUniformLocation() {
+        DeleteOnce();
+    }
+
+    void Delete() {
+        mProgram = nsnull;
+        mContext->mUniformLocations.RemoveElement(mMonotonicHandle);
+    }
 
     WebGLProgram *Program() const { return mProgram; }
     GLint Location() const { return mLocation; }
     PRUint32 ProgramGeneration() const { return mProgramGeneration; }
 
-    // needed for our generic helpers to check nsIxxx parameters, see GetConcreteObject.
-    bool Deleted() { return false; }
-
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLUNIFORMLOCATION
 protected:
-    WebGLObjectRefPtr<WebGLProgram> mProgram;
+    // nsRefPtr, not WebGLRefPtr, so that we don't prevent the program from being explicitly deleted.
+    // we just want to avoid having a dangling pointer.
+    nsRefPtr<WebGLProgram> mProgram;
+
     PRUint32 mProgramGeneration;
     GLint mLocation;
+    WebGLMonotonicHandle mMonotonicHandle;
+    friend class WebGLProgram;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLUniformLocation, WEBGLUNIFORMLOCATION_PRIVATE_IID)
-
-#define WEBGLACTIVEINFO_PRIVATE_IID \
-    {0x90def5ec, 0xc672, 0x4ac3, {0xb8, 0x97, 0x04, 0xa2, 0x6d, 0xda, 0x66, 0xd7}}
-class WebGLActiveInfo :
-    public nsIWebGLActiveInfo
+class WebGLActiveInfo
+    : public nsIWebGLActiveInfo
 {
 public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLACTIVEINFO_PRIVATE_IID)
-
     WebGLActiveInfo(WebGLint size, WebGLenum type, const char *nameptr, PRUint32 namelength) :
-        mDeleted(false),
         mSize(size),
         mType(type)
     {
         mName.AssignASCII(nameptr, namelength);
     }
 
-    void Delete() {
-        if (mDeleted)
-            return;
-        mDeleted = true;
-    }
-
-    bool Deleted() { return mDeleted; }
-
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLACTIVEINFO
 protected:
-    bool mDeleted;
     WebGLint mSize;
     WebGLenum mType;
     nsString mName;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLActiveInfo, WEBGLACTIVEINFO_PRIVATE_IID)
-
-#define WEBGLEXTENSION_PRIVATE_IID \
-    {0x457dd0b2, 0x9f77, 0x4c23, {0x95, 0x70, 0x9d, 0x62, 0x65, 0xc1, 0xa4, 0x81}}
-class WebGLExtension :
-    public nsIWebGLExtension,
-    public WebGLContextBoundObject,
-    public WebGLZeroingObject<2> // WebGLExtensions probably won't have many owers and
-                                 // can be very small objects. Also, we have a static array of those. So, saving some memory
-                                 // by using a small value such as 2 here.
+class WebGLExtension
+    : public nsIWebGLExtension
+    , public WebGLContextBoundObject
 {
 public:
     WebGLExtension(WebGLContext *baseContext)
         : WebGLContextBoundObject(baseContext)
     {}
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLEXTENSION
-
-    NS_DECLARE_STATIC_IID_ACCESSOR(WEBGLEXTENSION_PRIVATE_IID)
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(WebGLExtension, WEBGLACTIVEINFO_PRIVATE_IID)
-
 /**
  ** Template implementations
  **/
 
 /* Helper function taking a BaseInterfaceType pointer, casting it to
  * ConcreteObjectType and performing some checks along the way.
  *
  * By default, null (respectively: deleted) aInterface pointers are
@@ -2241,38 +2351,30 @@ WebGLContext::GetConcreteObject(const ch
                 ErrorInvalidValue("%s: null object passed as argument", info);
             return false;
         }
     }
 
     if (isNull)
         *isNull = false;
 
-#ifdef DEBUG
-    {
-        // once bug 694114 is implemented, we want to replace this by a static assertion, without #ifdef DEBUG
-        nsresult rv = NS_OK;
-        nsCOMPtr<ConcreteObjectType> tmp(do_QueryInterface(aInterface, &rv));
-        NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
-                          "QueryInterface failed. WebGL objects are builtinclass, so this should never happen. "
-                          "Please file a bug at bugzilla.mozilla.org -> Core -> Canvas:WebGL and link to the present page.");
-    }
-#endif
-    
-    *aConcreteObject = static_cast<ConcreteObjectType*>(aInterface);
+    // the key to why this static_cast is all we need to do (as opposed to the QueryInterface check we used to do)
+    // is that since bug 638328, WebGL interfaces are marked 'builtinclass' in the IDL
+    ConcreteObjectType *concrete = static_cast<ConcreteObjectType*>(aInterface);
+    *aConcreteObject = concrete;
 
-    if (!(*aConcreteObject)->IsCompatibleWithContext(this)) {
+    if (!concrete->IsCompatibleWithContext(this)) {
         // the object doesn't belong to this WebGLContext
         if (generateErrors)
             ErrorInvalidOperation("%s: object from different WebGL context (or older generation of this one) "
                                   "passed as argument", info);
         return false;
     }
 
-    if ((*aConcreteObject)->Deleted()) {
+    if (concrete->IsDeleted()) {
         if (NS_LIKELY(isDeleted)) {
             // non-null isDeleted means that the caller will accept a deleted arg
             *isDeleted = true;
             return true;
         } else {
             if (generateErrors)
                 ErrorInvalidValue("%s: deleted object passed as argument", info);
             return false;
@@ -2367,159 +2469,100 @@ class WebGLMemoryReporter
         ContextsArrayType & contexts = Contexts();
         contexts.RemoveElement(c);
         if (contexts.IsEmpty()) {
             delete sUniqueInstance;
             sUniqueInstance = nsnull;
         }
     }
 
-    static PLDHashOperator TextureMemoryUsageFunction(const PRUint32&, WebGLTexture *aValue, void *aData)
-    {
-        PRInt64 *result = (PRInt64*) aData;
-        *result += aValue->MemoryUsage();
-        return PL_DHASH_NEXT;
-    }
-
     static PRInt64 GetTextureMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            PRInt64 textureMemoryUsageForThisContext = 0;
-            contexts[i]->mMapTextures.EnumerateRead(TextureMemoryUsageFunction, &textureMemoryUsageForThisContext);
-            result += textureMemoryUsageForThisContext;
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            for (size_t t = 0; t < contexts[i]->mTextures.Length(); ++t)
+              result += contexts[i]->mTextures[t]->MemoryUsage();
         return result;
     }
-    
+
     static PRInt64 GetTextureCount() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            result += contexts[i]->mMapTextures.Count();
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            result += contexts[i]->mTextures.Length();
         return result;
     }
-    
-    static PLDHashOperator BufferMemoryUsageFunction(const PRUint32&, WebGLBuffer *aValue, void *aData)
-    {
-        PRInt64 *result = (PRInt64*) aData;
-        *result += aValue->ByteLength();
-        return PL_DHASH_NEXT;
-    }
 
     static PRInt64 GetBufferMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            PRInt64 bufferMemoryUsageForThisContext = 0;
-            contexts[i]->mMapBuffers.EnumerateRead(BufferMemoryUsageFunction, &bufferMemoryUsageForThisContext);
-            result += bufferMemoryUsageForThisContext;
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            for (size_t b = 0; b < contexts[i]->mBuffers.Length(); ++b)
+                result += contexts[i]->mBuffers[b]->ByteLength();
         return result;
     }
-    
-    static PLDHashOperator BufferCacheMemoryUsageFunction(const PRUint32&, WebGLBuffer *aValue, void *aData)
-    {
-        PRInt64 *result = (PRInt64*) aData;
-        // element array buffers are cached in the WebGL implementation. Other buffers aren't.
-        if (aValue->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
-          *result += aValue->ByteLength();
-        return PL_DHASH_NEXT;
-    }
 
     static PRInt64 GetBufferCacheMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            PRInt64 bufferCacheMemoryUsageForThisContext = 0;
-            contexts[i]->mMapBuffers.EnumerateRead(BufferCacheMemoryUsageFunction, &bufferCacheMemoryUsageForThisContext);
-            result += bufferCacheMemoryUsageForThisContext;
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            for (size_t b = 0; b < contexts[i]->mBuffers.Length(); ++b)
+                if (contexts[i]->mBuffers[b]->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
+                    result += contexts[i]->mBuffers[b]->ByteLength();
         return result;
     }
 
     static PRInt64 GetBufferCount() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            result += contexts[i]->mMapBuffers.Count();
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            result += contexts[i]->mBuffers.Length();
         return result;
     }
-    
-    static PLDHashOperator RenderbufferMemoryUsageFunction(const PRUint32&, WebGLRenderbuffer *aValue, void *aData)
-    {
-        PRInt64 *result = (PRInt64*) aData;
-        *result += aValue->MemoryUsage();
-        return PL_DHASH_NEXT;
-    }
 
     static PRInt64 GetRenderbufferMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            PRInt64 bufferMemoryUsageForThisContext = 0;
-            contexts[i]->mMapRenderbuffers.EnumerateRead(RenderbufferMemoryUsageFunction, &bufferMemoryUsageForThisContext);
-            result += bufferMemoryUsageForThisContext;
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            for (size_t r = 0; r < contexts[i]->mRenderbuffers.Length(); ++r)
+              result += contexts[i]->mRenderbuffers[r]->MemoryUsage();
         return result;
     }
-    
+
     static PRInt64 GetRenderbufferCount() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            result += contexts[i]->mMapRenderbuffers.Count();
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            result += contexts[i]->mRenderbuffers.Length();
         return result;
     }
 
-    static PLDHashOperator ShaderSourceSizeFunction(const PRUint32&, WebGLShader *aValue, void *aData)
-    {
-        PRInt64 *result = (PRInt64*) aData;
-        *result += aValue->Source().Length();
-        return PL_DHASH_NEXT;
-    }
-
-    static PLDHashOperator ShaderTranslationLogSizeFunction(const PRUint32&, WebGLShader *aValue, void *aData)
-    {
-        PRInt64 *result = (PRInt64*) aData;
-        *result += aValue->TranslationLog().Length();
-        return PL_DHASH_NEXT;
-    }
-
     static PRInt64 GetShaderSourcesSize() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            PRInt64 shaderSourcesSizeForThisContext = 0;
-            contexts[i]->mMapShaders.EnumerateRead(ShaderSourceSizeFunction, &shaderSourcesSizeForThisContext);
-            result += shaderSourcesSizeForThisContext;
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            for (size_t s = 0; s < contexts[i]->mShaders.Length(); ++s)
+                result += contexts[i]->mShaders[s]->Source().Length();
         return result;
     }
-    
+
     static PRInt64 GetShaderTranslationLogsSize() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            PRInt64 shaderTranslationLogsSizeForThisContext = 0;
-            contexts[i]->mMapShaders.EnumerateRead(ShaderTranslationLogSizeFunction, &shaderTranslationLogsSizeForThisContext);
-            result += shaderTranslationLogsSizeForThisContext;
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            for (size_t s = 0; s < contexts[i]->mShaders.Length(); ++s)
+                result += contexts[i]->mShaders[s]->TranslationLog().Length();
         return result;
     }
-    
+
     static PRInt64 GetShaderCount() {
         const ContextsArrayType & contexts = Contexts();
         PRInt64 result = 0;
-        for(size_t i = 0; i < contexts.Length(); ++i) {
-            result += contexts[i]->mMapShaders.Count();
-        }
+        for(size_t i = 0; i < contexts.Length(); ++i)
+            result += contexts[i]->mShaders.Length();
         return result;
     }
 
     static PRInt64 GetContextCount() {
         return Contexts().Length();
     }
 };
 
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -116,46 +116,30 @@ NS_IMETHODIMP WebGLContext::name(t1 a1, 
 }
 
 #define GL_SAME_METHOD_6(glname, name, t1, t2, t3, t4, t5, t6)          \
 NS_IMETHODIMP WebGLContext::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) { \
     if (mContextLost) { return NS_OK; }                                 \
     MakeContextCurrent(); gl->f##glname(a1,a2,a3,a4,a5,a6); return NS_OK; \
 }
 
-already_AddRefed<WebGLUniformLocation>
-WebGLProgram::GetUniformLocationObject(GLint glLocation)
-{
-    WebGLUniformLocation *existingLocationObject;
-    if (mMapUniformLocations.Get(glLocation, &existingLocationObject)) {
-        return existingLocationObject;
-    }
-
-    if (glLocation < 0) {
-        return nsnull;
-    }
-
-    nsRefPtr<WebGLUniformLocation> loc = new WebGLUniformLocation(mContext, this, glLocation);
-    mMapUniformLocations.Put(glLocation, loc);
-    return loc.forget();
-}
 
 //
 //  WebGL API
 //
 
 
 /* void GlActiveTexture (in GLenum texture); */
 NS_IMETHODIMP
 WebGLContext::ActiveTexture(WebGLenum texture)
 {
     if (mContextLost)
         return NS_OK;
 
-    if (texture < LOCAL_GL_TEXTURE0 || texture >= LOCAL_GL_TEXTURE0+mBound2DTextures.Length())
+    if (texture < LOCAL_GL_TEXTURE0 || texture >= LOCAL_GL_TEXTURE0 + mBound2DTextures.Length())
         return ErrorInvalidEnum("ActiveTexture: texture unit %d out of range (0..%d)",
                                 texture, mBound2DTextures.Length()-1);
 
     MakeContextCurrent();
     mActiveTexture = texture - LOCAL_GL_TEXTURE0;
     gl->fActiveTexture(texture);
     return NS_OK;
 }
@@ -181,20 +165,16 @@ WebGLContext::AttachShader(nsIWebGLProgr
     // attached.  This renders the next test somewhat moot, but we'll
     // leave it for when we support more than one shader of each type.
     if (program->HasAttachedShaderOfType(shader->ShaderType()))
         return ErrorInvalidOperation("AttachShader: only one of each type of shader may be attached to a program");
 
     if (!program->AttachShader(shader))
         return ErrorInvalidOperation("AttachShader: shader is already attached");
 
-    MakeContextCurrent();
-
-    gl->fAttachShader(progname, shadername);
-
     return NS_OK;
 }
 
 
 NS_IMETHODIMP
 WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, const nsAString& name)
 {
     if (mContextLost)
@@ -1082,23 +1062,18 @@ WebGLContext::CopyTexSubImage2D(WebGLenu
 NS_IMETHODIMP
 WebGLContext::CreateProgram(nsIWebGLProgram **retval)
 {
     if (mContextLost)
         return NS_OK;
 
     *retval = nsnull;
 
-    MakeContextCurrent();
-
-    WebGLuint name = gl->fCreateProgram();
-
-    WebGLProgram *prog = new WebGLProgram(this, name);
+    WebGLProgram *prog = new WebGLProgram(this);
     NS_ADDREF(*retval = prog);
-    mMapPrograms.Put(name, prog);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::CreateShader(WebGLenum type, nsIWebGLShader **retval)
 {
     if (mContextLost)
@@ -1107,23 +1082,18 @@ WebGLContext::CreateShader(WebGLenum typ
     *retval = nsnull;
 
     if (type != LOCAL_GL_VERTEX_SHADER &&
         type != LOCAL_GL_FRAGMENT_SHADER)
     {
         return ErrorInvalidEnumInfo("createShader: type", type);
     }
 
-    MakeContextCurrent();
-
-    WebGLuint name = gl->fCreateShader(type);
-
-    WebGLShader *shader = new WebGLShader(this, name, type);
+    WebGLShader *shader = new WebGLShader(this, type);
     NS_ADDREF(*retval = shader);
-    mMapShaders.Put(name, shader);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::CullFace(WebGLenum face)
 {
     if (mContextLost)
@@ -1147,111 +1117,109 @@ WebGLContext::DeleteBuffer(nsIWebGLBuffe
     WebGLBuffer *buf;
     bool isNull, isDeleted;
     if (!GetConcreteObjectAndGLName("deleteBuffer", bobj, &buf, &bufname, &isNull, &isDeleted))
         return NS_OK;
 
     if (isNull || isDeleted)
         return NS_OK;
 
-    MakeContextCurrent();
-
-    gl->fDeleteBuffers(1, &bufname);
-    buf->Delete();
-    mMapBuffers.Remove(bufname);
+    if (mBoundArrayBuffer == buf)
+        BindBuffer(LOCAL_GL_ARRAY_BUFFER, nsnull);
+    if (mBoundElementArrayBuffer == buf)
+        BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nsnull);
+
+    for (int i = 0; i < mGLMaxVertexAttribs; i++) {
+        if (mAttribBuffers[i].buf == buf)
+            mAttribBuffers[i].buf = nsnull;
+    }
+
+    buf->RequestDelete();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::DeleteFramebuffer(nsIWebGLFramebuffer *fbobj)
 {
     if (mContextLost)
         return NS_OK;
 
+    WebGLFramebuffer *fbuf;
     WebGLuint fbufname;
-    WebGLFramebuffer *fbuf;
     bool isNull, isDeleted;
     if (!GetConcreteObjectAndGLName("deleteFramebuffer", fbobj, &fbuf, &fbufname, &isNull, &isDeleted))
         return NS_OK;
 
     if (isNull || isDeleted)
         return NS_OK;
 
-    MakeContextCurrent();
-
-    gl->fDeleteFramebuffers(1, &fbufname);
-    fbuf->Delete();
-    mMapFramebuffers.Remove(fbufname);
-
-    if (mBoundFramebuffer && mBoundFramebuffer->GLName() == fbufname)
-        mBoundFramebuffer = NULL;