Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Wed, 29 Aug 2012 17:51:24 -0700
changeset 113609 6cd206b371761294125cb98fe9d0c11e2383795f
parent 113608 b63bb39ed1c08605128c984987bbf176dfd81999 (current diff)
parent 110512 a0240c1043eefc60f08dc3e4dd2e8a0043b0d75e (diff)
child 113610 7bf95bb092331b1db96ba9d561400fcdfb9f09d6
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)
milestone18.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.
.hgtags
accessible/src/base/AccEvent.h
accessible/src/base/NotificationController.cpp
accessible/src/base/NotificationController.h
accessible/src/generic/Accessible.cpp
b2g/confvars.sh
b2g/installer/package-manifest.in
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/highlighter.css
browser/base/content/tabbrowser.xml
browser/base/content/test/test_contextmenu.html
browser/components/nsBrowserGlue.js
browser/components/thumbnails/test/browser_thumbnails_bug753755.js
browser/config/tooltool-manifests/macosx32/clang.manifest
browser/config/tooltool-manifests/macosx64/clang.manifest
browser/config/version.txt
browser/devtools/commandline/GcliCommands.jsm
browser/devtools/commandline/GcliCookieCommands.jsm
browser/devtools/commandline/GcliTiltCommands.jsm
browser/devtools/commandline/gcli.css
browser/devtools/commandline/gclioutput.xhtml
browser/devtools/commandline/gclitooltip.xhtml
browser/devtools/commandline/test/browser_gcli_addon.js
browser/devtools/commandline/test/browser_gcli_break.html
browser/devtools/commandline/test/browser_gcli_break.js
browser/devtools/commandline/test/browser_gcli_calllog.js
browser/devtools/commandline/test/browser_gcli_commands.js
browser/devtools/commandline/test/browser_gcli_cookie.js
browser/devtools/commandline/test/browser_gcli_dbg.js
browser/devtools/commandline/test/browser_gcli_edit.js
browser/devtools/commandline/test/browser_gcli_inspect.html
browser/devtools/commandline/test/browser_gcli_inspect.js
browser/devtools/commandline/test/browser_gcli_integrate.js
browser/devtools/commandline/test/browser_gcli_jsb.js
browser/devtools/commandline/test/browser_gcli_pagemod_export.js
browser/devtools/commandline/test/browser_gcli_pref.js
browser/devtools/commandline/test/browser_gcli_responsivemode.js
browser/devtools/commandline/test/browser_gcli_restart.js
browser/devtools/commandline/test/browser_gcli_settings.js
browser/devtools/commandline/test/resources.html
browser/devtools/commandline/test/resources_dbg.html
browser/devtools/commandline/test/resources_inpage.js
browser/devtools/commandline/test/resources_inpage1.css
browser/devtools/commandline/test/resources_inpage2.css
browser/devtools/commandline/test/resources_jsb_script.js
browser/devtools/highlighter/Makefile.in
browser/devtools/highlighter/test/Makefile.in
browser/devtools/highlighter/test/browser_inspector_editor.js
browser/devtools/highlighter/test/browser_inspector_editor_name.js
browser/devtools/highlighter/test/browser_inspector_highlighter.js
browser/devtools/highlighter/test/browser_inspector_initialization.js
browser/devtools/highlighter/test/browser_inspector_tab_switch.js
browser/devtools/highlighter/test/browser_inspector_treePanel_click.js
browser/devtools/highlighter/test/browser_inspector_treePanel_input.html
browser/devtools/highlighter/test/browser_inspector_treePanel_menu.js
browser/devtools/highlighter/test/browser_inspector_treePanel_navigation.html
browser/devtools/highlighter/test/browser_inspector_treePanel_navigation.js
browser/devtools/highlighter/test/browser_inspector_treePanel_output.js
browser/devtools/highlighter/test/browser_inspector_treePanel_result.html
browser/devtools/jar.mn
browser/devtools/webconsole/HUDService.jsm
browser/devtools/webconsole/test/Makefile.in
browser/locales/en-US/chrome/browser/browser.dtd
browser/locales/en-US/chrome/browser/browser.properties
browser/themes/gnomestripe/devtools/gcli.css
browser/themes/gnomestripe/devtools/inspector-option-icon.png
browser/themes/gnomestripe/share-button-active.png
browser/themes/gnomestripe/share-button-shared.png
browser/themes/gnomestripe/share-button.png
browser/themes/pinstripe/Secure-Glyph-White.png
browser/themes/pinstripe/devtools/gcli.css
browser/themes/pinstripe/devtools/inspector-option-icon.png
browser/themes/pinstripe/hud-style-check-box-checked.png
browser/themes/pinstripe/hud-style-check-box-empty.png
browser/themes/pinstripe/hud-style-dropmarker-double-arrows.png
browser/themes/pinstripe/hud-style-expander-closed.png
browser/themes/pinstripe/hud-style-expander-open.png
browser/themes/pinstripe/hud-style-new-folder-plus-sign.png
browser/themes/pinstripe/hud-style-twisties.png
browser/themes/pinstripe/share-button-active.png
browser/themes/pinstripe/share-button-shared.png
browser/themes/pinstripe/share-button.png
browser/themes/pinstripe/social/panelarrow-down.png
browser/themes/pinstripe/social/panelarrow-horiz.png
browser/themes/pinstripe/social/panelarrow-up.png
browser/themes/winstripe/browser.css
browser/themes/winstripe/devtools/gcli.css
browser/themes/winstripe/devtools/inspector-option-icon.png
browser/themes/winstripe/share-button-active.png
browser/themes/winstripe/share-button-shared.png
browser/themes/winstripe/share-button.png
build/mobile/devicemanagerADB.py
build/mobile/devicemanagerSUT.py
build/unix/build-clang/create-manifest.py
caps/include/nsScriptSecurityManager.h
caps/src/nsPrincipal.cpp
caps/src/nsScriptSecurityManager.cpp
caps/src/nsSecurityManagerFactory.cpp
config/makedep.cpp
config/makedep.exe
config/milestone.txt
config/mkdepend/Makefile.in
config/mkdepend/cppsetup.c
config/mkdepend/def.h
config/mkdepend/ifparser.c
config/mkdepend/ifparser.h
config/mkdepend/imakemdep.h
config/mkdepend/include.c
config/mkdepend/main.c
config/mkdepend/mkdepend.man
config/mkdepend/parse.c
config/mkdepend/pr.c
config/system-headers
configure.in
content/base/public/nsBlobProtocolHandler.h
content/base/public/nsContentUtils.h
content/base/public/nsIDocument.h
content/base/public/nsIFrameMessageManager.idl
content/base/public/nsIMessageManager.idl
content/base/src/FragmentOrElement.cpp
content/base/src/Makefile.in
content/base/src/nsAttrValue.cpp
content/base/src/nsAttrValue.h
content/base/src/nsBlobProtocolHandler.cpp
content/base/src/nsCCUncollectableMarker.cpp
content/base/src/nsContentList.cpp
content/base/src/nsContentSink.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDOMFile.cpp
content/base/src/nsDOMTokenList.cpp
content/base/src/nsDocument.cpp
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsFrameMessageManager.h
content/base/src/nsGkAtomList.h
content/base/src/nsImageLoadingContent.cpp
content/base/src/nsInProcessTabChildGlobal.cpp
content/base/src/nsInProcessTabChildGlobal.h
content/base/src/nsNodeInfo.cpp
content/base/src/nsNodeInfoManager.cpp
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
content/base/src/nsXMLHttpRequest.cpp
content/base/test/Makefile.in
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
content/canvas/test/test_canvas.html
content/events/src/nsDOMEventTargetHelper.cpp
content/events/src/nsEventListenerManager.cpp
content/events/src/nsEventListenerManager.h
content/events/src/nsEventListenerService.cpp
content/events/src/nsEventListenerService.h
content/events/src/nsIMEStateManager.cpp
content/html/content/public/nsHTMLMediaElement.h
content/html/content/src/nsDOMStringMap.cpp
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLBodyElement.cpp
content/html/content/src/nsHTMLFormElement.cpp
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/html/content/src/nsHTMLSelectElement.cpp
content/html/content/src/nsHTMLTableCellElement.cpp
content/html/content/src/nsHTMLTableElement.cpp
content/html/content/src/nsHTMLTableRowElement.cpp
content/html/content/src/nsHTMLTableSectionElement.cpp
content/media/MediaResource.cpp
content/media/nsBuiltinDecoder.cpp
content/media/nsBuiltinDecoder.h
content/media/nsBuiltinDecoderReader.cpp
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/nsBuiltinDecoderStateMachine.h
content/media/nsMediaDecoder.h
content/svg/content/src/DOMSVGAnimatedLengthList.cpp
content/svg/content/src/DOMSVGAnimatedNumberList.cpp
content/svg/content/src/DOMSVGAnimatedTransformList.cpp
content/svg/content/src/DOMSVGPathSegList.cpp
content/svg/content/src/DOMSVGPointList.cpp
content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
content/svg/content/src/SVGAnimatedPreserveAspectRatio.h
content/svg/content/src/SVGLength.cpp
content/svg/content/src/nsSVGAngle.cpp
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGEnum.cpp
content/svg/content/src/nsSVGLength2.cpp
content/svg/content/src/nsSVGLength2.h
content/svg/content/src/nsSVGViewBox.cpp
content/svg/content/src/nsSVGViewBox.h
content/xbl/src/nsBindingManager.cpp
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLBinding.h
content/xbl/src/nsXBLInsertionPoint.h
content/xbl/src/nsXBLProtoImplProperty.cpp
content/xbl/src/nsXBLPrototypeBinding.cpp
content/xul/content/src/nsXULElement.cpp
content/xul/content/src/nsXULElement.h
content/xul/document/src/nsXULPrototypeDocument.cpp
docshell/base/nsDSURIContentListener.cpp
docshell/base/nsDocShell.cpp
docshell/base/nsWebNavigationInfo.cpp
dom/Makefile.in
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMClassInfoClasses.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSTimeoutHandler.cpp
dom/base/nsLocation.cpp
dom/base/nsPIDOMWindow.h
dom/base/nsScriptNameSpaceManager.cpp
dom/base/nsScriptNameSpaceManager.h
dom/base/nsStructuredCloneContainer.cpp
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IndexedDatabaseManager.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/interfaces/core/Makefile.in
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/plugins/base/nsJSNPRuntime.cpp
dom/plugins/base/nsNPAPIPlugin.h
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginHost.h
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/plugins/ipc/PluginModuleChild.h
dom/plugins/ipc/PluginModuleParent.cpp
dom/src/json/nsJSON.cpp
dom/src/storage/StorageChild.cpp
dom/wifi/WifiWorker.js
dom/workers/RuntimeService.cpp
dom/workers/ScriptLoader.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerScope.cpp
editor/txmgr/src/nsTransactionItem.cpp
editor/txmgr/src/nsTransactionItem.h
embedding/android/GeckoAppShell.java
embedding/android/GeckoSurfaceView.java
embedding/browser/webBrowser/nsContextMenuInfo.cpp
embedding/components/windowwatcher/src/nsWindowWatcher.cpp
extensions/cookie/nsPermissionManager.cpp
extensions/cookie/nsPermissionManager.h
extensions/permissions/nsContentBlocker.cpp
extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
gfx/gl/GLContext.h
gfx/layers/Layers.cpp
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/basic/BasicImageLayer.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
image/src/RasterImage.cpp
image/src/imgLoader.cpp
image/src/imgLoader.h
image/src/imgRequest.cpp
image/src/imgRequest.h
image/src/imgTools.cpp
intl/locale/src/os2/nsDateTimeFormatOS2.cpp
intl/locale/src/windows/nsWin32Locale.cpp
intl/lwbrk/tests/TestLineBreak.cpp
intl/strres/src/nsStringBundle.cpp
intl/uconv/src/nsCharsetConverterManager.cpp
intl/uconv/src/nsScriptableUConv.cpp
intl/uconv/tests/TestUConv.cpp
intl/uconv/tests/nsTestUConv.cpp
intl/uconv/util/nsUnicodeDecodeHelper.cpp
intl/unicharutil/src/nsUnicodeNormalizer.cpp
intl/unicharutil/tests/NormalizationTest.cpp
intl/unicharutil/tests/UnicharSelfTest.cpp
ipc/chromium/src/base/file_util_linux.cc
ipc/glue/GeckoChildProcessHost.cpp
ipc/glue/IPCSerializableParams.ipdlh
ipc/testshell/TestShellParent.cpp
ipc/testshell/XPCShellEnvironment.cpp
js/ductwork/debugger/JSDebugger.cpp
js/jsd/jsd_scpt.c
js/jsd/jsd_stak.c
js/jsd/jsd_val.c
js/jsd/jsd_xpc.cpp
js/src/Makefile.in
js/src/assembler/wtf/Platform.h
js/src/builtin/Eval.cpp
js/src/config/milestone.txt
js/src/config/mkdepend/Makefile.in
js/src/config/mkdepend/cppsetup.c
js/src/config/mkdepend/def.h
js/src/config/mkdepend/ifparser.c
js/src/config/mkdepend/ifparser.h
js/src/config/mkdepend/imakemdep.h
js/src/config/mkdepend/include.c
js/src/config/mkdepend/main.c
js/src/config/mkdepend/mkdepend.man
js/src/config/mkdepend/parse.c
js/src/config/mkdepend/pr.c
js/src/config/system-headers
js/src/configure.in
js/src/ds/LifoAlloc.h
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/gc/Barrier.h
js/src/gc/Marking.cpp
js/src/gc/Marking.h
js/src/ion/CodeGenerator.cpp
js/src/ion/IonBuilder.cpp
js/src/ion/IonBuilder.h
js/src/ion/MCallOptimize.cpp
js/src/ion/MIR.cpp
js/src/ion/MIR.h
js/src/ion/TypeOracle.cpp
js/src/ion/TypeOracle.h
js/src/jit-test/jit_test.py
js/src/js.msg
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi-tests/Makefile.in
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi-tests/testDebugger.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
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/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/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsopcode.cpp
js/src/jsprobes.cpp
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsreops.tbl
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jstypedarray.cpp
js/src/jstypedarrayinlines.h
js/src/jsweakcache.h
js/src/jsweakmap.cpp
js/src/jswrapper.cpp
js/src/jswrapper.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.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/PolyIC.h
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/tests/user.js
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/SPSProfiler.cpp
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/src/vm/String.cpp
js/xpconnect/idl/nsIXPConnect.idl
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSComponentLoader.h
js/xpconnect/loader/mozJSSubScriptLoader.cpp
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCDebug.cpp
js/xpconnect/src/XPCInlines.h
js/xpconnect/src/XPCJSID.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCStack.cpp
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/XPCWrappedJS.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/dom_quickstubs.qsconf
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/AccessCheck.cpp
js/xpconnect/wrappers/AccessCheck.h
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/WrapperFactory.h
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/nsCSSRendering.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/build/nsContentDLF.cpp
layout/build/nsLayoutModule.cpp
layout/forms/nsHTMLButtonControlFrame.cpp
layout/forms/nsProgressFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsImageFrame.cpp
layout/generic/nsSubDocumentFrame.cpp
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
layout/reftests/reftest.list
layout/reftests/w3c-css/submitted/conditional3/pass.html
layout/style/AnimationCommon.cpp
layout/style/AnimationCommon.h
layout/style/Declaration.cpp
layout/style/Declaration.h
layout/style/nsAnimationManager.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSRules.cpp
layout/style/nsCSSRules.h
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsDOMCSSAttrDeclaration.h
layout/style/nsDOMCSSDeclaration.cpp
layout/style/nsDOMCSSDeclaration.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleAnimation.cpp
layout/style/nsStyleCoord.cpp
layout/style/nsStyleCoord.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/nsTransitionManager.cpp
layout/svg/base/src/nsSVGUtils.cpp
layout/tools/reftest/reftest.js
layout/xul/base/src/nsLeafBoxFrame.cpp
layout/xul/base/src/nsMenuPopupFrame.h
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/base/resources/drawable-hdpi/abouthome_sync_logo.png
mobile/android/base/resources/drawable-xhdpi/abouthome_sync_logo.png
mobile/android/base/resources/drawable/abouthome_sync_logo.png
mobile/android/chrome/content/browser.js
mobile/android/themes/core/aboutReader.css
mobile/xul/chrome/content/WebappsUI.js
mobile/xul/confvars.sh
modules/libjar/nsJARChannel.cpp
modules/libjar/nsJARChannel.h
modules/libjar/nsJARURI.cpp
modules/libjar/nsJARURI.h
modules/libpref/public/PPrefTuple.h
modules/libpref/public/PrefTuple.h
modules/libpref/public/Preferences.h
modules/libpref/src/Preferences.cpp
modules/libpref/src/init/all.js
modules/libpref/src/prefapi.cpp
modules/libpref/src/prefapi_private_data.h
netwerk/base/public/nsIIPCSerializableObsolete.idl
netwerk/base/src/nsBufferedStreams.cpp
netwerk/base/src/nsBufferedStreams.h
netwerk/base/src/nsFileStreams.cpp
netwerk/base/src/nsFileStreams.h
netwerk/base/src/nsMIMEInputStream.cpp
netwerk/base/src/nsSimpleNestedURI.cpp
netwerk/base/src/nsSimpleNestedURI.h
netwerk/base/src/nsSimpleURI.cpp
netwerk/base/src/nsSimpleURI.h
netwerk/base/src/nsStandardURL.cpp
netwerk/base/src/nsStandardURL.h
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsDiskCacheBinding.cpp
netwerk/cache/nsDiskCacheDevice.cpp
netwerk/cache/nsDiskCacheDevice.h
netwerk/cache/nsDiskCacheDeviceSQL.cpp
netwerk/cache/nsDiskCacheMap.cpp
netwerk/cache/nsDiskCacheStreams.cpp
netwerk/cache/nsMemoryCacheDevice.cpp
netwerk/cookie/CookieServiceChild.cpp
netwerk/cookie/nsCookieService.cpp
netwerk/mime/nsMIMEHeaderParamImpl.cpp
netwerk/protocol/about/nsAboutCache.cpp
netwerk/protocol/about/nsAboutProtocolHandler.cpp
netwerk/protocol/data/nsDataHandler.cpp
netwerk/protocol/ftp/FTPChannelChild.cpp
netwerk/protocol/ftp/FTPChannelChild.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/SpdySession2.cpp
netwerk/protocol/http/SpdySession3.cpp
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
netwerk/protocol/http/nsHttpChannelAuthProvider.cpp
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpHeaderArray.cpp
netwerk/protocol/http/nsHttpPipeline.cpp
netwerk/protocol/http/nsHttpPipeline.h
netwerk/protocol/http/nsHttpTransaction.cpp
netwerk/protocol/http/nsHttpTransaction.h
netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
netwerk/socket/nsSOCKSIOLayer.cpp
netwerk/streamconv/converters/ParseFTPList.cpp
netwerk/streamconv/converters/nsFTPDirListingConv.cpp
netwerk/streamconv/converters/nsUnknownDecoder.cpp
netwerk/test/TestProtocols.cpp
netwerk/wifi/nsWifiScannerUnix.cpp
security/manager/boot/src/nsStrictTransportSecurityService.cpp
security/manager/boot/src/nsStrictTransportSecurityService.h
security/manager/ssl/src/SSLServerCertVerification.cpp
security/manager/ssl/src/TransportSecurityInfo.cpp
security/manager/ssl/src/TransportSecurityInfo.h
security/manager/ssl/src/nsCrypto.cpp
security/manager/ssl/src/nsNSSIOLayer.cpp
startupcache/test/TestStartupCache.cpp
testing/xpcshell/xpcshell.ini
toolkit/components/alerts/mac/nsGrowlAlertsService.h
toolkit/components/alerts/mac/nsGrowlAlertsService.mm
toolkit/components/places/History.cpp
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/mozapps/extensions/AddonRepository.jsm
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/installer/packager.mk
toolkit/mozapps/update/nsUpdateService.js
toolkit/system/gnome/nsAlertsIconListener.cpp
toolkit/system/gnome/nsAlertsIconListener.h
toolkit/themes/pinstripe/global/arrow/arrow-dn-white.png
toolkit/themes/pinstripe/global/arrow/panelarrow-down.png
toolkit/themes/pinstripe/global/arrow/panelarrow-horiz.png
toolkit/themes/pinstripe/global/arrow/panelarrow-up.png
toolkit/themes/pinstripe/global/media/videocontrols.css
toolkit/themes/winstripe/global/media/videocontrols.css
toolkit/webapps/WebappsInstaller.jsm
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsUpdateDriver.cpp
toolkit/xre/nsXREDirProvider.cpp
uriloader/exthandler/ExternalHelperAppParent.cpp
uriloader/exthandler/ExternalHelperAppParent.h
uriloader/exthandler/nsExternalHelperAppService.cpp
uriloader/prefetch/OfflineCacheUpdateChild.cpp
uriloader/prefetch/OfflineCacheUpdateParent.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/nsWindow.cpp
widget/cocoa/nsMenuItemIconX.mm
widget/gtk2/nsFilePicker.cpp
widget/gtk2/nsFilePicker.h
widget/nsIWidget.h
widget/qt/nsNativeThemeQt.cpp
widget/windows/nsWindow.cpp
widget/xpwidgets/PuppetWidget.cpp
xpcom/base/nsAgg.h
xpcom/base/nsCycleCollector.cpp
xpcom/build/nsXPCOM.h
xpcom/build/nsXPCOMPrivate.h
xpcom/components/Module.h
xpcom/glue/nsCycleCollectionParticipant.cpp
xpcom/glue/nsCycleCollectionParticipant.h
xpcom/glue/nsISupportsImpl.h
xpcom/glue/standalone/nsXPCOMGlue.cpp
xpcom/idl-parser/xpidl.py
xpcom/io/nsMultiplexInputStream.cpp
xpcom/io/nsStringStream.cpp
xpcom/reflect/xptcall/src/md/unix/Makefile.in
xpcom/stub/nsXPComStub.cpp
xpcom/tests/unit/test_seek_multiplex.js
xpfe/appshell/src/nsAppShellService.cpp
xpfe/appshell/src/nsContentTreeOwner.cpp
--- a/.hgtags
+++ b/.hgtags
@@ -81,8 +81,9 @@ bbc7014db2de49e2301680d2a86be8a53108a88a
 b6627f28b7ec17e1b46a594df0f780d3a40847e4 FIREFOX_AURORA_13_BASE
 357da346ceb705d196a46574804c7c4ec44ac186 FIREFOX_AURORA_14_BASE
 26dcd1b1a20893ad99341c61c6b1239ff1523858 FIREFOX_AURORA_15_BASE
 0accd12a8e7e217836ea3f1ee7c411913fc75d8e FIREFOX_AURORA_16_BASE
 0000000000000000000000000000000000000000 FIREFOX_AURORA_16_BASE
 9697eadafa13b4e9233b39aaeecfeac79503cb54 FIREFOX_AURORA_16_BASE
 9697eadafa13b4e9233b39aaeecfeac79503cb54 FIREFOX_AURORA_16_BASE
 6fdf9985acfe6f939da584b2559464ab22264fe7 FIREFOX_AURORA_16_BASE
+fd72dbbd692012224145be1bf13df1d7675fd277 FIREFOX_AURORA_17_BASE
--- a/accessible/src/base/AccEvent.h
+++ b/accessible/src/base/AccEvent.h
@@ -102,17 +102,17 @@ public:
   virtual unsigned int GetEventGroups() const
   {
     return 1U << eGenericEvent;
   }
 
   /**
    * Reference counting and cycle collection.
    */
-  NS_INLINE_DECL_REFCOUNTING(AccEvent)
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AccEvent)
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(AccEvent)
 
 protected:
   /**
    * Get an accessible from event target node.
    */
   Accessible* GetAccessibleForNode() const;
 
--- a/accessible/src/base/NotificationController.cpp
+++ b/accessible/src/base/NotificationController.cpp
@@ -50,18 +50,18 @@ NotificationController::~NotificationCon
   NS_ASSERTION(!mDocument, "Controller wasn't shutdown properly!");
   if (mDocument)
     Shutdown();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // NotificationCollector: AddRef/Release and cycle collection
 
-NS_IMPL_ADDREF(NotificationController)
-NS_IMPL_RELEASE(NotificationController)
+NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(NotificationController)
+NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE(NotificationController)
 
 NS_IMPL_CYCLE_COLLECTION_NATIVE_CLASS(NotificationController)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(NotificationController)
   if (tmp->mDocument)
     tmp->Shutdown();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
--- a/accessible/src/base/NotificationController.h
+++ b/accessible/src/base/NotificationController.h
@@ -168,17 +168,17 @@ public:
   }
 
 #ifdef DEBUG
   bool IsUpdating() const
     { return mObservingState == eRefreshProcessingForUpdate; }
 #endif
 
 protected:
