Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Wed, 29 Aug 2012 17:51:24 -0700
changeset 105678 6cd206b371761294125cb98fe9d0c11e2383795f
parent 105030 b63bb39ed1c08605128c984987bbf176dfd81999 (current diff)
parent 105677 a0240c1043eefc60f08dc3e4dd2e8a0043b0d75e (diff)
child 105829 7bf95bb092331b1db96ba9d561400fcdfb9f09d6
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
milestone18.0a1
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);