Merge from mozilla-central (objshrink, yay!)
authorDavid Anderson <danderson@mozilla.com>
Mon, 05 Dec 2011 16:57:50 -0800
changeset 112249 220dd5cad2ac17e53112582e5b007737ff77d586
parent 112246 cd45a4d73fed79ad4bb853cd3a3fda232ea8dbc4 (current diff)
parent 83447 fafaf614791f698e9f66902560206e37065eee39 (diff)
child 112250 08b94171c35f5614ab449ddc0da8b0e7da598bc3
push id239
push userakeybl@mozilla.com
push dateThu, 03 Jan 2013 21:54:43 +0000
treeherdermozilla-release@3a7b66445659 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge 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;
+    fbuf->RequestDelete();
+
+    if (mBoundFramebuffer == fbuf)
+        BindFramebuffer(LOCAL_GL_FRAMEBUFFER, nsnull);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::DeleteRenderbuffer(nsIWebGLRenderbuffer *rbobj)
 {
     if (mContextLost)
         return NS_OK;
 
+    WebGLRenderbuffer *rbuf;
     WebGLuint rbufname;
-    WebGLRenderbuffer *rbuf;
     bool isNull, isDeleted;
     if (!GetConcreteObjectAndGLName("deleteRenderbuffer", rbobj, &rbuf, &rbufname, &isNull, &isDeleted))
         return NS_OK;
 
     if (isNull || isDeleted)
         return NS_OK;