-  nsAutoRefCnt mRefCnt;
+  nsCycleCollectingAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
   /**
    * Start to observe refresh to make notifications and events processing after
    * layout.
    */
   void ScheduleProcessing();
 
@@ -267,17 +267,17 @@ private:
    * Storage for content inserted notification information.
    */
   class ContentInsertion
   {
   public:
     ContentInsertion(DocAccessible* aDocument, Accessible* aContainer);
     virtual ~ContentInsertion() { mDocument = nullptr; }
 
-    NS_INLINE_DECL_REFCOUNTING(ContentInsertion)
+    NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ContentInsertion)
     NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ContentInsertion)
 
     bool InitChildList(nsIContent* aStartChildNode, nsIContent* aEndChildNode);
     void Process();
 
   private:
     ContentInsertion();
     ContentInsertion(const ContentInsertion&);
--- a/accessible/src/base/RoleAsserts.cpp
+++ b/accessible/src/base/RoleAsserts.cpp
@@ -7,11 +7,13 @@
 #include "nsIAccessibleRole.h"
 #include "Role.h"
 
 #include "mozilla/Assertions.h"
 
 using namespace mozilla::a11y;
 
 #define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule) \
-  MOZ_STATIC_ASSERT(roles::geckoRole == nsIAccessibleRole::ROLE_ ## geckoRole, "internal and xpcom roles differ!");
+  MOZ_STATIC_ASSERT(static_cast<uint32_t>(roles::geckoRole) \
+                    == static_cast<uint32_t>(nsIAccessibleRole::ROLE_ ## geckoRole), \
+                    "internal and xpcom roles differ!");
 #include "RoleMap.h"
 #undef ROLE
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -794,18 +794,17 @@ Accessible::ChildAtPoint(int32_t aX, int
   NS_ENSURE_TRUE(frame, nullptr);
 
   nsPresContext *presContext = frame->PresContext();
 
   nsRect screenRect = frame->GetScreenRectInAppUnits();
   nsPoint offset(presContext->DevPixelsToAppUnits(aX) - screenRect.x,
                  presContext->DevPixelsToAppUnits(aY) - screenRect.y);
 
-  nsIPresShell* presShell = presContext->PresShell();
-  nsIFrame *foundFrame = presShell->GetFrameForPoint(frame, offset);
+  nsIFrame *foundFrame = nsLayoutUtils::GetFrameForPoint(frame, offset);
 
   nsIContent* content = nullptr;
   if (!foundFrame || !(content = foundFrame->GetContent()))
     return fallbackAnswer;
 
   // Get accessible for the node with the point or the first accessible in
   // the DOM parent chain.
   DocAccessible* contentDocAcc = GetAccService()->
--- a/accessible/src/jsat/TouchAdapter.jsm
+++ b/accessible/src/jsat/TouchAdapter.jsm
@@ -80,48 +80,51 @@ var TouchAdapter = {
     if (Utils.OS != 'Android')
       Mouse2Touch.detach(aWindow);
 
     delete this.chromeWin;
   },
 
   handleEvent: function TouchAdapter_handleEvent(aEvent) {
     let touches = aEvent.changedTouches;
+    // XXX: Until bug 77992 is resolved, on desktop we get microseconds
+    // instead of milliseconds.
+    let timeStamp = (Utils.OS == 'Android') ? aEvent.timeStamp : Date.now();
     switch (aEvent.type) {
       case 'touchstart':
         for (var i = 0; i < touches.length; i++) {
           let touch = touches[i];
-          let touchPoint = new TouchPoint(touch, aEvent.timeStamp, this._dpi);
+          let touchPoint = new TouchPoint(touch, timeStamp, this._dpi);
           this._touchPoints[touch.identifier] = touchPoint;
-          this._lastExploreTime = aEvent.timeStamp + this.SWIPE_MAX_DURATION;
+          this._lastExploreTime = timeStamp + this.SWIPE_MAX_DURATION;
         }
         this._dwellTimeout = this.chromeWin.setTimeout(
           (function () {
-             this.compileAndEmit(aEvent.timeStamp + this.DWELL_THRESHOLD);
+             this.compileAndEmit(timeStamp + this.DWELL_THRESHOLD);
            }).bind(this), this.DWELL_THRESHOLD);
         break;
       case 'touchmove':
         for (var i = 0; i < touches.length; i++) {
           let touch = touches[i];
           let touchPoint = this._touchPoints[touch.identifier];
-          touchPoint.update(touch, aEvent.timeStamp);
+          touchPoint.update(touch, timeStamp);
         }
-        if (aEvent.timeStamp - this._lastExploreTime >= EXPLORE_THROTTLE) {
-          this.compileAndEmit(aEvent.timeStamp);
-          this._lastExploreTime = aEvent.timeStamp;
+        if (timeStamp - this._lastExploreTime >= EXPLORE_THROTTLE) {
+          this.compileAndEmit(timeStamp);
+          this._lastExploreTime = timeStamp;
         }
         break;
       case 'touchend':
         for (var i = 0; i < touches.length; i++) {
           let touch = touches[i];
           let touchPoint = this._touchPoints[touch.identifier];
-          touchPoint.update(touch, aEvent.timeStamp);
+          touchPoint.update(touch, timeStamp);
           touchPoint.finish();
         }
-        this.compileAndEmit(aEvent.timeStamp);
+        this.compileAndEmit(timeStamp);
         break;
     }
   },
 
   cleanupTouches: function cleanupTouches() {
     for (var identifier in this._touchPoints) {
       if (!this._touchPoints[identifier].done)
         continue;
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -7,27 +7,33 @@
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Cu.import('resource://gre/modules/Services.jsm');
 
 var EXPORTED_SYMBOLS = ['Utils', 'Logger'];
 
-var gAccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1'].
-  getService(Ci.nsIAccessibleRetrieval);
-
 var Utils = {
   _buildAppMap: {
     '{3c2e2abc-06d4-11e1-ac3b-374f68613e61}': 'b2g',
     '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'browser',
     '{aa3c5121-dab2-40e2-81ca-7ea25febc110}': 'mobile/android',
     '{a23983c0-fd0e-11dc-95ff-0800200c9a66}': 'mobile/xul'
   },
 
+  get AccRetrieval() {
+    if (!this._AccRetrieval) {
+      this._AccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1'].
+        getService(Ci.nsIAccessibleRetrieval);
+    }
+
+    return this._AccRetrieval;
+  },
+
   get MozBuildApp() {
     if (!this._buildApp)
       this._buildApp = this._buildAppMap[Services.appinfo.ID];
     return this._buildApp;
   },
 
   get OS() {
     if (!this._OS)
@@ -67,17 +73,17 @@ var Utils = {
 
   getCurrentContentDoc: function getCurrentContentDoc(aWindow) {
     if (this.MozBuildApp == "b2g")
       return this.getBrowserApp(aWindow).contentBrowser.contentDocument;
     return this.getBrowserApp(aWindow).selectedBrowser.contentDocument;
   },
 
   getAllDocuments: function getAllDocuments(aWindow) {
-    let doc = gAccRetrieval.
+    let doc = this.AccRetrieval.
       getAccessibleFor(this.getCurrentContentDoc(aWindow)).
       QueryInterface(Ci.nsIAccessibleDocument);
     let docs = [];
     function getAllDocuments(aDocument) {
       docs.push(aDocument.DOMDocument);
       for (let i = 0; i < aDocument.childDocumentCount; i++)
         getAllDocuments(aDocument.getChildDocumentAt(i));
     }
@@ -101,17 +107,17 @@ var Utils = {
     let state = {};
     let extState = {};
     aAccessible.getState(state, extState);
     return [state.value, extState.value];
   },
 
   getVirtualCursor: function getVirtualCursor(aDocument) {
     let doc = (aDocument instanceof Ci.nsIAccessible) ? aDocument :
-      gAccRetrieval.getAccessibleFor(aDocument);
+      this.AccRetrieval.getAccessibleFor(aDocument);
 
     while (doc) {
       try {
         return doc.QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor;
       } catch (x) {
         doc = doc.parentDocument;
       }
     }
@@ -165,17 +171,17 @@ var Utils = {
   changePage: function changePage(aWindow, aPage) {
     for each (let doc in this.getAllDocuments(aWindow)) {
       // Get current main section or active target.
       let main = doc.querySelector('[role=main]') ||
         doc.querySelector(':target');
       if (!main)
         continue;
 
-      let mainAcc = gAccRetrieval.getAccessibleFor(main);
+      let mainAcc = this.AccRetrieval.getAccessibleFor(main);
       if (!mainAcc)
         continue;
 
       let controllers = mainAcc.
         getRelationByType(Ci.nsIAccessibleRelation.RELATION_CONTROLLED_BY);
 
       for (var i=0; controllers.targetsCount > i; i++) {
         let controller = controllers.getTarget(i);
@@ -232,41 +238,41 @@ var Logger = {
   error: function error() {
     this.log.apply(
       this, [this.ERROR].concat(Array.prototype.slice.call(arguments)));
   },
 
   accessibleToString: function accessibleToString(aAccessible) {
     let str = '[ defunct ]';
     try {
-      str = '[ ' + gAccRetrieval.getStringRole(aAccessible.role) +
+      str = '[ ' + Utils.AccRetrieval.getStringRole(aAccessible.role) +
         ' | ' + aAccessible.name + ' ]';
     } catch (x) {
     }
 
     return str;
   },
 
   eventToString: function eventToString(aEvent) {
-    let str = gAccRetrieval.getStringEventType(aEvent.eventType);
+    let str = Utils.AccRetrieval.getStringEventType(aEvent.eventType);
     if (aEvent.eventType == Ci.nsIAccessibleEvent.EVENT_STATE_CHANGE) {
       let event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent);
       let stateStrings = (event.isExtraState()) ?
-        gAccRetrieval.getStringStates(0, event.state) :
-        gAccRetrieval.getStringStates(event.state, 0);
+        Utils.AccRetrieval.getStringStates(0, event.state) :
+        Utils.AccRetrieval.getStringStates(event.state, 0);
       str += ' (' + stateStrings.item(0) + ')';
     }
 
     return str;
   },
 
   statesToString: function statesToString(aAccessible) {
     let [state, extState] = Utils.getStates(aAccessible);
     let stringArray = [];
-    let stateStrings = gAccRetrieval.getStringStates(state, extState);
+    let stateStrings = Utils.AccRetrieval.getStringStates(state, extState);
     for (var i=0; i < stateStrings.length; i++)
       stringArray.push(stateStrings.item(i));
     return stringArray.join(' ');
   },
 
   dumpTree: function dumpTree(aLogLevel, aRootAccessible) {
     if (aLogLevel < this.logLevel)
       return;
--- a/accessible/src/jsat/UtteranceGenerator.jsm
+++ b/accessible/src/jsat/UtteranceGenerator.jsm
@@ -12,21 +12,21 @@ const Cr = Components.results;
 const INCLUDE_DESC = 0x01;
 const INCLUDE_NAME = 0x02;
 const INCLUDE_CUSTOM = 0x04;
 
 var gStringBundle = Cc['@mozilla.org/intl/stringbundle;1'].
   getService(Ci.nsIStringBundleService).
   createBundle('chrome://global/locale/AccessFu.properties');
 
-var gAccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1'].
-  getService(Ci.nsIAccessibleRetrieval);
 
 var EXPORTED_SYMBOLS = ['UtteranceGenerator'];
 
+Cu.import('resource://gre/modules/accessibility/Utils.jsm');
+
 /**
  * Generates speech utterances from objects, actions and state changes.
  * An utterance is an array of strings.
  *
  * It should not be assumed that flattening an utterance array would create a
  * gramatically correct sentence. For example, {@link genForObject} might
  * return: ['graphic', 'Welcome to my home page'].
  * Each string element in an utterance should be gramatically correct in itself.
@@ -61,17 +61,17 @@ var UtteranceGenerator = {
    * @param {nsIAccessible} aAccessible accessible object to generate utterance
    *    for.
    * @return {Array} Two string array. The first string describes the object
    *    and its states. The second string is the object's name. Whether the
    *    object's description or it's role is included is determined by
    *    {@link verbosityRoleMap}.
    */
   genForObject: function genForObject(aAccessible) {
-    let roleString = gAccRetrieval.getStringRole(aAccessible.role);
+    let roleString = Utils.AccRetrieval.getStringRole(aAccessible.role);
 
     let func = this.objectUtteranceFunctions[roleString] ||
       this.objectUtteranceFunctions.defaultFunc;
 
     let flags = this.verbosityRoleMap[roleString] || 0;
 
     if (aAccessible.childCount == 0)
       flags |= INCLUDE_NAME;
@@ -147,17 +147,17 @@ var UtteranceGenerator = {
     'toolbar': INCLUDE_DESC,
     'table': INCLUDE_DESC | INCLUDE_NAME,
     'link': INCLUDE_DESC,
     'listitem': INCLUDE_DESC,
     'outline': INCLUDE_DESC,
     'outlineitem': INCLUDE_DESC,
     'pagetab': INCLUDE_DESC,
     'graphic': INCLUDE_DESC,
-    'pushbutton': INCLUDE_DESC | INCLUDE_NAME,
+    'pushbutton': INCLUDE_DESC,
     'checkbutton': INCLUDE_DESC,
     'radiobutton': INCLUDE_DESC,
     'combobox': INCLUDE_DESC,
     'droplist': INCLUDE_DESC,
     'progressbar': INCLUDE_DESC,
     'slider': INCLUDE_DESC,
     'spinbutton': INCLUDE_DESC,
     'diagram': INCLUDE_DESC,
--- a/accessible/src/jsat/VirtualCursorController.jsm
+++ b/accessible/src/jsat/VirtualCursorController.jsm
@@ -9,19 +9,16 @@ const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 var EXPORTED_SYMBOLS = ['VirtualCursorController'];
 
 Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 
-var gAccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1'].
-  getService(Ci.nsIAccessibleRetrieval);
-
 function BaseTraversalRule(aRoles, aMatchFunc) {
   this._matchRoles = aRoles;
   this._matchFunc = aMatchFunc;
 }
 
 BaseTraversalRule.prototype = {
     getMatchRoles: function BaseTraversalRule_getmatchRoles(aRules) {
       aRules.value = this._matchRoles;
@@ -344,48 +341,48 @@ var VirtualCursorController = {
     if (aLast) {
       virtualCursor.moveLast(TraversalRules.Simple);
     } else {
       try {
         virtualCursor.moveNext(aRule || TraversalRules.Simple);
       } catch (x) {
         this.moveCursorToObject(
           virtualCursor,
-          gAccRetrieval.getAccessibleFor(aDocument.activeElement), aRule);
+          Utils.AccRetrieval.getAccessibleFor(aDocument.activeElement), aRule);
       }
     }
   },
 
   moveBackward: function moveBackward(aDocument, aFirst, aRule) {
     let virtualCursor = Utils.getVirtualCursor(aDocument);
     if (aFirst) {
       virtualCursor.moveFirst(TraversalRules.Simple);
     } else {
       try {
         virtualCursor.movePrevious(aRule || TraversalRules.Simple);
       } catch (x) {
         this.moveCursorToObject(
           virtualCursor,
-          gAccRetrieval.getAccessibleFor(aDocument.activeElement), aRule);
+          Utils.AccRetrieval.getAccessibleFor(aDocument.activeElement), aRule);
       }
     }
   },
 
   activateCurrent: function activateCurrent(document) {
     let virtualCursor = Utils.getVirtualCursor(document);
     let acc = virtualCursor.position;
 
     if (acc.actionCount > 0) {
       acc.doAction(0);
     } else {
       // XXX Some mobile widget sets do not expose actions properly
       // (via ARIA roles, etc.), so we need to generate a click.
       // Could possibly be made simpler in the future. Maybe core
       // engine could expose nsCoreUtiles::DispatchMouseEvent()?
-      let docAcc = gAccRetrieval.getAccessibleFor(this.chromeWin.document);
+      let docAcc = Utils.AccRetrieval.getAccessibleFor(this.chromeWin.document);
       let docX = {}, docY = {}, docW = {}, docH = {};
       docAcc.getBounds(docX, docY, docW, docH);
 
       let objX = {}, objY = {}, objW = {}, objH = {};
       acc.getBounds(objX, objY, objW, objH);
 
       let x = Math.round((objX.value - docX.value) + objW.value / 2);
       let y = Math.round((objY.value - docY.value) + objH.value / 2);
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -96,17 +96,18 @@ GetClosestInterestingAccessible(id anObj
 #pragma mark -
 
 - (BOOL)accessibilityIsIgnored
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   // unknown (either unimplemented, or irrelevant) elements are marked as ignored
   // as well as expired elements.
-  return !mGeckoAccessible || [[self role] isEqualToString:NSAccessibilityUnknownRole];
+  return !mGeckoAccessible || ([[self role] isEqualToString:NSAccessibilityUnknownRole] &&
+                               !(mGeckoAccessible->InteractiveState() & states::FOCUSABLE));
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
 - (NSArray*)accessibilityAttributeNames
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
--- a/accessible/src/mac/mozActionElements.mm
+++ b/accessible/src/mac/mozActionElements.mm
@@ -333,16 +333,29 @@ enum CheckboxValue {
   [mTabs release];
   mTabs = nil;
 }
 
 @end
 
 @implementation mozPaneAccessible
 
+- (NSUInteger)accessibilityArrayAttributeCount:(NSString*)attribute
+{
+  if (!mGeckoAccessible)
+    return 0;
+
+  // By default this calls -[[mozAccessible children] count].
+  // Since we don't cache mChildren. This is faster.
+  if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
+    return mGeckoAccessible->ChildCount() ? 1 : 0;
+
+  return [super accessibilityArrayAttributeCount:attribute];
+}
+
 - (NSArray*)children
 {
   if (!mGeckoAccessible)
     return nil;
 
   nsDeckFrame* deckFrame = do_QueryFrame(mGeckoAccessible->GetFrame());
   nsIFrame* selectedFrame = deckFrame ? deckFrame->GetSelectedBox() : nullptr;
 
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -102,22 +102,16 @@ if [ "$OS_ARCH" != "WINNT" -a "$OS_ARCH"
   fi
   if [ "$USE_ELF_HACK" ]; then
     add_makefiles "
       build/unix/elfhack/Makefile
     "
   fi
 fi
 
-if [ "$COMPILER_DEPEND" = "" -a "$MOZ_NATIVE_MAKEDEPEND" = "" ]; then
-  add_makefiles "
-    config/mkdepend/Makefile
-  "
-fi
-
 if [ "$ENABLE_MARIONETTE" ]; then
   add_makefiles "
     testing/marionette/Makefile
     testing/marionette/components/Makefile
   "
 fi
 
 if [ "$ENABLE_TESTS" ]; then
--- a/b2g/app/Makefile.in
+++ b/b2g/app/Makefile.in
@@ -6,16 +6,20 @@ DEPTH     = @DEPTH@
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 PREF_JS_EXPORTS = $(srcdir)/b2g.js
 
+ifdef ENABLE_MARIONETTE
+DEFINES += -DENABLE_MARIONETTE=1
+endif
+
 ifndef LIBXUL_SDK
 PROGRAM=$(MOZ_APP_NAME)$(BIN_SUFFIX)
 
 CPPSRCS = nsBrowserApp.cpp
 
 LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
 LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/base
 LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/build
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -427,26 +427,29 @@ pref("full-screen-api.enabled", true);
 // fill the whole screen, we'll just make the content fill the client window,
 // i.e. it won't give the impression to content that the number of device
 // screen pixels changes!
 pref("full-screen-api.ignore-widgets", true);
 #endif
 
 pref("media.volume.steps", 10);
 
+#ifdef ENABLE_MARIONETTE
 //Enable/disable marionette server, set listening port
 pref("marionette.defaultPrefs.enabled", true);
 pref("marionette.defaultPrefs.port", 2828);
+#endif
 
 #ifdef MOZ_UPDATER
 pref("app.update.enabled", true);
 pref("app.update.auto", true);
 pref("app.update.silent", true);
 pref("app.update.mode", 0);
 pref("app.update.incompatible.mode", 0);
+pref("app.update.stage.enabled", true);
 pref("app.update.service.enabled", true);
 
 // The URL hosting the update manifest.
 pref("app.update.url", "http://update.boot2gecko.org/m2.5/updates.xml");
 // Interval at which update manifest is fetched.  In units of seconds.
 pref("app.update.interval", 3600); // 1 hour
 // First interval to elapse before checking for update.  In units of
 // milliseconds.  Capped at 10 seconds.
@@ -508,16 +511,21 @@ pref("dom.ipc.processPriorityManager.ena
 pref("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
 pref("hal.processPriorityManager.gonk.masterOomAdjust", 0);
 pref("hal.processPriorityManager.gonk.foregroundOomAdjust", 1);
 pref("hal.processPriorityManager.gonk.backgroundOomAdjust", 2);
 pref("hal.processPriorityManager.gonk.masterNice", -1);
 pref("hal.processPriorityManager.gonk.foregroundNice", 0);
 pref("hal.processPriorityManager.gonk.backgroundNice", 10);
 
+#ifndef DEBUG
 // Enable pre-launching content processes for improved startup time
 // (hiding latency).
 pref("dom.ipc.processPrelauch.enabled", true);
 // Wait this long before pre-launching a new subprocess.
 pref("dom.ipc.processPrelauch.delayMs", 1000);
+#endif
 
 // Ignore the "dialog=1" feature in window.open.
 pref("dom.disable_window_open_dialog_feature", true);
+
+// Screen reader support
+pref("accessibility.accessfu.activate", 2);
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -13,16 +13,17 @@ Cu.import('resource://gre/modules/XPCOMU
 Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/ContactService.jsm');
 Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm');
 Cu.import('resource://gre/modules/Webapps.jsm');
 Cu.import('resource://gre/modules/AlarmService.jsm');
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
 Cu.import('resource://gre/modules/ObjectWrapper.jsm');
+Cu.import("resource://gre/modules/accessibility/AccessFu.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(Services, 'env',
                                    '@mozilla.org/process/environment;1',
                                    'nsIEnvironment');
 
 XPCOMUtils.defineLazyServiceGetter(Services, 'ss',
                                    '@mozilla.org/content/style-sheet-service;1',
                                    'nsIStyleSheetService');
@@ -43,17 +44,17 @@ XPCOMUtils.defineLazyServiceGetter(Servi
 
 XPCOMUtils.defineLazyGetter(this, 'DebuggerServer', function() {
   Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
   return DebuggerServer;
 });
 
 XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
   return Cc["@mozilla.org/parentprocessmessagemanager;1"]
-         .getService(Ci.nsIFrameMessageManager);
+         .getService(Ci.nsIMessageListenerManager);
 });
 
 function getContentWindow() {
   return shell.contentBrowser.contentWindow;
 }
 
 var shell = {
 
@@ -144,16 +145,17 @@ var shell = {
     try {
       Services.audioManager.masterVolume = 0.5;
     } catch(e) {
       dump('Error setting master volume: ' + e + '\n');
     }
 
     CustomEventManager.init();
     WebappsHelper.init();
+    AccessFu.attach(window);
 
     // XXX could factor out into a settings->pref map.  Not worth it yet.
     SettingsListener.observe("debug.fps.enabled", false, function(value) {
       Services.prefs.setBoolPref("layers.acceleration.draw-fps", value);
     });
     SettingsListener.observe("debug.paint-flashing.enabled", false, function(value) {
       Services.prefs.setBoolPref("nglayout.debug.paint_flashing", value);
     });
--- a/b2g/components/ContentHandler.js
+++ b/b2g/components/ContentHandler.js
@@ -9,17 +9,18 @@ const Cr = Components.results;
 const Cu = Components.utils;
 
 const PDF_CONTENT_TYPE = "application/pdf";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
-  return Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager);
+  return Cc["@mozilla.org/childprocessmessagemanager;1"]
+           .getService(Ci.nsIMessageSender);
 });
 
 function log(aMsg) {
   let msg = "ContentHandler.js: " + (aMsg.join ? aMsg.join("") : aMsg);
   Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService)
                                      .logStringMessage(msg);
   dump(msg + "\n");
 }
--- a/b2g/components/DirectoryProvider.js
+++ b/b2g/components/DirectoryProvider.js
@@ -17,17 +17,18 @@ function DirectoryProvider() {
 
 DirectoryProvider.prototype = {
   classID: Components.ID("{9181eb7c-6f87-11e1-90b1-4f59d80dd2e5}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]),
 
   getFile: function dp_getFile(prop, persistent) {
 #ifdef MOZ_WIDGET_GONK
-    let localProps = ["cachePDir", "webappsDir", "PrefD", "indexedDBPDir", "permissionDBPDir"];
+    let localProps = ["cachePDir", "webappsDir", "PrefD", "indexedDBPDir",
+      "permissionDBPDir", "UpdRootD"];
     if (localProps.indexOf(prop) != -1) {
       prop.persistent = true;
       let file = Cc["@mozilla.org/file/local;1"]
                    .createInstance(Ci.nsILocalFile)
       file.initWithPath(LOCAL_DIR);
       return file;
     }
 #endif
--- a/b2g/components/MozKeyboard.js
+++ b/b2g/components/MozKeyboard.js
@@ -9,17 +9,17 @@ const Ci = Components.interfaces;
 const Cu = Components.utils;
 const kFormsFrameScript = "chrome://browser/content/forms.js";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/ObjectWrapper.jsm");
 
 const messageManager = Cc["@mozilla.org/globalmessagemanager;1"]
-                         .getService(Ci.nsIChromeFrameMessageManager);
+                         .getService(Ci.nsIMessageBroadcaster);
 
 
 // -----------------------------------------------------------------------
 // MozKeyboard
 // -----------------------------------------------------------------------
 
 function MozKeyboard() { } 
 
@@ -65,29 +65,29 @@ MozKeyboard.prototype = {
   sendKey: function mozKeyboardSendKey(keyCode, charCode) {
     charCode = (charCode == undefined) ? keyCode : charCode;
     ["keydown", "keypress", "keyup"].forEach((function sendKey(type) {
       this._utils.sendKeyEvent(type, keyCode, charCode, null);
     }).bind(this));
   },
 
   setSelectedOption: function mozKeyboardSetSelectedOption(index) {
-    messageManager.sendAsyncMessage("Forms:Select:Choice", {
+    messageManager.broadcastAsyncMessage("Forms:Select:Choice", {
       "index": index
     });
   },
 
   setValue: function mozKeyboardSetValue(value) {
-    messageManager.sendAsyncMessage("Forms:Input:Value", {
+    messageManager.broadcastAsyncMessage("Forms:Input:Value", {
       "value": value
     });
   },
 
   setSelectedOptions: function mozKeyboardSetSelectedOptions(indexes) {
-    messageManager.sendAsyncMessage("Forms:Select:Choice", {
+    messageManager.broadcastAsyncMessage("Forms:Select:Choice", {
       "indexes": indexes || []
     });
   },
 
   set onfocuschange(val) {
     this._focusHandler = val;
   },
 
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -74,16 +74,16 @@ UpdatePrompt.prototype = {
     this._selfDestructTimer = timer;
 #endif
   },
 
   showUpdateInstalled: function UP_showUpdateInstalled() { },
 
   showUpdateError: function UP_showUpdateError(aUpdate) {
     if (aUpdate.state == "failed") {
-      log("Failed to download update");
+      log("Failed to download update, errorCode: " + aUpdate.errorCode);
     }
   },
 
   showUpdateHistory: function UP_showUpdateHistory(aParent) { },
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([UpdatePrompt]);
--- a/b2g/config/mozconfigs/gb_armv7a_gecko/debug
+++ b/b2g/config/mozconfigs/gb_armv7a_gecko/debug
@@ -6,12 +6,12 @@ ac_add_options --enable-application=b2g
 
 ac_add_options --target=arm-android-eabi
 ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
 ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-eabi-4.4.3/bin/arm-eabi-"
 ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-debug
 ac_add_options --with-ccache
-ac_add_options --enable-marionette
+ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
--- a/b2g/config/mozconfigs/gb_armv7a_gecko/nightly
+++ b/b2g/config/mozconfigs/gb_armv7a_gecko/nightly
@@ -6,12 +6,12 @@ ac_add_options --enable-application=b2g
 
 ac_add_options --target=arm-android-eabi
 ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
 ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-eabi-4.4.3/bin/arm-eabi-"
 ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-profiling
 ac_add_options --with-ccache
-ac_add_options --enable-marionette
+ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
--- a/b2g/config/mozconfigs/ics_armv7a_gecko/debug
+++ b/b2g/config/mozconfigs/ics_armv7a_gecko/debug
@@ -9,12 +9,12 @@ ac_add_options --target=arm-android-eabi
 ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
 export TOOLCHAIN_HOST=linux-x86
 export GONK_PRODUCT=generic
 ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-"
 ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-debug
 #ac_add_options --with-ccache
-ac_add_options --enable-marionette
+ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"
--- a/b2g/config/mozconfigs/ics_armv7a_gecko/nightly
+++ b/b2g/config/mozconfigs/ics_armv7a_gecko/nightly
@@ -9,12 +9,12 @@ ac_add_options --target=arm-android-eabi
 ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
 export TOOLCHAIN_HOST=linux-x86
 export GONK_PRODUCT=generic
 ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-"
 ac_add_options --disable-elf-hack
 ac_add_options --enable-debug-symbols
 ac_add_options --enable-profiling
 #ac_add_options --with-ccache
-ac_add_options --enable-marionette
+ENABLE_MARIONETTE=1
 
 # Enable dump() from JS.
 export CXXFLAGS="-DMOZ_ENABLE_JS_DUMP -include $topsrcdir/gonk-toolchain/gonk-misc/Unicode.h -include $topsrcdir/gonk-toolchain/system/vold/ResponseCode.h"
--- a/b2g/config/mozconfigs/linux32_gecko/nightly
+++ b/b2g/config/mozconfigs/linux32_gecko/nightly
@@ -28,11 +28,11 @@ export MOZ_TELEMETRY_REPORTING=1
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 #B2G options
 ac_add_options --enable-application=b2g
-ac_add_options --enable-marionette
+ENABLE_MARIONETTE=1
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
--- a/b2g/config/mozconfigs/linux64_gecko/nightly
+++ b/b2g/config/mozconfigs/linux64_gecko/nightly
@@ -30,11 +30,11 @@ export MOZ_TELEMETRY_REPORTING=1
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 #B2G options
 ac_add_options --enable-application=b2g
-ac_add_options --enable-marionette
+ENABLE_MARIONETTE=1
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
--- a/b2g/config/mozconfigs/macosx64_gecko/nightly
+++ b/b2g/config/mozconfigs/macosx64_gecko/nightly
@@ -18,11 +18,11 @@ mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # B2G Stuff
 ac_add_options --enable-application=b2g
 ac_add_options --enable-debug-symbols
 ac_add_options --with-ccache
-ac_add_options --enable-marionette
+ENABLE_MARIONETTE=1
 
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
--- a/b2g/config/mozconfigs/win32_gecko/nightly
+++ b/b2g/config/mozconfigs/win32_gecko/nightly
@@ -19,11 +19,11 @@ mk_add_options MOZ_MAKE_FLAGS=-j1
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # B2G Options
 ac_add_options --enable-application=b2g
-ac_add_options --enable-marionette
+ENABLE_MARIONETTE=1
 
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -1,18 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOZ_APP_BASENAME=B2G
 MOZ_APP_VENDOR=Mozilla
 
-MOZ_APP_VERSION=17.0a1
-
-MOZ_UA_OS_AGNOSTIC=1
+MOZ_APP_VERSION=18.0a1
 MOZ_APP_UA_NAME=Firefox
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
 MOZ_SERVICES_SYNC=1
@@ -33,11 +31,11 @@ if test "$LIBXUL_SDK"; then
 MOZ_XULRUNNER=1
 else
 MOZ_XULRUNNER=
 MOZ_PLACES=1
 fi
 
 MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
 MOZ_EXTENSION_MANAGER=1
-ENABLE_MARIONETTE=1
 
 MOZ_SYS_MSG=1
+MOZ_TOOLKIT_SEARCH=
--- a/b2g/installer/Makefile.in
+++ b/b2g/installer/Makefile.in
@@ -33,16 +33,20 @@ JAREXT=.jar
 else
 JAREXT=
 endif
 DEFINES += -DJAREXT=$(JAREXT)
 
 include $(topsrcdir)/ipc/app/defs.mk
 DEFINES += -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
+ifdef ENABLE_MARIONETTE
+DEFINES += -DENABLE_MARIONETTE=1
+endif
+
 ifdef MOZ_PKG_MANIFEST_P
 MOZ_PKG_MANIFEST = package-manifest
 endif
 
 MOZ_POST_STAGING_CMD = find chrome -type f -name *.properties -exec sed -i '/^\#/d' {} \;
 
 include $(topsrcdir)/toolkit/mozapps/installer/packager.mk
 
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -339,18 +339,16 @@
 @BINPATH@/components/nsBrowserContentHandler.js
 @BINPATH@/components/nsBrowserGlue.js
 @BINPATH@/components/nsSetDefaultBrowser.manifest
 @BINPATH@/components/nsSetDefaultBrowser.js
 @BINPATH@/components/BrowserPlaces.manifest
 @BINPATH@/components/nsPrivateBrowsingService.manifest
 @BINPATH@/components/nsPrivateBrowsingService.js
 @BINPATH@/components/toolkitsearch.manifest
-@BINPATH@/components/nsSearchService.js
-@BINPATH@/components/nsSearchSuggestions.js
 @BINPATH@/components/nsTryToClose.manifest
 @BINPATH@/components/nsTryToClose.js
 @BINPATH@/components/passwordmgr.manifest
 @BINPATH@/components/nsLoginInfo.js
 @BINPATH@/components/nsLoginManager.js
 @BINPATH@/components/nsLoginManagerPrompter.js
 @BINPATH@/components/storage-Legacy.js
 @BINPATH@/components/storage-mozStorage.js
@@ -670,20 +668,22 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DL
 [b2g]
 @BINPATH@/chrome/icons/
 @BINPATH@/chrome/chrome@JAREXT@
 @BINPATH@/chrome/chrome.manifest
 @BINPATH@/components/B2GComponents.manifest
 @BINPATH@/components/B2GComponents.xpt
 @BINPATH@/components/CameraContent.js
 @BINPATH@/@DLL_PREFIX@omxplugin@DLL_SUFFIX@
+#ifdef ENABLE_MARIONETTE
 @BINPATH@/chrome/marionette@JAREXT@
 @BINPATH@/chrome/marionette.manifest
 @BINPATH@/components/MarionetteComponents.manifest
 @BINPATH@/components/marionettecomponent.js
+#endif
 @BINPATH@/components/AlertsService.js
 @BINPATH@/components/ContentPermissionPrompt.js
 #ifdef MOZ_UPDATER
 @BINPATH@/components/UpdatePrompt.js
 #endif
 @BINPATH@/components/MozKeyboard.js
 @BINPATH@/components/DirectoryProvider.js
 @BINPATH@/components/ActivitiesGlue.js
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -7,16 +7,20 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 DIRS        = profile/extensions
 dist_dest   = $(DIST)/$(MOZ_MACBUNDLE_NAME)
 
+ifdef ENABLE_MARIONETTE
+DEFINES += -DENABLE_MARIONETTE=1
+endif
+
 PREF_JS_EXPORTS = $(srcdir)/profile/firefox.js \
 		  $(NULL)
 
 
 # hardcode en-US for the moment
 AB_CD = en-US
 
 DEFINES += \
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1345147390000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1345657032000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
@@ -434,16 +434,19 @@
                   <match name="filename" exp="npmozax\.dll" />                      <versionRange  minVersion="0" maxVersion="*"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p113">
                   <match name="filename" exp="npuplaypc\.dll" />                      <versionRange  minVersion="0" maxVersion="1.0.0.0" severity="1"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p123">
                   <match name="filename" exp="JavaPlugin2_NPAPI\.plugin" />                      <versionRange  minVersion="0" maxVersion="14.2.0" severity="1"></versionRange>
                   </pluginItem>
+      <pluginItem  blockID="p129">
+                  <match name="filename" exp="Silverlight\.plugin" />                      <versionRange  minVersion="0" maxVersion="5.0.99999" severity="1"></versionRange>
+                  </pluginItem>
     </pluginItems>
 
   <gfxItems>
     <gfxBlacklistEntry  blockID="g35">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
                       <device>0x0a6c</device>
                   </devices>
             <feature>DIRECT2D</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>8.17.12.5896</driverVersion>      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
     <gfxBlacklistEntry  blockID="g36">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1002,18 +1002,16 @@ pref("devtools.gcli.allowSet", false);
 pref("devtools.commands.dir", "");
 
 // Enable the Inspector
 pref("devtools.inspector.enabled", true);
 pref("devtools.inspector.htmlHeight", 112);
 pref("devtools.inspector.htmlPanelOpen", false);
 pref("devtools.inspector.sidebarOpen", false);
 pref("devtools.inspector.activeSidebar", "ruleview");
-pref("devtools.inspector.highlighterShowVeil", true);
-pref("devtools.inspector.highlighterShowInfobar", true);
 
 // Enable the Layout View
 pref("devtools.layoutview.enabled", true);
 pref("devtools.layoutview.open", false);
 
 // Enable the Responsive UI tool
 pref("devtools.responsiveUI.enabled", true);
 
@@ -1025,17 +1023,19 @@ pref("devtools.debugger.remote-autoconne
 pref("devtools.debugger.remote-connection-retries", 3);
 pref("devtools.debugger.remote-timeout", 3000);
 
 // The default Debugger UI settings
 pref("devtools.debugger.ui.height", 250);
 pref("devtools.debugger.ui.remote-win.width", 900);
 pref("devtools.debugger.ui.remote-win.height", 400);
 pref("devtools.debugger.ui.stackframes-width", 200);
+pref("devtools.debugger.ui.stackframes-pane-visible", true);
 pref("devtools.debugger.ui.variables-width", 300);
+pref("devtools.debugger.ui.variables-pane-visible", true);
 
 // Enable the style inspector
 pref("devtools.styleinspector.enabled", true);
 
 // Enable the Tilt inspector
 pref("devtools.tilt.enabled", true);
 pref("devtools.tilt.intro_transition", true);
 pref("devtools.tilt.outro_transition", true);
@@ -1085,16 +1085,19 @@ pref("devtools.webconsole.filter.csserro
 pref("devtools.webconsole.filter.cssparser", true);
 pref("devtools.webconsole.filter.exception", true);
 pref("devtools.webconsole.filter.jswarn", true);
 pref("devtools.webconsole.filter.error", true);
 pref("devtools.webconsole.filter.warn", true);
 pref("devtools.webconsole.filter.info", true);
 pref("devtools.webconsole.filter.log", true);
 
+// Text size in the Web Console. Use 0 for the system default size.
+pref("devtools.webconsole.fontSize", 0);
+
 // The number of lines that are displayed in the web console for the Net,
 // CSS, JS and Web Developer categories.
 pref("devtools.hud.loglimit.network", 200);
 pref("devtools.hud.loglimit.cssparser", 200);
 pref("devtools.hud.loglimit.exception", 200);
 pref("devtools.hud.loglimit.console", 200);
 
 // The developer tools editor configuration:
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -145,66 +145,86 @@ var gPluginHandler = {
         self.addLinkClickCallback(updateLink, "openPluginUpdatePage");
         /* FALLTHRU */
 
       case "PluginVulnerableNoUpdate":
       case "PluginClickToPlay":
         self._handleClickToPlayEvent(plugin);
         break;
 
+      case "PluginPlayPreview":
+        self._handlePlayPreviewEvent(plugin);
+        break;
+
       case "PluginDisabled":
         let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink");
         self.addLinkClickCallback(manageLink, "managePlugins");
         break;
     }
 
     // Hide the in-content UI if it's too big. The crashed plugin handler already did this.
     if (event.type != "PluginCrashed") {
       let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
       /* overlay might be null, so only operate on it if it exists */
       if (overlay != null && self.isTooSmall(plugin, overlay))
           overlay.style.visibility = "hidden";
     }
   },
 
+  canActivatePlugin: function PH_canActivatePlugin(objLoadingContent) {
+    return !objLoadingContent.activated &&
+           objLoadingContent.pluginFallbackType !== Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW;
+  },
+
   activatePlugins: function PH_activatePlugins(aContentWindow) {
     let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
     browser._clickToPlayPluginsActivated = true;
     let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindowUtils);
     let plugins = cwu.plugins;
     for (let plugin of plugins) {
       let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-      if (!objLoadingContent.activated)
+      if (gPluginHandler.canActivatePlugin(objLoadingContent))
         objLoadingContent.playPlugin();
     }
     let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
     if (notification)
       notification.remove();
   },
 
   activateSinglePlugin: function PH_activateSinglePlugin(aContentWindow, aPlugin) {
     let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
-    if (!objLoadingContent.activated)
+    if (gPluginHandler.canActivatePlugin(objLoadingContent))
       objLoadingContent.playPlugin();
 
     let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindowUtils);
     let haveUnplayedPlugins = cwu.plugins.some(function(plugin) {
       let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-      return (plugin != aPlugin && !objLoadingContent.activated);
+      return (plugin != aPlugin && gPluginHandler.canActivatePlugin(objLoadingContent));
     });
     let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
     let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
     if (notification && !haveUnplayedPlugins) {
       browser._clickToPlayDoorhangerShown = false;
       notification.remove();
     }
   },
 
+  stopPlayPreview: function PH_stopPlayPreview(aPlugin, aPlayPlugin) {
+    let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
+    if (objLoadingContent.activated)
+      return;
+
+    if (aPlayPlugin)
+      objLoadingContent.playPlugin();
+    else
+      objLoadingContent.cancelPlayPreview();
+  },
+
   newPluginInstalled : function(event) {
     // browser elements are anonymous so we can't just use target.
     var browser = event.originalTarget;
     // clear the plugin list, now that at least one plugin has been installed
     browser.missingPlugins = null;
 
     var notificationBox = gBrowser.getNotificationBox(browser);
     var notification = notificationBox.getNotificationWithValue("missing-plugins");
@@ -285,32 +305,72 @@ var gPluginHandler = {
           gPluginHandler.activateSinglePlugin(aEvent.target.ownerDocument.defaultView.top, aPlugin);
       }, true);
     }
 
     if (!browser._clickToPlayDoorhangerShown)
       gPluginHandler._showClickToPlayNotification(browser);
   },
 
+  _handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) {
+    let doc = aPlugin.ownerDocument;
+    let previewContent = doc.getAnonymousElementByAttribute(aPlugin, "class", "previewPluginContent");
+    if (!previewContent) {
+      // the XBL binding is not attached (element is display:none), fallback to click-to-play logic
+      gPluginHandler.stopPlayPreview(aPlugin, false);
+      return;
+    }
+    let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
+    if (!iframe) {
+      // lazy initialization of the iframe
+      iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
+      iframe.className = "previewPluginContentFrame";
+      previewContent.appendChild(iframe);
+
+      // Force a style flush, so that we ensure our binding is attached.
+      aPlugin.clientTop;
+    }
+    let pluginInfo = getPluginInfo(aPlugin);
+    let playPreviewUri = "data:application/x-moz-playpreview;," + pluginInfo.mimetype;
+    iframe.src = playPreviewUri;
+
+    // MozPlayPlugin event can be dispatched from the extension chrome
+    // code to replace the preview content with the native plugin
+    previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(aEvent) {
+      if (!aEvent.isTrusted)
+        return;
+
+      previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
+
+      let playPlugin = !aEvent.detail;
+      gPluginHandler.stopPlayPreview(aPlugin, playPlugin);
+
+      // cleaning up: removes overlay iframe from the DOM
+      let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
+      if (iframe)
+        previewContent.removeChild(iframe);
+    }, true);
+  },
+
   reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() {
     if (!Services.prefs.getBoolPref("plugins.click_to_play"))
       return;
 
     let browser = gBrowser.selectedBrowser;
 
     let pluginsPermission = Services.perms.testPermission(browser.currentURI, "plugins");
     if (pluginsPermission == Ci.nsIPermissionManager.DENY_ACTION)
       return;
 
     let contentWindow = browser.contentWindow;
     let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
     let pluginNeedsActivation = cwu.plugins.some(function(plugin) {
       let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-      return !objLoadingContent.activated;
+      return gPluginHandler.canActivatePlugin(objLoadingContent);
     });
     if (pluginNeedsActivation)
       gPluginHandler._showClickToPlayNotification(browser);
   },
 
   _showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser) {
     aBrowser._clickToPlayDoorhangerShown = true;
     let contentWindow = aBrowser.contentWindow;
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -36,16 +36,17 @@ let SocialUI = {
         // Exceptions here sometimes don't get reported properly, report them
         // manually :(
         try {
           this.updateToggleCommand();
           SocialShareButton.updateButtonHiddenState();
           SocialToolbar.updateButtonHiddenState();
           SocialSidebar.updateSidebar();
           SocialChatBar.update();
+          SocialFlyout.unload();
         } catch (e) {
           Components.utils.reportError(e);
           throw e;
         }
         break;
       case "social:ambient-notification-changed":
         SocialToolbar.updateButton();
         break;
@@ -66,19 +67,21 @@ let SocialUI = {
   _providerReady: function SocialUI_providerReady() {
     // If we couldn't find a provider, nothing to do here.
     if (!Social.provider)
       return;
 
     this.updateToggleCommand();
 
     let toggleCommand = this.toggleCommand;
-    let label = gNavigatorBundle.getFormattedString("social.enable.label",
-                                                    [Social.provider.name]);
-    let accesskey = gNavigatorBundle.getString("social.enable.accesskey");
+    let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
+    let label = gNavigatorBundle.getFormattedString("social.toggle.label",
+                                                    [Social.provider.name,
+                                                     brandShortName]);
+    let accesskey = gNavigatorBundle.getString("social.toggle.accesskey");
     toggleCommand.setAttribute("label", label);
     toggleCommand.setAttribute("accesskey", accesskey);
 
     SocialToolbar.init();
     SocialShareButton.init();
     SocialSidebar.init();
   },
 
@@ -132,17 +135,17 @@ let SocialUI = {
     Social.lastEventReceived = now;
 
     // Enable the social functionality, and indicate that it was activated
     Social.active = true;
 
     // Show a warning, allow undoing the activation
     let description = document.getElementById("social-activation-message");
     let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
-    let message = gNavigatorBundle.getFormattedString("social.activated.message",
+    let message = gNavigatorBundle.getFormattedString("social.activated.description",
                                                       [Social.provider.name, brandShortName]);
     description.value = message;
 
     SocialUI.notificationPanel.hidden = false;
 
     setTimeout(function () {
       SocialUI.notificationPanel.openPopup(SocialToolbar.button, "bottomcenter topright");
     }.bind(this), 0);
@@ -164,27 +167,143 @@ let SocialChatBar = {
   },
   // Whether the chats can be shown for this window.
   get canShow() {
     let docElem = document.documentElement;
     let chromeless = docElem.getAttribute("disablechrome") ||
                      docElem.getAttribute("chromehidden").indexOf("extrachrome") >= 0;
     return Social.uiVisible && !chromeless;
   },
-  newChat: function(aProvider, aURL, aCallback) {
+  openChat: function(aProvider, aURL, aCallback, aMode) {
     if (this.canShow)
-      this.chatbar.newChat(aProvider, aURL, aCallback);
+      this.chatbar.openChat(aProvider, aURL, aCallback, aMode);
   },
   update: function() {
     if (!this.canShow)
       this.chatbar.removeAll();
   }
 }
 
+function sizeSocialPanelToContent(iframe) {
+  // FIXME: bug 764787: Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
+  // Need to handle dynamic sizing
+  let doc = iframe.contentDocument;
+  if (!doc) {
+    return;
+  }
+  // "notif" is an implementation detail that we should get rid of
+  // eventually
+  let body = doc.getElementById("notif") || doc.body;
+  if (!body || !body.firstChild) {
+    return;
+  }
+
+  let [height, width] = [body.firstChild.offsetHeight || 300, 330];
+  iframe.style.width = width + "px";
+  iframe.style.height = height + "px";
+}
+
+let SocialFlyout = {
+  get panel() {
+    return document.getElementById("social-flyout-panel");
+  },
+
+  dispatchPanelEvent: function(name) {
+    let doc = this.panel.firstChild.contentDocument;
+    let evt = doc.createEvent("CustomEvent");
+    evt.initCustomEvent(name, true, true, {});
+    doc.documentElement.dispatchEvent(evt);
+  },
+
+  _createFrame: function() {
+    let panel = this.panel;
+    if (!Social.provider || panel.firstChild)
+      return;
+    // create and initialize the panel for this window
+    let iframe = document.createElement("iframe");
+    iframe.setAttribute("type", "content");
+    iframe.setAttribute("flex", "1");
+    iframe.setAttribute("origin", Social.provider.origin);
+    panel.appendChild(iframe);
+  },
+
+  unload: function() {
+    let panel = this.panel;
+    if (!panel.firstChild)
+      return
+    panel.removeChild(panel.firstChild);
+  },
+
+  onShown: function(aEvent) {
+    let iframe = this.panel.firstChild;
+    iframe.docShell.isActive = true;
+    iframe.docShell.isAppTab = true;
+    if (iframe.contentDocument.readyState == "complete") {
+      this.dispatchPanelEvent("socialFrameShow");
+    } else {
+      // first time load, wait for load and dispatch after load
+      iframe.addEventListener("load", function panelBrowserOnload(e) {
+        iframe.removeEventListener("load", panelBrowserOnload, true);
+        setTimeout(function() {
+          SocialFlyout.dispatchPanelEvent("socialFrameShow");
+        }, 0);
+      }, true);
+    }
+  },
+
+  onHidden: function(aEvent) {
+    this.panel.firstChild.docShell.isActive = false;
+    this.dispatchPanelEvent("socialFrameHide");
+  },
+
+  open: function(aURL, yOffset, aCallback) {
+    if (!Social.provider)
+      return;
+    let panel = this.panel;
+    if (!panel.firstChild)
+      this._createFrame();
+    panel.hidden = false;
+    let iframe = panel.firstChild;
+
+    let src = iframe.getAttribute("src");
+    if (src != aURL) {
+      iframe.addEventListener("load", function documentLoaded() {
+        iframe.removeEventListener("load", documentLoaded, true);
+        sizeSocialPanelToContent(iframe);
+        if (aCallback) {
+          try {
+            aCallback(iframe.contentWindow);
+          } catch(e) {
+            Cu.reportError(e);
+          }
+        }
+      }, true);
+      iframe.setAttribute("src", aURL);
+    }
+    else if (aCallback) {
+      try {
+        aCallback(iframe.contentWindow);
+      } catch(e) {
+        Cu.reportError(e);
+      }
+    }
+
+    sizeSocialPanelToContent(iframe);
+    let anchor = document.getElementById("social-sidebar-browser");
+    panel.openPopup(anchor, "start_before", 0, yOffset, false, false);
+  }
+}
+
 let SocialShareButton = {
+  // promptImages and promptMessages being null means we are yet to get the
+  // message back from the provider with the images and icons (or that we got
+  // the response but determined it was invalid.)
+  promptImages: null,
+  promptMessages: null,
+
   // Called once, after window load, when the Social.provider object is initialized
   init: function SSB_init() {
     this.updateButtonHiddenState();
     this.updateProfileInfo();
   },
 
   updateProfileInfo: function SSB_updateProfileInfo() {
     let profileRow = document.getElementById("editSharePopupHeader");
@@ -193,33 +312,88 @@ let SocialShareButton = {
       profileRow.hidden = false;
       let portrait = document.getElementById("socialUserPortrait");
       portrait.setAttribute("src", profile.portrait || "chrome://browser/skin/social/social.png");
       let displayName = document.getElementById("socialUserDisplayName");
       displayName.setAttribute("label", profile.displayName);
     } else {
       profileRow.hidden = true;
     }
+    // XXX - this shouldn't be done as part of updateProfileInfo, but instead
+    // whenever we notice the provider has changed - but the concept of
+    // "provider changed" will only exist once bug 774520 lands. 
+    this.promptImages = null;
+    this.promptMessages = null;
+    // get the recommend-prompt info.
+    let port = Social.provider._getWorkerPort();
+    if (port) {
+      port.onmessage = function(evt) {
+        if (evt.data.topic == "social.user-recommend-prompt-response") {
+          port.close();
+          this.acceptRecommendInfo(evt.data.data);
+          this.updateButtonHiddenState();
+          this.updateShareState();
+        }
+      }.bind(this);
+      port.postMessage({topic: "social.user-recommend-prompt"});
+    }
+  },
+
+  acceptRecommendInfo: function SSB_acceptRecommendInfo(data) {
+    // Accept *and validate* the user-recommend-prompt-response message.
+    let promptImages = {};
+    let promptMessages = {};
+    function reportError(reason) {
+      Cu.reportError("Invalid recommend data from provider: " + reason + ": sharing is disabled for this provider");
+      return false;
+    }
+    if (!data ||
+        !data.images || typeof data.images != "object" ||
+        !data.messages || typeof data.messages != "object") {
+      return reportError("data is missing valid 'images' or 'messages' elements");
+    }
+    for (let sub of ["share", "unshare"]) {
+      let url = data.images[sub];
+      if (!url || typeof url != "string" || url.length == 0) {
+        return reportError('images["' + sub + '"] is missing or not a non-empty string');
+      }
+      // resolve potentially relative URLs then check the scheme is acceptable.
+      url = Services.io.newURI(Social.provider.origin, null, null).resolve(url);
+      let uri = Services.io.newURI(url, null, null);
+      if (!uri.schemeIs("http") && !uri.schemeIs("https") && !uri.schemeIs("data")) {
+        return reportError('images["' + sub + '"] does not have a valid scheme');
+      }
+      promptImages[sub] = url;
+    }
+    for (let sub of ["shareTooltip", "unshareTooltip", "sharedLabel", "unsharedLabel"]) {
+      if (typeof data.messages[sub] != "string" || data.messages[sub].length == 0) {
+        return reportError('messages["' + sub + '"] is not a valid string');
+      }
+      promptMessages[sub] = data.messages[sub];
+    }
+    this.promptImages = promptImages;
+    this.promptMessages = promptMessages;
+    return true;
   },
 
   get shareButton() {
     return document.getElementById("share-button");
   },
   get sharePopup() {
     return document.getElementById("editSharePopup");
   },
 
   dismissSharePopup: function SSB_dismissSharePopup() {
     this.sharePopup.hidePopup();
   },
 
   updateButtonHiddenState: function SSB_updateButtonHiddenState() {
     let shareButton = this.shareButton;
     if (shareButton)
-      shareButton.hidden = !Social.uiVisible;
+      shareButton.hidden = !Social.uiVisible || this.promptImages == null;
   },
 
   onClick: function SSB_onClick(aEvent) {
     if (aEvent.button != 0)
       return;
 
     // Don't bubble to the textbox, to avoid unwanted selection of the address.
     aEvent.stopPropagation();
@@ -252,49 +426,51 @@ let SocialShareButton = {
   },
 
   updateShareState: function SSB_updateShareState() {
     let currentPageShared = Social.isPageShared(gBrowser.currentURI);
 
     // Provide a11y-friendly notification of share.
     let status = document.getElementById("share-button-status");
     if (status) {
+      // XXX - this should also be capable of reflecting that the page was
+      // unshared (ie, it needs to manage three-states: (1) nothing done, (2)
+      // shared, (3) shared then unshared)
+      // Note that we *do* have an appropriate string from the provider for
+      // this (promptMessages['unsharedLabel'] but currently lack a way of
+      // tracking this state)
       let statusString = currentPageShared ?
-                           gNavigatorBundle.getString("social.pageShared.label") : "";
+                           this.promptMessages['sharedLabel'] : "";
       status.setAttribute("value", statusString);
     }
 
     // Update the share button, if present
     let shareButton = this.shareButton;
-    if (!shareButton)
+    if (!shareButton || shareButton.hidden)
       return;
 
+    let imageURL;
     if (currentPageShared) {
       shareButton.setAttribute("shared", "true");
-      shareButton.setAttribute("tooltiptext", gNavigatorBundle.getString("social.shareButton.sharedtooltip"));
+      shareButton.setAttribute("tooltiptext", this.promptMessages['unshareTooltip']);
+      imageURL = this.promptImages["unshare"]
     } else {
       shareButton.removeAttribute("shared");
-      shareButton.setAttribute("tooltiptext", gNavigatorBundle.getString("social.shareButton.tooltip"));
+      shareButton.setAttribute("tooltiptext", this.promptMessages['shareTooltip']);
+      imageURL = this.promptImages["share"]
     }
+    shareButton.style.backgroundImage = 'url("' + encodeURI(imageURL) + '")';
   }
 };
 
 var SocialToolbar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialToolbar_init() {
     document.getElementById("social-provider-image").setAttribute("image", Social.provider.iconURL);
 
-    let removeItem = document.getElementById("social-remove-menuitem");
-    let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
-    let label = gNavigatorBundle.getFormattedString("social.remove.label",
-                                                    [brandShortName]);
-    let accesskey = gNavigatorBundle.getString("social.remove.accesskey");
-    removeItem.setAttribute("label", label);
-    removeItem.setAttribute("accesskey", accesskey);
-
     let statusAreaPopup = document.getElementById("social-statusarea-popup");
     statusAreaPopup.addEventListener("popupshown", function(e) {
       this.button.setAttribute("open", "true");
     }.bind(this));
     statusAreaPopup.addEventListener("popuphidden", function(e) {
       this.button.removeAttribute("open");
     }.bind(this));
 
@@ -339,33 +515,36 @@ var SocialToolbar = {
   },
 
   updateButton: function SocialToolbar_updateButton() {
     this.updateButtonHiddenState();
     let provider = Social.provider;
     let iconNames = Object.keys(provider.ambientNotificationIcons);
     let iconBox = document.getElementById("social-status-iconbox");
     let notifBox = document.getElementById("social-notification-box");
-    let notifBrowsers = document.createDocumentFragment();
+    let panel = document.getElementById("social-notification-panel");
+    panel.hidden = false;
+    let notificationFrames = document.createDocumentFragment();
     let iconContainers = document.createDocumentFragment();
 
     for each(let name in iconNames) {
       let icon = provider.ambientNotificationIcons[name];
 
-      let notifBrowserId = "social-status-" + icon.name;
-      let notifBrowser = document.getElementById(notifBrowserId);
-      if (!notifBrowser) {
-        notifBrowser = document.createElement("iframe");
-        notifBrowser.setAttribute("type", "content");
-        notifBrowser.setAttribute("id", notifBrowserId);
-        notifBrowsers.appendChild(notifBrowser);
+      let notificationFrameId = "social-status-" + icon.name;
+      let notificationFrame = document.getElementById(notificationFrameId);
+      if (!notificationFrame) {
+        notificationFrame = document.createElement("iframe");
+        notificationFrame.setAttribute("type", "content");
+        notificationFrame.setAttribute("id", notificationFrameId);
+        notificationFrame.setAttribute("mozbrowser", "true");
+        notificationFrames.appendChild(notificationFrame);
       }
-      notifBrowser.setAttribute("origin", provider.origin);
-      if (notifBrowser.getAttribute("src") != icon.contentPanel)
-        notifBrowser.setAttribute("src", icon.contentPanel);
+      notificationFrame.setAttribute("origin", provider.origin);
+      if (notificationFrame.getAttribute("src") != icon.contentPanel)
+        notificationFrame.setAttribute("src", icon.contentPanel);
 
       let iconId = "social-notification-icon-" + icon.name;
       let iconContainer = document.getElementById(iconId);
       let iconImage, iconCounter;
       if (iconContainer) {
         iconImage = iconContainer.getElementsByClassName("social-notification-icon-image")[0];
         iconCounter = iconContainer.getElementsByClassName("social-notification-icon-counter")[0];
       } else {
@@ -382,89 +561,65 @@ var SocialToolbar = {
         iconCounter.classList.add("social-notification-icon-counter");
         iconCounter.appendChild(document.createTextNode(""));
         iconCounter = iconContainer.appendChild(iconCounter);
 
         iconContainers.appendChild(iconContainer);
       }
       if (iconImage.getAttribute("src") != icon.iconURL)
         iconImage.setAttribute("src", icon.iconURL);
-      iconImage.setAttribute("notifBrowserId", notifBrowserId);
+      iconImage.setAttribute("notificationFrameId", notificationFrameId);
 
       iconCounter.collapsed = !icon.counter;
       iconCounter.firstChild.textContent = icon.counter || "";
     }
-    notifBox.appendChild(notifBrowsers);
+    notifBox.appendChild(notificationFrames);
     iconBox.appendChild(iconContainers);
-
-    let browserIter = notifBox.firstElementChild;
-    while (browserIter) {
-      browserIter.docShell.isAppTab = true;
-      browserIter = browserIter.nextElementSibling;
-    }
   },
 
   showAmbientPopup: function SocialToolbar_showAmbientPopup(iconContainer) {
     let iconImage = iconContainer.firstChild;
     let panel = document.getElementById("social-notification-panel");
     let notifBox = document.getElementById("social-notification-box");
-    let notifBrowser = document.getElementById(iconImage.getAttribute("notifBrowserId"));
-
-    panel.hidden = false;
+    let notificationFrame = document.getElementById(iconImage.getAttribute("notificationFrameId"));
 
-    function sizePanelToContent() {
-      // FIXME: bug 764787: Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
-      // Need to handle dynamic sizing
-      let doc = notifBrowser.contentDocument;
-      if (!doc) {
-        return;
-      }
-      // "notif" is an implementation detail that we should get rid of
-      // eventually
-      let body = doc.getElementById("notif") || doc.body;
-      if (!body || !body.firstChild) {
-        return;
-      }
-
-      // Clear dimensions on all browsers so the panel size will
-      // only use the selected browser.
-      let browserIter = notifBox.firstElementChild;
-      while (browserIter) {
-        browserIter.hidden = (browserIter != notifBrowser);
-        browserIter = browserIter.nextElementSibling;
-      }
-
-      let [height, width] = [body.firstChild.offsetHeight || 300, 330];
-      notifBrowser.style.width = width + "px";
-      notifBrowser.style.height = height + "px";
+    // Clear dimensions on all browsers so the panel size will
+    // only use the selected browser.
+    let frameIter = notifBox.firstElementChild;
+    while (frameIter) {
+      frameIter.collapsed = (frameIter != notificationFrame);
+      frameIter = frameIter.nextElementSibling;
     }
 
-    sizePanelToContent();
-
     function dispatchPanelEvent(name) {
-      let evt = notifBrowser.contentDocument.createEvent("CustomEvent");
+      let evt = notificationFrame.contentDocument.createEvent("CustomEvent");
       evt.initCustomEvent(name, true, true, {});
-      notifBrowser.contentDocument.documentElement.dispatchEvent(evt);
+      notificationFrame.contentDocument.documentElement.dispatchEvent(evt);
     }
 
-    panel.addEventListener("popuphiding", function onpopuphiding() {
-      panel.removeEventListener("popuphiding", onpopuphiding);
+    panel.addEventListener("popuphidden", function onpopuphiding() {
+      panel.removeEventListener("popuphidden", onpopuphiding);
       SocialToolbar.button.removeAttribute("open");
+      notificationFrame.docShell.isActive = false;
       dispatchPanelEvent("socialFrameHide");
     });
 
     panel.addEventListener("popupshown", function onpopupshown() {
       panel.removeEventListener("popupshown", onpopupshown);
       SocialToolbar.button.setAttribute("open", "true");
-      if (notifBrowser.contentDocument.readyState == "complete") {
+      notificationFrame.docShell.isActive = true;
+      notificationFrame.docShell.isAppTab = true;
+      if (notificationFrame.contentDocument.readyState == "complete") {
+        sizeSocialPanelToContent(notificationFrame);
         dispatchPanelEvent("socialFrameShow");
       } else {
         // first time load, wait for load and dispatch after load
-        notifBrowser.addEventListener("load", function panelBrowserOnload(e) {
-          notifBrowser.removeEventListener("load", panelBrowserOnload, true);
+        notificationFrame.addEventListener("load", function panelBrowserOnload(e) {
+          notificationFrame.removeEventListener("load", panelBrowserOnload, true);
+          sizeSocialPanelToContent(notificationFrame);
           setTimeout(function() {
             dispatchPanelEvent("socialFrameShow");
           }, 0);
         }, true);
       }
     });
 
     panel.openPopup(iconImage, "bottomcenter topleft", 0, 0, false, false);
--- a/browser/base/content/browser-tabPreviews.js
+++ b/browser/base/content/browser-tabPreviews.js
@@ -184,19 +184,24 @@ var ctrlTab = {
 
     // Rotate the list until the selected tab is first
     while (!list[0].selected)
       list.push(list.shift());
 
     list = list.filter(function (tab) !tab.closing);
 
     if (this.recentlyUsedLimit != 0) {
-      let recentlyUsedTabs = this._recentlyUsedTabs;
-      if (this.recentlyUsedLimit > 0)
-        recentlyUsedTabs = this._recentlyUsedTabs.slice(0, this.recentlyUsedLimit);
+      let recentlyUsedTabs = [];
+      for (let tab of this._recentlyUsedTabs) {
+        if (!tab.hidden && !tab.closing) {
+          recentlyUsedTabs.push(tab);
+          if (this.recentlyUsedLimit > 0 && recentlyUsedTabs.length >= this.recentlyUsedLimit)
+            break;
+        }
+      }
       for (let i = recentlyUsedTabs.length - 1; i >= 0; i--) {
         list.splice(list.indexOf(recentlyUsedTabs[i]), 1);
         list.unshift(recentlyUsedTabs[i]);
       }
     }
 
     return this._tabList = list;
   },
--- a/browser/base/content/browser-thumbnails.js
+++ b/browser/base/content/browser-thumbnails.js
@@ -31,30 +31,32 @@ let gBrowserThumbnails = {
   _tabEvents: ["TabClose", "TabSelect"],
 
   init: function Thumbnails_init() {
     try {
       if (Services.prefs.getBoolPref("browser.pagethumbnails.capturing_disabled"))
         return;
     } catch (e) {}
 
+    PageThumbs.addExpirationFilter(this);
     gBrowser.addTabsProgressListener(this);
     Services.prefs.addObserver(this.PREF_DISK_CACHE_SSL, this, false);
 
     this._sslDiskCacheEnabled =
       Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
 
     this._tabEvents.forEach(function (aEvent) {
       gBrowser.tabContainer.addEventListener(aEvent, this, false);
     }, this);
 
     this._timeouts = new WeakMap();
   },
 
   uninit: function Thumbnails_uninit() {
+    PageThumbs.removeExpirationFilter(this);
     gBrowser.removeTabsProgressListener(this);
     Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this);
 
     this._tabEvents.forEach(function (aEvent) {
       gBrowser.tabContainer.removeEventListener(aEvent, this, false);
     }, this);
   },
 
@@ -75,16 +77,21 @@ let gBrowserThumbnails = {
     }
   },
 
   observe: function Thumbnails_observe() {
     this._sslDiskCacheEnabled =
       Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
   },
 
+  filterForThumbnailExpiration:
+  function Thumbnails_filterForThumbnailExpiration(aCallback) {
+    aCallback([browser.currentURI.spec for (browser of gBrowser.browsers)]);
+  },
+
   /**
    * State change progress listener for all tabs.
    */
   onStateChange: function Thumbnails_onStateChange(aBrowser, aWebProgress,
                                                    aRequest, aStateFlags, aStatus) {
     if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK)
       this._delayedCapture(aBrowser);
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -59,16 +59,26 @@ tabbrowser {
   display: none;
 }
 
 .tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned] {
   position: fixed !important;
   display: block; /* position:fixed already does this (bug 579776), but let's be explicit */
 }
 
+.tabbrowser-tabs[movingtab] > .tabbrowser-tab[selected] {
+  position: relative;
+  z-index: 2;
+  pointer-events: none; /* avoid blocking dragover events on scroll buttons */
+}
+
+.tabbrowser-tabs[movingtab] > .tabbrowser-tab[fadein]:not([selected]) {
+  transition: transform 200ms ease-out;
+}
+
 #alltabs-popup {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-alltabs-popup");
 }
 
 toolbar[printpreview="true"] {
   -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
 }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -355,17 +355,17 @@ const gSessionHistoryObserver = {
       return;
 
     var backCommand = document.getElementById("Browser:Back");
     backCommand.setAttribute("disabled", "true");
     var fwdCommand = document.getElementById("Browser:Forward");
     fwdCommand.setAttribute("disabled", "true");
 
     // Hide session restore button on about:home
-    window.messageManager.sendAsyncMessage("Browser:HideSessionRestoreButton");
+    window.messageManager.broadcastAsyncMessage("Browser:HideSessionRestoreButton");
 
     if (gURLBar) {
       // Clear undo history of the URL bar
       gURLBar.editor.transactionManager.clear()
     }
   }
 };
 
@@ -1015,16 +1015,17 @@ var gBrowserInit = {
     gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver, false);
 
     gBrowser.addEventListener("PluginNotFound",     gPluginHandler, true);
     gBrowser.addEventListener("PluginCrashed",      gPluginHandler, true);
     gBrowser.addEventListener("PluginBlocklisted",  gPluginHandler, true);
     gBrowser.addEventListener("PluginOutdated",     gPluginHandler, true);
     gBrowser.addEventListener("PluginDisabled",     gPluginHandler, true);
     gBrowser.addEventListener("PluginClickToPlay",  gPluginHandler, true);
+    gBrowser.addEventListener("PluginPlayPreview",  gPluginHandler, true);
     gBrowser.addEventListener("PluginVulnerableUpdatable", gPluginHandler, true);
     gBrowser.addEventListener("PluginVulnerableNoUpdate", gPluginHandler, true);
     gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true);
 #ifdef XP_MACOSX
     gBrowser.addEventListener("npapi-carbon-event-model-failure", gPluginHandler, true);
 #endif
 
     Services.obs.addObserver(gPluginHandler.pluginCrashed, "plugin-crashed", false);
@@ -1234,17 +1235,16 @@ var gBrowserInit = {
 
     // Misc. inits.
     CombinedStopReload.init();
     allTabs.readPref();
     TabsOnTop.init();
     BookmarksMenuButton.init();
     TabsInTitlebar.init();
     gPrivateBrowsingUI.init();
-    DownloadsButton.initializePlaceholder();
     retrieveToolbarIconsizesFromTheme();
 
     gDelayedStartupTimeoutId = setTimeout(this._delayedStartup.bind(this), 0, isLoadingBlank, mustLoadSidebar);
     gStartupRan = true;
   },
 
   _delayedStartup: function(isLoadingBlank, mustLoadSidebar) {
     let tmp = {};
@@ -1281,19 +1281,17 @@ var gBrowserInit = {
     if (mustLoadSidebar) {
       let sidebar = document.getElementById("sidebar");
       let sidebarBox = document.getElementById("sidebar-box");
       sidebar.setAttribute("src", sidebarBox.getAttribute("src"));
     }
 
     UpdateUrlbarSearchSplitterState();
 
-    if (isLoadingBlank && gURLBar)
-      gURLBar.focus();
-    if (!isLoadingBlank || !gURLBar || !gURLBar.focused)
+    if (!isLoadingBlank || !focusAndSelectUrlBar())
       gBrowser.selectedBrowser.focus();
 
     gNavToolbox.customizeDone = BrowserToolboxCustomizeDone;
     gNavToolbox.customizeChange = BrowserToolboxCustomizeChange;
 
     // Set up Sanitize Item
     this._initializeSanitizer();
 
@@ -1985,17 +1983,17 @@ function loadOneOrMoreURIs(aURIString)
 }
 
 function focusAndSelectUrlBar() {
   if (gURLBar) {
     if (window.fullScreen)
       FullScreen.mouseoverToggle(true);
 
     gURLBar.focus();
-    if (gURLBar.focused) {
+    if (document.activeElement == gURLBar.inputField) {
       gURLBar.select();
       return true;
     }
   }
   return false;
 }
 
 function openLocation() {
@@ -3124,39 +3122,16 @@ var newWindowButtonObserver = {
     url = getShortcutOrURI(url, postData);
     if (url) {
       // allow third-party services to fixup this URL
       openNewWindowWith(url, null, postData.value, true);
     }
   }
 }
 
-var DownloadsButtonDNDObserver = {
-  onDragOver: function (aEvent)
-  {
-    var types = aEvent.dataTransfer.types;
-    if (types.contains("text/x-moz-url") ||
-        types.contains("text/uri-list") ||
-        types.contains("text/plain"))
-      aEvent.preventDefault();
-  },
-
-  onDragExit: function (aEvent)
-  {
-  },
-
-  onDrop: function (aEvent)
-  {
-    let name = { };
-    let url = browserDragAndDrop.drop(aEvent, name);
-    if (url)
-      saveURL(url, name, null, true, true);
-  }
-}
-
 const DOMLinkHandler = {
   handleEvent: function (event) {
     switch (event.type) {
       case "DOMLinkAdded":
         this.onLinkAdded(event);
         break;
     }
   },
@@ -3345,17 +3320,17 @@ const BrowserSearch = {
       return;
     }
 #endif
     var searchBar = this.searchBar;
     if (searchBar && window.fullScreen)
       FullScreen.mouseoverToggle(true);
     if (searchBar)
       searchBar.focus();
-    if (searchBar && searchBar.textbox.focused) {
+    if (searchBar && document.activeElement == searchBar.textbox.inputField) {
       searchBar.select();
     } else {
       openUILinkIn(Services.search.defaultEngine.searchForm, "current");
     }
   },
 
   /**
    * Loads a search results page, given a set of search terms. Uses the current
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -187,33 +187,33 @@
       <hbox flex="1">
         <image src="chrome://browser/content/social-icon.png" class="popup-notification-icon"/>
         <vbox flex="1">
           <description id="social-activation-message" class="popup-notification-description"/>
           <spacer flex="1"/>
           <hbox pack="end" align="center" class="popup-notification-button-container">
 #ifdef XP_UNIX
         <button id="social-undoactivation-button"
-                label="&social.activated.button.label;"
-                accesskey="&social.activated.button.accesskey;"
+                label="&social.activated.undobutton.label;"
+                accesskey="&social.activated.undobutton.accesskey;"
                 onclick="SocialUI.undoActivation();"/>
         <button default="true"
                 autofocus="autofocus"
                 label="&social.ok.label;"
                 accesskey="&social.ok.accesskey;"
                 oncommand="SocialUI.notificationPanel.hidePopup();"/>
 #else
         <button default="true"
                 autofocus="autofocus"
                 label="&social.ok.label;"
                 accesskey="&social.ok.accesskey;"
                 oncommand="SocialUI.notificationPanel.hidePopup();"/>
         <button id="social-undoactivation-button"
-                label="&social.activated.button.label;"
-                accesskey="&social.activated.button.accesskey;"
+                label="&social.activated.undobutton.label;"
+                accesskey="&social.activated.undobutton.accesskey;"
                 onclick="SocialUI.undoActivation();"/>
 #endif
           </hbox>
         </vbox>
       </hbox>
     </panel>
 
     <panel id="editSharePopup"
@@ -266,16 +266,23 @@
                 command="Social:UnsharePage"/>
 #endif
       </hbox>
     </panel>
 
     <panel id="social-notification-panel" type="arrow" hidden="true" noautofocus="true">
       <box id="social-notification-box" flex="1"></box>
     </panel>
+    <panel id="social-flyout-panel"
+           onpopupshown="SocialFlyout.onShown()"
+           onpopuphidden="SocialFlyout.onHidden()"
+           type="arrow"
+           hidden="true"
+           noautofocus="true"
+           position="topcenter topright"/>
 
     <menupopup id="inspector-node-popup">
       <menuitem id="inspectorHTMLCopyInner"
                 label="&inspectorHTMLCopyInner.label;"
                 accesskey="&inspectorHTMLCopyInner.accesskey;"
                 command="Inspector:CopyInner"/>
       <menuitem id="inspectorHTMLCopyOuter"
                 label="&inspectorHTMLCopyOuter.label;"
@@ -510,17 +517,17 @@
       <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
 #endif
     </toolbar>
 
     <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar"
              toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
              fullscreentoolbar="true" mode="icons" customizable="true"
              iconsize="large"
-             defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,home-button,bookmarks-menu-button-container,window-controls"
+             defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,downloads-button,home-button,bookmarks-menu-button-container,window-controls"
              context="toolbar-context-menu">
 
       <toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
                    context="backForwardMenu" removable="true"
                    forwarddisabled="true"
                    title="&backForwardItem.title;">
         <toolbarbutton id="back-button" class="toolbarbutton-1"
                        label="&backCmd.label;"
@@ -669,18 +676,16 @@
                 <image id="social-statusarea-user-portrait"/>
                 <vbox>
                   <label id="social-statusarea-notloggedin"
                          value="&social.notLoggedIn.label;"/>
                   <button id="social-statusarea-username"
                           oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();"/>
                 </vbox>
               </hbox>
-              <menuitem id="social-remove-menuitem"
-                        oncommand="Social.active = false;"/>
               <menuitem id="social-toggle-sidebar-menuitem"
                         type="checkbox"
                         autocheck="false"
                         command="Social:ToggleSidebar"
                         label="&social.toggleSidebar.label;"
                         accesskey="&social.toggleSidebar.accesskey;"/>
             </menupopup>
           </button>
@@ -927,24 +932,24 @@
 # Update primaryToolbarButtons in browser/themes/browserShared.inc when adding
 # or removing default items with the toolbarbutton-1 class.
 
       <toolbarbutton id="print-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&printButton.label;" command="cmd_print"
                      tooltiptext="&printButton.tooltip;"/>
 
       <!-- This is a placeholder for the Downloads Indicator.  It is visible
-           only during the customization of the toolbar or in the palette, and
-           is replaced when customization is done. -->
+           during the customization of the toolbar, in the palette, and before
+           the Downloads Indicator overlay is loaded. -->
       <toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     observes="Tools:Downloads"
-                     ondrop="DownloadsButtonDNDObserver.onDrop(event)"
-                     ondragover="DownloadsButtonDNDObserver.onDragOver(event)"
-                     ondragenter="DownloadsButtonDNDObserver.onDragOver(event)"
-                     ondragexit="DownloadsButtonDNDObserver.onDragExit(event)"
+                     oncommand="DownloadsIndicatorView.onCommand(event);"
+                     ondrop="DownloadsIndicatorView.onDrop(event);"
+                     ondragover="DownloadsIndicatorView.onDragOver(event);"
+                     ondragenter="DownloadsIndicatorView.onDragOver(event);"
+                     ondragleave="DownloadsIndicatorView.onDragLeave(event);"
                      label="&downloads.label;"
                      tooltiptext="&downloads.tooltip;"/>
 
       <toolbarbutton id="history-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      observes="viewHistorySidebar" label="&historyButton.label;"
                      tooltiptext="&historyButton.tooltip;"/>
 
       <toolbarbutton id="bookmarks-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
@@ -1065,16 +1070,17 @@
     <splitter id="social-sidebar-splitter"
               class="chromeclass-extrachrome sidebar-splitter"
               observes="socialSidebarBroadcaster"/>
     <vbox id="social-sidebar-box"
           class="chromeclass-extrachrome"
           observes="socialSidebarBroadcaster">
       <browser id="social-sidebar-browser"
                type="content"
+               disableglobalhistory="true"
                flex="1"
                style="min-width: 14em; width: 18em; max-width: 36em;"/>
     </vbox>
     <vbox id="browser-border-end" hidden="true" layer="true"/>
   </hbox>
 
   <hbox id="full-screen-warning-container" hidden="true" fadeout="true">
     <hbox style="width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. -->
@@ -1103,34 +1109,16 @@
              nowindowdrag="true"
              hidden="true">
 #ifdef XP_MACOSX
       <toolbarbutton id="highlighter-closebutton"
                      class="devtools-closebutton"
                      oncommand="InspectorUI.closeInspectorUI(false);"
                      tooltiptext="&inspectCloseButton.tooltiptext;"/>
 #endif
-      <toolbarbutton id="inspector-option-toolbarbutton"
-                     type="menu"
-                     tabindex="0"
-                     tooltiptext="&inspectOptionButton.tooltiptext;">
-        <menupopup id="inspector-option-popup"
-                   position="before_start">
-          <menuitem id="inspectorToggleVeil"
-                    type="checkbox"
-                    label="&inspectorToggleVeil.label;"
-                    accesskey="&inspectorToggleVeil.accesskey;"
-                    command="Inspector:ToggleVeil"/>
-          <menuitem id="inspectorToggleInfobar"
-                    type="checkbox"
-                    label="&inspectorToggleInfobar.label;"
-                    accesskey="&inspectorToggleInfobar.accesskey;"
-                    command="Inspector:ToggleInfobar"/>
-        </menupopup>
-      </toolbarbutton>
       <toolbarbutton id="inspector-inspect-toolbutton"
                      class="devtools-toolbarbutton"
                      command="Inspector:Inspect"/>
       <toolbarbutton id="inspector-treepanel-toolbutton"
                      class="devtools-toolbarbutton"
                      tabindex="0"
                      aria-label="&markupButton.arialabel;"
                      accesskey="&markupButton.accesskey;"
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -7,58 +7,59 @@
 }
 
 #highlighter-controls {
   position: absolute;
   top: 0;
   left: 0;
 }
 
-#highlighter-veil-container {
+#highlighter-outline-container {
   overflow: hidden;
+  position: relative;
 }
 
-#highlighter-veil-container:not([dim]) > .highlighter-veil,
-#highlighter-veil-container:not([dim]) > hbox > .highlighter-veil {
-  visibility: hidden;
+#highlighter-outline {
+  position: absolute;
 }
 
-#highlighter-veil-container:not([disable-transitions]) > .highlighter-veil,
-#highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox,
-#highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox > .highlighter-veil,
-#highlighter-veil-container:not([disable-transitions]) > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
-  transition-property: width, height;
+#highlighter-outline[hidden] {
+  opacity: 0;
+  pointer-events: none;
+  display: -moz-box;
+}
+
+#highlighter-outline:not([disable-transitions]) {
+  transition-property: opacity, top, left, width, height;
   transition-duration: 0.1s;
   transition-timing-function: linear;
 }
 
-#highlighter-veil-bottombox,
-#highlighter-veil-rightbox {
-  -moz-box-flex: 1;
-}
-
-#highlighter-veil-middlebox:-moz-locale-dir(rtl) {
-  -moz-box-direction: reverse;
-}
-
 .inspector-breadcrumbs-button {
   direction: ltr;
 }
 
 /*
  * Node Infobar
  */
 
 #highlighter-nodeinfobar-container {
   position: absolute;
   max-width: 95%;
 }
 
-#highlighter-nodeinfobar-container:not([disable-transitions]) {
-  transition-property: top, left;
+#highlighter-nodeinfobar-container[hidden] {
+  opacity: 0;
+  pointer-events: none;
+  display: -moz-box;
+}
+
+#highlighter-nodeinfobar-container:not([disable-transitions]),
+#highlighter-nodeinfobar-container[disable-transitions][force-transitions] {
+  transition-property: transform, opacity, top, left;
   transition-duration: 0.1s;
   transition-timing-function: linear;
 }
 
 #highlighter-nodeinfobar-text {
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -20,16 +20,43 @@
                   xbl:inherits="src,origin,collapsed=minimized" type="content"/>
     </content>
 
     <implementation implements="nsIDOMEventListener">
       <field name="iframe" readonly="true">
         document.getAnonymousElementByAttribute(this, "anonid", "iframe");
       </field>
 
+      <property name="minimized">
+        <getter>
+          return this.getAttribute("minimized") == "true";
+        </getter>
+        <setter>
+          this.isActive = !val;
+          if (val)
+            this.setAttribute("minimized", "true");
+          else
+            this.removeAttribute("minimized");
+        </setter>
+      </property>
+
+      <property name="isActive">
+        <getter>
+          return this.iframe.docShell.isActive;
+        </getter>
+        <setter>
+          this.iframe.docShell.isActive = !!val;
+
+          // let the chat frame know if it is being shown or hidden
+          let evt = this.iframe.contentDocument.createEvent("CustomEvent");
+          evt.initCustomEvent(val ? "socialFrameHide" : "socialFrameShow", true, true, {});
+          this.iframe.contentDocument.documentElement.dispatchEvent(evt);
+        </setter>
+      </property>
+
       <method name="init">
         <parameter name="aProvider"/>
         <parameter name="aURL"/>
         <parameter name="aCallback"/>
         <body><![CDATA[
           this._callback = aCallback;
           this.setAttribute("origin", aProvider.origin);
           this.setAttribute("src", aURL);
@@ -39,37 +66,29 @@
       <method name="close">
         <body><![CDATA[
           this.parentNode.remove(this);
         ]]></body>
       </method>
 
       <method name="toggle">
         <body><![CDATA[
-          let type;
-          if (this.getAttribute("minimized") == "true") {
-            this.removeAttribute("minimized");
-            type = "socialFrameShow";
-          } else {
-            this.setAttribute("minimized", "true");
-            type = "socialFrameHide";
-          }
-          // let the chat frame know if it is being shown or hidden
-          let evt = this.iframe.contentDocument.createEvent("CustomEvent");
-          evt.initCustomEvent(type, true, true, {});
-          this.iframe.contentDocument.documentElement.dispatchEvent(evt);
+          this.minimized = !this.minimized;
         ]]></body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="focus" phase="capturing">
         this.parentNode.selectedChat = this;
       </handler>
-      <handler event="DOMContentLoaded" action="if (this._callback) this._callback(this.iframe.contentWindow);"/>
+      <handler event="load"><![CDATA[
+        this.isActive = !this.minimized;
+        if (this._callback) this._callback(this.iframe.contentWindow);
+      ]]></handler>
       <handler event="DOMTitleChanged" action="this.setAttribute('label', this.iframe.contentDocument.title);"/>
       <handler event="DOMLinkAdded"><![CDATA[
         // much of this logic is from DOMLinkHandler in browser.js
         // this sets the presence icon for a chat user, we simply use favicon style updating
         let link = event.originalTarget;
         let rel = link.rel && link.rel.toLowerCase();
         if (!link || !link.ownerDocument || !rel || !link.href)
           return;
@@ -111,16 +130,17 @@
         <getter>
           return document.getAnonymousElementByAttribute(this, "anonid", "spacer").boxObject.width;
         </getter>
       </property>
 
       <field name="selectedChat"/>
 
       <field name="menuitemMap">new WeakMap()</field>
+      <field name="chatboxForURL">new Map();</field>
 
       <property name="firstCollapsedChild">
         <getter><![CDATA[
           let child = this.lastChild;
           while (child && !child.collapsed) {
             child = child.previousSibling;
           }
           return child;
@@ -187,63 +207,84 @@
             this.showChat(newChat);
         ]]></body>
       </method>
 
       <method name="collapseChat">
         <parameter name="aChatbox"/>
         <body><![CDATA[
           aChatbox.collapsed = true;
+          aChatbox.isActive = false;
           let menu = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
           menu.setAttribute("label", aChatbox.iframe.contentDocument.title);
           menu.chat = aChatbox;
           this.menuitemMap.set(aChatbox, menu);
           this.menupopup.appendChild(menu);
           this.menupopup.parentNode.collapsed = false;
         ]]></body>
       </method>
 
       <method name="showChat">
         <parameter name="aChatbox"/>
         <body><![CDATA[
           let menuitem = this.menuitemMap.get(aChatbox);
           this.menuitemMap.delete(aChatbox);
           this.menupopup.removeChild(menuitem);
           aChatbox.collapsed = false;
+          aChatbox.isActive = !aChatbox.minimized;
         ]]></body>
       </method>
 
       <method name="remove">
         <parameter name="aChatbox"/>
         <body><![CDATA[
           if (this.selectedChat == aChatbox) {
             this.selectedChat = aChatbox.previousSibling ? aChatbox.previousSibling : aChatbox.nextSibling
           }
           this.removeChild(aChatbox);
           this.resize();
+          this.chatboxForURL.delete(aChatbox.getAttribute('src'));
         ]]></body>
       </method>
 
       <method name="removeAll">
         <body><![CDATA[
           while (this.firstChild) {
             this.removeChild(this.firstChild);
           }
+          this.chatboxForURL = new Map();
         ]]></body>
       </method>
 
-      <method name="newChat">
+      <method name="openChat">
         <parameter name="aProvider"/>
         <parameter name="aURL"/>
         <parameter name="aCallback"/>
+        <parameter name="aMode"/>
         <body><![CDATA[
-          let cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox");
+          let cb = this.chatboxForURL.get(aURL);
+          if (cb) {
+            cb = cb.get();
+            if (cb.parentNode) {
+              // ensure this chatbox is visible
+              if (this.selectedChat != cb)
+                this.selectedChat = cb;
+              if (cb.collapsed)
+                this.showChat(cb);
+              return;
+            }
+            this.chatboxForURL.delete(aURL);
+          }
+          cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox");
+          if (aMode == "minimized")
+            cb.minimized = true;
           this.selectedChat = cb;
-          this.appendChild(cb);
+          this.insertBefore(cb, this.firstChild);
           cb.init(aProvider, aURL, aCallback);
+          this.chatboxForURL.set(aURL, Cu.getWeakReference(cb));
         ]]></body>
       </method>
 
     </implementation>
     <handlers>
       <handler event="overflow"><![CDATA[
         // make sure we're not getting an overflow from content
         if (event.originalTarget != this.innerbox)
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3122,16 +3122,137 @@
 
             this.style.MozMarginStart = "";
           }
 
           this.mTabstrip.ensureElementIsVisible(this.selectedItem, false);
         ]]></body>
       </method>
 
+      <method name="_animateTabMove">
+        <parameter name="event"/>
+        <body><![CDATA[
+          let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
+
+          if (this.getAttribute("movingtab") != "true") {
+            this.setAttribute("movingtab", "true");
+            this.selectedItem = draggedTab;
+          }
+
+          if (!("animLastScreenX" in draggedTab._dragData))
+            draggedTab._dragData.animLastScreenX = draggedTab._dragData.screenX;
+
+          let screenX = event.screenX;
+          if (screenX == draggedTab._dragData.animLastScreenX)
+            return;
+
+          let draggingRight = screenX > draggedTab._dragData.animLastScreenX;
+          draggedTab._dragData.animLastScreenX = screenX;
+
+          let rtl = (window.getComputedStyle(this).direction == "rtl");
+          let pinned = draggedTab.pinned;
+          let numPinned = this.tabbrowser._numPinnedTabs;
+          let tabs = this.tabbrowser.visibleTabs
+                                    .slice(pinned ? 0 : numPinned,
+                                           pinned ? numPinned : undefined);
+          if (rtl)
+            tabs.reverse();
+          let tabWidth = draggedTab.getBoundingClientRect().width;
+
+          // Move the dragged tab based on the mouse position.
+
+          let leftTab = tabs[0];
+          let rightTab = tabs[tabs.length - 1];
+          let tabScreenX = draggedTab.boxObject.screenX;
+          let translateX = screenX - draggedTab._dragData.screenX;
+          if (!pinned)
+            translateX += this.mTabstrip.scrollPosition - draggedTab._dragData.scrollX;
+          let leftBound = leftTab.boxObject.screenX - tabScreenX;
+          let rightBound = (rightTab.boxObject.screenX + rightTab.boxObject.width) -
+                           (tabScreenX + tabWidth);
+          translateX = Math.max(translateX, leftBound);
+          translateX = Math.min(translateX, rightBound);
+          draggedTab.style.transform = "translateX(" + translateX + "px)";
+
+          // Determine what tab we're dragging over.
+          // * Point of reference is the center of the dragged tab. If that
+          //   point touches a background tab, the dragged tab would take that
+          //   tab's position when dropped.
+          // * We're doing a binary search in order to reduce the amount of
+          //   tabs we need to check.
+
+          let tabCenter = tabScreenX + translateX + tabWidth / 2;
+          let newIndex = -1;
+          let oldIndex = "animDropIndex" in draggedTab._dragData ?
+                         draggedTab._dragData.animDropIndex : draggedTab._tPos;
+          let low = 0;
+          let high = tabs.length - 1;
+          while (low <= high) {
+            let mid = Math.floor((low + high) / 2);
+            if (tabs[mid] == draggedTab &&
+                ++mid > high)
+              break;
+            let boxObject = tabs[mid].boxObject;
+            let screenX = boxObject.screenX + getTabShift(tabs[mid], oldIndex);
+            if (screenX > tabCenter) {
+              high = mid - 1;
+            } else if (screenX + boxObject.width < tabCenter) {
+              low = mid + 1;
+            } else {
+              newIndex = tabs[mid]._tPos;
+              break;
+            }
+          }
+          if (newIndex >= oldIndex)
+            newIndex++;
+          if (newIndex < 0 || newIndex == oldIndex)
+            return;
+          draggedTab._dragData.animDropIndex = newIndex;
+
+          // Shift background tabs to leave a gap where the dragged tab
+          // would currently be dropped.
+
+          for (let tab of tabs) {
+            if (tab != draggedTab) {
+              let shift = getTabShift(tab, newIndex);
+              tab.style.transform = shift ? "translateX(" + shift + "px)" : "";
+            }
+          }
+
+          function getTabShift(tab, dropIndex) {
+            if (tab._tPos < draggedTab._tPos && tab._tPos >= dropIndex)
+              return rtl ? -tabWidth : tabWidth;
+            if (tab._tPos > draggedTab._tPos && tab._tPos < dropIndex)
+              return rtl ? tabWidth : -tabWidth;
+            return 0;
+          }
+        ]]></body>
+      </method>
+
+      <method name="_finishAnimateTabMove">
+        <parameter name="event"/>
+        <body><![CDATA[
+          if (this.getAttribute("movingtab") != "true")
+            return;
+
+          let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
+          if ("animDropIndex" in draggedTab._dragData) {
+            let newIndex = draggedTab._dragData.animDropIndex;
+            if (newIndex > draggedTab._tPos)
+              newIndex--;
+            this.tabbrowser.moveTabTo(draggedTab, newIndex);
+          }
+
+          for (let tab of this.tabbrowser.visibleTabs)
+            tab.style.transform = "";
+
+          this.removeAttribute("movingtab");
+        ]]></body>
+      </method>
+
       <method name="handleEvent">
         <parameter name="aEvent"/>
         <body><![CDATA[
           switch (aEvent.type) {
             case "load":
               this.updateVisibility();
               break;
             case "resize":
@@ -3253,52 +3374,35 @@
 
           var types = dt.mozTypesAt(0);
           var sourceNode = null;
           // tabs are always added as the first type
           if (types[0] == TAB_DROP_TYPE) {
             var sourceNode = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
             if (sourceNode instanceof XULElement &&
                 sourceNode.localName == "tab" &&
-                (sourceNode.parentNode == this ||
-                 (sourceNode.ownerDocument.defaultView instanceof ChromeWindow &&
-                  sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser"))) {
-              if (sourceNode.parentNode == this &&
-                  (event.screenX >= sourceNode.boxObject.screenX &&
-                    event.screenX <= (sourceNode.boxObject.screenX +
-                                       sourceNode.boxObject.width))) {
-                return dt.effectAllowed = "none";
-              }
-
-              return dt.effectAllowed = "copyMove";
+                sourceNode.ownerDocument.defaultView instanceof ChromeWindow &&
+                sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser" &&
+                sourceNode.ownerDocument.defaultView.gBrowser.tabContainer == sourceNode.parentNode) {
+#ifdef XP_MACOSX
+              return dt.effectAllowed = event.altKey ? "copy" : "move";
+#else
+              return dt.effectAllowed = event.ctrlKey ? "copy" : "move";
+#endif
             }
           }
 
           if (browserDragAndDrop.canDropLink(event)) {
             // Here we need to do this manually
             return dt.effectAllowed = dt.dropEffect = "link";
           }
           return dt.effectAllowed = "none";
         ]]></body>
       </method>
 
-      <method name="_continueScroll">
-        <parameter name="event"/>
-        <body><![CDATA[
-          // Workaround for bug 481904: Dragging a tab stops scrolling at
-          // the tab's position when dragging to the first/last tab and back.
-          var t = this.selectedItem;
-          if (event.screenX >= t.boxObject.screenX &&
-              event.screenX <= t.boxObject.screenX + t.boxObject.width &&
-              event.screenY >= t.boxObject.screenY &&
-              event.screenY <= t.boxObject.screenY + t.boxObject.height)
-            this.mTabstrip.ensureElementIsVisible(t);
-        ]]></body>
-      </method>
-
       <method name="_handleNewTab">
         <parameter name="tab"/>
         <body><![CDATA[
           if (tab.parentNode != this)
             return;
           tab._fullyOpen = true;
 
           this.adjustTabstrip();
@@ -3449,50 +3553,46 @@
         // may result in an "internet shortcut"
         dt.mozSetDataAt("text/x-moz-text-internal", spec, 0);
 
         // Set the cursor to an arrow during tab drags.
         dt.mozCursor = "default";
 
         // Create a canvas to which we capture the current tab.
         let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+        let browser = tab.linkedBrowser;
         canvas.mozOpaque = true;
-
-        // We want drag images to be about 1/6th of the available screen width.
-        const widthFactor = 0.1739; // 1:5.75 inverse
-        canvas.width = Math.ceil(screen.availWidth * widthFactor);
-
-        // Maintain a 16:9 aspect ratio for drag images.
-        const aspectRatio = 0.5625; // 16:9 inverse
-        canvas.height = Math.round(canvas.width * aspectRatio);
-
-        let browser = tab.linkedBrowser;
+        canvas.width = 160;
+        canvas.height = 90;
         PageThumbs.captureToCanvas(browser.contentWindow, canvas);
         dt.setDragImage(canvas, 0, 0);
 
-        // _dragOffsetX/Y give the coordinates that the mouse should be
+        // _dragData.offsetX/Y give the coordinates that the mouse should be
         // positioned relative to the corner of the new window created upon
         // dragend such that the mouse appears to have the same position
         // relative to the corner of the dragged tab.
         function clientX(ele) ele.getBoundingClientRect().left;
         let tabOffsetX = clientX(tab) -
                          clientX(this.children[0].pinned ? this.children[0] : this);
-        tab._dragOffsetX = event.screenX - window.screenX - tabOffsetX;
-        tab._dragOffsetY = event.screenY - window.screenY;
+        tab._dragData = {
+          offsetX: event.screenX - window.screenX - tabOffsetX,
+          offsetY: event.screenY - window.screenY,
+          scrollX: this.mTabstrip.scrollPosition,
+          screenX: event.screenX
+        };
 
         event.stopPropagation();
       ]]></handler>
 
       <handler event="dragover"><![CDATA[
         var effects = this._setEffectAllowedForDataTransfer(event);
 
         var ind = this._tabDropIndicator;
         if (effects == "" || effects == "none") {
           ind.collapsed = true;
-          this._continueScroll(event);
           return;
         }
         event.preventDefault();
         event.stopPropagation();
 
         var tabStrip = this.mTabstrip;
         var ltr = (window.getComputedStyle(this, null).direction == "ltr");
 
@@ -3509,16 +3609,25 @@
             case "scrollbutton-down":
               pixelsToScroll = tabStrip.scrollIncrement;
               break;
           }
           if (pixelsToScroll)
             tabStrip.scrollByPixels((ltr ? 1 : -1) * pixelsToScroll);
         }
 
+        if (effects == "move" &&
+            this == event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0).parentNode) {
+          ind.collapsed = true;
+          this._animateTabMove(event);
+          return;
+        }
+
+        this._finishAnimateTabMove(event);
+
         if (effects == "link") {
           let tab = this._getDragTargetTab(event);
           if (tab) {
             if (!this._dragTime)
               this._dragTime = Date.now();
             if (Date.now() >= this._dragTime + this._dragOverDelay)
               this.selectedItem = tab;
             ind.collapsed = true;
@@ -3576,53 +3685,40 @@
           draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
           // not our drop then
           if (!draggedTab)
             return;
         }
 
         this._tabDropIndicator.collapsed = true;
         event.stopPropagation();
-
-        if (draggedTab && (dropEffect == "copy" ||
-            draggedTab.parentNode == this)) {
+        if (draggedTab && dropEffect == "copy") {
+          // copy the dropped tab (wherever it's from)
           let newIndex = this._getDropIndex(event);
-          if (dropEffect == "copy") {
-            // copy the dropped tab (wherever it's from)
-            let newTab = this.tabbrowser.duplicateTab(draggedTab);
-            this.tabbrowser.moveTabTo(newTab, newIndex);
-            if (draggedTab.parentNode != this || event.shiftKey)
-              this.selectedItem = newTab;
-          } else {
-            // move the dropped tab
-            if (newIndex > draggedTab._tPos)
-              newIndex--;
-
-            if (draggedTab.pinned) {
-              if (newIndex >= this.tabbrowser._numPinnedTabs)
-                this.tabbrowser.unpinTab(draggedTab);
-            } else {
-              if (newIndex <= this.tabbrowser._numPinnedTabs - 1)
-                this.tabbrowser.pinTab(draggedTab);
-            }
-
-            this.tabbrowser.moveTabTo(draggedTab, newIndex);
-          }
+          let newTab = this.tabbrowser.duplicateTab(draggedTab);
+          this.tabbrowser.moveTabTo(newTab, newIndex);
+          if (draggedTab.parentNode != this || event.shiftKey)
+            this.selectedItem = newTab;
+        } else if (draggedTab && draggedTab.parentNode == this) {
+          this._finishAnimateTabMove(event);
         } else if (draggedTab) {
           // swap the dropped tab with a new one we create and then close
           // it in the other window (making it seem to have moved between
           // windows)
           let newIndex = this._getDropIndex(event);
           let newTab = this.tabbrowser.addTab("about:blank");
           let newBrowser = this.tabbrowser.getBrowserForTab(newTab);
           // Stop the about:blank load
           newBrowser.stop();
           // make sure it has a docshell
           newBrowser.docShell;
 
+          let numPinned = this.tabbrowser._numPinnedTabs;
+          if (newIndex < numPinned || draggedTab.pinned && newIndex == numPinned)
+            this.tabbrowser.pinTab(newTab);
           this.tabbrowser.moveTabTo(newTab, newIndex);
 
           this.tabbrowser.swapBrowsersAndCloseOther(newTab, draggedTab);
 
           // We need to select the tab after we've done
           // swapBrowsersAndCloseOther, so that the updateCurrentBrowser
           // it triggers will correctly update our URL bar.
           this.tabbrowser.selectedTab = newTab;
@@ -3655,66 +3751,65 @@
               if (!bgLoad)
                 this.selectedItem = tab;
             } catch(ex) {
               // Just ignore invalid urls
             }
           }
         }
 
-        // these offsets are only used in dragend, but we need to free them here
-        // as well
         if (draggedTab) {
-          delete draggedTab._dragOffsetX;
-          delete draggedTab._dragOffsetY;
+          delete draggedTab._dragData;
         }
       ]]></handler>
 
       <handler event="dragend"><![CDATA[
         // Note: while this case is correctly handled here, this event
         // isn't dispatched when the tab is moved within the tabstrip,
         // see bug 460801.
 
-        // * mozUserCancelled = the user pressed ESC to cancel the drag
+        this._finishAnimateTabMove(event);
+
         var dt = event.dataTransfer;
-        if (dt.mozUserCancelled || dt.dropEffect != "none")
+        var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
+        if (dt.mozUserCancelled || dt.dropEffect != "none") {
+          delete draggedTab._dragData;
           return;
+        }
 
         // Disable detach within the browser toolbox
         var eX = event.screenX;
         var eY = event.screenY;
         var wX = window.screenX;
         // check if the drop point is horizontally within the window
         if (eX > wX && eX < (wX + window.outerWidth)) {
           let bo = this.mTabstrip.boxObject;
           // also avoid detaching if the the tab was dropped too close to
           // the tabbar (half a tab)
           let endScreenY = bo.screenY + 1.5 * bo.height;
           if (eY < endScreenY && eY > window.screenY)
             return;
         }
 
-        var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
         // screen.availLeft et. al. only check the screen that this window is on,
         // but we want to look at the screen the tab is being dropped onto.
         var sX = {}, sY = {}, sWidth = {}, sHeight = {};
         Cc["@mozilla.org/gfx/screenmanager;1"]
           .getService(Ci.nsIScreenManager)
           .screenForRect(eX, eY, 1, 1)
           .GetAvailRect(sX, sY, sWidth, sHeight);
         // ensure new window entirely within screen
         var winWidth = Math.min(window.outerWidth, sWidth.value);
         var winHeight = Math.min(window.outerHeight, sHeight.value);
-        var left = Math.min(Math.max(eX - draggedTab._dragOffsetX, sX.value),
+        var left = Math.min(Math.max(eX - draggedTab._dragData.offsetX, sX.value),
                             sX.value + sWidth.value - winWidth);
-        var top = Math.min(Math.max(eY - draggedTab._dragOffsetY, sY.value),
+        var top = Math.min(Math.max(eY - draggedTab._dragData.offsetY, sY.value),
                            sY.value + sHeight.value - winHeight);
 
-        delete draggedTab._dragOffsetX;
-        delete draggedTab._dragOffsetY;
+        delete draggedTab._dragData;
 
         if (this.tabbrowser.tabs.length == 1) {
           // resize _before_ move to ensure the window fits the new screen.  if
           // the window is too large for its screen, the window manager may do
           // automatic repositioning.
           window.resizeTo(winWidth, winHeight);
           window.moveTo(left, top);
           window.focus();
@@ -3736,17 +3831,16 @@
         // This does not work at all (see bug 458613)
         var target = event.relatedTarget;
         while (target && target != this)
           target = target.parentNode;
         if (target)
           return;
 
         this._tabDropIndicator.collapsed = true;
-        this._continueScroll(event);
         event.stopPropagation();
       ]]></handler>
     </handlers>
   </binding>
 
   <!-- close-tab-button binding
        This binding relies on the structure of the tabbrowser binding.
        Therefore it should only be used as a child of the tab or the tabs
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -59,19 +59,16 @@ endif
 # 480169)
 
 # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 
 # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
 
 # browser_pageInfo.js + feed_tab.html is disabled for leaking (bug 767896)
 
-# browser_social_shareButton.js is disabled for not properly
-#   tearing down the social providers (bug 780010).
-
 _BROWSER_FILES = \
                  head.js \
                  browser_typeAheadFind.js \
                  browser_keywordSearch.js \
                  browser_allTabsPanel.js \
                  browser_alltabslistener.js \
                  browser_bug304198.js \
                  title_test.svg \
@@ -177,16 +174,17 @@ endif
                  browser_hide_removing.js \
                  browser_overflowScroll.js \
                  browser_locationBarCommand.js \
                  browser_locationBarExternalLoad.js \
                  browser_page_style_menu.js \
                  browser_pinnedTabs.js \
                  browser_plainTextLinks.js \
                  browser_pluginnotification.js \
+                 browser_pluginplaypreview.js \
                  browser_relatedTabs.js \
                  browser_sanitize-passwordDisabledHosts.js \
                  browser_sanitize-sitepermissions.js \
                  browser_sanitize-timespans.js \
                  browser_clearplugindata.js \
                  browser_clearplugindata.html \
                  browser_clearplugindata_noage.html \
                  browser_popupUI.js \
@@ -258,23 +256,27 @@ endif
                  browser_minimize.js \
                  browser_aboutSyncProgress.js \
                  browser_middleMouse_inherit.js \
                  redirect_bug623155.sjs \
                  browser_tabDrop.js \
                  browser_lastAccessedTab.js \
                  browser_bug734076.js \
                  browser_social_toolbar.js \
+                 browser_social_shareButton.js \
                  browser_social_sidebar.js \
+                 browser_social_flyout.js \
                  browser_social_mozSocial_API.js \
                  browser_social_isVisible.js \
                  browser_social_chatwindow.js \
                  social_panel.html \
+                 social_share_image.png \
                  social_sidebar.html \
                  social_chat.html \
+                 social_flyout.html \
                  social_window.html \
                  social_worker.js \
                  $(NULL)
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _BROWSER_FILES += \
 		browser_bug462289.js \
 		$(NULL)
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -2,28 +2,16 @@ var rootDir = getRootDirectory(gTestPath
 const gTestRoot = rootDir;
 const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
 
 var gTestBrowser = null;
 var gNextTest = null;
 var gClickToPlayPluginActualEvents = 0;
 var gClickToPlayPluginExpectedEvents = 5;
 
-function get_test_plugin() {
-  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
-  var tags = ph.getPluginTags();
-
-  // Find the test plugin
-  for (var i = 0; i < tags.length; i++) {
-    if (tags[i].name == "Test Plug-in")
-      return tags[i];
-  }
-  ok(false, "Unable to find plugin");
-}
-
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 // This listens for the next opened tab and checks it is of the right url.
 // opencallback is called when the new tab is fully loaded
 // closecallback is called when the tab is closed
 function TabOpenListener(url, opencallback, closecallback) {
   this.url = url;
   this.opencallback = opencallback;
@@ -112,31 +100,31 @@ function test1() {
   ok("application/x-unknown" in gTestBrowser.missingPlugins, "Test 1, Should know about application/x-unknown");
   ok(!("application/x-test" in gTestBrowser.missingPlugins), "Test 1, Should not know about application/x-test");
 
   var pluginNode = gTestBrowser.contentDocument.getElementById("unknown");
   ok(pluginNode, "Test 1, Found plugin in page");
   var objLoadingContent = pluginNode.QueryInterface(Ci.nsIObjectLoadingContent);
   is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED, "Test 1, plugin fallback type should be PLUGIN_UNSUPPORTED");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   ok(plugin, "Should have a test plugin");
   plugin.disabled = false;
   plugin.blocklisted = false;
   prepareTest(test2, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a working plugin in it.
 function test2() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
   ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 2, Should not have displayed the missing plugin notification");
   ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 2, Should not have displayed the blocked plugin notification");
   ok(!gTestBrowser.missingPlugins, "Test 2, Should not be a missing plugin list");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   ok(plugin, "Should have a test plugin");
   plugin.disabled = true;
   prepareTest(test3, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a disabled plugin in it.
 function test3() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
@@ -157,17 +145,17 @@ function test3() {
 }
 
 function test4(tab, win) {
   is(win.wrappedJSObject.gViewController.currentViewId, "addons://list/plugin", "Test 4, Should have displayed the plugins pane");
   gBrowser.removeTab(tab);
 }
 
 function prepareTest5() {
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = true;
   prepareTest(test5, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a blocked plugin in it.
 function test5() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
@@ -200,17 +188,17 @@ function test6() {
 function test7() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
   ok(notificationBox.getNotificationWithValue("missing-plugins"), "Test 7, Should have displayed the missing plugin notification");
   ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 7, Should not have displayed the blocked plugin notification");
   ok(gTestBrowser.missingPlugins, "Test 7, Should be a missing plugin list");
   ok("application/x-unknown" in gTestBrowser.missingPlugins, "Test 7, Should know about application/x-unknown");
   ok("application/x-test" in gTestBrowser.missingPlugins, "Test 7, Should know about application/x-test");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = false;
   Services.prefs.setBoolPref("plugins.click_to_play", true);
 
   prepareTest(test8, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a working plugin that is click-to-play
@@ -456,17 +444,17 @@ function test13c() {
 }
 
 // Tests that the plugin's "activated" property is true for working plugins with click-to-play disabled.
 function test14() {
   var plugin = gTestBrowser.contentDocument.getElementById("test1");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 14, Plugin should be activated");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = false;
   Services.perms.removeAll();
   Services.prefs.setBoolPref("plugins.click_to_play", true);
   prepareTest(test15, gTestRoot + "plugin_alternate_content.html");
 }
 
 // Tests that the overlay is shown instead of alternate content when
@@ -635,17 +623,17 @@ function test18c() {
   is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE, "Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE");
   ok(!objLoadingContent.activated, "Test 18c, Plugin should not be activated");
   var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
   ok(overlay.style.visibility != "hidden", "Test 18c, Plugin overlay should exist, not be hidden");
   var updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
   ok(updateLink.style.display != "block", "Test 18c, Plugin should not have an update link");
 
   unregisterFakeBlocklistService();
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.clicktoplay = false;
 
   prepareTest(test19a, gTestRoot + "plugin_test.html");
 }
 
 // Tests that clicking the icon of the overlay activates the plugin
 function test19a() {
   var doc = gTestBrowser.contentDocument;
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_pluginplaypreview.js
@@ -0,0 +1,311 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir;
+
+var gTestBrowser = null;
+var gNextTest = null;
+var gNextTestSkip = 0;
+var gPlayPreviewPluginActualEvents = 0;
+var gPlayPreviewPluginExpectedEvents = 1;
+
+var gPlayPreviewRegistration = null;
+
+function registerPlayPreview(mimeType, targetUrl) {
+
+  function StreamConverterFactory() {}
+  StreamConverterFactory.prototype = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]),
+    _targetConstructor: null,
+
+    register: function register(targetConstructor) {
+      this._targetConstructor = targetConstructor;
+      var proto = targetConstructor.prototype;
+      var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+      registrar.registerFactory(proto.classID, proto.classDescription,
+                                proto.contractID, this);
+    },
+
+    unregister: function unregister() {
+      var proto = this._targetConstructor.prototype;
+      var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+      registrar.unregisterFactory(proto.classID, this);
+      this._targetConstructor = null;
+    },
+
+    // nsIFactory
+    createInstance: function createInstance(aOuter, iid) {
+      if (aOuter !== null)
+        throw Cr.NS_ERROR_NO_AGGREGATION;
+      return (new (this._targetConstructor)).QueryInterface(iid);
+    },
+
+    // nsIFactory
+    lockFactory: function lockFactory(lock) {
+      // No longer used as of gecko 1.7.
+      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  };
+
+  function OverlayStreamConverter() {}
+  OverlayStreamConverter.prototype = {
+    QueryInterface: XPCOMUtils.generateQI([
+        Ci.nsISupports,
+        Ci.nsIStreamConverter,
+        Ci.nsIStreamListener,
+        Ci.nsIRequestObserver
+    ]),
+
+    classID: Components.ID('{4c6030f7-e20a-264f-0f9b-ada3a9e97384}'),
+    classDescription: 'overlay-test-data Component',
+    contractID: '@mozilla.org/streamconv;1?from=application/x-moz-playpreview&to=*/*',
+
+    // nsIStreamConverter::convert
+    convert: function(aFromStream, aFromType, aToType, aCtxt) {
+      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+    },
+
+    // nsIStreamConverter::asyncConvertData
+    asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
+      var isValidRequest = false;
+      try {
+        var request = aCtxt;
+        request.QueryInterface(Ci.nsIChannel);
+        var spec = request.URI.spec;
+        var expectedSpec = 'data:application/x-moz-playpreview;,' + mimeType;
+        isValidRequest = (spec == expectedSpec);
+      } catch (e) { }
+      if (!isValidRequest)
+        throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+
+      // Store the listener passed to us
+      this.listener = aListener;
+    },
+
+    // nsIStreamListener::onDataAvailable
+    onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
+      // Do nothing since all the data loading is handled by the viewer.
+      ok(false, "onDataAvailable should not be called");
+    },
+
+    // nsIRequestObserver::onStartRequest
+    onStartRequest: function(aRequest, aContext) {
+
+      // Setup the request so we can use it below.
+      aRequest.QueryInterface(Ci.nsIChannel);
+      // Cancel the request so the viewer can handle it.
+      aRequest.cancel(Cr.NS_BINDING_ABORTED);
+
+      // Create a new channel that is viewer loaded as a resource.
+      var ioService = Services.io;
+      var channel = ioService.newChannel(targetUrl, null, null);
+      channel.asyncOpen(this.listener, aContext);
+    },
+
+    // nsIRequestObserver::onStopRequest
+    onStopRequest: function(aRequest, aContext, aStatusCode) {
+      // Do nothing.
+    }
+  };
+
+  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+  ph.registerPlayPreviewMimeType(mimeType);
+
+  var factory = new StreamConverterFactory();
+  factory.register(OverlayStreamConverter);
+
+  return (gPlayPreviewRegistration = {
+    unregister: function() {
+      ph.unregisterPlayPreviewMimeType(mimeType);
+      factory.unregister();
+      gPlayPreviewRegistration = null;
+    }
+  });
+}
+
+function unregisterPlayPreview() {
+  gPlayPreviewRegistration.unregister();
+}
+
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(function() {
+    if (gPlayPreviewRegistration)
+      gPlayPreviewRegistration.unregister();
+    Services.prefs.clearUserPref("plugins.click_to_play");
+  });
+
+  var newTab = gBrowser.addTab();
+  gBrowser.selectedTab = newTab;
+  gTestBrowser = gBrowser.selectedBrowser;
+  gTestBrowser.addEventListener("load", pageLoad, true);
+  gTestBrowser.addEventListener("PluginPlayPreview", handlePluginPlayPreview, true);
+
+  registerPlayPreview('application/x-test', 'about:');
+  prepareTest(test1a, gTestRoot + "plugin_test.html", 1);
+}
+
+function finishTest() {
+  gTestBrowser.removeEventListener("load", pageLoad, true);
+  gTestBrowser.removeEventListener("PluginPlayPreview", handlePluginPlayPreview, true);
+  gBrowser.removeCurrentTab();
+  window.focus();
+  finish();
+}
+
+function handlePluginPlayPreview() {
+  gPlayPreviewPluginActualEvents++;
+}
+
+function pageLoad() {
+  // The plugin events are async dispatched and can come after the load event
+  // This just allows the events to fire before we then go on to test the states
+
+  // iframe might triggers load event as well, making sure we skip some to let
+  // all iframes on the page be loaded as well
+  if (gNextTestSkip) {
+    gNextTestSkip--;
+    return;
+  }
+  executeSoon(gNextTest);
+}
+
+function prepareTest(nextTest, url, skip) {
+  gNextTest = nextTest;
+  gNextTestSkip = skip;
+  gTestBrowser.contentWindow.location = url;
+}
+
+// Tests a page with normal play preview registration (1/2)
+function test1a() {
+  var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
+  ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 1a, Should not have displayed the missing plugin notification");
+  ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 1a, Should not have displayed the blocked plugin notification");
+
+  var pluginInfo = getTestPlugin();
+  ok(pluginInfo, "Should have a test plugin");
+
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 1a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 1a, the overlay div is expected");
+
+  var iframe = overlay.getElementsByClassName("previewPluginContentFrame")[0];
+  ok(iframe && iframe.localName == "iframe", "Test 1a, the overlay iframe is expected");
+  var iframeHref = iframe.contentWindow.location.href;
+  ok(iframeHref == "about:", "Test 1a, the overlay about: content is expected");
+
+  var rect = iframe.getBoundingClientRect();
+  ok(rect.width == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being replaced by actual plugin");
+  ok(rect.height == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being replaced by actual plugin");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, null);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test1b, "Test 1a, Waited too long for plugin to stop play preview");
+}
+
+// Tests that activating via MozPlayPlugin through the notification works (part 2/2)
+function test1b() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 1b, Plugin should be activated");
+
+  is(gPlayPreviewPluginActualEvents, gPlayPreviewPluginExpectedEvents,
+     "There should be exactly one PluginPlayPreview event");
+
+  unregisterPlayPreview();
+
+  prepareTest(test2, gTestRoot + "plugin_test.html");
+}
+
+// Tests a page with a working plugin in it -- the mime type was just unregistered.
+function test2() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 2, Plugin should be activated");
+
+  registerPlayPreview('application/x-unknown', 'about:');
+
+  prepareTest(test3, gTestRoot + "plugin_test.html");
+}
+
+// Tests a page with a working plugin in it -- diffent play preview type is reserved.
+function test3() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 3, Plugin should be activated");
+
+  unregisterPlayPreview();
+
+  registerPlayPreview('application/x-test', 'about:');
+  Services.prefs.setBoolPref("plugins.click_to_play", true);
+  prepareTest(test4a, gTestRoot + "plugin_test.html", 1);
+}
+
+// Test a fallback to the click-to-play
+function test4a() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 4a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 4a, the overlay div is expected");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, true);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY;
+  waitForCondition(condition, test4b, "Test 4a, Waited too long for plugin to stop play preview");
+}
+
+function test4b() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.pluginFallbackType != Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4b, plugin fallback type should not be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 4b, Plugin should not be activated");
+
+  prepareTest(test5a, gTestRoot + "plugin_test.html", 1);
+}
+
+// Test a bypass of the click-to-play
+function test5a() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 5a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 5a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 5a, the overlay div is expected");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, false);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test5b, "Test 5a, Waited too long for plugin to stop play preview");
+}
+
+function test5b() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 5b, Plugin should be activated");
+
+  finishTest();
+}
+
--- a/browser/base/content/test/browser_social_chatwindow.js
+++ b/browser/base/content/test/browser_social_chatwindow.js
@@ -50,17 +50,17 @@ var tests = {
           break;
         case "got-chatbox-message":
           ok(true, "got chatbox message");
           ok(e.data.result == "ok", "got chatbox windowRef result: "+e.data.result);
           chats.selectedChat.toggle();
           break;
       }
     }
-    port.postMessage({topic: "test-init"});
+    port.postMessage({topic: "test-init", data: { id: 1 }});
   },
   testManyChats: function(next) {
     // open enough chats to overflow the window, then check
     // if the menupopup is visible
     let port = Social.provider.port;
     ok(port, "provider has a port");
     let width = document.documentElement.boxObject.width;
     let numToOpen = (width / 200) + 1;
@@ -82,13 +82,31 @@ var tests = {
           }
           ok(!chats.selectedChat, "chats are all closed");
           next();
           break;
       }
     }
     let num = numToOpen;
     while (num-- > 0) {
-      port.postMessage({topic: "test-chatbox-open"});
+      port.postMessage({topic: "test-chatbox-open", data: { id: num }});
     }
+  },
+  testWorkerChatWindow: function(next) {
+    let port = Social.provider.port;
+    ok(port, "provider has a port");
+    port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "got-chatbox-message":
+          ok(true, "got a chat window opened");
+          let chats = document.getElementById("pinnedchats");
+          while (chats.selectedChat) {
+            chats.selectedChat.close();
+          }
+          ok(!chats.selectedChat, "chats are all closed");
+          next();
+          break;
+      }
+    }
+    port.postMessage({topic: "test-worker-chat" });
   }
 }
-
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_social_flyout.js
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function test() {
+  waitForExplicitFinish();
+
+  let manifest = { // normal provider
+    name: "provider 1",
+    origin: "https://example.com",
+    sidebarURL: "https://example.com/browser/browser/base/content/test/social_sidebar.html",
+    workerURL: "https://example.com/browser/browser/base/content/test/social_worker.js",
+    iconURL: "chrome://branding/content/icon48.png"
+  };
+  runSocialTestWithProvider(manifest, function (finishcb) {
+    runSocialTests(tests, undefined, undefined, finishcb);
+  });
+}
+
+var tests = {
+  testOpenCloseFlyout: function(next) {
+    let panel = document.getElementById("social-flyout-panel");
+    let port = Social.provider.port;
+    ok(port, "provider has a port");
+    port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "got-sidebar-message":
+          port.postMessage({topic: "test-flyout-open"});
+          break;
+        case "got-flyout-visibility":
+          if (e.data.result == "hidden") {
+            ok(true, "flyout visibility is 'hidden'");
+            next();
+          } else if (e.data.result == "shown") {
+            ok(true, "flyout visibility is 'shown");
+            panel.hidePopup();
+          }
+          break;
+        case "got-flyout-message":
+          ok(e.data.result == "ok", "got flyout message");
+          break;
+      }
+    }
+    port.postMessage({topic: "test-init"});
+  }
+}
+
--- a/browser/base/content/test/browser_social_mozSocial_API.js
+++ b/browser/base/content/test/browser_social_mozSocial_API.js
@@ -37,26 +37,29 @@ var tests = {
 
     let port = Social.provider.port;
     ok(port, "provider has a port");
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
         case "got-panel-message":
           ok(true, "got panel message");
+          // Check the panel isn't in our history.
+          ensureSocialUrlNotRemembered(e.data.location);
           break;
         case "got-social-panel-visibility":
           if (e.data.result == "shown") {
             ok(true, "panel shown");
             let panel = document.getElementById("social-notification-panel");
             panel.hidePopup();
           } else if (e.data.result == "hidden") {
             ok(true, "panel hidden");
             next();
           }
+          break;
         case "got-sidebar-message":
           // The sidebar message will always come first, since it loads by default
           ok(true, "got sidebar message");
           gotSidebarMessage = true;
           checkNext();
           break;
       }
     }
@@ -75,53 +78,10 @@ var tests = {
         // Let the other observers (like the one that updates the UI) run before
         // checking the icons.
         executeSoon(function () {
           iconsReady = true;
           checkNext();
         });
       }, "social:ambient-notification-changed", false);
     }
-  },
-
-  testServiceWindow: function(next) {
-    // our test provider was initialized in the test above, we just
-    // initiate our specific test now.
-    let port = Social.provider.port;
-    ok(port, "provider has a port");
-    port.postMessage({topic: "test-service-window"});
-    port.onmessage = function (e) {
-      let topic = e.data.topic;
-      switch (topic) {
-        case "got-service-window-message":
-          // The sidebar message will always come first, since it loads by default
-          ok(true, "got service window message");
-          port.postMessage({topic: "test-close-service-window"});
-          break;
-        case "got-service-window-closed-message":
-          ok(true, "got service window closed message");
-          next();
-          break;
-      }
-    }
-  },
-
-  testServiceWindowTwice: function(next) {
-    let port = Social.provider.port;
-    port.postMessage({topic: "test-service-window-twice"});
-    Social.provider.port.onmessage = function (e) {
-      let topic = e.data.topic;
-      switch (topic) {
-        case "test-service-window-twice-result":
-          is(e.data.result, "ok", "only one window should open when name is reused");
-          break;
-        case "got-service-window-message":
-          ok(true, "got service window message");
-          port.postMessage({topic: "test-close-service-window"});
-          break;
-        case "got-service-window-closed-message":
-          ok(true, "got service window closed message");
-          next();
-          break;
-      }
-    }
   }
 }
--- a/browser/base/content/test/browser_social_shareButton.js
+++ b/browser/base/content/test/browser_social_shareButton.js
@@ -1,17 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 let prefName = "social.enabled",
-    shareButton,
-    sharePopup,
-    okButton,
-    undoButton,
     gFinishCB;
 
 function test() {
   waitForExplicitFinish();
 
   // Need to load a non-empty page for the social share button to appear
   let tab = gBrowser.selectedTab = gBrowser.addTab("about:", {skipAnimation: true});
   tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
@@ -41,54 +37,80 @@ function tabLoaded() {
   });
 }
 
 function testInitial(finishcb) {
   ok(Social.provider, "Social provider is active");
   ok(Social.provider.enabled, "Social provider is enabled");
   ok(Social.provider.port, "Social provider has a port to its FrameWorker");
 
-  shareButton = SocialShareButton.shareButton;
-  sharePopup = SocialShareButton.sharePopup;
+  let {shareButton, sharePopup} = SocialShareButton;
   ok(shareButton, "share button exists");
   ok(sharePopup, "share popup exists");
 
-  okButton = document.getElementById("editSharePopupOkButton");
-  undoButton = document.getElementById("editSharePopupUndoButton");
-
-  is(shareButton.hidden, false, "share button should be visible");
+  let okButton = document.getElementById("editSharePopupOkButton");
+  let undoButton = document.getElementById("editSharePopupUndoButton");
+  let shareStatusLabel = document.getElementById("share-button-status");
 
-  // Test clicking the share button
-  shareButton.addEventListener("click", function listener() {
-    shareButton.removeEventListener("click", listener);
-    is(shareButton.hasAttribute("shared"), true, "Share button should have 'shared' attribute after share button is clicked");
-    executeSoon(testSecondClick.bind(window, testPopupOKButton));
-  });
-  EventUtils.synthesizeMouseAtCenter(shareButton, {});
+  // ensure the worker initialization and handshakes are all done and we
+  // have a profile and the worker has responsed to the recommend-prompt msg.
+  waitForCondition(function() Social.provider.profile && SocialShareButton.promptImages != null, function() {
+    is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' attribute before share button is clicked");
+    // check dom values
+    let profile = Social.provider.profile;
+    let portrait = document.getElementById("socialUserPortrait").getAttribute("src");
+    is(profile.portrait, portrait, "portrait is set");
+    let displayName = document.getElementById("socialUserDisplayName");
+    is(displayName.label, profile.displayName, "display name is set");
+    ok(!document.getElementById("editSharePopupHeader").hidden, "user profile is visible");
+  
+    // Check the strings from our worker actually ended up on the button.
+    is(shareButton.getAttribute("tooltiptext"), "Share this page", "check tooltip text is correct");
+    is(shareStatusLabel.getAttribute("value"), "", "check status label text is blank");
+    // Check the relative URL was resolved correctly (note this image has offsets of zero...)
+    is(shareButton.style.backgroundImage, 'url("https://example.com/browser/browser/base/content/test/social_share_image.png")', "check image url is correct");
+
+    // Test clicking the share button
+    shareButton.addEventListener("click", function listener() {
+      shareButton.removeEventListener("click", listener);
+      is(shareButton.hasAttribute("shared"), true, "Share button should have 'shared' attribute after share button is clicked");
+      is(shareButton.getAttribute("tooltiptext"), "Unshare this page", "check tooltip text is correct");
+      is(shareStatusLabel.getAttribute("value"), "This page has been shared", "check status label text is correct");
+      // Check the URL and offsets were applied correctly
+      is(shareButton.style.backgroundImage, 'url("https://example.com/browser/browser/base/content/test/social_share_image.png")', "check image url is correct");
+      executeSoon(testSecondClick.bind(window, testPopupOKButton));
+    });
+    EventUtils.synthesizeMouseAtCenter(shareButton, {});
+  }, "provider didn't provide user-recommend-prompt response");
 }
 
 function testSecondClick(nextTest) {
+  let {shareButton, sharePopup} = SocialShareButton;
   sharePopup.addEventListener("popupshown", function listener() {
     sharePopup.removeEventListener("popupshown", listener);
     ok(true, "popup was shown after second click");
     executeSoon(nextTest);
   });
   EventUtils.synthesizeMouseAtCenter(shareButton, {});
 }
 
 function testPopupOKButton() {
+  let {shareButton, sharePopup} = SocialShareButton;
+  let okButton = document.getElementById("editSharePopupOkButton");
   sharePopup.addEventListener("popuphidden", function listener() {
     sharePopup.removeEventListener("popuphidden", listener);
     is(shareButton.hasAttribute("shared"), true, "Share button should still have 'shared' attribute after OK button is clicked");
     executeSoon(testSecondClick.bind(window, testPopupUndoButton));
   });
   EventUtils.synthesizeMouseAtCenter(okButton, {});
 }
 
 function testPopupUndoButton() {
+  let {shareButton, sharePopup} = SocialShareButton;
+  let undoButton = document.getElementById("editSharePopupUndoButton");
   sharePopup.addEventListener("popuphidden", function listener() {
     sharePopup.removeEventListener("popuphidden", listener);
     is(shareButton.hasAttribute("shared"), false, "Share button should not have 'shared' attribute after Undo button is clicked");
     executeSoon(testShortcut);
   });
   EventUtils.synthesizeMouseAtCenter(undoButton, {});
 }
 
@@ -97,28 +119,31 @@ function testShortcut() {
   keyTarget.addEventListener("keyup", function listener() {
     keyTarget.removeEventListener("keyup", listener);
     executeSoon(checkShortcutWorked.bind(window, keyTarget));
   });
   EventUtils.synthesizeKey("l", {accelKey: true, shiftKey: true}, keyTarget);
 }
 
 function checkShortcutWorked(keyTarget) {
+  let {sharePopup, shareButton} = SocialShareButton;
   is(shareButton.hasAttribute("shared"), true, "Share button should be in the 'shared' state after keyboard shortcut is used");
 
   // Test a second invocation of the shortcut
   sharePopup.addEventListener("popupshown", function listener() {
     sharePopup.removeEventListener("popupshown", listener);
     ok(true, "popup was shown after second use of keyboard shortcut");
     executeSoon(checkOKButton);
   });
   EventUtils.synthesizeKey("l", {accelKey: true, shiftKey: true}, keyTarget);
 }
 
 function checkOKButton() {
+  let okButton = document.getElementById("editSharePopupOkButton");
+  let undoButton = document.getElementById("editSharePopupUndoButton");
   is(document.activeElement, okButton, "ok button should be focused by default");
 
   // This rest of particular test doesn't really apply on Mac, since buttons
   // aren't focusable by default.
   if (navigator.platform.indexOf("Mac") != -1) {
     executeSoon(testCloseBySpace);
     return;
   }
@@ -151,22 +176,24 @@ function checkNextInTabOrder(element, ne
   // Register a cleanup function to remove the listener in case this test fails
   registerCleanupFunction(function () {
     element.removeEventListener("focus", listener);
   });
   EventUtils.synthesizeKey("VK_TAB", {});
 }
 
 function testCloseBySpace() {
-  is(document.activeElement.id, okButton.id, "testCloseBySpace, the ok button should be focused");
+  let sharePopup = SocialShareButton.sharePopup;
+  is(document.activeElement.id, "editSharePopupOkButton", "testCloseBySpace, the ok button should be focused");
   sharePopup.addEventListener("popuphidden", function listener() {
     sharePopup.removeEventListener("popuphidden", listener);
     ok(true, "space closed the share popup");
     executeSoon(testDisable);
   });
   EventUtils.synthesizeKey("VK_SPACE", {});
 }
 
 function testDisable() {
+  let shareButton = SocialShareButton.shareButton;
   Services.prefs.setBoolPref(prefName, false);
   is(shareButton.hidden, true, "Share button should be hidden when pref is disabled");
   gFinishCB();
 }
--- a/browser/base/content/test/head.js
+++ b/browser/base/content/test/head.js
@@ -83,31 +83,71 @@ function waitForCondition(condition, nex
     if (condition()) {
       moveOn();
     }
     tries++;
   }, 100);
   var moveOn = function() { clearInterval(interval); nextTest(); };
 }
 
+// Check that a specified (string) URL hasn't been "remembered" (ie, is not
+// in history, will not appear in about:newtab or auto-complete, etc.)
+function ensureSocialUrlNotRemembered(url) {
+  let gh = Cc["@mozilla.org/browser/global-history;2"]
+           .getService(Ci.nsIGlobalHistory2);
+  let uri = Services.io.newURI(url, null, null);
+  ok(!gh.isVisited(uri), "social URL " + url + " should not be in global history");
+}
+
+function getTestPlugin() {
+  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+  var tags = ph.getPluginTags();
+
+  // Find the test plugin
+  for (var i = 0; i < tags.length; i++) {
+    if (tags[i].name == "Test Plug-in")
+      return tags[i];
+  }
+  ok(false, "Unable to find plugin");
+  return null;
+}
+
 function runSocialTestWithProvider(manifest, callback) {
   let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
 
+  // Check that none of the provider's content ends up in history.
+  registerCleanupFunction(function () {
+    for (let what of ['sidebarURL', 'workerURL', 'iconURL']) {
+      if (manifest[what]) {
+        ensureSocialUrlNotRemembered(manifest[what]);
+      }
+    }
+  });
+
   info("runSocialTestWithProvider: " + manifest.toSource());
 
   let oldProvider;
   SocialService.addProvider(manifest, function(provider) {
     info("runSocialTestWithProvider: provider added");
     oldProvider = Social.provider;
     Social.provider = provider;
 
     // Now that we've set the UI's provider, enable the social functionality
     Services.prefs.setBoolPref("social.enabled", true);
 
     registerCleanupFunction(function () {
+      // if one test happens to fail, it is likely finishSocialTest will not
+      // be called, causing most future social tests to also fail as they
+      // attempt to add a provider which already exists - so work
+      // around that by also attempting to remove the test provider.
+      try {
+        SocialService.removeProvider(provider.origin, finish);
+      } catch (ex) {
+        ;
+      }
       Social.provider = oldProvider;
       Services.prefs.clearUserPref("social.enabled");
     });
 
     function finishSocialTest() {
       SocialService.removeProvider(provider.origin, finish);
     }
     callback(finishSocialTest);
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/social_flyout.html
@@ -0,0 +1,22 @@
+<html>
+  <head>
+    <meta charset="utf-8">
+    <script>
+      function pingWorker() {
+        var port = navigator.mozSocial.getWorker().port;
+        port.postMessage({topic: "flyout-message", result: "ok"});
+      }
+      window.addEventListener("socialFrameShow", function(e) {
+        var port = navigator.mozSocial.getWorker().port;
+        port.postMessage({topic: "flyout-visibility", result: "shown"});
+      }, false);
+      window.addEventListener("socialFrameHide", function(e) {
+        var port = navigator.mozSocial.getWorker().port;
+        port.postMessage({topic: "flyout-visibility", result: "hidden"});
+      }, false);
+    </script>
+  </head>
+  <body onload="pingWorker();">
+    <p>This is a test social flyout panel.</p>
+  </body>
+</html>
--- a/browser/base/content/test/social_panel.html
+++ b/browser/base/content/test/social_panel.html
@@ -1,15 +1,17 @@
 <html>
   <head>
     <meta charset="utf-8">
     <script>
       function pingWorker() {
         var port = navigator.mozSocial.getWorker().port;
-        port.postMessage({topic: "panel-message", result: "ok"});
+        port.postMessage({topic: "panel-message",
+                          result: "ok",
+                          location: window.location.href});
       }
       window.addEventListener("socialFrameShow", function(e) {
         var port = navigator.mozSocial.getWorker().port;
         port.postMessage({topic: "status-panel-visibility", result: "shown"});
       }, false);
       window.addEventListener("socialFrameHide", function(e) {
         var port = navigator.mozSocial.getWorker().port;
         port.postMessage({topic: "status-panel-visibility", result: "hidden"});
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa1f8fb0e23b9689e51f667a5745898f929c0960
GIT binary patch
literal 934
zc$@*I16lluP)<h;3K|Lk000e1NJLTq001BW000mO0ssI2_+sh~00001b5ch_0Itp)
z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&13O7XK~y+Tl~h?w
z6HyeMX{VqdxP&#JML>gzF^WngX*5D0u|Y_zMiP}w{Nn>rQGbz7P5f-4KNwn+O$AF>
zgVKtXvK0svEfujSv``QVEiLUV-kGsuAw}@@HhD91-#O>r^WH<~?G2J7H9f<d<x(^S
zLC^$25iY{@Soa9#T(SV!#&9@Y4ei=7lR026jnMF(LMVW<I4yTO@3fd(V9q6PO)zbp
zf7PN{b~tI8+Khm!V8A+XTU~4>%ov98nOhJH8ceDV?e4Hp5)gc%_{E?d0-#BRtRAg?
z*i-7p+yYcU5r3s@O5i1k=1!fqe<WgWxCj%vTyBb5R{`G{r`J)YE_?a)1r~&%6zX+)
zuO{bjQNf~prKa)ygn2qVEHouaJo&@IIp(jO?|V_}twFmU(7^}qs`rvuhM&Mu6y4N=
zZ&Nc>s*Z(4dvK5_OLD4PKMLBp0c*InFr8st)ta@owK*XwL`W7rL58Q|C<5?-2w=gd
z{t;DsmuJl*6rj0T68(sAb=AdM$cC@!OYWryP4}e=>9}pY;qu$un7rKRJk^y({3I?w
z1j>E|*T8kV$i3!y)1ua~dV%S}`Sj%#r*Xo}%jZ2X+Kh#Dg`@KZPALSQhC^_wD|#y`
zdKEr=-!`4K{ZiC5PfpEnaFWx<VxuD3H9CKEj-ca9hg>aB+>@BOKQlWayK11y-xy_&
zver<Gi7>tb6vTcuO%55xcLWE8hU^4$hQ~}d^K&swIAgU9jv9Yj=6HyEh1Yp+0RoO|
z$?KBT_|$?k1@K;}Q#Kiz9F&73$hN{Z3}sFO^FMOvAOwd3e6zL%pp1`=YVGVkm!2v~
zJN`kZ_osm_(~K}$go=vJ78N%XGkb<Y`o8y7;+12TvGR}Q{4Qb=H=IvsSJS&LX@=x^
zjS4==q#1{k#8cB&jZS|<Cgp4AOUZeb1M?6hM1D;kxhs-!g8hMxz*j|d<UVm+tbN4+
z+)3hiK!>~oaWQ}n6W&;Mu>c;!1Yw95DZN<AptFN}|3`Pg3v$il(e@2Jd8$}uY5sAE
zk~FC?YU=g%aF2o|zU|EHLv93U5yuP%%`$5{nv%Ssf&csX8$88<_@TT+ApigX07*qo
IM6N<$f?A)aGynhq
--- a/browser/base/content/test/social_sidebar.html
+++ b/browser/base/content/test/social_sidebar.html
@@ -1,45 +1,35 @@
 <html>
   <head>
     <meta charset="utf-8">
     <script>
-      var win;
+      var testwindow;
       function pingWorker() {
         var port = navigator.mozSocial.getWorker().port;
         port.onmessage = function(e) {
           var topic = e.data.topic;
           switch (topic) {
+            case "test-flyout-open":
+              navigator.mozSocial.openPanel("social_flyout.html");
+              break;
             case "test-chatbox-open":
-              navigator.mozSocial.openChatWindow("social_chat.html", function(chatwin) {
-                port.postMessage({topic: "chatbox-opened", result: chatwin ? "ok" : "failed"});
+              var url = "social_chat.html";
+              var data = e.data.data;
+              if (data && data.id) {
+                url = url + "?id="+data.id;
+              }
+              navigator.mozSocial.openChatWindow(url, function(chatwin) {
+                port.postMessage({topic: "chatbox-opened",
+                                  result: chatwin ? "ok" : "failed"});
               });
               break;
-            case "test-service-window":
-              win = navigator.mozSocial.openServiceWindow("social_window.html", "test-service-window", "width=300,height=300");
-              break;
-            case "test-service-window-twice":
-              win = navigator.mozSocial.openServiceWindow("social_window.html", "test-service-window", "width=300,height=300");
-              var win2 = navigator.mozSocial.openServiceWindow("social_window.html", "test-service-window", "");
-              var result;
-              if (win == win2)
-                result = "ok";
-              else
-                result = "not ok: " + win2 + " != " + win;
-              port.postMessage({topic: "test-service-window-twice-result", result: result});
-              break;
-            case "test-close-service-window":
-              win.addEventListener("unload", function watchClose() {
-                win.removeEventListener("unload", watchClose);
-                port.postMessage({topic: "service-window-closed-message", result: "ok"});
-              }, false)
-              win.close();
-              break;
             case "test-isVisible":
-              port.postMessage({topic: "test-isVisible-response", result: navigator.mozSocial.isVisible});
+              port.postMessage({topic: "test-isVisible-response",
+                                result: navigator.mozSocial.isVisible});
               break;
           }
         }
         port.postMessage({topic: "sidebar-message", result: "ok"});
       }
     </script>
   </head>
   <body onload="pingWorker();">
--- a/browser/base/content/test/social_window.html
+++ b/browser/base/content/test/social_window.html
@@ -1,14 +1,17 @@
 <html>
   <head>
     <meta charset="utf-8">
     <script>
       function pingWorker() {
         var port = navigator.mozSocial.getWorker().port;
-        port.postMessage({topic: "service-window-message", result: "ok"});
+        port.postMessage({topic: "service-window-message",
+                          location: window.location.href,
+                          result: "ok"
+                         });
       }
     </script>
   </head>
   <body onload="pingWorker();">
     <p>This is a test social service window.</p>
   </body>
 </html>
--- a/browser/base/content/test/social_worker.js
+++ b/browser/base/content/test/social_worker.js
@@ -1,29 +1,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-let testPort, sidebarPort;
+let testPort, sidebarPort, apiPort;
 
 onconnect = function(e) {
   let port = e.ports[0];
   port.onmessage = function onMessage(event) {
     let topic = event.data.topic;
     switch (topic) {
       case "test-init":
         testPort = port;
         break;
       case "sidebar-message":
         sidebarPort = port;
         if (testPort && event.data.result == "ok")
           testPort.postMessage({topic:"got-sidebar-message"});
         break;
       case "service-window-message":
-        testPort.postMessage({topic:"got-service-window-message"});
+        testPort.postMessage({topic:"got-service-window-message",
+                              location: event.data.location});
         break;
       case "service-window-closed-message":
         testPort.postMessage({topic:"got-service-window-closed-message"});
         break;
       case "test-service-window":
         sidebarPort.postMessage({topic:"test-service-window"});
         break;
       case "test-service-window-twice":
@@ -32,46 +33,83 @@ onconnect = function(e) {
       case "test-service-window-twice-result":
         testPort.postMessage({topic: "test-service-window-twice-result", result: event.data.result })
         break;
       case "test-close-service-window":
         sidebarPort.postMessage({topic:"test-close-service-window"});
         break;
       case "panel-message":
         if (testPort && event.data.result == "ok")
-          testPort.postMessage({topic:"got-panel-message"});
+          testPort.postMessage({topic:"got-panel-message",
+                                location: event.data.location
+                               });
         break;
       case "status-panel-visibility":
         testPort.postMessage({topic:"got-social-panel-visibility", result: event.data.result });
         break;
       case "test-chatbox-open":
-        sidebarPort.postMessage({topic:"test-chatbox-open"});
+        sidebarPort.postMessage( event.data );
         break;
       case "chatbox-message":
         testPort.postMessage({topic:"got-chatbox-message", result: event.data.result});
         break;
       case "chatbox-visibility":
         testPort.postMessage({topic:"got-chatbox-visibility", result: event.data.result});
         break;
+      case "test-flyout-open":
+        sidebarPort.postMessage({topic:"test-flyout-open"});
+        break;
+      case "flyout-message":
+        testPort.postMessage({topic:"got-flyout-message", result: event.data.result});
+        break;
+      case "flyout-visibility":
+        testPort.postMessage({topic:"got-flyout-visibility", result: event.data.result});
+        break;
+      case "test-worker-chat":
+        apiPort.postMessage({topic: "social.request-chat", data: "https://example.com/browser/browser/base/content/test/social_chat.html" });
+        break;
       case "social.initialize":
         // This is the workerAPI port, respond and set up a notification icon.
+        apiPort = port;
         port.postMessage({topic: "social.initialize-response"});
         let profile = {
-          userName: "foo"
+          portrait: "https://example.com/portrait.jpg",
+          userName: "trickster",
+          displayName: "Kuma Lisa",
+          profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
         };
         port.postMessage({topic: "social.user-profile", data: profile});
         let icon = {
           name: "testIcon",
           iconURL: "chrome://branding/content/icon48.png",
           contentPanel: "https://example.com/browser/browser/base/content/test/social_panel.html",
           counter: 1
         };
         port.postMessage({topic: "social.ambient-notification", data: icon});
         break;
       case "test-isVisible":
         sidebarPort.postMessage({topic: "test-isVisible"});
         break;
       case "test-isVisible-response":
         testPort.postMessage({topic: "got-isVisible-response", result: event.data.result});
         break;
+      case "social.user-recommend-prompt":
+        port.postMessage({
+          topic: "social.user-recommend-prompt-response",
+          data: {
+            images: {
+              // this one is relative to test we handle relative ones.
+              share: "browser/browser/base/content/test/social_share_image.png",
+              // absolute to check we handle them too.
+              unshare: "https://example.com/browser/browser/base/content/test/social_share_image.png"
+            },
+            messages: {
+              shareTooltip: "Share this page",
+              unshareTooltip: "Unshare this page",
+              sharedLabel: "This page has been shared",
+              unsharedLabel: "This page is no longer shared",
+            }
+          }
+        });
+        break;
     }
   }
 }
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -47,23 +47,23 @@ function openContextMenuFor(element, shi
 function closeContextMenu() {
     contextMenu.hidePopup();
 }
 
 function executeCopyCommand(command, expectedValue)
 {
   // Just execute the command directly rather than simulating a context menu
   // press to avoid having to deal with its asynchronous nature
-  subwindow.controllers.getControllerForCommand(command).doCommand(command);
+  SpecialPowers.wrap(subwindow).controllers.getControllerForCommand(command).doCommand(command);
 
   // The easiest way to check the clipboard is to paste the contents into a
   // textbox
   input.focus();
   input.value = "";
-  input.controllers.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
+  SpecialPowers.wrap(input).controllers.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
   is(input.value, expectedValue, "paste for command " + command);
 }
 
 function invokeItemAction(generatedItemId)
 {
   var item = contextMenu.getElementsByAttribute("generateditemid",
                                                 generatedItemId)[0];
   ok(item, "Got generated XUL menu item");
@@ -245,17 +245,16 @@ function checkMenu(menu, expectedItems, 
  *
  * Called by a popupshowing event handler. Each test checks for expected menu
  * contents, closes the popup, and finally triggers the popup on a new element
  * (thus kicking off another cycle).
  *
  */
 function runTest(testNum) {
   // Seems we need to enable this again, or sendKeyEvent() complaints.
-  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
   ok(true, "Starting test #" + testNum);
 
   var inspectItems = [];
   if (SpecialPowers.getBoolPref("devtools.inspector.enabled")) {
     inspectItems = ["---", null,
                     "context-inspect", true];
   }
 
--- a/browser/components/downloads/content/download.xml
+++ b/browser/components/downloads/content/download.xml
@@ -10,52 +10,41 @@
 
 <bindings id="downloadBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="download"
            extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
-    <resources>
-      <stylesheet src="chrome://browser/skin/downloads/downloads.css"/>
-    </resources>
-    <content orient="horizontal">
-      <xul:hbox class="downloadInfo"
-                align="center"
-                flex="1"
-                onclick="DownloadsView.onDownloadClick(event);">
-        <xul:vbox pack="center">
-          <xul:image class="downloadTypeIcon"
-                     validate="always"
-                     xbl:inherits="src=image"/>
-          <xul:image class="downloadTypeIcon blockedIcon"/>
-        </xul:vbox>
-        <xul:vbox pack="center"
-                  flex="1">
-          <xul:description class="downloadTarget"
-                           crop="center"
-                           xbl:inherits="value=target,tooltiptext=target"/>
-          <xul:progressmeter anonid="progressmeter"
-                             class="downloadProgress"
-                             min="0"
-                             max="100"
-                             xbl:inherits="mode=progressmode,value=progress"/>
-          <xul:description class="downloadDetails"
-                           crop="end"
-                           xbl:inherits="value=status,tooltiptext=statusTip"/>
-        </xul:vbox>
-      </xul:hbox>
-      <xul:hbox class="downloadButtonContainer"
-                align="center">
-        <xul:button class="downloadButton downloadCancel"
-                    tooltiptext="&cmd.cancel.label;"
-                    oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_cancel');"/>
-        <xul:button class="downloadButton downloadRetry"
-                    tooltiptext="&cmd.retry.label;"
-                    oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_retry');"/>
-        <xul:button class="downloadButton downloadShow"
-                    tooltiptext="&cmd.show.label;"
-                    oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
-      </xul:hbox>
+    <content orient="horizontal"
+             align="center"
+             onclick="DownloadsView.onDownloadClick(event);">
+      <xul:image class="downloadTypeIcon"
+                 validate="always"
+                 xbl:inherits="src=image"/>
+      <xul:image class="downloadTypeIcon blockedIcon"/>
+      <xul:vbox pack="center"
+                flex="1">
+        <xul:description class="downloadTarget"
+                         crop="center"
+                         xbl:inherits="value=target,tooltiptext=target"/>
+        <xul:progressmeter anonid="progressmeter"
+                           class="downloadProgress"
+                           min="0"
+                           max="100"
+                           xbl:inherits="mode=progressmode,value=progress"/>
+        <xul:description class="downloadDetails"
+                         crop="end"
+                         xbl:inherits="value=status,tooltiptext=statusTip"/>
+      </xul:vbox>
+      <xul:button class="downloadButton downloadCancel"
+                  tooltiptext="&cmd.cancel.label;"
+                  oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_cancel');"/>
+      <xul:button class="downloadButton downloadRetry"
+                  tooltiptext="&cmd.retry.label;"
+                  oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_retry');"/>
+      <xul:button class="downloadButton downloadShow"
+                  tooltiptext="&cmd.show.label;"
+                  oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
     </content>
   </binding>
 </bindings>
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -255,22 +255,21 @@ const DownloadsPanel = {
   //////////////////////////////////////////////////////////////////////////////
   //// Related operations
 
   /**
    * Shows or focuses the user interface dedicated to downloads history.
    */
   showDownloadsHistory: function DP_showDownloadsHistory()
   {
-    // Hide the panel before invoking the Library window, otherwise focus will
-    // return to the browser window when the panel closes automatically.
+    // Hide the panel before showing another window, otherwise focus will return
+    // to the browser window when the panel closes automatically.
     this.hidePanel();
 
-    // Open the Library window and select the Downloads query.
-    PlacesCommandHook.showPlacesOrganizer("Downloads");
+    BrowserDownloadsUI();
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// Internal functions
 
   /**
    * Move focus to the main element in the downloads panel, unless another
    * element in the panel is already focused.
@@ -351,17 +350,17 @@ const DownloadsOverlayLoader = {
   _loadedOverlays: {},
 
   /**
    * Loads the specified overlay and invokes the given callback when finished.
    *
    * @param aOverlay
    *        String containing the URI of the overlay to load in the current
    *        window.  If this overlay has already been loaded using this
-   *        function, then the overlay is not loaded again. 
+   *        function, then the overlay is not loaded again.
    * @param aCallback
    *        Invoked when loading is completed.  If the overlay is already
    *        loaded, the function is called immediately.
    */
   ensureOverlayLoaded: function DOL_ensureOverlayLoaded(aOverlay, aCallback)
   {
     // The overlay is already loaded, invoke the callback immediately.
     if (aOverlay in this._loadedOverlays) {
@@ -420,47 +419,79 @@ const DownloadsOverlayLoader = {
  * download state and real-time data.  In addition, handles part of the user
  * interaction events raised by the downloads list widget.
  */
 const DownloadsView = {
   //////////////////////////////////////////////////////////////////////////////
   //// Functions handling download items in the list
 
   /**
+   * Maximum number of items shown by the list at any given time.
+   */
+  kItemCountLimit: 3,
+
+  /**
    * Indicates whether we are still loading downloads data asynchronously.
    */
   loading: false,
 
   /**
-   * Object containing all the available DownloadsViewItem objects, indexed by
-   * their numeric download identifier.
+   * Ordered array of all DownloadsDataItem objects.  We need to keep this array
+   * because only a limited number of items are shown at once, and if an item
+   * that is currently visible is removed from the list, we might need to take
+   * another item from the array and make it appear at the bottom.
+   */
+  _dataItems: [],
+
+  /**
+   * Object containing the available DownloadsViewItem objects, indexed by their
+   * numeric download identifier.  There is a limited number of view items in
+   * the panel at any given time.
    */
   _viewItems: {},
 
   /**
    * Called when the number of items in the list changes.
    */
   _itemCountChanged: function DV_itemCountChanged()
   {
-    if (Object.keys(this._viewItems).length > 0) {
+    let count = this._dataItems.length;
+    let hiddenCount = count - this.kItemCountLimit;
+
+    if (count > 0) {
       DownloadsPanel.panel.setAttribute("hasdownloads", "true");
     } else {
       DownloadsPanel.panel.removeAttribute("hasdownloads");
     }
+
+    let s = DownloadsCommon.strings;
+    this.downloadsHistory.label = (hiddenCount > 0)
+                                  ? s.showMoreDownloads(hiddenCount)
+                                  : s.showAllDownloads;
+    this.downloadsHistory.accessKey = s.showDownloadsAccessKey;
   },
 
   /**
    * Element corresponding to the list of downloads.
    */
   get richListBox()
   {
     delete this.richListBox;
     return this.richListBox = document.getElementById("downloadsListBox");
   },
 
+  /**
+   * Element corresponding to the button for showing more downloads.
+   */
+  get downloadsHistory()
+  {
+    delete this.downloadsHistory;
+    return this.downloadsHistory = document.getElementById("downloadsHistory");
+  },
+
   //////////////////////////////////////////////////////////////////////////////
   //// Callback functions from DownloadsData
 
   /**
    * Called before multiple downloads are about to be loaded.
    */
   onDataLoadStarting: function DV_onDataLoadStarting()
   {
@@ -469,16 +500,20 @@ const DownloadsView = {
 
   /**
    * Called after data loading finished.
    */
   onDataLoadCompleted: function DV_onDataLoadCompleted()
   {
     this.loading = false;
 
+    // We suppressed item count change notifications during the batch load, at
+    // this point we should just call the function once.
+    this._itemCountChanged();
+
     // Notify the panel that all the initially available downloads have been
     // loaded.  This ensures that the interface is visible, if still required.
     DownloadsPanel.onViewLoadCompleted();
   },
 
   /**
    * Called when the downloads database becomes unavailable (for example,
    * entering Private Browsing Mode).  References to existing data should be
@@ -488,16 +523,17 @@ const DownloadsView = {
   {
     DownloadsPanel.terminate();
 
     // Clear the list by replacing with a shallow copy.
     let emptyView = this.richListBox.cloneNode(false);
     this.richListBox.parentNode.replaceChild(emptyView, this.richListBox);
     this.richListBox = emptyView;
     this._viewItems = {};
+    this._dataItems = [];
   },
 
   /**
    * Called when a new download data item is available, either during the
    * asynchronous data load or when a new download is started.
    *
    * @param aDataItem
    *        DownloadsDataItem object that was just added.
@@ -505,59 +541,119 @@ const DownloadsView = {
    *        When true, indicates that this item is the most recent and should be
    *        added in the topmost position.  This happens when a new download is
    *        started.  When false, indicates that the item is the least recent
    *        and should be appended.  The latter generally happens during the
    *        asynchronous data load.
    */
   onDataItemAdded: function DV_onDataItemAdded(aDataItem, aNewest)
   {
-    // Make the item and add it in the appropriate place in the list.
-    let element = document.createElement("richlistitem");
-    let viewItem = new DownloadsViewItem(aDataItem, element);
-    this._viewItems[aDataItem.downloadId] = viewItem;
     if (aNewest) {
-      this.richListBox.insertBefore(element, this.richListBox.firstChild);
+      this._dataItems.unshift(aDataItem);
     } else {
-      this.richListBox.appendChild(element);
+      this._dataItems.push(aDataItem);
     }
 
-    this._itemCountChanged();
+    let itemsNowOverflow = this._dataItems.length > this.kItemCountLimit;
+    if (aNewest || !itemsNowOverflow) {
+      // The newly added item is visible in the panel and we must add the
+      // corresponding element.  This is either because it is the first item, or
+      // because it was added at the bottom but the list still doesn't overflow.
+      this._addViewItem(aDataItem, aNewest);
+    }
+    if (aNewest && itemsNowOverflow) {
+      // If the list overflows, remove the last item from the panel to make room
+      // for the new one that we just added at the top.
+      this._removeViewItem(this._dataItems[this.kItemCountLimit]);
+    }
+
+    // For better performance during batch loads, don't update the count for
+    // every item, because the interface won't be visible until load finishes.
+    if (!this.loading) {
+      this._itemCountChanged();
+    }
   },
 
   /**
    * Called when a data item is removed.  Ensures that the widget associated
    * with the view item is removed from the user interface.
    *
    * @param aDataItem
    *        DownloadsDataItem object that is being removed.
    */
   onDataItemRemoved: function DV_onDataItemRemoved(aDataItem)
   {
-    let element = this.getViewItem(aDataItem)._element;
-    let previousSelectedIndex = this.richListBox.selectedIndex;
-    this.richListBox.removeChild(element);
-    this.richListBox.selectedIndex = Math.min(previousSelectedIndex,
-                                              this.richListBox.itemCount - 1);
-    delete this._viewItems[aDataItem.downloadId];
+    let itemIndex = this._dataItems.indexOf(aDataItem);
+    this._dataItems.splice(itemIndex, 1);
+
+    if (itemIndex < this.kItemCountLimit) {
+      // The item to remove is visible in the panel.
+      this._removeViewItem(aDataItem);
+      if (this._dataItems.length >= this.kItemCountLimit) {
+        // Reinsert the next item into the panel.
+        this._addViewItem(this._dataItems[this.kItemCountLimit - 1], false);
+      }
+    }
 
     this._itemCountChanged();
   },
 
   /**
    * Returns the view item associated with the provided data item for this view.
    *
    * @param aDataItem
    *        DownloadsDataItem object for which the view item is requested.
    *
    * @return Object that can be used to notify item status events.
    */
   getViewItem: function DV_getViewItem(aDataItem)
   {
-    return this._viewItems[aDataItem.downloadId];
+    // If the item is visible, just return it, otherwise return a mock object
+    // that doesn't react to notifications.
+    if (aDataItem.downloadId in this._viewItems) {
+      return this._viewItems[aDataItem.downloadId];
+    }
+    return this._invisibleViewItem;
+  },
+
+  /**
+   * Mock DownloadsDataItem object that doesn't react to notifications.
+   */
+  _invisibleViewItem: Object.freeze({
+    onStateChange: function () { },
+    onProgressChange: function () { }
+  }),
+
+  /**
+   * Creates a new view item associated with the specified data item, and adds
+   * it to the top or the bottom of the list.
+   */
+  _addViewItem: function DV_addViewItem(aDataItem, aNewest)
+  {
+    let element = document.createElement("richlistitem");
+    let viewItem = new DownloadsViewItem(aDataItem, element);
+    this._viewItems[aDataItem.downloadId] = viewItem;
+    if (aNewest) {
+      this.richListBox.insertBefore(element, this.richListBox.firstChild);
+    } else {
+      this.richListBox.appendChild(element);
+    }
+  },
+
+  /**
+   * Removes the view item associated with the specified data item.
+   */
+  _removeViewItem: function DV_removeViewItem(aDataItem)
+  {
+    let element = this.getViewItem(aDataItem)._element;
+    let previousSelectedIndex = this.richListBox.selectedIndex;
+    this.richListBox.removeChild(element);
+    this.richListBox.selectedIndex = Math.min(previousSelectedIndex,
+                                              this.richListBox.itemCount - 1);
+    delete this._viewItems[aDataItem.downloadId];
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// User interface event functions
 
   /**
    * Helper function to do commands on a specific download item.
    *
@@ -574,18 +670,19 @@ const DownloadsView = {
     while (target.nodeName != "richlistitem") {
       target = target.parentNode;
     }
     new DownloadsViewItemController(target).doCommand(aCommand);
   },
 
   onDownloadClick: function DV_onDownloadClick(aEvent)
   {
-    // Handle primary clicks only.
-    if (aEvent.button == 0) {
+    // Handle primary clicks only, and exclude the action button.
+    if (aEvent.button == 0 &&
+        !aEvent.originalTarget.hasAttribute("oncommand")) {
       goDoCommand("downloadsCmd_open");
     }
   },
 
   onDownloadKeyPress: function DV_onDownloadKeyPress(aEvent)
   {
     // Handle unmodified keys only.
     if (aEvent.altKey || aEvent.ctrlKey || aEvent.shiftKey || aEvent.metaKey) {
--- a/browser/components/downloads/content/downloadsOverlay.xul
+++ b/browser/components/downloads/content/downloadsOverlay.xul
@@ -103,14 +103,12 @@
                    flex="1"
                    context="downloadsContextMenu"
                    onkeypress="DownloadsView.onDownloadKeyPress(event);"
                    oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
                    ondragstart="DownloadsView.onDownloadDragStart(event);"/>
 
       <button id="downloadsHistory"
               class="plain"
-              label="&downloadshistory.label;"
-              accesskey="&downloadshistory.accesskey;"
               oncommand="DownloadsPanel.showDownloadsHistory();"/>
     </panel>
   </popupset>
 </overlay>
--- a/browser/components/downloads/content/indicator.js
+++ b/browser/components/downloads/content/indicator.js
@@ -48,40 +48,16 @@ const DownloadsButton = {
    * if not available because it has been removed from the toolbars.
    */
   get _placeholder()
   {
     return document.getElementById("downloads-button");
   },
 
   /**
-   * This function is called synchronously at window initialization.  It only
-   * sets the visibility of user interface elements to avoid flickering.
-   *
-   * NOTE: To keep startup time to a minimum, this function should not perform
-   *       any expensive operations or input/output, and should not cause the
-   *       Download Manager service to start.
-   */
-  initializePlaceholder: function DB_initializePlaceholder()
-  {
-    // Exit now if the feature is disabled.  To improve startup time, we don't
-    // load the DownloadsCommon module yet, but check the preference directly.
-    if (gPrefService.getBoolPref("browser.download.useToolkitUI")) {
-      return;
-    }
-
-    // We must hide the placeholder used for toolbar customization, unless it
-    // has been removed from the toolbars and is now located in the palette.
-    let placeholder = this._placeholder;
-    if (placeholder) {
-      placeholder.collapsed = true;
-    }
-  },
-
-  /**
    * This function is called asynchronously just after window initialization.
    *
    * NOTE: This function should limit the input/output it performs to improve
    *       startup time, and in particular should not cause the Download Manager
    *       service to start.
    */
   initializeIndicator: function DB_initializeIndicator()
   {
@@ -136,22 +112,18 @@ const DownloadsButton = {
    *
    * NOTE: This function is also called on startup, thus it should limit the
    *       input/output it performs, and in particular should not cause the
    *       Download Manager service to start.
    */
   _update: function DB_update() {
     this._updatePositionInternal();
 
-    let placeholder = this._placeholder;
     if (!DownloadsCommon.useToolkitUI) {
       DownloadsIndicatorView.ensureInitialized();
-      if (placeholder) {
-        placeholder.collapsed = true;
-      }
     } else {
       DownloadsIndicatorView.ensureTerminated();
     }
   },
 
   /**
    * Determines the position where the indicator should appear, and moves its
    * associated element to the new position.  This does not happen if the
@@ -176,57 +148,49 @@ const DownloadsButton = {
   {
     let indicator = DownloadsIndicatorView.indicator;
     if (!indicator) {
       // Exit now if the indicator overlay isn't loaded yet.
       return null;
     }
 
     let placeholder = this._placeholder;
-
-    // Firstly, determine if we should always hide the indicator.
-    if (!placeholder && !this._anchorRequested &&
-        !DownloadsIndicatorView.hasDownloads) {
+    if (!placeholder) {
+      // The placeholder has been removed from the browser window.
       indicator.collapsed = true;
       return null;
     }
+
+    // Position the indicator where the placeholder is located.  We should
+    // update the position even if the placeholder is located on an invisible
+    // toolbar, because the toolbar may be displayed later.
+    placeholder.parentNode.insertBefore(indicator, placeholder);
+    placeholder.collapsed = true;
     indicator.collapsed = false;
 
     indicator.open = this._anchorRequested;
 
-    // Determine if we should display the indicator in a known position.
-    if (placeholder) {
-      placeholder.parentNode.insertBefore(indicator, placeholder);
-      // Determine if the placeholder is located on a visible toolbar.
-      if (isElementVisible(placeholder.parentNode)) {
-        return DownloadsIndicatorView.indicatorAnchor;
-      }
-    }
-
-    // If not customized, the indicator is normally in the navigation bar.
-    // Always place it in the default position, unless we need an anchor.
-    if (!this._anchorRequested) {
-      this._navBar.appendChild(indicator);
+    // Determine if the placeholder is located on an invisible toolbar.
+    if (!isElementVisible(placeholder.parentNode)) {
       return null;
     }
 
-    // Show the indicator temporarily in the navigation bar, if visible.
-    if (isElementVisible(this._navBar)) {
-      this._navBar.appendChild(indicator);
-      return DownloadsIndicatorView.indicatorAnchor;
-    }
+    return DownloadsIndicatorView.indicatorAnchor;
+  },
 
-    // Show the indicator temporarily in the tab bar, if visible.
-    if (!this._tabsToolbar.collapsed) {
-      this._tabsToolbar.appendChild(indicator);
-      return DownloadsIndicatorView.indicatorAnchor;
+  /**
+   * Indicates whether the indicator is visible in the browser window.
+   */
+  get isVisible()
+  {
+    if (!this._placeholder) {
+      return false;
     }
-
-    // The temporary anchor cannot be shown.
-    return null;
+    let element = DownloadsIndicatorView.indicator || this._placeholder;
+    return isElementVisible(element.parentNode);
   },
 
   /**
    * Indicates whether we should try and show the indicator temporarily as an
    * anchor for the panel, even if the indicator would be hidden by default.
    */
   _anchorRequested: false,
 
@@ -379,16 +343,20 @@ const DownloadsIndicatorView = {
       return;
     }
 
     function DIV_SEN_callback() {
       if (this._notificationTimeout) {
         clearTimeout(this._notificationTimeout);
       }
 
+      // Now that the overlay is loaded, place the indicator in its final
+      // position.
+      DownloadsButton.updatePosition();
+
       let indicator = this.indicator;
       indicator.setAttribute("notification", "true");
       this._notificationTimeout = setTimeout(
         function () indicator.removeAttribute("notification"), 1000);
     }
 
     this._ensureOperational(DIV_SEN_callback.bind(this));
   },
@@ -525,17 +493,17 @@ const DownloadsIndicatorView = {
 
   onCommand: function DIV_onCommand(aEvent)
   {
     if (DownloadsCommon.useToolkitUI) {
       // The panel won't suppress attention for us, we need to clear now.
       DownloadsCommon.indicatorData.attention = false;
     }
 
-    BrowserDownloadsUI();
+    DownloadsPanel.showPanel();
 
     aEvent.stopPropagation();
   },
 
   onDragOver: function DIV_onDragOver(aEvent)
   {
     browserDragAndDrop.dragOver(aEvent);
   },
--- a/browser/components/downloads/src/DownloadsCommon.jsm
+++ b/browser/components/downloads/src/DownloadsCommon.jsm
@@ -47,16 +47,18 @@ const Cr = Components.results;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gBrowserGlue",
                                    "@mozilla.org/browser/browserglue;1",
                                    "nsIBrowserGlue");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
 
 const nsIDM = Ci.nsIDownloadManager;
 
 const kDownloadsStringBundleUrl =
   "chrome://browser/locale/downloads/downloads.properties";
 
 const kDownloadsStringsRequiringFormatting = {
   sizeWithUnits: true,
@@ -64,16 +66,20 @@ const kDownloadsStringsRequiringFormatti
   shortTimeLeftMinutes: true,
   shortTimeLeftHours: true,
   shortTimeLeftDays: true,
   statusSeparator: true,
   statusSeparatorBeforeNumber: true,
   fileExecutableSecurityWarning: true
 };
 
+const kDownloadsStringsRequiringPluralForm = {
+  showMoreDownloads: true
+};
+
 XPCOMUtils.defineLazyGetter(this, "DownloadsLocalFileCtor", function () {
   return Components.Constructor("@mozilla.org/file/local;1",
                                 "nsILocalFile", "initWithPath");
 });
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsCommon
 
@@ -97,16 +103,24 @@ const DownloadsCommon = {
       let stringName = string.key;
       if (stringName in kDownloadsStringsRequiringFormatting) {
         strings[stringName] = function () {
           // Convert "arguments" to a real array before calling into XPCOM.
           return sb.formatStringFromName(stringName,
                                          Array.slice(arguments, 0),
                                          arguments.length);
         };
+      } else if (stringName in kDownloadsStringsRequiringPluralForm) {
+        strings[stringName] = function (aCount) {
+          // Convert "arguments" to a real array before calling into XPCOM.
+          let formattedString = sb.formatStringFromName(stringName,
+                                         Array.slice(arguments, 0),
+                                         arguments.length);
+          return PluralForm.get(aCount, formattedString);
+        };
       } else {
         strings[stringName] = string.value;
       }
     }
     delete this.strings;
     return this.strings = strings;
   },
 
@@ -430,33 +444,36 @@ const DownloadsData = {
 
     if (aActiveOnly) {
       if (this._loadState == this.kLoadNone) {
         // Indicate to the views that a batch loading operation is in progress.
         this._views.forEach(
           function (view) view.onDataLoadStarting()
         );
 
-        // Reload the list using the Download Manager service.
+        // Reload the list using the Download Manager service.  The list is
+        // returned in no particular order.
         let downloads = Services.downloads.activeDownloads;
         while (downloads.hasMoreElements()) {
           let download = downloads.getNext().QueryInterface(Ci.nsIDownload);
           this._getOrAddDataItem(download, true);
         }
         this._loadState = this.kLoadActive;
 
         // Indicate to the views that the batch loading operation is complete.
         this._views.forEach(
           function (view) view.onDataLoadCompleted()
         );
       }
     } else {
       if (this._loadState != this.kLoadAll) {
         // Load only the relevant columns from the downloads database.  The
-        // columns are read in the init_FromDataRow method of DownloadsDataItem.
+        // columns are read in the _initFromDataRow method of DownloadsDataItem.
+        // Order by descending download identifier so that the most recent
+        // downloads are notified first to the listening views.
         let statement = Services.downloads.DBConnection.createAsyncStatement(
           "SELECT id, target, name, source, referrer, state, "
         +        "startTime, endTime, currBytes, maxBytes "
         + "FROM moz_downloads "
         + "ORDER BY id DESC"
         );
         try {
           this