Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Wed, 18 Jul 2012 19:02:32 -0700
changeset 106612 adb60cc7b1505bc91ca1c3bb846270cfd19926cb
parent 106611 5d1128ed64af3daa90e95d18c06c06cc03dcac9f (current diff)
parent 99762 9b876829ed322df8cee0120ec5dfe0bb33670794 (diff)
child 106613 e4cf8b5d1baa6bd3579e3763ea65d24a049cab67
push id14706
push usereakhgari@mozilla.com
push dateTue, 11 Sep 2012 20:39:52 +0000
treeherdermozilla-inbound@d50bf1edaabe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
.hgtags
accessible/src/base/nsAccDocManager.h
b2g/confvars.sh
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/components/shell/src/nsWindowsShellService.cpp
browser/components/tabview/groupitems.js
browser/components/tabview/tabitems.js
browser/config/version.txt
browser/devtools/webconsole/HUDService.jsm
browser/devtools/webconsole/test/Makefile.in
browser/extensions/pdfjs/bootstrap.js
browser/extensions/pdfjs/install.rdf.in
browser/locales/en-US/chrome/browser/browser.dtd
browser/locales/en-US/chrome/browser/browser.properties
browser/locales/en-US/chrome/browser/devtools/styleinspector.properties
browser/themes/winstripe/browser.css
build/mobile/devicemanagerADB.py
build/mobile/devicemanagerSUT.py
caps/include/nsScriptSecurityManager.h
caps/src/nsScriptSecurityManager.cpp
config/milestone.txt
configure.in
content/base/public/nsContentUtils.h
content/base/src/nsAttrAndChildArray.cpp
content/base/src/nsAttrAndChildArray.h
content/base/src/nsCSPService.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.h
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
content/base/src/nsGenericElement.cpp
content/base/src/nsGkAtomList.h
content/base/src/nsMappedAttributes.cpp
content/base/src/nsMappedAttributes.h
content/base/src/nsNodeIterator.h
content/base/src/nsRange.cpp
content/base/src/nsXMLHttpRequest.h
content/canvas/src/WebGLContext.cpp
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMTouchEvent.h
content/events/src/nsEventListenerManager.cpp
content/events/src/nsEventStateManager.cpp
content/events/src/nsEventStateManager.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/html/content/src/nsTextEditorState.cpp
content/html/document/src/nsHTMLDocument.cpp
content/media/raw/Makefile.in
content/smil/nsSMILAnimationController.cpp
content/smil/nsSMILCSSProperty.cpp
content/smil/nsSMILCompositor.cpp
content/smil/nsSMILTimedElement.cpp
content/svg/content/src/DOMSVGPathSegList.cpp
content/svg/content/src/DOMSVGPointList.cpp
content/svg/content/src/SVGAnimatedPreserveAspectRatio.h
content/svg/content/src/nsSVGElement.cpp
content/svg/content/src/nsSVGElement.h
content/xbl/src/nsXBLBinding.cpp
content/xul/content/src/nsXULElement.cpp
content/xul/content/src/nsXULElement.h
docshell/base/nsDocShell.cpp
docshell/shistory/src/nsSHEntry.h
docshell/shistory/src/nsSHEntryShared.cpp
docshell/shistory/src/nsSHEntryShared.h
docshell/shistory/src/nsSHistory.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMClassInfoClasses.h
dom/base/nsDOMNavigationTiming.cpp
dom/base/nsDOMNavigationTiming.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsIScriptObjectOwner.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSTimeoutHandler.cpp
dom/base/nsWrapperCache.h
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/bindings/parser/tests/test_distinguishability.py
dom/bluetooth/BluetoothFirmware.cpp
dom/bluetooth/BluetoothFirmware.h
dom/bluetooth/BluetoothUtils.h
dom/indexedDB/CheckPermissionsHelper.h
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBObjectStore.h
dom/indexedDB/test/unit/head_idb.js
dom/interfaces/base/domstubs.idl
dom/interfaces/base/nsIDOMPerformance.idl
dom/interfaces/base/nsIDOMPerformanceNavigation.idl
dom/interfaces/base/nsIDOMPerformanceTiming.idl
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/Makefile.in
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/wifi/WifiWorker.js
dom/workers/WorkerPrivate.cpp
dom/workers/XMLHttpRequest.cpp
editor/composer/src/nsComposeTxtSrvFilter.cpp
editor/composer/src/nsComposeTxtSrvFilter.h
editor/composer/src/nsComposerCommands.cpp
editor/composer/src/nsComposerCommands.h
editor/composer/src/nsComposerCommandsUpdater.cpp
editor/composer/src/nsComposerCommandsUpdater.h
editor/composer/src/nsComposerDocumentCommands.cpp
editor/composer/src/nsComposerRegistration.cpp
editor/composer/src/nsEditingSession.cpp
editor/composer/src/nsEditingSession.h
editor/composer/src/nsEditorSpellCheck.cpp
editor/composer/src/nsEditorSpellCheck.h
editor/libeditor/base/ChangeAttributeTxn.cpp
editor/libeditor/base/ChangeAttributeTxn.h
editor/libeditor/base/ChangeCSSInlineStyleTxn.cpp
editor/libeditor/base/ChangeCSSInlineStyleTxn.h
editor/libeditor/base/CreateElementTxn.cpp
editor/libeditor/base/DeleteNodeTxn.cpp
editor/libeditor/base/DeleteRangeTxn.cpp
editor/libeditor/base/DeleteTextTxn.cpp
editor/libeditor/base/EditAggregateTxn.cpp
editor/libeditor/base/EditAggregateTxn.h
editor/libeditor/base/EditTxn.cpp
editor/libeditor/base/EditTxn.h
editor/libeditor/base/IMETextTxn.cpp
editor/libeditor/base/IMETextTxn.h
editor/libeditor/base/InsertElementTxn.cpp
editor/libeditor/base/InsertTextTxn.cpp
editor/libeditor/base/InsertTextTxn.h
editor/libeditor/base/JoinElementTxn.cpp
editor/libeditor/base/PlaceholderTxn.cpp
editor/libeditor/base/SetDocTitleTxn.cpp
editor/libeditor/base/SetDocTitleTxn.h
editor/libeditor/base/SplitElementTxn.cpp
editor/libeditor/base/nsEditRules.h
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/base/nsEditorCommands.cpp
editor/libeditor/base/nsEditorCommands.h
editor/libeditor/base/nsEditorEventListener.cpp
editor/libeditor/base/nsEditorEventListener.h
editor/libeditor/base/nsEditorUtils.cpp
editor/libeditor/base/nsEditorUtils.h
editor/libeditor/base/nsSelectionState.cpp
editor/libeditor/base/nsSelectionState.h
editor/libeditor/html/TextEditorTest.cpp
editor/libeditor/html/TypeInState.cpp
editor/libeditor/html/TypeInState.h
editor/libeditor/html/nsHTMLAbsPosition.cpp
editor/libeditor/html/nsHTMLAnonymousUtils.cpp
editor/libeditor/html/nsHTMLCSSUtils.cpp
editor/libeditor/html/nsHTMLCSSUtils.h
editor/libeditor/html/nsHTMLDataTransfer.cpp
editor/libeditor/html/nsHTMLEditRules.cpp
editor/libeditor/html/nsHTMLEditRules.h
editor/libeditor/html/nsHTMLEditUtils.cpp
editor/libeditor/html/nsHTMLEditor.cpp
editor/libeditor/html/nsHTMLEditor.h
editor/libeditor/html/nsHTMLEditorEventListener.cpp
editor/libeditor/html/nsHTMLEditorStyle.cpp
editor/libeditor/html/nsHTMLInlineTableEditor.cpp
editor/libeditor/html/nsHTMLObjectResizer.cpp
editor/libeditor/html/nsHTMLURIRefObject.cpp
editor/libeditor/html/nsTableEditor.cpp
editor/libeditor/html/nsWSRunObject.cpp
editor/libeditor/html/nsWSRunObject.h
editor/libeditor/text/nsInternetCiter.cpp
editor/libeditor/text/nsInternetCiter.h
editor/libeditor/text/nsPlaintextDataTransfer.cpp
editor/libeditor/text/nsPlaintextEditor.cpp
editor/libeditor/text/nsPlaintextEditor.h
editor/libeditor/text/nsTextEditRules.cpp
editor/libeditor/text/nsTextEditRules.h
editor/libeditor/text/nsTextEditRulesBidi.cpp
editor/libeditor/text/nsTextEditUtils.cpp
editor/libeditor/text/nsTextEditUtils.h
editor/txmgr/src/nsTransactionItem.cpp
editor/txmgr/src/nsTransactionItem.h
editor/txmgr/src/nsTransactionList.cpp
editor/txmgr/src/nsTransactionManager.cpp
editor/txmgr/src/nsTransactionManager.h
editor/txtsvc/src/nsFilteredContentIterator.cpp
editor/txtsvc/src/nsFilteredContentIterator.h
editor/txtsvc/src/nsTextServicesDocument.cpp
editor/txtsvc/src/nsTextServicesDocument.h
extensions/cookie/nsPopupWindowManager.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/layers/ImageLayers.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/basic/BasicContainerLayer.cpp
gfx/layers/basic/BasicContainerLayer.h
gfx/layers/basic/BasicImageLayer.cpp
gfx/layers/basic/BasicLayerManager.cpp
gfx/layers/basic/BasicLayers.h
gfx/layers/ipc/PLayers.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/ipc/ShadowLayersParent.cpp
gfx/layers/ipc/ShadowLayersParent.h
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/thebes/gfxFont.h
gfx/thebes/gfxPlatform.cpp
image/decoders/nsBMPDecoder.cpp
image/decoders/nsBMPDecoder.h
image/decoders/nsPNGDecoder.h
image/encoders/bmp/nsBMPEncoder.cpp
image/encoders/bmp/nsBMPEncoder.h
ipc/chromium/src/base/process_util_linux.cc
ipc/glue/GeckoChildProcessHost.cpp
js/src/Makefile.in
js/src/builtin/Eval.cpp
js/src/builtin/ParallelArray.cpp
js/src/config/milestone.txt
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/Parser.cpp
js/src/gc/Root.h
js/src/ion/CodeGenerator.cpp
js/src/ion/IonBuilder.cpp
js/src/ion/IonCaches.cpp
js/src/ion/MIRGraph.cpp
js/src/ion/MIRGraph.h
js/src/js.msg
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jsdate.cpp
js/src/jsdate.h
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsgcinlines.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jsprvtd.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jstypedarrayinlines.h
js/src/jsutil.h
js/src/jsweakmap.cpp
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastOps.cpp
js/src/methodjit/PolyIC.cpp
js/src/shell/js.cpp
js/src/tests/js1_8_5/regress/regress-667047.js
js/src/vm/ArgumentsObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/MethodGuard-inl.h
js/src/vm/MethodGuard.cpp
js/src/vm/MethodGuard.h
js/src/vm/ScopeObject-inl.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/xpconnect/idl/nsIXPConnect.idl
js/xpconnect/idl/xpccomponents.idl
js/xpconnect/public/xpc_map_end.h
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/dom_quickstubs.qsconf
js/xpconnect/src/xpcprivate.h
js/xpconnect/wrappers/CrossOriginWrapper.cpp
js/xpconnect/wrappers/CrossOriginWrapper.h
js/xpconnect/wrappers/FilteringWrapper.cpp
js/xpconnect/wrappers/WaiveXrayWrapper.cpp
js/xpconnect/wrappers/WaiveXrayWrapper.h
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/WrapperFactory.h
js/xpconnect/wrappers/XrayWrapper.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsLayoutDebugger.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/tests/Makefile.in
layout/base/tests/TestPoisonArea.cpp
layout/build/nsContentDLF.cpp
layout/build/nsContentDLF.h
layout/build/nsLayoutModule.cpp
layout/forms/nsTextControlFrame.cpp
layout/forms/nsTextControlFrame.h
layout/generic/nsBlockFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsObjectFrame.cpp
layout/generic/nsVideoFrame.cpp
layout/inspector/src/inCSSValueSearch.cpp
layout/inspector/src/inDOMUtils.cpp
layout/ipc/RenderFrameParent.cpp
layout/ipc/RenderFrameParent.h
layout/reftests/bugs/reftest.list
layout/reftests/svg/reftest.list
layout/style/CSSCalc.h
layout/style/Declaration.cpp
layout/style/nsCSSParser.cpp
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsDOMCSSDeclaration.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleAnimation.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
layout/style/test/test_transitions_per_property.html
layout/svg/base/src/SVGFELeafFrame.cpp
layout/svg/base/src/nsSVGContainerFrame.cpp
layout/svg/base/src/nsSVGForeignObjectFrame.cpp
layout/svg/base/src/nsSVGForeignObjectFrame.h
layout/svg/base/src/nsSVGGlyphFrame.cpp
layout/svg/base/src/nsSVGGradientFrame.h
layout/svg/base/src/nsSVGIntegrationUtils.cpp
layout/svg/base/src/nsSVGIntegrationUtils.h
layout/svg/base/src/nsSVGOuterSVGFrame.cpp
layout/svg/base/src/nsSVGOuterSVGFrame.h
layout/svg/base/src/nsSVGPaintServerFrame.cpp
layout/svg/base/src/nsSVGPaintServerFrame.h
layout/svg/base/src/nsSVGPatternFrame.cpp
layout/svg/base/src/nsSVGPatternFrame.h
layout/svg/base/src/nsSVGUtils.cpp
layout/tables/BasicTableLayoutStrategy.cpp
layout/tables/SpanningCellSorter.cpp
layout/tables/SpanningCellSorter.h
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/GeckoConnectivityReceiver.java
mobile/android/base/LauncherShortcuts.java.in
mobile/android/base/Makefile.in
mobile/android/base/resources/drawable-large-hdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-large-hdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-large-hdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-large-hdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-large-hdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-large-hdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-large-hdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-large-hdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-large-hdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-large-hdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-large-hdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-large-hdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-large-hdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-large-hdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-large-hdpi/menu.png
mobile/android/base/resources/drawable-large-hdpi/reader.png
mobile/android/base/resources/drawable-large-hdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-large-hdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-large-hdpi/site_security_identified.png
mobile/android/base/resources/drawable-large-hdpi/site_security_verified.png
mobile/android/base/resources/drawable-large-hdpi/tab_new.png
mobile/android/base/resources/drawable-large-hdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-large-hdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-large-hdpi/tabs_crop_expanded_normal.png
mobile/android/base/resources/drawable-large-hdpi/tabs_crop_expanded_pressed.png
mobile/android/base/resources/drawable-large-hdpi/tabs_crop_normal.png
mobile/android/base/resources/drawable-large-hdpi/tabs_crop_pressed.png
mobile/android/base/resources/drawable-large-hdpi/urlbar_stop.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_bg.xml
mobile/android/base/resources/drawable-large-mdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-large-mdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-large-mdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-large-mdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-large-mdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-large-mdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-large-mdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-large-mdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-large-mdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-large-mdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-large-mdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-large-mdpi/menu.png
mobile/android/base/resources/drawable-large-mdpi/reader.png
mobile/android/base/resources/drawable-large-mdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-large-mdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-large-mdpi/site_security_identified.png
mobile/android/base/resources/drawable-large-mdpi/site_security_verified.png
mobile/android/base/resources/drawable-large-mdpi/tab_new.png
mobile/android/base/resources/drawable-large-mdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-large-mdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-large-mdpi/tabs_crop_button.xml
mobile/android/base/resources/drawable-large-mdpi/tabs_crop_expanded_normal.png
mobile/android/base/resources/drawable-large-mdpi/tabs_crop_expanded_pressed.png
mobile/android/base/resources/drawable-large-mdpi/tabs_crop_normal.png
mobile/android/base/resources/drawable-large-mdpi/tabs_crop_pressed.png
mobile/android/base/resources/drawable-large-mdpi/tabs_level.xml
mobile/android/base/resources/drawable-large-mdpi/urlbar_stop.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_back_button_bg.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_back_button_pressed_bg.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_texture_tablet.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-large-xhdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-large-xhdpi/awesomebar_tab_center.9.png
mobile/android/base/resources/drawable-large-xhdpi/awesomebar_tab_left.9.png
mobile/android/base/resources/drawable-large-xhdpi/awesomebar_tab_right.9.png
mobile/android/base/resources/drawable-large-xhdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-large-xhdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-large-xhdpi/ic_menu_bookmark_add.png
mobile/android/base/resources/drawable-large-xhdpi/ic_menu_bookmark_remove.png
mobile/android/base/resources/drawable-large-xhdpi/ic_menu_forward.png
mobile/android/base/resources/drawable-large-xhdpi/ic_menu_reload.png
mobile/android/base/resources/drawable-large-xhdpi/menu.png
mobile/android/base/resources/drawable-large-xhdpi/reader.png
mobile/android/base/resources/drawable-large-xhdpi/remote_tabs_off.png
mobile/android/base/resources/drawable-large-xhdpi/remote_tabs_on.png
mobile/android/base/resources/drawable-large-xhdpi/site_security_identified.png
mobile/android/base/resources/drawable-large-xhdpi/site_security_verified.png
mobile/android/base/resources/drawable-large-xhdpi/tab_new.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_carat_contracted.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_carat_expanded.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_crop_expanded_normal.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_crop_expanded_pressed.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_crop_normal.png
mobile/android/base/resources/drawable-large-xhdpi/tabs_crop_pressed.png
mobile/android/base/resources/drawable-large-xhdpi/urlbar_stop.png
mobile/android/base/resources/layout-large/awesomebar_search.xml
mobile/android/base/resources/layout-large/awesomebar_tab_indicator.xml
mobile/android/base/resources/layout-large/browser_toolbar.xml
mobile/android/base/resources/layout-large/browser_toolbar_menu.xml
mobile/android/base/resources/layout-large/doorhangerpopup.xml
mobile/android/base/resources/layout-large/gecko_app.xml
mobile/android/base/resources/layout-large/remote_tabs_child.xml
mobile/android/base/resources/layout-large/remote_tabs_group.xml
mobile/android/base/resources/layout-large/site_identity_popup.xml
mobile/android/base/resources/layout-large/tabs_panel_toolbar.xml
mobile/android/base/resources/layout-large/tabs_panel_toolbar_menu.xml
mobile/android/base/resources/layout-large/tabs_row.xml
mobile/android/base/resources/menu-large-v11/gecko_menu.xml.in
mobile/android/base/resources/values-large-v14/dimens.xml
mobile/android/base/resources/values-large/dimens.xml
mobile/android/base/resources/values-large/styles.xml
mobile/android/chrome/content/browser.js
mobile/xul/confvars.sh
modules/libpref/src/init/all.js
netwerk/cache/nsDiskCacheDeviceSQL.cpp
netwerk/cache/nsDiskCacheDeviceSQL.h
netwerk/dns/nsHostResolver.cpp
netwerk/protocol/data/nsDataHandler.cpp
parser/html/nsHtml5AttributeName.h
parser/html/nsHtml5Parser.h
parser/html/nsHtml5Tokenizer.h
parser/htmlparser/public/nsIContentSink.h
parser/htmlparser/src/nsParser.cpp
services/sync/version.txt
storage/src/mozStorageConnection.cpp
testing/testsuite-targets.mk
testing/xpcshell/xpcshell.ini
toolkit/components/social/SocialProvider.jsm
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
toolkit/components/url-classifier/nsUrlClassifierStreamUpdater.h
toolkit/components/url-classifier/nsUrlClassifierUtils.h
toolkit/content/widgets/popup.xml
toolkit/mozapps/extensions/AddonRepository.jsm
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/mozapps/installer/packager.mk
uriloader/exthandler/win/nsOSHelperAppService.cpp
uriloader/prefetch/nsOfflineCacheUpdate.cpp
uriloader/prefetch/nsOfflineCacheUpdate.h
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJNI.cpp
widget/android/nsWindow.cpp
widget/android/nsWindow.h
widget/nsGUIEvent.h
widget/nsIWidget.h
widget/os2/nsWindow.cpp
widget/os2/nsWindow.h
widget/xpwidgets/PuppetWidget.cpp
widget/xpwidgets/PuppetWidget.h
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
xpcom/base/nsAutoRef.h
xpcom/components/Module.h
xpcom/glue/nsProxyRelease.h
xpcom/string/public/nsTString.h
xpcom/string/public/nsTSubstring.h
xpcom/string/public/nsTSubstringTuple.h
xpcom/string/public/nsXPCOMStrings.h
--- a/.hgtags
+++ b/.hgtags
@@ -76,8 +76,13 @@ 462c726144bc1fb45b61e774f64ac5d61b4e047c
 bbc7014db2de49e2301680d2a86be8a53108a88a AURORA_BASE_20120131
 bbc7014db2de49e2301680d2a86be8a53108a88a AURORA_BASE_20120131
 0000000000000000000000000000000000000000 AURORA_BASE_20120131
 0000000000000000000000000000000000000000 AURORA_BASE_20120131
 bbc7014db2de49e2301680d2a86be8a53108a88a AURORA_BASE_20120131
 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
--- a/accessible/src/base/RoleMap.h
+++ b/accessible/src/base/RoleMap.h
@@ -826,17 +826,17 @@ ROLE(COMBOBOX_OPTION,
      ATK_ROLE_MENU_ITEM,
      NSAccessibilityMenuItemRole,
      ROLE_SYSTEM_LISTITEM,
      ROLE_SYSTEM_LISTITEM)
 
 ROLE(IMAGE_MAP,
      "image map",
      ATK_ROLE_IMAGE,
-     NSAccessibilityImageRole,
+     NSAccessibilityUnknownRole,
      ROLE_SYSTEM_GRAPHIC,
      ROLE_SYSTEM_GRAPHIC)
 
 ROLE(OPTION,
      "listbox option",
      ATK_ROLE_LIST_ITEM,
      NSAccessibilityRowRole,
      ROLE_SYSTEM_LISTITEM,
--- a/accessible/src/base/nsAccDocManager.h
+++ b/accessible/src/base/nsAccDocManager.h
@@ -19,17 +19,17 @@ class DocAccessible;
 /**
  * Manage the document accessible life cycle.
  */
 class nsAccDocManager : public nsIWebProgressListener,
                         public nsIDOMEventListener,
                         public nsSupportsWeakReference
 {
 public:
-  virtual ~nsAccDocManager() { };
+  virtual ~nsAccDocManager() { }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIWEBPROGRESSLISTENER
   NS_DECL_NSIDOMEVENTLISTENER
 
   /**
    * Return document accessible for the given DOM node.
    */
@@ -65,17 +65,17 @@ public:
     mDocAccessibleCache.Remove(aDocument);
   }
 
 #ifdef DEBUG
   bool IsProcessingRefreshDriverNotification() const;
 #endif
 
 protected:
-  nsAccDocManager() { };
+  nsAccDocManager() { }
 
   /**
    * Initialize the manager.
    */
   bool Init();
 
   /**
    * Shutdown the manager.
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -407,17 +407,17 @@ GetClosestInterestingAccessible(id anObj
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (NSString*)role
 {
   if (!mGeckoAccessible)
     return nil;
 
-#ifdef DEBUG
+#ifdef DEBUG_A11Y
   NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(mGeckoAccessible),
                "Does not support nsIAccessibleText when it should");
 #endif
 
 #define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role) \
   case roles::geckoRole: \
     return macRole;
 
--- a/accessible/src/mac/mozHTMLAccessible.mm
+++ b/accessible/src/mac/mozHTMLAccessible.mm
@@ -87,16 +87,26 @@
     return;
 
   if ([action isEqualToString:NSAccessibilityPressAction])
     mGeckoAccessible->DoAction(0);
   else
     [super accessibilityPerformAction:action];
 }
 
+- (NSString*)customDescription
+{
+  return @"";
+}
+
+- (NSString*)value
+{
+  return @"";
+}
+
 - (NSURL*)url
 {
   if (!mGeckoAccessible || mGeckoAccessible->IsDefunct())
     return nil;
 
   nsAutoString value;
   mGeckoAccessible->Value(value);
 
--- a/accessible/tests/mochitest/events/test_focus_autocomplete.xul
+++ b/accessible/tests/mochitest/events/test_focus_autocomplete.xul
@@ -225,17 +225,17 @@
             var itemX = {}, itemY = {}, treeX = {}, treeY = {};
             accessible.getBounds(itemX, itemY, {}, {});
             tree.getBounds(treeX, treeY, {}, {});
             x = itemX.value - treeX.value;
             y = itemY.value - treeY.value;
           }
         }
 
-        synthesizeMouse(node, x + 1, y + 1, {}, targetWindow);
+        synthesizeMouseAtCenter(node, {}, targetWindow);
       }
 
       this.getID = function selectByClick_getID()
       {
         return "select by click " + prettyName(aIDFunc.call(null, aIDFuncArg));
       }
     }
 
--- a/accessible/tests/mochitest/tree/test_map.html
+++ b/accessible/tests/mochitest/tree/test_map.html
@@ -17,19 +17,19 @@
     function doTest()
     {
       // map used as imagemap, not accessible
       var accTree =
         { SECTION: [ ] };
 
       testAccessibleTree("imagemapcontainer", accTree);
 
-      // map group
+      // map group.  Imagemaps are inlines by default, so TEXT_CONTAINER.
       accTree =
-        { PARAGRAPH: [
+        { TEXT_CONTAINER: [
           { PARAGRAPH: [
             { TEXT_LEAF: [ ] },
             { LINK: [
               { TEXT_LEAF: [ ] }
             ] },
             { TEXT_LEAF: [ ] },
             { LINK: [
               { TEXT_LEAF: [ ] }
--- a/accessible/tests/mochitest/treeupdate/test_imagemap.html
+++ b/accessible/tests/mochitest/treeupdate/test_imagemap.html
@@ -422,13 +422,16 @@
   <map name="atoz_map" id="map">
     <area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#b"
           coords="17,0,30,14" alt="b" shape="rect">
   </map>
 
   <div id="container">
     <img id="imgmap" width="447" height="15"
          usemap="#atoz_map"
-         src="../letters.gif">
-  </div>
+         src="../letters.gif"><!--
+    Important: no whitespace between the <img> and the </div>, so we
+    don't end up with textframes there, because those would be reflected
+    in our accessible tree in some cases.
+    --></div>
 
 </body>
 </html>
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -240,17 +240,18 @@ pref("editor.singleLine.pasteNewlines", 
 
 // threshold where a tap becomes a drag, in 1/240" reference pixels
 // The names of the preferences are to be in sync with nsEventStateManager.cpp
 pref("ui.dragThresholdX", 25);
 pref("ui.dragThresholdY", 25);
 
 // Layers Acceleration
 pref("layers.acceleration.disabled", false);
-pref("layers.offmainthreadcomposition.enabled", false);
+pref("layers.offmainthreadcomposition.enabled", true);
+pref("layers.async-video.enabled", true);
 
 // Web Notifications
 pref("notification.feature.enabled", true);
 
 // IndexedDB
 pref("indexedDB.feature.enabled", true);
 pref("dom.indexedDB.warningQuota", 5);
 
@@ -404,16 +405,26 @@ pref("b2g.remote-js.port", 9999);
 // Handle hardware buttons in the b2g chrome package
 pref("b2g.keys.menu.enabled", true);
 
 // Screen timeout in seconds
 pref("power.screen.timeout", 60);
 
 pref("full-screen-api.enabled", true);
 
+#ifndef MOZ_WIDGET_GONK
+// If we're not actually on physical hardware, don't make the top level widget
+// fullscreen when transitioning to fullscreen. This means in emulated
+// environments (like the b2g desktop client) we won't make the client window
+// 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);
 
 //Enable/disable marionette server, set listening port
 pref("marionette.defaultPrefs.enabled", true);
 pref("marionette.defaultPrefs.port", 2828);
 
 #ifdef MOZ_UPDATER
 pref("app.update.enabled", true);
@@ -455,8 +466,14 @@ pref("media.plugins.enabled", true);
 // Disable printing (particularly, window.print())
 pref("dom.disable_window_print", true);
 
 // Disable window.showModalDialog
 pref("dom.disable_window_showModalDialog", true);
 
 // Turns on gralloc-based direct texturing for Gonk
 pref("gfx.gralloc.enabled", false);
+
+// XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging 
+pref("javascript.options.mem.log", true);
+
+// Increase mark slice time from 10ms to 30ms
+pref("javascript.options.mem.gc_incremental_slice_ms", 30);
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -42,16 +42,25 @@ var SettingsListener = {
     }));
 
     this._callbacks[name] = callback;
   }
 };
 
 SettingsListener.init();
 
+// =================== Audio ====================
+SettingsListener.observe('audio.volume.master', 0.5, function(value) {
+  let audioManager = Services.audioManager;
+  if (!audioManager)
+    return;
+
+  audioManager.masterVolume = Math.max(0.0, Math.min(value, 1.0));
+});
+
 
 // =================== Languages ====================
 SettingsListener.observe('language.current', 'en-US', function(value) {
   Services.prefs.setCharPref('intl.accept_languages', value);
 });
 
 
 // =================== RIL ====================
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -171,69 +171,32 @@ var shell = {
     window.removeEventListener('sizemodechange', this);
     this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
 
 #ifndef MOZ_WIDGET_GONK
     delete Services.audioManager;
 #endif
   },
 
-  changeVolume: function shell_changeVolume(delta) {
-    let steps = 10;
-    try {
-      steps = Services.prefs.getIntPref("media.volume.steps");
-      if (steps <= 0)
-        steps = 1;
-    } catch(e) {}
-
-    let audioManager = Services.audioManager;
-    if (!audioManager)
-      return;
-
-    let currentVolume = audioManager.masterVolume;
-    let newStep = Math.round(steps * Math.sqrt(currentVolume)) + delta;
-    let volume = (newStep / steps) * (newStep / steps);
-
-    if (volume > 1)
-      volume = 1;
-    if (volume < 0)
-      volume = 0;
-    audioManager.masterVolume = volume;
-  },
-
   forwardKeyToContent: function shell_forwardKeyToContent(evt) {
     let content = shell.contentBrowser.contentWindow;
     let generatedEvent = content.document.createEvent('KeyboardEvent');
     generatedEvent.initKeyEvent(evt.type, true, true, evt.view, evt.ctrlKey,
                                 evt.altKey, evt.shiftKey, evt.metaKey,
                                 evt.keyCode, evt.charCode);
 
     content.document.documentElement.dispatchEvent(generatedEvent);
   },
 
   handleEvent: function shell_handleEvent(evt) {
     let content = this.contentBrowser.contentWindow;
     switch (evt.type) {
       case 'keydown':
       case 'keyup':
       case 'keypress':
-        // For debug purposes and because some of the APIs are not yet exposed
-        // to the content, let's react on some of the keyup events.
-        if (evt.type == 'keyup' && evt.eventPhase == evt.BUBBLING_PHASE) {
-          switch (evt.keyCode) {
-            case evt.DOM_VK_PAGE_DOWN:
-              this.changeVolume(-1);
-              break;
-
-            case evt.DOM_VK_PAGE_UP:
-              this.changeVolume(1);
-              break;
-          }
-        }
-
         // Redirect the HOME key to System app and stop the applications from
         // handling it.
         let rootContentEvt = (evt.target.ownerDocument.defaultView == content);
         if (!rootContentEvt && evt.eventPhase == evt.CAPTURING_PHASE &&
             evt.keyCode == evt.DOM_VK_HOME) {
           this.forwardKeyToContent(evt);
           evt.preventDefault();
           evt.stopImmediatePropagation();
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -1,16 +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=16.0a1
+MOZ_APP_VERSION=17.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
--- 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="1341001222000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1341959296000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i86" id="{45147e67-4020-47e2-8f7a-55464fb535aa}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
@@ -23,17 +23,17 @@
                   </emItem>
       <emItem  blockID="i43" id="supportaccessplugin@gmail.com">
                         </emItem>
       <emItem  blockID="i82" id="{8f42fb8b-b6f6-45de-81c0-d6d39f54f971}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i107" os="WINNT" id="{ABDE892B-13A8-4d1b-88E6-365A6E755758}">
-                        <versionRange  minVersion="0" maxVersion="15.0.4" severity="1">
+                        <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i88" id="anttoolbar@ant.com">
                         <versionRange  minVersion="2.4.6.4" maxVersion="2.4.6.4" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
                         <versionRange  minVersion="2.2" maxVersion="2.2">
@@ -210,16 +210,20 @@
       <emItem  blockID="i109" id="{392e123b-b691-4a5e-b52f-c4c1027e749c}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i60" id="youtb3@youtb3.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i111" os="WINNT" id="{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}">
+                        <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i38" id="{B7082FAA-CB62-4872-9106-E42DD88EDE45}">
                         <versionRange  minVersion="0.1" maxVersion="3.3.0.*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.7a1" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                                 <versionRange  minVersion="3.3.1" maxVersion="*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
@@ -323,17 +327,17 @@
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i77" id="{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i106" os="WINNT" id="{97E22097-9A2F-45b1-8DAF-36AD648C7EF4}">
-                        <versionRange  minVersion="0" maxVersion="15.0.4" severity="1">
+                        <versionRange  minVersion="0" maxVersion="15.0.5" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i11" id="yslow@yahoo-inc.com">
                         <versionRange  minVersion="2.0.5" maxVersion="2.0.5">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.5.7" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1179,9 +1179,9 @@ pref("pdfjs.previousHandler.preferredAct
 pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
 
 // The maximum amount of decoded image data we'll willingly keep around (we
 // might keep around more than this, but we'll try to get down to this value).
 // (This is intentionally on the high side; see bug 746055.)
 pref("image.mem.max_decoded_image_kb", 256000);
 
 // Example social provider
-pref("social.manifest.motown", "{\"origin\":\"https://motown-dev.mozillalabs.com\",\"name\":\"MoTown\",\"workerURL\":\"https://motown-dev.mozillalabs.com/social/worker.js\"}");
+pref("social.manifest.motown", "{\"origin\":\"https://motown-dev.mozillalabs.com\",\"name\":\"MoTown\",\"workerURL\":\"https://motown-dev.mozillalabs.com/social/worker.js\",\"iconURL\":\"https://motown-dev.mozillalabs.com/images/motown-icon.png\"}");
--- a/browser/base/content/aboutRobots.xhtml
+++ b/browser/base/content/aboutRobots.xhtml
@@ -44,17 +44,17 @@
     <style type="text/css"><![CDATA[
       #errorPageContainer:before {
         content: url('chrome://browser/content/aboutRobots-icon.png');
         position: absolute;
       }
 
       body[dir=rtl] #icon,
       body[dir=rtl] #errorPageContainer:before {
-        -moz-transform: scaleX(-1);
+        transform: scaleX(-1);
       }
     ]]></style>
   </head>
 
   <body dir="&locale.dir;">
 
     <!-- PAGE CONTAINER (for styling purposes only) -->
     <div id="errorPageContainer">
@@ -92,13 +92,13 @@
       <!-- Button -->
       <button id="errorTryAgain"
               label2="&robots.dontpress;"
               onclick="robotButton();">&retry.label;</button>
 
       <img src="chrome://browser/content/aboutRobots-widget-left.png"
            style="position: absolute; bottom: -12px; left: -10px;"/>
       <img src="chrome://browser/content/aboutRobots-widget-left.png"
-           style="position: absolute; bottom: -12px; right: -10px; -moz-transform: scaleX(-1);"/>
+           style="position: absolute; bottom: -12px; right: -10px; transform: scaleX(-1);"/>
     </div>
 
   </body>
 </html>
--- a/browser/base/content/abouthome/aboutHome.css
+++ b/browser/base/content/abouthome/aboutHome.css
@@ -38,16 +38,17 @@ a {
 }
 
 #topSection {
   text-align: center;
 }
 
 #brandLogo {
   height: 154px;
+  width: 154px;
   margin: 22px 0 31px;
 }
 
 #searchForm,
 #snippets {
   width: 470px;
 }
 
@@ -59,16 +60,18 @@ a {
   display: -moz-box;
   -moz-box-align: center;
   padding-top: 2px;
   -moz-padding-end: 8px;
 }
 
 #searchEngineLogo {
   display: inline-block;
+  height: 28px;
+  width: 70px;
 }
 
 #searchText {
   -moz-box-flex: 1;
   padding: 6px 8px;
   background: hsla(0,0%,100%,.9) padding-box;
   border: 1px solid;
   border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
@@ -77,17 +80,18 @@ a {
               0 1px 0 hsla(0,0%,100%,.2);
   border-radius: 2.5px 0 0 2.5px;
 }
 
 body[dir=rtl] #searchText {
   border-radius: 0 2.5px 2.5px 0;
 }
 
-#searchText:focus {
+#searchText:focus,
+#searchText[autofocus] {
   border-color: hsla(206,100%,60%,.6) hsla(206,76%,52%,.6) hsla(204,100%,40%,.6);
 }
 
 #searchSubmit {
   -moz-margin-start: -1px;
   background: -moz-linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1)) padding-box;
   padding: 0 9px;
   border: 1px solid;
@@ -101,22 +105,24 @@ body[dir=rtl] #searchText {
   transition-duration: 150ms;
 }
 
 body[dir=rtl] #searchSubmit {
   border-radius: 2.5px 0 0 2.5px;
 }
 
 #searchText:focus + #searchSubmit,
-#searchText + #searchSubmit:hover {
+#searchText + #searchSubmit:hover,
+#searchText[autofocus] + #searchSubmit {
   border-color: #59b5fc #45a3e7 #3294d5;
   color: white;
 }
 
-#searchText:focus + #searchSubmit {
+#searchText:focus + #searchSubmit,
+#searchText[autofocus] + #searchSubmit {
   background-image: -moz-linear-gradient(#4cb1ff, #1793e5);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset,
               0 0 0 1px hsla(0,0%,100%,.1) inset,
               0 1px 0 hsla(210,54%,20%,.03);
 }
 
 #searchText + #searchSubmit:hover {
   background-image: -moz-linear-gradient(#66bdff, #0d9eff);
@@ -155,16 +161,22 @@ body[dir=rtl] #defaultSnippet2 {
 }
 
 #snippets {
   display: inline-block;
   text-align: start;
   margin: 12px 0;
   color: #3c3c3c;
   font-size: 75%;
+  /* 12px is the computed font size, 15px the computed line height of the snippets
+     with Segoe UI on a default Windows 7 setup. The 15/12 multiplier approximately
+     converts em from units of font-size to units of line-height. The goal is to
+     preset the height of a three-line snippet to avoid visual moving/flickering as
+     the snippets load. */
+  min-height: -moz-calc(15/12 * 3em);
 }
 
 #launcher {
   display: -moz-box;
   -moz-box-align: center;
   -moz-box-pack: center;
   width: 100%;
   background-color: hsla(0,0%,0%,.03);
@@ -251,18 +263,19 @@ body[narrow] #restorePreviousSessionSepa
 }
 
 body[narrow] #restorePreviousSession {
   font-size: 80%;
 }
 
 .launchButton::before {
   display: block;
+  width: 32px;
   height: 32px;
-  margin-bottom: 6px;
+  margin: 0 auto 6px;
   line-height: 0; /* remove extra vertical space due to non-zero font-size */
 }
 
 #downloads::before {
   content: url("chrome://browser/content/abouthome/downloads.png");
 }
 
 #bookmarks::before {
@@ -295,17 +308,17 @@ body[narrow] #restorePreviousSession {
   width: 48px;
   display: inline-block; /* display on same line as text label */
   vertical-align: middle;
   margin-bottom: 0;
   -moz-margin-end: 8px;
 }
 
 body[dir=rtl] #restorePreviousSession::before {
-  -moz-transform: scaleX(-1);
+  transform: scaleX(-1);
 }
 
 body[narrow] #restorePreviousSession::before {
   content: url("chrome://browser/content/abouthome/restore.png");
   height: 32px;
   width: 32px;
 }
 
--- a/browser/base/content/abouthome/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -160,16 +160,25 @@ function setupSearchEngine()
 
   // Add search engine logo.
   if (gSearchEngine.image) {
     let logoElt = document.getElementById("searchEngineLogo");
     logoElt.src = gSearchEngine.image;
     logoElt.alt = gSearchEngine.name;
   }
 
+  // The "autofocus" attribute doesn't focus the form element
+  // immediately when the element is first drawn, so the
+  // attribute is also used for styling when the page first loads.
+  let searchText = document.getElementById("searchText");
+  searchText.addEventListener("blur", function searchText_onBlur() {
+    searchText.removeEventListener("blur", searchText_onBlur);
+    searchText.removeAttribute("autofocus");
+  });
+
 }
 
 function loadSnippets()
 {
   // Check last snippets update.
   let lastUpdate = localStorage["snippets-last-update"];
   let updateURL = localStorage["snippets-update-url"];
   if (updateURL && (!lastUpdate ||
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -100,16 +100,18 @@
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing" oncommand="gPrivateBrowsingUI.toggleMode();"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
+    <command id="Social:SharePage" oncommand="SocialShareButton.sharePage();"/>
+    <command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
   </commandset>
 
   <commandset id="placesCommands">
     <command id="Browser:ShowAllBookmarks"
              oncommand="PlacesCommandHook.showPlacesOrganizer('AllBookmarks');"/>
     <command id="Browser:ShowAllHistory"
              oncommand="PlacesCommandHook.showPlacesOrganizer('History');"/>
   </commandset>
@@ -332,16 +334,17 @@
     <key id="manBookmarkKb" key="&bookmarksGtkCmd.commandkey;" command="Browser:ShowAllBookmarks" modifiers="accel,shift"/>
 #endif
     <key id="viewBookmarksSidebarKb" key="&bookmarksCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
 #ifdef XP_WIN
 # Cmd+I is conventially mapped to Info on MacOS X, thus it should not be
 # overridden for other purposes there.
     <key id="viewBookmarksSidebarWinKb" key="&bookmarksWinCmd.commandkey;" command="viewBookmarksSidebar" modifiers="accel"/>
 #endif
+    <key id="sharePage" key="&sharePageCmd.commandkey;" command="Social:SharePage" modifiers="accel,shift"/>
 
 # don't use |command="Browser:Stop"|, ESC is being used to freeze animated gifs,
 # even if the stop button and menuitem are disabled (see Bug 284140)
     <key id="key_stop" keycode="VK_ESCAPE" oncommand="BrowserStop();"/>
 
 #ifdef XP_MACOSX
     <key id="key_stop_mac" modifiers="accel" key="&stopCmd.macCommandKey;" oncommand="BrowserStop();"/>
 #endif
new file mode 100644
--- /dev/null
+++ b/browser/base/content/browser-social.js
@@ -0,0 +1,256 @@
+// 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 SocialUI = {
+  // Called on delayed startup to initialize UI
+  init: function SocialUI_init() {
+    Services.obs.addObserver(this, "social:pref-changed", false);
+    Services.obs.addObserver(this, "social:ambient-notification-changed", false);
+    Services.obs.addObserver(this, "social:profile-changed", false);
+
+    Social.init(this._providerReady.bind(this));
+  },
+
+  // Called on window unload
+  uninit: function SocialUI_uninit() {
+    Services.obs.removeObserver(this, "social:pref-changed");
+    Services.obs.removeObserver(this, "social:ambient-notification-changed");
+    Services.obs.removeObserver(this, "social:profile-changed");
+  },
+
+  showProfile: function SocialUI_showProfile() {
+    if (Social.provider)
+      openUILink(Social.provider.profile.profileURL);
+  },
+
+  observe: function SocialUI_observe(subject, topic, data) {
+    switch (topic) {
+      case "social:pref-changed":
+        SocialShareButton.updateButtonHiddenState();
+        SocialToolbar.updateButtonHiddenState();
+        break;
+      case "social:ambient-notification-changed":
+        SocialToolbar.updateButton();
+        break;
+      case "social:profile-changed":
+        SocialToolbar.updateProfile();
+        break;
+    }
+  },
+
+  // Called once Social.jsm's provider has been set
+  _providerReady: function SocialUI_providerReady() {
+    SocialToolbar.init();
+    SocialShareButton.init();
+  }
+}
+
+let SocialShareButton = {
+  init: function SSB_init() {
+    this.sharePopup.hidden = false;
+    this.updateButtonHiddenState();
+
+    let profileRow = document.getElementById("editSharePopupHeader");
+    let profile = Social.provider.profile;
+    if (profile && profile.portrait && profile.displayName) {
+      profileRow.hidden = false;
+      let portrait = document.getElementById("socialUserPortrait");
+      portrait.style.listStyleImage = profile.portrait;
+      let displayName = document.getElementById("socialUserDisplayName");
+      displayName.setAttribute("label", profile.displayName);
+    } else {
+      profileRow.hidden = 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;
+  },
+
+  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();
+
+    this.sharePage();
+  },
+
+  panelShown: function SSB_panelShown(aEvent) {
+    let sharePopupOkButton = document.getElementById("editSharePopupOkButton");
+    if (sharePopupOkButton)
+      sharePopupOkButton.focus();
+  },
+
+  sharePage: function SSB_sharePage() {
+    let uri = gBrowser.currentURI;
+    if (!Social.isPageShared(uri)) {
+      Social.sharePage(uri);
+      this.updateShareState();
+    } else {
+      this.sharePopup.openPopup(this.shareButton, "bottomcenter topright");
+    }
+  },
+
+  unsharePage: function SSB_unsharePage() {
+    Social.unsharePage(gBrowser.currentURI);
+    this.updateShareState();
+    this.dismissSharePopup();
+  },
+
+  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) {
+      let statusString = currentPageShared ?
+                           gNavigatorBundle.getString("social.pageShared.label") : "";
+      status.setAttribute("value", statusString);
+    }
+
+    // Update the share button, if present
+    let shareButton = this.shareButton;
+    if (!shareButton)
+      return;
+
+    if (currentPageShared) {
+      shareButton.setAttribute("shared", "true");
+      shareButton.setAttribute("tooltiptext", gNavigatorBundle.getString("social.shareButton.sharedtooltip"));
+    } else {
+      shareButton.removeAttribute("shared");
+      shareButton.setAttribute("tooltiptext", gNavigatorBundle.getString("social.shareButton.tooltip"));
+    }
+  }
+};
+
+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);
+    
+    // handle button state
+    document.getElementById("social-statusarea-popup").addEventListener("popupshowing", function(e) {
+      document.getElementById("social-toolbar-button").setAttribute("open", "true");
+    }, false);
+    document.getElementById("social-statusarea-popup").addEventListener("popuphiding", function(e) {
+      document.getElementById("social-toolbar-button").removeAttribute("open");
+    }, false);
+
+    this.updateButton();
+    this.updateProfile();
+  },
+
+  updateButtonHiddenState: function SocialToolbar_updateButtonHiddenState() {
+    let toolbarbutton = document.getElementById("social-toolbar-button");
+    toolbarbutton.hidden = !Social.uiVisible;
+  },
+
+  updateProfile: function SocialToolbar_updateProfile() {
+    // Profile may not have been initialized yet, since it depends on a worker
+    // response. In that case we'll be called again when it's available, via
+    // social:profile-changed
+    let profile = Social.provider.profile || {};
+    let userPortrait = profile.portrait || "chrome://browser/skin/social/social.png";
+    document.getElementById("social-statusarea-user-portrait").setAttribute("src", userPortrait);
+
+    let notLoggedInLabel = document.getElementById("social-statusarea-notloggedin");
+    let userNameBtn = document.getElementById("social-statusarea-username");
+    if (profile.userName) {
+      notLoggedInLabel.hidden = true;
+      userNameBtn.hidden = false;
+      userNameBtn.label = profile.userName;
+    } else {
+      notLoggedInLabel.hidden = false;
+      userNameBtn.hidden = true;
+    }
+  },
+
+  updateButton: function SocialToolbar_updateButton() {
+    this.updateButtonHiddenState();
+
+    let provider = Social.provider;
+    // if there are no ambient icons, we collapse them in the following loop
+    let iconNames = Object.keys(provider.ambientNotificationIcons);
+    let iconBox = document.getElementById("social-status-iconbox");
+    for (var i = 0; i < iconBox.childNodes.length; i++) {
+      let iconContainer = iconBox.childNodes[i];
+      if (i > iconNames.length - 1) {
+        iconContainer.collapsed = true;
+        continue;
+      }
+
+      iconContainer.collapsed = false;
+      let icon = provider.ambientNotificationIcons[iconNames[i]];
+      let iconImage = iconContainer.firstChild;
+      let iconCounter = iconImage.nextSibling;
+
+      iconImage.setAttribute("contentPanel", icon.contentPanel);
+      iconImage.setAttribute("src", icon.iconURL);
+
+      if (iconCounter.firstChild)
+        iconCounter.removeChild(iconCounter.firstChild);
+
+      if (icon.counter) {
+        iconCounter.appendChild(document.createTextNode(icon.counter));
+        iconCounter.collapsed = false;
+      } else {
+        iconCounter.collapsed = true;
+      }
+    }
+  },
+
+  showAmbientPopup: function SocialToolbar_showAmbientPopup(iconContainer) {
+    let iconImage = iconContainer.firstChild;
+    let panel = document.getElementById("social-notification-panel");
+    let notifBrowser = document.getElementById("social-notification-browser");
+
+    panel.hidden = false;
+
+    function sizePanelToContent() {
+      // XXX Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
+      // XXX need to handle dynamic sizing
+      let doc = notifBrowser.contentDocument;
+      // XXX "notif" is an implementation detail that we should get rid of
+      // eventually
+      let body = doc.getElementById("notif") || doc.body.firstChild;
+      if (!body)
+        return;
+      let h = body.scrollHeight > 0 ? body.scrollHeight : 300;
+      notifBrowser.style.width = body.scrollWidth + "px";
+      notifBrowser.style.height = h + "px";
+    }
+
+    notifBrowser.addEventListener("DOMContentLoaded", function onload() {
+      notifBrowser.removeEventListener("DOMContentLoaded", onload);
+      sizePanelToContent();
+    });
+
+    panel.addEventListener("popuphiding", function onpopuphiding() {
+      panel.removeEventListener("popuphiding", onpopuphiding);
+      // unload the panel
+      document.getElementById("social-toolbar-button").removeAttribute("open");
+      notifBrowser.setAttribute("src", "about:blank");
+    });
+
+    notifBrowser.service = Social.provider;
+    notifBrowser.setAttribute("src", iconImage.getAttribute("contentPanel"));
+    document.getElementById("social-toolbar-button").setAttribute("open", "true");
+    panel.openPopup(iconImage, "bottomcenter topleft", 0, 0, false, false);
+  }
+}
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -136,17 +136,17 @@ let gSyncUI = {
 
   onLoginFinish: function SUI_onLoginFinish() {
     // Clear out any login failure notifications
     let title = this._stringBundle.GetStringFromName("error.login.title");
     this.clearError(title);
   },
 
   onSetupComplete: function SUI_onSetupComplete() {
-    onLoginFinish();
+    this.onLoginFinish();
   },
 
   onLoginError: function SUI_onLoginError() {
     // if login fails, any other notifications are essentially moot
     Weave.Notifications.removeAll();
 
     // if we haven't set up the client, don't show errors
     if (this._needsSetup()) {
--- a/browser/base/content/browser-tabPreviews.js
+++ b/browser/base/content/browser-tabPreviews.js
@@ -92,17 +92,16 @@ var tabPreviews = {
 
 var tabPreviewPanelHelper = {
   opening: function (host) {
     host.panel.hidden = false;
 
     var handler = this._generateHandler(host);
     host.panel.addEventListener("popupshown", handler, false);
     host.panel.addEventListener("popuphiding", handler, false);
-    host.panel.addEventListener("popuphidden", handler, false);
 
     host._prevFocus = document.commandDispatcher.focusedElement;
   },
   _generateHandler: function (host) {
     var self = this;
     return function (event) {
       if (event.target == host.panel) {
         host.panel.removeEventListener(event.type, arguments.callee, false);
@@ -125,21 +124,16 @@ var tabPreviewPanelHelper = {
       host._prevFocus = null;
     } else
       gBrowser.selectedBrowser.focus();
 
     if (host.tabToSelect) {
       gBrowser.selectedTab = host.tabToSelect;
       host.tabToSelect = null;
     }
-  },
-  _popuphidden: function (host) {
-    // Destroy the widget in order to prevent outdated content
-    // when re-opening the panel.
-    host.panel.hidden = true;
   }
 };
 
 /**
  * Ctrl-Tab panel
  */
 var ctrlTab = {
   get panel () {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -129,30 +129,37 @@ XPCOMUtils.defineLazyGetter(this, "Debug
 });
 
 XPCOMUtils.defineLazyGetter(this, "Tilt", function() {
   let tmp = {};
   Cu.import("resource:///modules/devtools/Tilt.jsm", tmp);
   return new tmp.Tilt(window);
 });
 
+XPCOMUtils.defineLazyGetter(this, "Social", function() {
+  let tmp = {};
+  Cu.import("resource:///modules/Social.jsm", tmp);
+  return tmp.Social;
+});
+
 let gInitialPages = [
   "about:blank",
   "about:newtab",
   "about:home",
   "about:privatebrowsing",
   "about:sessionrestore"
 ];
 
 #include browser-addons.js
 #include browser-feeds.js
 #include browser-fullScreen.js
 #include browser-fullZoom.js
 #include browser-places.js
 #include browser-plugins.js
+#include browser-social.js
 #include browser-tabPreviews.js
 #include browser-tabview.js
 #include browser-thumbnails.js
 
 #ifdef MOZ_SERVICES_SYNC
 #include browser-syncui.js
 #endif
 
@@ -1241,16 +1248,17 @@ var gBrowserInit = {
     Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
     Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
     Services.obs.addObserver(gFormSubmitObserver, "invalidformsubmit", false);
 
     BrowserOffline.init();
     OfflineApps.init();
     IndexedDBPromptHelper.init();
     gFormSubmitObserver.init();
+    SocialUI.init();
     AddonManager.addAddonListener(AddonsMgrListener);
 
     gBrowser.addEventListener("pageshow", function(evt) { setTimeout(pageShowEventHandlers, 0, evt); }, true);
 
     // Ensure login manager is up and running.
     Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
 
     if (mustLoadSidebar) {
@@ -1612,16 +1620,17 @@ var gBrowserInit = {
       } catch (ex) {
         Cu.reportError(ex);
       }
 
       BrowserOffline.uninit();
       OfflineApps.uninit();
       IndexedDBPromptHelper.uninit();
       AddonManager.removeAddonListener(AddonsMgrListener);
+      SocialUI.uninit();
     }
 
     // Final window teardown, do this last.
     window.XULBrowserWindow.destroy();
     window.XULBrowserWindow = null;
     window.QueryInterface(Ci.nsIInterfaceRequestor)
           .getInterface(Ci.nsIWebNavigation)
           .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
@@ -3557,16 +3566,17 @@ function BrowserToolboxCustomizeDone(aTo
   UpdateUrlbarSearchSplitterState();
   setUrlAndSearchBarWidthForConditionalForwardButton();
 
   // Update the urlbar
   if (gURLBar) {
     URLBarSetURI();
     XULBrowserWindow.asyncUpdateUI();
     PlacesStarButton.updateState();
+    SocialShareButton.updateShareState();
   }
 
   TabsInTitlebar.allowedBy("customizing-toolbars", true);
 
   // Re-enable parts of the UI we disabled during the dialog
   var menubar = document.getElementById("main-menubar");
   for (var i = 0; i < menubar.childNodes.length; ++i)
     menubar.childNodes[i].setAttribute("disabled", false);
@@ -4035,16 +4045,17 @@ var XULBrowserWindow = {
         let uri = aLocationURI;
         try {
           uri = this._uriFixup.createExposableURI(uri);
         } catch (e) {}
         URLBarSetURI(uri);
 
         // Update starring UI
         PlacesStarButton.updateState();
+        SocialShareButton.updateShareState();
       }
 
       // Show or hide browser chrome based on the whitelist
       if (this.hideChromeForLocation(location)) {
         document.documentElement.setAttribute("disablechrome", "true");
       } else {
         let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
         if (ss.getTabValue(gBrowser.selectedTab, "appOrigin"))
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -177,16 +177,72 @@
                 class="editBookmarkPanelBottomButton"
                 label="&editBookmark.done.label;"
                 default="true"
                 oncommand="StarUI.panel.hidePopup();"/>
 #endif
       </hbox>
     </panel>
 
+    <panel id="editSharePopup"
+           type="arrow"
+           orient="vertical"
+           ignorekeys="true"
+           hidden="true"
+           onpopupshown="SocialShareButton.panelShown(event);"
+           consumeoutsideclicks="true"
+           level="top">
+      <row id="editSharePopupHeader" align="center">
+        <vbox align="center">
+          <image id="socialUserPortrait" onclick="SocialUI.showProfile();"
+                 aria-label="&social.sharePopup.portrait.arialabel;"/>
+        </vbox>
+        <vbox id="editSharePopupText">
+          <button id="socialUserDisplayName"
+                  oncommand="SocialUI.showProfile();"/>
+          <spacer flex="1"/>
+          <label id="socialUserRecommendedText"
+                 value="&social.sharePopup.shared.label;"/>
+        </vbox>
+      </row>
+      <hbox id="editSharePopupBottomButtons" pack="end">
+#ifdef XP_UNIX
+        <button id="editSharePopupUndoButton"
+                class="editSharePopupBottomButton"
+                label="&social.sharePopup.undo.label;"
+                accesskey="&social.sharePopup.undo.accesskey;"
+                command="Social:UnsharePage"/>
+        <button id="editSharePopupOkButton"
+                class="editSharePopupBottomButton"
+                default="true"
+                autofocus="autofocus"
+                label="&social.sharePopup.ok.label;"
+                accesskey="&social.sharePopup.ok.accesskey;"
+                oncommand="SocialShareButton.dismissSharePopup();"/>
+#else
+        <button id="editSharePopupOkButton"
+                class="editSharePopupBottomButton"
+                default="true"
+                autofocus="autofocus"
+                label="&social.sharePopup.ok.label;"
+                accesskey="&social.sharePopup.ok.accesskey;"
+                oncommand="SocialShareButton.dismissSharePopup();"/>
+        <button id="editSharePopupUndoButton"
+                class="editSharePopupBottomButton"
+                label="&social.sharePopup.undo.label;"
+                accesskey="&social.sharePopup.undo.accesskey;"
+                command="Social:UnsharePage"/>
+#endif
+      </hbox>
+    </panel>
+
+    <panel id="social-notification-panel" type="arrow" hidden="true" noautofocus="true">
+      <browser id="social-notification-browser" type="content" flex="1"/>
+    </panel>
+
     <menupopup id="inspector-node-popup">
       <menuitem id="inspectorHTMLCopyInner"
                 label="&inspectorHTMLCopyInner.label;"
                 accesskey="&inspectorHTMLCopyInner.accesskey;"
                 command="Inspector:CopyInner"/>
       <menuitem id="inspectorHTMLCopyOuter"
                 label="&inspectorHTMLCopyOuter.label;"
                 accesskey="&inspectorHTMLCopyOuter.accesskey;"
@@ -459,16 +515,17 @@
                  autocompletesearch="urlinline history"
                  autocompletesearchparam="enable-actions"
                  autocompletepopup="PopupAutoCompleteRichResult"
                  completeselectedindex="true"
                  tabscrolling="true"
                  showcommentcolumn="true"
                  showimagecolumn="true"
                  enablehistory="true"
+                 maxrows="6"
                  newlines="stripsurroundingwhitespace"
                  oninput="gBrowser.userTypedValue = this.value;"
                  ontextentered="this.handleCommand(param);"
                  ontextreverted="return this.handleRevert();"
                  pageproxystate="invalid"
                  onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
                  onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
           <box id="notification-popup-box" hidden="true" align="center">
@@ -502,16 +559,22 @@
           </box>
           <hbox id="urlbar-icons">
             <image id="page-report-button"
                    class="urlbar-icon"
                    hidden="true"
                    tooltiptext="&pageReportIcon.tooltip;"
                    onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
 
+            <label id="share-button-status" collapsed="true" role="status"/>
+            <image id="share-button"
+                   class="urlbar-icon"
+                   hidden="true"
+                   onclick="SocialShareButton.onClick(event);"/>
+
             <image id="star-button"
                    class="urlbar-icon"
                    onclick="PlacesStarButton.onClick(event);"/>
             <image id="go-button"
                    class="urlbar-icon"
                    tooltiptext="&goEndCap.tooltip;"
                    onclick="gURLBar.handleCommand(event);"/>
           </hbox>
@@ -553,16 +616,55 @@
                      label="&homeButton.label;"
                      ondragover="homeButtonObserver.onDragOver(event)"
                      ondragenter="homeButtonObserver.onDragOver(event)"
                      ondrop="homeButtonObserver.onDrop(event)"
                      ondragexit="homeButtonObserver.onDragExit(event)"
                      onclick="BrowserGoHome(event);"
                      aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
 
+      <toolbaritem id="social-toolbar-button"
+                   class="toolbarbutton-1 chromeclass-toolbar-additional"
+                   removable="false"
+                   title="&socialToolbar.title;"
+                   hidden="true">
+        <hbox id="social-toolbar-button-box" class="social-statusarea-container">
+          <button id="social-provider-image" type="menu">
+            <menupopup id="social-statusarea-popup">
+              <hbox id="social-statusarea-user" pack="left" align="center">
+                <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>
+            </menupopup>
+          </button>
+          <hbox id="social-status-iconbox" flex="1">
+            <box class="social-notification-icon-container" collapsed="true"
+                     onclick="SocialToolbar.showAmbientPopup(this);">
+              <image class="social-notification-icon-image"/>
+              <box class="social-notification-icon-counter" collapsed="true"/>
+            </box>
+            <box class="social-notification-icon-container" collapsed="true"
+                     onclick="SocialToolbar.showAmbientPopup(this);">
+              <image class="social-notification-icon-image"/>
+              <box class="social-notification-icon-counter" collapsed="true"/>
+            </box>
+            <box class="social-notification-icon-container" collapsed="true"
+                     onclick="SocialToolbar.showAmbientPopup(this);">
+              <image class="social-notification-icon-image"/>
+              <box class="social-notification-icon-counter" collapsed="true"/>
+            </box>
+          </hbox>
+        </hbox>
+      </toolbaritem>
+
       <toolbaritem id="bookmarks-menu-button-container"
                    class="chromeclass-toolbar-additional"
                    removable="true"
                    title="&bookmarksMenuButton.label;">
         <toolbarbutton id="bookmarks-menu-button"
                        type="menu"
                        class="toolbarbutton-1"
                        label="&bookmarksMenuButton.label;"
--- a/browser/base/content/newtab/drag.js
+++ b/browser/base/content/newtab/drag.js
@@ -102,22 +102,27 @@ let gDrag = {
   },
 
   /**
    * Checks whether we're responsible for a given drag event.
    * @param aEvent The drag event to check.
    * @return Whether we should handle this drag and drop operation.
    */
   isValid: function Drag_isValid(aEvent) {
-    let dt = aEvent.dataTransfer;
-    let mimeType = "text/x-moz-url";
+    let link = gDragDataHelper.getLinkFromDragEvent(aEvent);
 
     // Check that the drag data is non-empty.
     // Can happen when dragging places folders.
-    return dt && dt.types.contains(mimeType) && dt.getData(mimeType);
+    if (!link || !link.url) {
+      return false;
+    }
+
+    // Check that we're not accepting URLs which would inherit the caller's
+    // principal (such as javascript: or data:).
+    return gLinkChecker.checkLoadURI(link.url);
   },
 
   /**
    * Initializes the drag data for the current drag operation.
    * @param aSite The site that's being dragged.
    * @param aEvent The 'dragstart' event.
    */
   _setDragData: function Drag_setDragData(aSite, aEvent) {
new file mode 100644
--- /dev/null
+++ b/browser/base/content/newtab/dragDataHelper.js
@@ -0,0 +1,22 @@
+#ifdef 0
+/* 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/. */
+#endif
+
+let gDragDataHelper = {
+  get mimeType() {
+    return "text/x-moz-url";
+  },
+
+  getLinkFromDragEvent: function DragDataHelper_getLinkFromDragEvent(aEvent) {
+    let dt = aEvent.dataTransfer;
+    if (!dt || !dt.types.contains(this.mimeType)) {
+      return null;
+    }
+
+    let data = dt.getData(this.mimeType) || "";
+    let [url, title] = data.split(/[\r\n]+/);
+    return {url: url, title: title};
+  }
+};
--- a/browser/base/content/newtab/drop.js
+++ b/browser/base/content/newtab/drop.js
@@ -85,24 +85,24 @@ let gDrop = {
     let index = aCell.index;
     let draggedSite = gDrag.draggedSite;
 
     if (draggedSite) {
       // Pin the dragged site at its new place.
       if (aCell != draggedSite.cell)
         draggedSite.pin(index);
     } else {
-      // A new link was dragged onto the grid. Create it by pinning its URL.
-      let dt = aEvent.dataTransfer;
-      let [url, title] = dt.getData("text/x-moz-url").split(/[\r\n]+/);
-      let link = {url: url, title: title};
-      gPinnedLinks.pin(link, index);
+      let link = gDragDataHelper.getLinkFromDragEvent(aEvent);
+      if (link) {
+        // A new link was dragged onto the grid. Create it by pinning its URL.
+        gPinnedLinks.pin(link, index);
 
-      // Make sure the newly added link is not blocked.
-      gBlockedLinks.unblock(link);
+        // Make sure the newly added link is not blocked.
+        gBlockedLinks.unblock(link);
+      }
     }
   },
 
   /**
    * Time a rearrange with a little delay.
    * @param aCell The drop target cell.
    */
   _delayedRearrange: function Drop_delayedRearrange(aCell) {
--- a/browser/base/content/newtab/newTab.js
+++ b/browser/base/content/newtab/newTab.js
@@ -13,16 +13,17 @@ Cu.import("resource:///modules/PageThumb
 Cu.import("resource:///modules/NewTabUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Rect",
   "resource://gre/modules/Geometry.jsm");
 
 let {
   links: gLinks,
   allPages: gAllPages,
+  linkChecker: gLinkChecker,
   pinnedLinks: gPinnedLinks,
   blockedLinks: gBlockedLinks
 } = NewTabUtils;
 
 XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
   return Services.strings.
     createBundle("chrome://browser/locale/newTab.properties");
 });
@@ -48,15 +49,16 @@ const HTML_NAMESPACE = "http://www.w3.or
 
 #include batch.js
 #include transformations.js
 #include page.js
 #include grid.js
 #include cells.js
 #include sites.js
 #include drag.js
+#include dragDataHelper.js
 #include drop.js
 #include dropTargetShim.js
 #include dropPreview.js
 #include updater.js
 
 // Everything is loaded. Initialize the New Tab Page.
 gPage.init();
--- a/browser/base/content/sync/utils.js
+++ b/browser/base/content/sync/utils.js
@@ -192,18 +192,16 @@ let gSyncUtils = {
     if (!el2)
       valid = val1.length >= Weave.MIN_PASS_LENGTH;
     else if (val1 && val1 == Weave.Identity.username)
       error = "change.password.pwSameAsUsername";
     else if (val1 && val1 == Weave.Identity.account)
       error = "change.password.pwSameAsEmail";
     else if (val1 && val1 == Weave.Identity.basicPassword)
       error = "change.password.pwSameAsPassword";
-    else if (val1 && val1 == Weave.Identity.syncKey)
-      error = "change.password.pwSameAsRecoveryKey";
     else if (val1 && val2) {
       if (val1 == val2 && val1.length >= Weave.MIN_PASS_LENGTH)
         valid = true;
       else if (val1.length < Weave.MIN_PASS_LENGTH)
         error = "change.password.tooShort";
       else if (val1 != val2)
         error = "change.password.mismatch";
     }
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3492,17 +3492,17 @@
         }
 
         ind.collapsed = false;
 
         newMargin += ind.clientWidth / 2;
         if (!ltr)
           newMargin *= -1;
 
-        ind.style.MozTransform = "translate(" + Math.round(newMargin) + "px)";
+        ind.style.transform = "translate(" + Math.round(newMargin) + "px)";
         ind.style.MozMarginStart = (-ind.clientWidth) + "px";
       ]]></handler>
 
       <handler event="drop"><![CDATA[
         var dt = event.dataTransfer;
         var dropEffect = dt.dropEffect;
         var draggedTab;
         if (dropEffect != "link") { // copy or move
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -57,16 +57,18 @@ endif
 # browser_sanitizeDialog_treeView.js is disabled until the tree view is added
 # back to the clear recent history dialog (sanitize.xul), if it ever is (bug
 # 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_FILES = \
                  head.js \
                  browser_typeAheadFind.js \
                  browser_keywordSearch.js \
                  browser_allTabsPanel.js \
                  browser_alltabslistener.js \
                  browser_bug304198.js \
                  title_test.svg \
@@ -149,16 +151,17 @@ endif
                  browser_bug710878.js \
                  browser_bug719271.js \
                  browser_bug724239.js \
                  browser_bug735471.js \
                  browser_bug743421.js \
                  browser_bug749738.js \
                  browser_bug763468.js \
                  browser_bug767836.js \
+                 browser_shareButton.js \
                  browser_canonizeURL.js \
                  browser_customize.js \
                  browser_findbarClose.js \
                  browser_homeDrop.js \
                  browser_keywordBookmarklets.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_customize_popupNotification.js \
@@ -166,17 +169,16 @@ endif
                  browser_discovery.js \
                  browser_duplicateIDs.js \
                  browser_gestureSupport.js \
                  browser_getshortcutoruri.js \
                  browser_hide_removing.js \
                  browser_overflowScroll.js \
                  browser_locationBarCommand.js \
                  browser_locationBarExternalLoad.js \
-                 browser_pageInfo.js \
                  browser_page_style_menu.js \
                  browser_pinnedTabs.js \
                  browser_plainTextLinks.js \
                  browser_pluginnotification.js \
                  browser_relatedTabs.js \
                  browser_sanitize-passwordDisabledHosts.js \
                  browser_sanitize-sitepermissions.js \
                  browser_sanitize-timespans.js \
@@ -214,17 +216,16 @@ endif
                  disablechrome.html \
                  discovery.html \
                  domplate_test.js \
                  moz.png \
                  video.ogg \
                  test_bug435035.html \
                  test_bug462673.html \
                  page_style_sample.html \
-                 feed_tab.html \
                  plugin_unknown.html \
                  plugin_test.html \
                  plugin_test2.html \
                  plugin_test3.html \
                  plugin_alternate_content.html \
                  plugin_both.html \
                  plugin_both2.html \
                  plugin_bug743421.html \
@@ -250,16 +251,17 @@ endif
                  authenticate.sjs \
                  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 \
                  $(NULL)
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _BROWSER_FILES += \
 		browser_bug462289.js \
 		$(NULL)
 else
 _BROWSER_FILES += \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_shareButton.js
@@ -0,0 +1,160 @@
+/* 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;
+
+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) {
+    tab.linkedBrowser.removeEventListener("load", tabLoad, true);
+    executeSoon(tabLoaded);
+  }, true);
+
+  // Enable the service to start
+  Services.prefs.setBoolPref(prefName, true);
+
+  registerCleanupFunction(function() {
+    Services.prefs.clearUserPref(prefName);
+    gBrowser.removeTab(tab);
+  });
+}
+
+function tabLoaded() {
+  ok(Social, "Social module loaded");
+
+  // If the UI is already active, run the test immediately, otherwise wait
+  // for initialization.
+  if (Social.provider) {
+    executeSoon(testInitial);
+  } else {
+    Services.obs.addObserver(function obs() {
+      Services.obs.removeObserver(obs, "test-social-ui-ready");
+      executeSoon(testInitial);
+    }, "test-social-ui-ready", false);
+  }
+}
+
+function testInitial() {
+  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;
+  ok(shareButton, "share button exists");
+  ok(sharePopup, "share popup exists");
+  ok(!sharePopup.hidden, "share popup is not hidden");
+
+  okButton = document.getElementById("editSharePopupOkButton");
+  undoButton = document.getElementById("editSharePopupUndoButton");
+
+  is(shareButton.hidden, false, "share button should be visible");
+
+  // 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, {});
+}
+
+function testSecondClick(nextTest) {
+  sharePopup.addEventListener("popupshown", function listener() {
+    sharePopup.removeEventListener("popupshown", listener);
+    ok(true, "popup was shown after second click");
+    executeSoon(nextTest);
+  });
+  EventUtils.synthesizeMouseAtCenter(shareButton, {});
+}
+
+function testPopupOKButton() {
+  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() {
+  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, {});
+}
+
+function testShortcut() {
+  let keyTarget = window;
+  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) {
+  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() {
+  is(document.activeElement, okButton, "ok button should be focused by default");
+  checkNextInTabOrder(undoButton, function () {
+    checkNextInTabOrder(okButton, testCloseBySpace);
+  });
+}
+
+function checkNextInTabOrder(element, next) {
+  // This particular test doesn't really apply on Mac, since buttons aren't
+  // focusable by default.
+  if (navigator.platform.indexOf("Mac") != -1) {
+    executeSoon(next);
+    return;
+  }
+
+  function listener() {
+    element.removeEventListener("focus", listener);
+    is(document.activeElement, element, element.id + " should be next in tab order");
+    executeSoon(next);
+  }
+  element.addEventListener("focus", listener);
+  // 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");
+  sharePopup.addEventListener("popuphidden", function listener() {
+    sharePopup.removeEventListener("popuphidden", listener);
+    ok(true, "space closed the share popup");
+    executeSoon(testDisable);
+  });
+  EventUtils.synthesizeKey("VK_SPACE", {});
+}
+
+function testDisable() {
+  Services.prefs.setBoolPref(prefName, false);
+  is(shareButton.hidden, true, "Share button should be hidden when pref is disabled");
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_social_toolbar.js
@@ -0,0 +1,140 @@
+/* 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 SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
+let gProvider;
+
+function test() {
+  waitForExplicitFinish();
+
+  Services.prefs.setBoolPref("social.enabled", true);
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("social.enabled");
+  });
+
+  let oldProvider;
+  function saveOldProviderAndStartTestWith(provider) {
+    oldProvider = Social.provider;
+    registerCleanupFunction(function () {
+      Social.provider = oldProvider;
+    });
+    Social.provider = gProvider = provider;
+    runTests(tests, undefined, undefined, function () {
+      SocialService.removeProvider(provider.origin, finish);
+    });
+  }
+
+  let manifest = { // normal provider
+    name: "provider 1",
+    origin: "https://example1.com",
+    workerURL: "https://example1.com/worker.js",
+    iconURL: "chrome://branding/content/icon48.png"
+  };
+  SocialService.addProvider(manifest, function(provider) {
+    // If the UI is already active, run the test immediately, otherwise wait
+    // for initialization.
+    if (Social.provider) {
+      saveOldProviderAndStartTestWith(provider);
+    } else {
+      Services.obs.addObserver(function obs() {
+        Services.obs.removeObserver(obs, "test-social-ui-ready");
+        saveOldProviderAndStartTestWith(provider);
+      }, "test-social-ui-ready", false);
+    }
+  });
+}
+
+var tests = {
+  testProfileSet: function(next) {
+    let profile = {
+      portrait: "chrome://branding/content/icon48.png",
+      userName: "trickster",
+      displayName: "Kuma Lisa",
+      profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
+    }
+    gProvider.updateUserProfile(profile);
+    // check dom values
+    let portrait = document.getElementById("social-statusarea-user-portrait").getAttribute("src");
+    is(portrait, profile.portrait, "portrait is set");
+    let userButton = document.getElementById("social-statusarea-username");
+    ok(!userButton.hidden, "username is visible");
+    is(userButton.label, profile.userName, "username is set");
+    next();
+  },
+  testAmbientNotifications: function(next) {
+    let ambience = {
+      name: "testIcon",
+      iconURL: "chrome://branding/content/icon48.png",
+      contentPanel: "about:blank",
+      counter: 42
+    };
+    gProvider.setAmbientNotification(ambience);
+
+    let statusIcons = document.getElementById("social-status-iconbox");
+    ok(!statusIcons.firstChild.collapsed, "status icon is visible");
+    ok(!statusIcons.firstChild.lastChild.collapsed, "status value is visible");
+    is(statusIcons.firstChild.lastChild.textContent, "42", "status value is correct");
+
+    ambience.counter = 0;
+    gProvider.setAmbientNotification(ambience);
+    ok(statusIcons.firstChild.lastChild.collapsed, "status value is not visible");
+    is(statusIcons.firstChild.lastChild.textContent, "", "status value is correct");
+    next();
+  },
+  testProfileUnset: function(next) {
+    gProvider.updateUserProfile({});
+    // check dom values
+    let portrait = document.getElementById("social-statusarea-user-portrait").getAttribute("src");
+    is(portrait, "chrome://browser/skin/social/social.png", "portrait is generic");
+    let userButton = document.getElementById("social-statusarea-username");
+    ok(userButton.hidden, "username is not visible");
+    let ambience = document.getElementById("social-status-iconbox").firstChild;
+    while (ambience) {
+      ok(ambience.collapsed, "ambient icon is collapsed");
+      ambience = ambience.nextSibling;
+    }
+    
+    next();
+  }
+}
+
+function runTests(tests, cbPreTest, cbPostTest, cbFinish) {
+  let testIter = Iterator(tests);
+
+  if (cbPreTest === undefined) {
+    cbPreTest = function(cb) {cb()};
+  }
+  if (cbPostTest === undefined) {
+    cbPostTest = function(cb) {cb()};
+  }
+
+  function runNextTest() {
+    let name, func;
+    try {
+      [name, func] = testIter.next();
+    } catch (err if err instanceof StopIteration) {
+      // out of items:
+      (cbFinish || finish)();
+      return;
+    }
+    // We run on a timeout as the frameworker also makes use of timeouts, so
+    // this helps keep the debug messages sane.
+    executeSoon(function() {
+      function cleanupAndRunNextTest() {
+        info("sub-test " + name + " complete");
+        cbPostTest(runNextTest);
+      }
+      cbPreTest(function() {
+        info("sub-test " + name + " starting");
+        try {
+          func.call(tests, cleanupAndRunNextTest);
+        } catch (ex) {
+          ok(false, "sub-test " + name + " failed: " + ex.toString() +"\n"+ex.stack);
+          cleanupAndRunNextTest();
+        }
+      })
+    });
+  }
+  runNextTest();
+}
--- a/browser/base/content/test/newtab/Makefile.in
+++ b/browser/base/content/test/newtab/Makefile.in
@@ -23,13 +23,14 @@ include $(topsrcdir)/config/rules.mk
 	browser_newtab_unpin.js \
 	browser_newtab_bug721442.js \
 	browser_newtab_bug722273.js \
 	browser_newtab_bug723102.js \
 	browser_newtab_bug723121.js \
 	browser_newtab_bug725996.js \
 	browser_newtab_bug734043.js \
 	browser_newtab_bug735987.js \
+	browser_newtab_bug765628.js \
 	head.js \
 	$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_bug765628.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const BAD_DRAG_DATA = "javascript:alert('h4ck0rz');\nbad stuff";
+const GOOD_DRAG_DATA = "http://example.com/#99\nsite 99";
+
+function runTests() {
+  yield setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  sendDropEvent(0, BAD_DRAG_DATA);
+  sendDropEvent(1, GOOD_DRAG_DATA);
+
+  yield whenPagesUpdated();
+  checkGrid("0,99p,1,2,3,4,5,6,7");
+}
+
+function sendDropEvent(aCellIndex, aDragData) {
+  let ifaceReq = getContentWindow().QueryInterface(Ci.nsIInterfaceRequestor);
+  let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
+
+  let event = createDragEvent("drop", aDragData);
+  windowUtils.dispatchDOMEventViaPresShell(getCell(aCellIndex).node, event, true);
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -620,18 +620,16 @@
             case "underflow":
               this._contentIsCropped = false;
               this._hideURLTooltip();
               break;
           }
         ]]></body>
       </method>
 
-      <property name="maxRows" onget="return this.popup.maxResults;"/>
-
       <property name="textValue"
                 onget="return this.value;">
         <setter>
           <![CDATA[
           try {
             val = losslessDecodeURI(makeURI(val));
           } catch (ex) { }
 
--- a/browser/branding/nightly/pref/firefox-branding.js
+++ b/browser/branding/nightly/pref/firefox-branding.js
@@ -1,21 +1,21 @@
 /* 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/. */
 
 pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/?oldversion=%OLD_VERSION%");
 pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
 // The time interval between checks for a new version (in seconds)
-pref("app.update.interval", 3600); // 1 hour
+pref("app.update.interval", 7200); // 2 hours
 // The time interval between the downloading of mar file chunks in the
 // background (in seconds)
 pref("app.update.download.backgroundInterval", 60);
-// Give the user x seconds to react before showing the big UI. default=1 hour
-pref("app.update.promptWaitTime", 3600);
+// Give the user x seconds to react before showing the big UI. default=12 hours
+pref("app.update.promptWaitTime", 43200);
 // URL user can browse to manually if for some reason all update installation
 // attempts fail.
 pref("app.update.url.manual", "http://nightly.mozilla.org/");
 // A default value for the "More information about this update" link
 // supplied in the "An update is available" page of the update wizard. 
 pref("app.update.url.details", "http://www.mozilla.org/projects/%APP%/");
 
 // Release notes and vendor URLs
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -116,25 +116,20 @@ AboutRedirector::NewChannel(nsIURI *aURI
       rv = ioService->NewChannel(nsDependentCString(kRedirMap[i].url),
                                  nsnull, nsnull, getter_AddRefs(tempChannel));
       NS_ENSURE_SUCCESS(rv, rv);
 
       tempChannel->SetOriginalURI(aURI);
 
       // Keep the page from getting unnecessary privileges unless it needs them
       if (kRedirMap[i].flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) {
-        nsCOMPtr<nsIScriptSecurityManager> securityManager =
-          do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        nsCOMPtr<nsIPrincipal> principal;
-        rv = securityManager->GetCodebasePrincipal(aURI, getter_AddRefs(principal));
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        rv = tempChannel->SetOwner(principal);
+        // Setting the owner to null means that we'll go through the normal
+        // path in GetChannelPrincipal and create a codebase principal based
+        // on the channel's originalURI
+        rv = tempChannel->SetOwner(nsnull);
         NS_ENSURE_SUCCESS(rv, rv);
       }
 
       NS_ADDREF(*result = tempChannel);
       return rv;
     }
   }
 
--- a/browser/components/downloads/content/downloadsOverlay.xul
+++ b/browser/components/downloads/content/downloadsOverlay.xul
@@ -93,16 +93,17 @@
         <menuseparator/>
 
         <menuitem command="downloadsCmd_clearList"
                   label="&cmd.clearList.label;"
                   accesskey="&cmd.clearList.accesskey;"/>
       </menupopup>
 
       <richlistbox id="downloadsListBox"
+                   style="width: &downloads.width;"
                    class="plain"
                    flex="1"
                    context="downloadsContextMenu"
                    onkeypress="DownloadsView.onDownloadKeyPress(event);"
                    oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
                    ondragstart="DownloadsView.onDownloadDragStart(event);"/>
 
       <button id="downloadsHistory"
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -1599,17 +1599,17 @@ PlacesToolbar.prototype = {
             translateX += this._rootElt.lastChild.getBoundingClientRect().right;
           else {
             translateX += this._rootElt.childNodes[dropPoint.beforeIndex]
                               .getBoundingClientRect().left;
           }
         }
       }
 
-      ind.style.MozTransform = "translate(" + Math.round(translateX) + "px)";
+      ind.style.transform = "translate(" + Math.round(translateX) + "px)";
       ind.style.MozMarginStart = (-ind.clientWidth) + "px";
       ind.collapsed = false;
 
       // Clear out old folder information.
       this._clearOverFolder();
     }
 
     aEvent.preventDefault();
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -189,29 +189,26 @@ static SETTING gDDESettings[] = {
   { MAKE_KEY_NAME1("Software\\Classes\\FirefoxURL", SOD) },
 
   // Protocol Handlers
   { MAKE_KEY_NAME1("Software\\Classes\\FTP", SOD) },
   { MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) },
   { MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) }
 };
 
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
 
 #define ONLY_SERVICE_LAUNCHING
 #include "updatehelper.h"
 #include "updatehelper.cpp"
 
 static const char *kPrefetchClearedPref =
   "app.update.service.lastVersionPrefetchCleared";
 static nsCOMPtr<nsIThread> sThread;
 #endif
-#endif
 
 nsresult
 GetHelperPath(nsAutoString& aPath)
 {
   nsresult rv;
   nsCOMPtr<nsIProperties> directoryService = 
     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -999,18 +996,16 @@ nsWindowsShellService::SetDesktopBackgro
   NS_ENSURE_SUCCESS(rv, rv);
 
   return regKey->Close();
 }
 
 nsWindowsShellService::nsWindowsShellService() : 
   mCheckedThisSession(false) 
 {
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
 
   // Check to make sure the service is installed
   PRUint32 installed = 0;
   nsCOMPtr<nsIWindowsRegKey> regKey = 
     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   if (!regKey || 
       NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
@@ -1045,38 +1040,32 @@ nsWindowsShellService::nsWindowsShellSer
   // service command.
   mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
   if (mTimer) {
     mTimer->InitWithFuncCallback(
       nsWindowsShellService::LaunchPrefetchClearCommand, 
       nsnull, CLEAR_PREFETCH_TIMEOUT_MS, nsITimer::TYPE_ONE_SHOT);
   }
 #endif
-#endif
 }
 
 nsWindowsShellService::~nsWindowsShellService()
 {
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
  if (mTimer) {
     mTimer->Cancel();
     mTimer = nsnull;
   }
   if (sThread) {
     sThread->Shutdown();
     sThread = nsnull;
   }
 #endif
-#endif
 }
 
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
 
 class ClearPrefetchEvent : public nsRunnable {
 public:
   ClearPrefetchEvent()
   {
   }
 
@@ -1089,29 +1078,26 @@ public:
     // If this command fails, it is not critical as prefetch will be cleared
     // on the next software update.
     StartServiceCommand(NS_ARRAY_LENGTH(updaterServiceArgv), 
                         updaterServiceArgv);
     return NS_OK;
   }
 };
 #endif
-#endif
 
 /**
  * For faster startup we attempt to clear the prefetch if the maintenance
  * service is installed.  Please see the definition of ClearPrefetch()
  * in toolkit/components/maintenanceservice/prefetch.cpp for more info.
  * For now the only application that gets prefetch cleaned is Firefox
  * since we have not done performance checking for other applications.
  * This is done on every update but also there is a one time operation done
  * from within the program for first time installs.
  */ 
-// See Bug 770883
-#if 0
 #if defined(MOZ_MAINTENANCE_SERVICE)
 void
 nsWindowsShellService::LaunchPrefetchClearCommand(nsITimer *aTimer, void*)
 {
   // Make sure we don't call this again from the application, it will be
   // called on each application update instead.
   nsCOMPtr<nsIPrefBranch> prefBranch;
   nsCOMPtr<nsIPrefService> prefs =
@@ -1126,17 +1112,16 @@ nsWindowsShellService::LaunchPrefetchCle
   // main thread, so start an event on another thread to handle the operation
   NS_NewThread(getter_AddRefs(sThread));
   if (sThread) {
     nsCOMPtr<nsIRunnable> prefetchEvent = new ClearPrefetchEvent();
     sThread->Dispatch(prefetchEvent, NS_DISPATCH_NORMAL);
   }
 }
 #endif
-#endif
 
 NS_IMETHODIMP
 nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication,
                                               const nsACString& aURI)
 {
   nsresult rv;
   nsCOMPtr<nsIProcess> process = 
     do_CreateInstance("@mozilla.org/process/util;1", &rv);
--- a/browser/components/tabview/groupitems.js
+++ b/browser/components/tabview/groupitems.js
@@ -614,17 +614,17 @@ GroupItem.prototype = Utils.extend(new I
       GroupItems.updateGroupCloseButtons();
     }
 
     if (this.hidden || (options && options.immediately)) {
       destroyGroup();
     } else {
       iQ(this.container).animate({
         opacity: 0,
-        "-moz-transform": "scale(.3)",
+        "transform": "scale(.3)",
       }, {
         duration: 170,
         complete: destroyGroup
       });
     }
 
     this.deleteData();
   },
@@ -636,17 +636,17 @@ GroupItem.prototype = Utils.extend(new I
     if (this._children.length > 0) {
       this._unfreezeItemSize();
       this._children.forEach(function(child) {
         iQ(child.container).hide();
       });
 
       iQ(this.container).animate({
          opacity: 0,
-         "-moz-transform": "scale(.3)",
+         "transform": "scale(.3)",
       }, {
         duration: 170,
         complete: function() {
           iQ(this).hide();
         }
       });
 
       this.droppable(false);
@@ -722,24 +722,24 @@ GroupItem.prototype = Utils.extend(new I
       UI.setActive(self);
       self._sendToSubscribers("groupShown");
     };
 
     let $container = iQ(this.container).show();
 
     if (!options || !options.immediately) {
       $container.animate({
-        "-moz-transform": "scale(1)",
+        "transform": "scale(1)",
         "opacity": 1
       }, {
         duration: 170,
         complete: finalize
       });
     } else {
-      $container.css({"-moz-transform": "none", opacity: 1});
+      $container.css({"transform": "none", opacity: 1});
       finalize();
     }
 
     GroupItems.updateGroupCloseButtons();
   },
 
   // ----------
   // Function: closeHidden
@@ -870,25 +870,25 @@ GroupItem.prototype = Utils.extend(new I
     let undoClose = iQ("<span/>")
       .addClass("close")
       .attr("title", tabviewString("groupItem.discardClosedGroup"))
       .appendTo(this.$undoContainer);
 
     this.$undoContainer.css({
       left: this.bounds.left + this.bounds.width/2 - iQ(self.$undoContainer).width()/2,
       top:  this.bounds.top + this.bounds.height/2 - iQ(self.$undoContainer).height()/2,
-      "-moz-transform": "scale(.1)",
+      "transform": "scale(.1)",
       opacity: 0
     });
     this.hidden = true;
 
     // hide group item and show undo container.
     setTimeout(function() {
       self.$undoContainer.animate({
-        "-moz-transform": "scale(1)",
+        "transform": "scale(1)",
         "opacity": 1
       }, {
         easing: "tabviewBounce",
         duration: 170,
         complete: function() {
           self._sendToSubscribers("groupHidden");
         }
       });
--- a/browser/components/tabview/items.js
+++ b/browser/components/tabview/items.js
@@ -249,17 +249,17 @@ Item.prototype = {
     return this.zIndex;
   },
 
   // ----------
   // Function: setRotation
   // Rotates the object to the given number of degrees.
   setRotation: function Item_setRotation(degrees) {
     var value = degrees ? "rotate(%deg)".replace(/%/, degrees) : null;
-    iQ(this.container).css({"-moz-transform": value});
+    iQ(this.container).css({"transform": value});
   },
 
   // ----------
   // Function: setParent
   // Sets the receiver's parent to the given <Item>.
   setParent: function Item_setParent(parent) {
     this.parent = parent;
     this.removeTrenches();
--- a/browser/components/tabview/tabitems.js
+++ b/browser/components/tabview/tabitems.js
@@ -530,17 +530,17 @@ TabItem.prototype = Utils.extend(new Ite
 
     UI.setActive(this);
     TabItems._update(this.tab, {force: true});
 
     // Zoom in!
     let tab = this.tab;
 
     function onZoomDone() {
-      $canvas.css({ '-moz-transform': null });
+      $canvas.css({ 'transform': null });
       $tabEl.removeClass("front");
 
       UI.goToTab(tab);
 
       // tab might not be selected because hideTabView() is invoked after 
       // UI.goToTab() so we need to setup everything for the gBrowser.selectedTab
       if (tab != gBrowser.selectedTab) {
         UI.onTabSelect(gBrowser.selectedTab);
@@ -558,18 +558,18 @@ TabItem.prototype = Utils.extend(new Ite
     if (animateZoom) {
       let transform = this.getZoomTransform();
       TabItems.pausePainting();
 
       if (this.parent && this.parent.expanded)
         $tabEl.removeClass("stack-trayed");
       $tabEl.addClass("front");
       $canvas
-        .css({ '-moz-transform-origin': transform.transformOrigin })
-        .animate({ '-moz-transform': transform.transform }, {
+        .css({ 'transform-origin': transform.transformOrigin })
+        .animate({ 'transform': transform.transform }, {
           duration: 230,
           easing: 'fast',
           complete: function() {
             onZoomDone();
 
             setTimeout(function() {
               TabItems.resumePainting();
             }, 0);
@@ -588,17 +588,17 @@ TabItem.prototype = Utils.extend(new Ite
   // Parameters:
   //   complete - a function to call after the zoom down animation
   zoomOut: function TabItem_zoomOut(complete) {
     let $tab = this.$container, $canvas = this.$canvas;
     var self = this;
     
     let onZoomDone = function onZoomDone() {
       $tab.removeClass("front");
-      $canvas.css("-moz-transform", null);
+      $canvas.css("transform", null);
 
       if (typeof complete == "function")
         complete();
     };
 
     UI.setActive(this);
     TabItems._update(this.tab, {force: true});
 
@@ -607,21 +607,21 @@ TabItem.prototype = Utils.extend(new Ite
     let animateZoom = gPrefBranch.getBoolPref("animate_zoom");
     if (animateZoom) {
       // The scaleCheat of 2 here is a clever way to speed up the zoom-out
       // code. See getZoomTransform() below.
       let transform = this.getZoomTransform(2);
       TabItems.pausePainting();
 
       $canvas.css({
-        '-moz-transform': transform.transform,
-        '-moz-transform-origin': transform.transformOrigin
+        'transform': transform.transform,
+        'transform-origin': transform.transformOrigin
       });
 
-      $canvas.animate({ "-moz-transform": "scale(1.0)" }, {
+      $canvas.animate({ "transform": "scale(1.0)" }, {
         duration: 300,
         easing: 'cubic-bezier', // note that this is legal easing, even without parameters
         complete: function() {
           TabItems.resumePainting();
           onZoomDone();
         }
       });
     } else {
--- a/browser/components/tabview/test/browser_tabview_bug624931.js
+++ b/browser/components/tabview/test/browser_tabview_bug624931.js
@@ -33,26 +33,26 @@ function onTabViewWindowLoaded() {
 function checkForFrontAddition(aEvent) {
   if (aEvent.attrName == "class" &&
       aEvent.target.classList.contains("front")) {
     frontChanged = true;
   }
 }
 
 function checkForTransformAddition(aEvent) {
-  if (aEvent.attrName == "style" && aEvent.target.style.MozTransform) {
+  if (aEvent.attrName == "style" && aEvent.target.style.transform) {
     transformChanged = true;
   }
 }
 
 function onTabViewHidden() {
   window.removeEventListener("tabviewhidden", onTabViewHidden, false);
 
   ok(frontChanged, "the CSS class 'front' was added while zooming in");
-  ok(transformChanged, "the CSS class '-moz-transform' was modified while " +
+  ok(transformChanged, "the CSS class 'transform' was modified while " +
      "zooming in");
 
   frontChanged = transformChanged = false;
   tab.$container[0].removeEventListener("DOMAttrModified",
                                         checkForFrontAddition, false);
   tab.$container[0].addEventListener("DOMAttrModified", checkForFrontRemoval,
                                      false);
 
--- a/browser/config/mozconfigs/macosx-universal/nightly
+++ b/browser/config/mozconfigs/macosx-universal/nightly
@@ -18,12 +18,11 @@ export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 ac_add_options --with-macbundlename-prefix=Firefox
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
-ac_add_options --with-ccache
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/macosx32/debug
+++ b/browser/config/mozconfigs/macosx32/debug
@@ -6,12 +6,11 @@ ENABLE_MARIONETTE=1
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
-ac_add_options --with-ccache
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/macosx64/debug
+++ b/browser/config/mozconfigs/macosx64/debug
@@ -11,12 +11,11 @@ mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
-ac_add_options --with-ccache
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/tooltool-manifests/linux32/clang.manifest
+++ b/browser/config/tooltool-manifests/linux32/clang.manifest
@@ -1,15 +1,17 @@
 [
-{"clang_version": "r159509"},
+{
+"clang_version": "r160364"
+},
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 74071397,
-"digest": "390e499161e8b5e91c179f3352ecbb07431e3d5a190298de7f338b48fe3807f3ddbeca72d8df39d11f89864fb1135f14500471faa741d3886b875b8e2b1d4416",
+"size": 65680370,
+"digest": "5d343ea80cb0ace0f2a1683466015679dfacd0ae5584a89f001710c6d665f9fbd757edef5b1bd440f234553f9dbad06c8d1eed74b71a3d11e04e7f4e2c929628",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -1,15 +1,17 @@
 [
-{"clang_version": "r159509"},
+{
+"clang_version": "r160364"
+},
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 72518043,
-"digest": "447dac319a8d7fa902cc065b758440bf6d4a7a98104362162fbdb0479a44d9b84c5878506f09be4398053a6ddc07935c7fb4f71e59b178073876fb5f90a45219",
+"size": 61020656,
+"digest": "822dc6f076309b1e45ef0ea77f88b9f5b73c8f1d0bb9c52147a2f99c4bdb67272442c9e89ab88bdadc94e2dead5e5cafc5ccea8211f42919b5ff9242bf2844d5",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
old mode 120000
new mode 100644
--- a/browser/config/tooltool-manifests/macosx32/clang.manifest
+++ b/browser/config/tooltool-manifests/macosx32/clang.manifest
@@ -1,1 +1,17 @@
-../macosx64/clang.manifest
\ No newline at end of file
+[
+{
+"clang_version": "r160364"
+},
+{
+"size": 47,
+"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
+"algorithm": "sha512",
+"filename": "setup.sh"
+},
+{
+"size": 54422251,
+"digest": "8208645d24ac87975a091ff66a90c20589ff8945936ed9b16ca81976c59bf1166ed9f79709698d435480774fba8ed9f9f178dc189305c86162acac8fda19830e",
+"algorithm": "sha512",
+"filename": "clang.tar.bz2"
+}
+]
--- a/browser/config/tooltool-manifests/macosx32/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx32/releng.manifest
@@ -1,1 +1,17 @@
-[]
+[
+{
+"clang_version": "r160364"
+},
+{
+"size": 47,
+"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
+"algorithm": "sha512",
+"filename": "setup.sh"
+},
+{
+"size": 54422251,
+"digest": "8208645d24ac87975a091ff66a90c20589ff8945936ed9b16ca81976c59bf1166ed9f79709698d435480774fba8ed9f9f178dc189305c86162acac8fda19830e",
+"algorithm": "sha512",
+"filename": "clang.tar.bz2"
+}
+]
--- a/browser/config/tooltool-manifests/macosx64/clang.manifest
+++ b/browser/config/tooltool-manifests/macosx64/clang.manifest
@@ -1,15 +1,17 @@
 [
-{"clang_version": "r159509"},
+{
+"clang_version": "r160364"
+},
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 63679229,
-"digest": "5257503e537b8d440b17e40aa06f0f70f1b124129c02f10e45b46ac642fc4170bfa77ae737a8bcac3ed7602ccd934a88cbe349986eb971d66a6fb553ae31f13c",
+"size": 54422251,
+"digest": "8208645d24ac87975a091ff66a90c20589ff8945936ed9b16ca81976c59bf1166ed9f79709698d435480774fba8ed9f9f178dc189305c86162acac8fda19830e",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -1,1 +1,17 @@
-[]
+[
+{
+"clang_version": "r160364"
+},
+{
+"size": 47,
+"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
+"algorithm": "sha512",
+"filename": "setup.sh"
+},
+{
+"size": 54422251,
+"digest": "8208645d24ac87975a091ff66a90c20589ff8945936ed9b16ca81976c59bf1166ed9f79709698d435480774fba8ed9f9f178dc189305c86162acac8fda19830e",
+"algorithm": "sha512",
+"filename": "clang.tar.bz2"
+}
+]
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-16.0a1
+17.0a1
--- a/browser/devtools/commandline/GcliCommands.jsm
+++ b/browser/devtools/commandline/GcliCommands.jsm
@@ -2,16 +2,19 @@
  * 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 EXPORTED_SYMBOLS = [ "GcliCommands" ];
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
+const XMLHttpRequest =
+  Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
+
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
                                   "resource:///modules/HUDService.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
@@ -21,16 +24,29 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource:///modules/devtools/LayoutHelpers.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "console",
                                   "resource:///modules/devtools/Console.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "js_beautify",
+                                  "resource:///modules/devtools/Jsbeautify.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
+  let JsDebugger = {};
+  Components.utils.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
+
+  let global = Components.utils.getGlobalForObject({});
+  JsDebugger.addDebuggerToGlobal(global);
+
+  return global.Debugger;
+});
+
 let prefSvc = "@mozilla.org/preferences-service;1";
 XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
   let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
   return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
 });
 
 Cu.import("resource:///modules/devtools/GcliTiltCommands.jsm", {});
 Cu.import("resource:///modules/devtools/GcliCookieCommands.jsm", {});
@@ -120,24 +136,26 @@ function loadCommandFile(aFile, aSandbox
 }
 
 /**
  * 'cmd' command
  */
 gcli.addCommand({
   name: "cmd",
   description: gcli.lookup("cmdDesc"),
+  hidden: true
 });
 
 /**
  * 'cmd refresh' command
  */
 gcli.addCommand({
   name: "cmd refresh",
   description: gcli.lookup("cmdRefreshDesc"),
+  hidden: true,
   exec: function Command_cmdRefresh(args, context) {
     GcliCommands.refreshAutoCommands(context.environment.chromeDocument.defaultView);
   }
 });
 
 /**
  * 'echo' command
  */
@@ -147,16 +165,17 @@ gcli.addCommand({
   params: [
     {
       name: "message",
       type: "string",
       description: gcli.lookup("echoMessageDesc")
     }
   ],
   returnType: "string",
+  hidden: true,
   exec: function Command_echo(args, context) {
     return args.message;
   }
 });
 
 
 /**
  * 'screenshot' command
@@ -276,16 +295,97 @@ gcli.addCommand({
     let source = ioService.newURI(data, "UTF8", null);
     persist.saveURI(source, null, null, null, null, file);
 
     return "Saved to " + filename;
   }
 });
 
 
+let callLogDebuggers = [];
+
+/**
+ * 'calllog' command
+ */
+gcli.addCommand({
+  name: "calllog",
+  description: gcli.lookup("calllogDesc")
+})
+
+/**
+ * 'calllog start' command
+ */
+gcli.addCommand({
+  name: "calllog start",
+  description: gcli.lookup("calllogStartDesc"),
+
+  exec: function(args, context) {
+    let contentWindow = context.environment.contentDocument.defaultView;
+
+    let dbg = new Debugger(contentWindow);
+    dbg.onEnterFrame = function(frame) {
+      // BUG 773652 -  Make the output from the GCLI calllog command nicer
+      contentWindow.console.log("Method call: " + this.callDescription(frame));
+    }.bind(this);
+
+    callLogDebuggers.push(dbg);
+
+    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab;
+    HUDService.activateHUDForContext(tab);
+
+    return gcli.lookup("calllogStartReply");
+  },
+
+  callDescription: function(frame) {
+    let name = "<anonymous>";
+    if (frame.callee.name) {
+      name = frame.callee.name;
+    }
+    else {
+      let desc = frame.callee.getOwnPropertyDescriptor("displayName");
+      if (desc && desc.value && typeof desc.value == "string") {
+        name = desc.value;
+      }
+    }
+
+    let args = frame.arguments.map(this.valueToString).join(", ");
+    return name + "(" + args + ")";
+  },
+
+  valueToString: function(value) {
+    if (typeof value !== "object" || value === null) {
+      return uneval(value);
+    }
+    return "[object " + value.class + "]";
+  }
+});
+
+/**
+ * 'calllog stop' command
+ */
+gcli.addCommand({
+  name: "calllog stop",
+  description: gcli.lookup("calllogStopDesc"),
+
+  exec: function(args, context) {
+    let numDebuggers = callLogDebuggers.length;
+    if (numDebuggers == 0) {
+      return gcli.lookup("calllogStopNoLogging");
+    }
+
+    for (let dbg of callLogDebuggers) {
+      dbg.onEnterFrame = undefined;
+    }
+    callLogDebuggers = [];
+
+    return gcli.lookupFormat("calllogStopReply", [ numDebuggers ]);
+  }
+});
+
+
 /**
  * 'console' command
  */
 gcli.addCommand({
   name: "console",
   description: gcli.lookup("consoleDesc"),
   manual: gcli.lookup("consoleManual")
 });
@@ -992,16 +1092,143 @@ gcli.addCommand({
     // been finished.
     let promise = context.createPromise();
     let types = aArgs.type == "all" ? null : [aArgs.type];
     AddonManager.getAddonsByTypes(types, list.bind(promise, aArgs.type));
     return promise;
   }
 });
 
+
+/**
+ * 'dbg' command
+ */
+gcli.addCommand({
+  name: "dbg",
+  description: gcli.lookup("dbgDesc"),
+  manual: gcli.lookup("dbgManual")
+});
+
+
+/**
+ * 'dbg interrupt' command
+ */
+gcli.addCommand({
+  name: "dbg interrupt",
+  description: gcli.lookup("dbgInterrupt"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (!thread.paused) {
+        thread.interrupt();
+      }
+    }
+  }
+});
+
+/**
+ * 'dbg continue' command
+ */
+gcli.addCommand({
+  name: "dbg continue",
+  description: gcli.lookup("dbgContinue"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.resume();
+      }
+    }
+  }
+});
+
+
+/**
+ * 'dbg step' command
+ */
+gcli.addCommand({
+  name: "dbg step",
+  description: gcli.lookup("dbgStepDesc"),
+  manual: gcli.lookup("dbgStepManual")
+});
+
+
+/**
+ * 'dbg step over' command
+ */
+gcli.addCommand({
+  name: "dbg step over",
+  description: gcli.lookup("dbgStepOverDesc"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.stepOver();
+      }
+    }
+  }
+});
+
+/**
+ * 'dbg step in' command
+ */
+gcli.addCommand({
+  name: 'dbg step in',
+  description: gcli.lookup("dbgStepInDesc"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.stepIn();
+      }
+    }
+  }
+});
+
+/**
+ * 'dbg step over' command
+ */
+gcli.addCommand({
+  name: 'dbg step out',
+  description: gcli.lookup("dbgStepOutDesc"),
+  params: [],
+  exec: function(args, context) {
+    let win = context.environment.chromeDocument.defaultView;
+    let dbg = win.DebuggerUI.getDebugger();
+
+    if (dbg) {
+      let controller = dbg.contentWindow.DebuggerController;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.stepOut();
+      }
+    }
+  }
+});
+
 // We need a list of addon names for the enable and disable commands. Because
 // getting the name list is async we do not add the commands until we have the
 // list.
 AddonManager.getAllAddons(function addonAsync(aAddons) {
   // We listen for installs to keep our addon list up to date. There is no need
   // to listen for uninstalls because uninstalled addons are simply disabled
   // until restart (to enable undo functionality).
   AddonManager.addAddonListener({
@@ -1192,8 +1419,131 @@ AddonManager.getAllAddons(function addon
         name: 'height',
         type: 'number',
         description: gcli.lookup("resizePageArgHeightDesc"),
       },
     ],
     exec: gcli_cmd_resize
   });
 })();
+
+/**
+ * jsb command.
+ */
+gcli.addCommand({
+  name: 'jsb',
+  description: gcli.lookup('jsbDesc'),
+  returnValue:'string',
+  hidden: true,
+  params: [
+    {
+      name: 'url',
+      type: 'string',
+      description: gcli.lookup('jsbUrlDesc'),
+      manual: 'The URL of the JS to prettify'
+    },
+    {
+      name: 'indentSize',
+      type: 'number',
+      description: gcli.lookup('jsbIndentSizeDesc'),
+      manual: gcli.lookup('jsbIndentSizeManual'),
+      defaultValue: 2
+    },
+    {
+      name: 'indentChar',
+      type: {
+        name: 'selection',
+        lookup: [{name: "space", value: " "}, {name: "tab", value: "\t"}]
+      },
+      description: gcli.lookup('jsbIndentCharDesc'),
+      manual: gcli.lookup('jsbIndentCharManual'),
+      defaultValue: ' ',
+    },
+    {
+      name: 'preserveNewlines',
+      type: 'boolean',
+      description: gcli.lookup('jsbPreserveNewlinesDesc'),
+      manual: gcli.lookup('jsbPreserveNewlinesManual'),
+      defaultValue: true
+    },
+    {
+      name: 'preserveMaxNewlines',
+      type: 'number',
+      description: gcli.lookup('jsbPreserveMaxNewlinesDesc'),
+      manual: gcli.lookup('jsbPreserveMaxNewlinesManual'),
+      defaultValue: -1
+    },
+    {
+      name: 'jslintHappy',
+      type: 'boolean',
+      description: gcli.lookup('jsbJslintHappyDesc'),
+      manual: gcli.lookup('jsbJslintHappyManual'),
+      defaultValue: false
+    },
+    {
+      name: 'braceStyle',
+      type: {
+        name: 'selection',
+        data: ['collapse', 'expand', 'end-expand', 'expand-strict']
+      },
+      description: gcli.lookup('jsbBraceStyleDesc'),
+      manual: gcli.lookup('jsbBraceStyleManual'),
+      defaultValue: "collapse"
+    },
+    {
+      name: 'spaceBeforeConditional',
+      type: 'boolean',
+      description: gcli.lookup('jsbSpaceBeforeConditionalDesc'),
+      manual: gcli.lookup('jsbSpaceBeforeConditionalManual'),
+      defaultValue: true
+    },
+    {
+      name: 'unescapeStrings',
+      type: 'boolean',
+      description: gcli.lookup('jsbUnescapeStringsDesc'),
+      manual: gcli.lookup('jsbUnescapeStringsManual'),
+      defaultValue: false
+    }
+  ],
+  exec: function(args, context) {
+  let opts = {
+    indent_size: args.indentSize,
+    indent_char: args.indentChar,
+    preserve_newlines: args.preserveNewlines,
+    max_preserve_newlines: args.preserveMaxNewlines == -1 ?
+                           undefined : args.preserveMaxNewlines,
+    jslint_happy: args.jslintHappy,
+    brace_style: args.braceStyle,
+    space_before_conditional: args.spaceBeforeConditional,
+    unescape_strings: args.unescapeStrings
+  }
+
+  let xhr = new XMLHttpRequest();
+
+  try {
+    xhr.open("GET", args.url, true);
+  } catch(e) {
+    return gcli.lookup('jsbInvalidURL');
+  }
+
+  let promise = context.createPromise();
+
+  xhr.onreadystatechange = function(aEvt) {
+    if (xhr.readyState == 4) {
+      if (xhr.status == 200 || xhr.status == 0) {
+        let browserDoc = context.environment.chromeDocument;
+        let browserWindow = browserDoc.defaultView;
+        let browser = browserWindow.gBrowser;
+
+        browser.selectedTab = browser.addTab("data:text/plain;base64," +
+          browserWindow.btoa(js_beautify(xhr.responseText, opts)));
+        promise.resolve();
+      }
+      else {
+        promise.resolve("Unable to load page to beautify: " + args.url + " " +
+                        xhr.status + " " + xhr.statusText);
+      }
+    };
+  }
+  xhr.send(null);
+  return promise;
+  }
+});
--- a/browser/devtools/commandline/GcliCookieCommands.jsm
+++ b/browser/devtools/commandline/GcliCookieCommands.jsm
@@ -32,19 +32,18 @@ var cookieListHtml = "" +
   "    <th>" + gcli.lookup("cookieListOutKey") + "</th>" +
   "    <th>" + gcli.lookup("cookieListOutValue") + "</th>" +
   "    <th>" + gcli.lookup("cookieListOutActions") + "</th>" +
   "  </tr>" +
   "  <tr foreach='cookie in ${cookies}'>" +
   "    <td>${cookie.key}</td>" +
   "    <td>${cookie.value}</td>" +
   "    <td>" +
-  "      <span class='gcli-out-shortcut'" +
-  "          onclick='${onclick}' ondblclick='${ondblclick}'" +
-  "          data-command='cookie set ${cookie.key}'" +
+  "      <span class='gcli-out-shortcut' onclick='${onclick}'" +
+  "          data-command='cookie set ${cookie.key} '" +
   "          >" + gcli.lookup("cookieListOutEdit") + "</span>" +
   "      <span class='gcli-out-shortcut'" +
   "          onclick='${onclick}' ondblclick='${ondblclick}'" +
   "          data-command='cookie remove ${cookie.key}'" +
   "          >" + gcli.lookup("cookieListOutRemove") + "</span>" +
   "    </td>" +
   "  </tr>" +
   "</table>" +
--- a/browser/devtools/commandline/gcli.jsm
+++ b/browser/devtools/commandline/gcli.jsm
@@ -1674,18 +1674,18 @@ exports.shutdown = function() {
  * - data: An array of strings - alternative to 'lookup' where the valid values
  *   are strings. i.e. there is no mapping between what is typed and the value
  *   that is used by the program
  * - stringifyProperty: Conversion from value to string is generally a process
  *   of looking through all the valid options for a matching value, and using
  *   the associated name. However the name maybe available directly from the
  *   value using a property lookup. Setting 'stringifyProperty' allows
  *   SelectionType to take this shortcut.
- * - cacheable : If lookup is a function, then we normally assume that
- *   the values fetched can change. Setting 'cacheable' enables internal
+ * - cacheable: If lookup is a function, then we normally assume that
+ *   the values fetched can change. Setting 'cacheable:true' enables internal
  *   caching.
  */
 function SelectionType(typeSpec) {
   if (typeSpec) {
     Object.keys(typeSpec).forEach(function(key) {
       this[key] = typeSpec[key];
     }, this);
   }
@@ -1769,58 +1769,67 @@ SelectionType.prototype._dataToLookup = 
  * @param arg The initial input to match
  * @return A trimmed array of string:value pairs
  */
 SelectionType.prototype._findPredictions = function(arg) {
   var predictions = [];
   var lookup = this.getLookup();
   var i, option;
   var maxPredictions = Conversion.maxPredictions;
+  var match = arg.text.toLowerCase();
 
   // If the arg has a suffix then we're kind of 'done'. Only an exact match
   // will do.
   if (arg.suffix.length > 0) {
     for (i = 0; i < lookup.length && predictions.length < maxPredictions; i++) {
       option = lookup[i];
       if (option.name === arg.text) {
         this._addToPredictions(predictions, option, arg);
       }
     }
 
     return predictions;
   }
 
+  // Cache lower case versions of all the option names
+  for (i = 0; i < lookup.length; i++) {
+    option = lookup[i];
+    if (option._gcliLowerName == null) {
+      option._gcliLowerName = option.name.toLowerCase();
+    }
+  }
+
   // Start with prefix matching
   for (i = 0; i < lookup.length && predictions.length < maxPredictions; i++) {
     option = lookup[i];
-    if (option.name.indexOf(arg.text) === 0) {
+    if (option._gcliLowerName.indexOf(match) === 0) {
       this._addToPredictions(predictions, option, arg);
     }
   }
 
   // Try infix matching if we get less half max matched
   if (predictions.length < (maxPredictions / 2)) {
     for (i = 0; i < lookup.length && predictions.length < maxPredictions; i++) {
       option = lookup[i];
-      if (option.name.indexOf(arg.text) !== -1) {
+      if (option._gcliLowerName.indexOf(match) !== -1) {
         if (predictions.indexOf(option) === -1) {
           this._addToPredictions(predictions, option, arg);
         }
       }
     }
   }
 
   // Try fuzzy matching if we don't get a prefix match
   if (false && predictions.length === 0) {
     var speller = new Speller();
     var names = lookup.map(function(opt) {
       return opt.name;
     });
     speller.train(names);
-    var corrected = speller.correct(arg.text);
+    var corrected = speller.correct(match);
     if (corrected) {
       lookup.forEach(function(opt) {
         if (opt.name === corrected) {
           predictions.push(opt);
         }
       }, this);
     }
   }
@@ -1847,19 +1856,18 @@ SelectionType.prototype.parse = function
   }
 
   // This is something of a hack it basically allows us to tell the
   // setting type to forget its last setting hack.
   if (this.noMatch) {
     this.noMatch();
   }
 
-  var value = predictions[0].value;
-
   if (predictions[0].name === arg.text) {
+    var value = predictions[0].value;
     return new Conversion(value, arg, Status.VALID, '', predictions);
   }
 
   return new Conversion(undefined, arg, Status.INCOMPLETE, '', predictions);
 };
 
 /**
  * For selections, up is down and black is white. It's like this, given a list
@@ -8415,17 +8423,19 @@ function getListTemplateData(args, conte
       return false;
     }
     if (!args.search && command.name.indexOf(' ') != -1) {
       // We don't show sub commands with plain 'help'
       return false;
     }
     return true;
   });
-  matchingCommands.sort();
+  matchingCommands.sort(function(c1, c2) {
+    return c1.name.localeCompare(c2.name);
+  });
 
   var heading;
   if (matchingCommands.length === 0) {
     heading = l10n.lookupFormat('helpListNone', [ args.search ]);
   }
   else if (args.search == null) {
     heading = l10n.lookup('helpListAll');
   }
@@ -8488,17 +8498,19 @@ function getManTemplateData(command, con
   };
 
   Object.defineProperty(manTemplateData, 'subcommands', {
     get: function() {
       var matching = canon.getCommands().filter(function(subcommand) {
         return subcommand.name.indexOf(command.name) === 0 &&
                 subcommand.name !== command.name;
       });
-      matching.sort();
+      matching.sort(function(c1, c2) {
+        return c1.name.localeCompare(c2.name);
+      });
       return matching;
     },
     enumerable: true
   });
 
   return manTemplateData;
 }
 
--- a/browser/devtools/commandline/test/Makefile.in
+++ b/browser/devtools/commandline/test/Makefile.in
@@ -9,33 +9,38 @@ srcdir    = @srcdir@
 VPATH     = @srcdir@
 relativesrcdir  = browser/devtools/commandline/test
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_FILES = \
   browser_gcli_addon.js \
   browser_gcli_break.js \
+  browser_gcli_calllog.js \
   browser_gcli_commands.js \
   browser_gcli_cookie.js \
+  browser_gcli_dbg.js \
   browser_gcli_edit.js \
   browser_gcli_inspect.js \
   browser_gcli_integrate.js \
+  browser_gcli_jsb.js \
   browser_gcli_pagemod_export.js \
   browser_gcli_pref.js \
   browser_gcli_responsivemode.js \
   browser_gcli_restart.js \
   browser_gcli_settings.js \
   browser_gcli_web.js \
   head.js \
   $(NULL)
 
 MOCHITEST_BROWSER_FILES += \
   browser_gcli_break.html \
   browser_gcli_inspect.html \
+  resources_dbg.html \
   resources_inpage.js \
   resources_inpage1.css \
   resources_inpage2.css \
+  resources_jsb_script.js \
   resources.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_calllog.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the calllog commands works as they should
+
+let imported = {};
+Components.utils.import("resource:///modules/HUDService.jsm", imported);
+
+const TEST_URI = "data:text/html;charset=utf-8,gcli-calllog";
+
+function test() {
+  DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
+    testCallLogStatus();
+    testCallLogExec();
+    finish();
+  });
+}
+
+function testCallLogStatus() {
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "calllog",
+    status: "ERROR"
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "calllog start",
+    status: "VALID",
+    emptyParameters: [ ]
+  });
+
+  DeveloperToolbarTest.checkInputStatus({
+    typed: "calllog start",
+    status: "VALID",
+    emptyParameters: [ ]
+  });
+}
+
+function testCallLogExec() {
+  DeveloperToolbarTest.exec({
+    typed: "calllog stop",
+    args: { },
+    outputMatch: /No call logging/,
+  });
+
+  DeveloperToolbarTest.exec({
+    typed: "calllog start",
+    args: { },
+    outputMatch: /Call logging started/,
+  });
+
+  let hud = imported.HUDService.getHudByWindow(content);
+  ok(hud.hudId in imported.HUDService.hudReferences, "console open");
+
+  DeveloperToolbarTest.exec({
+    typed: "calllog stop",
+    args: { },
+    outputMatch: /Stopped call logging/,
+  });
+
+  DeveloperToolbarTest.exec({
+    typed: "console clear",
+    args: {},
+    blankOutput: true,
+  });
+
+  let labels = hud.jsterm.outputNode.querySelectorAll(".webconsole-msg-output");
+  is(labels.length, 0, "no output in console");
+
+  DeveloperToolbarTest.exec({
+    typed: "console close",
+    args: {},
+    blankOutput: true,
+  });
+}
--- a/browser/devtools/commandline/test/browser_gcli_commands.js
+++ b/browser/devtools/commandline/test/browser_gcli_commands.js
@@ -14,21 +14,23 @@ function test() {
     testConsole(tab);
 
     imported = undefined;
     finish();
   });
 }
 
 function testEcho() {
+  /*
   DeveloperToolbarTest.exec({
     typed: "echo message",
     args: { message: "message" },
     outputMatch: /^message$/,
   });
+  */
 }
 
 function testConsole(tab) {
   DeveloperToolbarTest.exec({
     typed: "console open",
     args: {},
     blankOutput: true,
   });
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_dbg.js
@@ -0,0 +1,67 @@
+function test() {
+  const TEST_URI = TEST_BASE_HTTP + "resources_dbg.html";
+
+  DeveloperToolbarTest.test(TEST_URI, function GAT_test() {
+    let pane = DebuggerUI.toggleDebugger();
+    ok(pane, "toggleDebugger() should return a pane.");
+    let frame = pane._frame;
+
+    frame.addEventListener("Debugger:Connecting", function dbgConnected(aEvent) {
+      frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
+
+      // Wait for the initial resume...
+      aEvent.target.ownerDocument.defaultView.gClient
+          .addOneTimeListener("resumed", function() {
+
+        info("Starting tests.");
+
+        let contentDoc = content.window.document;
+        let output = contentDoc.querySelector("input[type=text]");
+        let btnDoit = contentDoc.querySelector("input[type=button]");
+
+        cmd("dbg interrupt", function() {
+          ok(true, "debugger is paused");
+          pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
+            ok(true, "debugger continued");
+            pane.contentWindow.gClient.addOneTimeListener("paused", function() {
+              cmd("dbg step in", function() {
+                cmd("dbg step in", function() {
+                  cmd("dbg step in", function() {
+                    is(output.value, "step in", "debugger stepped in");
+                    cmd("dbg step over", function() {
+                      is(output.value, "step over", "debugger stepped over");
+                      cmd("dbg step out", function() {
+                        is(output.value, "step out", "debugger stepped out");
+                        cmd("dbg continue", function() {
+                          cmd("dbg continue", function() {
+                            is(output.value, "dbg continue", "debugger continued");
+                            pane.contentWindow.gClient.close(function() {
+                              finish();
+                            });
+                          });
+                        });
+                      });
+                    });
+                  });
+                });
+              });
+            });
+            EventUtils.sendMouseEvent({type:"click"}, btnDoit);
+          });
+          DeveloperToolbarTest.exec({
+            typed: "dbg continue",
+            blankOutput: true
+          });
+        });
+      });
+
+      function cmd(aTyped, aCallback) {
+        pane.contentWindow.gClient.addOneTimeListener("paused", aCallback);
+        DeveloperToolbarTest.exec({
+          typed: aTyped,
+          blankOutput: true
+        });
+      }
+    });
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_gcli_jsb.js
@@ -0,0 +1,48 @@
+function test() {
+  const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
+                   "test/resources_jsb_script.js";
+
+  DeveloperToolbarTest.test("about:blank", function GJT_test() {
+    /* Commented out by bug 774057, re-enable with un-hidden jsb command
+    DeveloperToolbarTest.exec({
+      typed: "jsb AAA",
+      outputMatch: /valid/
+    });
+
+    gBrowser.addTabsProgressListener({
+      onProgressChange: function GJT_onProgressChange(aBrowser) {
+        gBrowser.removeTabsProgressListener(this);
+
+        let win = aBrowser._contentWindow;
+        let uri = win.document.location.href;
+        let result = win.atob(uri.replace(/.*,/, ""));
+
+        result = result.replace(/[\r\n]]/g, "\n");
+
+        checkResult(result);
+        finish();
+      }
+    });
+
+    info("Checking beautification");
+    DeveloperToolbarTest.checkInputStatus({
+      typed: "jsb " + TEST_URI + " 4 space true -1 false collapse true false",
+      status: "VALID"
+    });
+    DeveloperToolbarTest.exec({ completed: false });
+
+    function checkResult(aResult) {
+      let correct = "function somefunc() {\n" +
+                    "    for (let n = 0; n < 500; n++) {\n" +
+                    "        if (n % 2 == 1) {\n" +
+                    "            console.log(n);\n" +
+                    "            console.log(n + 1);\n" +
+                    "        }\n" +
+                    "    }\n" +
+                    "}";
+      is(aResult, correct, "JS has been correctly prettified");
+    }
+    */
+    finish();
+  });
+}
--- a/browser/devtools/commandline/test/browser_gcli_web.js
+++ b/browser/devtools/commandline/test/browser_gcli_web.js
@@ -2955,18 +2955,35 @@ exports.testCompleted = function(options
     args: {
       key: { value: 'key', status: 'VALID' },
       value: { value: 'value', status: 'VALID' },
       path: { value: 'path', status: 'VALID' },
       domain: { value: 'domain', status: 'VALID' },
       secure: { value: false, status: 'VALID' }
     }
   });
-
-  // Expand out to christmas tree command line
+};
+
+exports.testCase = function(options) {
+  helpers.setInput('tsg AA');
+  helpers.check({
+    input:  'tsg AA',
+    markup: 'VVVVII',
+    directTabText: '',
+    arrowTabText: 'aaa',
+    status: 'ERROR',
+    emptyParameters: [ ],
+    args: {
+      solo: { value: undefined, text: 'AA', status: 'INCOMPLETE' },
+      txt1: { value: undefined, status: 'VALID' },
+      bool: { value: undefined, status: 'VALID' },
+      txt2: { value: undefined, status: 'VALID' },
+      num: { value: undefined, status: 'VALID' }
+    }
+  });
 };
 
 exports.testIncomplete = function(options) {
   var requisition = options.display.requisition;
 
   helpers.setInput('tsm a a -');
   helpers.check({
     args: {
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/resources_dbg.html
@@ -0,0 +1,44 @@
+<html>
+<head>
+  <script type="application/javascript;version=1.7"/>
+    let output;
+
+    function init() {
+      output = document.querySelector("input");
+      output.value = "";
+    }
+
+    function doit() {
+      debugger;
+      stepIntoMe();             // step in
+
+      output.value = "dbg continue";
+      debugger;
+    }
+
+    function stepIntoMe() {
+      output.value = "step in";   // step in
+      stepOverMe();               // step over
+      let x = 0;                  // step out
+      output.value = "step out";
+    }
+
+    function stepOverMe() {
+      output.value = "step over";
+    }
+  </script>
+</head>
+<body onload="init()">
+  <input type="text" value=""/>
+  <input type="button" value="DOIT" onclick="doit()"/>
+  <br />
+  Use this file to test the following commands:
+  <ul>
+    <li>dbg interrupt</li>
+    <li>dbg continue</li>
+    <li>dbg step over</li>
+    <li>dbg step in</li>
+    <li>dbg step out</li>
+  </ul>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/resources_jsb_script.js
@@ -0,0 +1,1 @@
+function somefunc(){for(let n=0;n<500;n++){if(n%2==1){console.log(n);console.log(n+1);}}}
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -47,16 +47,17 @@ let DebuggerController = {
       return;
     }
     this._isInitialized = true;
     window.removeEventListener("DOMContentLoaded", this._startupDebugger, true);
 
     DebuggerView.initializePanes();
     DebuggerView.initializeEditor();
     DebuggerView.StackFrames.initialize();
+    DebuggerView.Breakpoints.initialize();
     DebuggerView.Properties.initialize();
     DebuggerView.Scripts.initialize();
     DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger);
 
     this.dispatchEvent("Debugger:Loaded");
     this._connect();
   },
 
@@ -70,16 +71,17 @@ let DebuggerController = {
     }
     this._isDestroyed = true;
     window.removeEventListener("unload", this._shutdownDebugger, true);
 
     DebuggerView.destroyPanes();
     DebuggerView.destroyEditor();
     DebuggerView.Scripts.destroy();
     DebuggerView.StackFrames.destroy();
+    DebuggerView.Breakpoints.destroy();
     DebuggerView.Properties.destroy();
 
     DebuggerController.Breakpoints.destroy();
     DebuggerController.SourceScripts.disconnect();
     DebuggerController.StackFrames.disconnect();
     DebuggerController.ThreadState.disconnect();
 
     this.dispatchEvent("Debugger:Unloaded");
@@ -108,18 +110,18 @@ let DebuggerController = {
       let prompt = new RemoteDebuggerPrompt();
       let result = prompt.show(!!this._remoteConnectionTimeout);
       // If the connection was not established before the user canceled the
       // prompt, close the remote debugger.
       if (!result && !DebuggerController.activeThread) {
         this.dispatchEvent("Debugger:Close");
         return false;
       }
-      Prefs.remoteHost = prompt.uri.host;
-      Prefs.remotePort = prompt.uri.port;
+      Prefs.remoteHost = prompt.remote.host;
+      Prefs.remotePort = prompt.remote.port;
     }
 
     // If this debugger is connecting remotely to a server, we need to check
     // after a while if the connection actually succeeded.
     this._remoteConnectionTry = ++this._remoteConnectionTry || 1;
     this._remoteConnectionTimeout = window.setTimeout(function() {
       // If we couldn't connect to any server yet, try again...
       if (!DebuggerController.activeThread) {
@@ -255,17 +257,18 @@ let DebuggerController = {
     return window._remoteFlag;
   },
 
   /**
    * Returns true if this is a chrome debugger instance.
    * @return boolean
    */
   get _isChromeDebugger() {
-    return !window.parent.content && !this._isRemoteDebugger;
+    // Directly accessing window.parent.content may throw in some cases.
+    return !("content" in window.parent) && !this._isRemoteDebugger;
   },
 
   /**
    * Attempts to quit the current process if allowed.
    */
   _quitApp: function DC__quitApp() {
     let canceled = Cc["@mozilla.org/supports-PRBool;1"]
       .createInstance(Ci.nsISupportsPRBool);
@@ -389,18 +392,16 @@ StackFrames.prototype = {
    * Watch the given thread client.
    *
    * @param function aCallback
    *        The next function in the initialization sequence.
    */
   connect: function SF_connect(aCallback) {
     window.addEventListener("Debugger:FetchedVariables", this._onFetchedVars, false);
 
-    this._onFramesCleared();
-
     this.activeThread.addListener("paused", this._onPaused);
     this.activeThread.addListener("resumed", this._onResume);
     this.activeThread.addListener("framesadded", this._onFrames);
     this.activeThread.addListener("framescleared", this._onFramesCleared);
 
     this.updatePauseOnExceptions(this.pauseOnExceptions);
 
     aCallback && aCallback();
@@ -500,22 +501,57 @@ StackFrames.prototype = {
     if (!frame) {
       return;
     }
 
     let url = frame.where.url;
     let line = frame.where.line;
     let editor = DebuggerView.editor;
 
-    // Move the editor's caret to the proper line.
-    if (DebuggerView.Scripts.isSelected(url) && line) {
-      editor.setDebugLocation(line - 1);
-    } else {
-      editor.setDebugLocation(-1);
+    this.updateEditorToLocation(url, line, true);
+  },
+
+  /**
+   * Update the source editor's current caret and debug location based on
+   * a specified url and line.
+   *
+   * @param string aUrl
+   *        The target source url.
+   * @param number aLine
+   *        The target line number in the source.
+   * @param boolean aNoSwitch
+   *        Pass true to not switch to the script if not currently selected.
+   * @param boolean aNoCaretFlag
+   *        Pass true to not set the caret location at the specified line.
+   * @param boolean aNoDebugFlag
+   *        Pass true to not set the debug location at the specified line.
+   */
+  updateEditorToLocation:
+  function SF_updateEditorToLocation(aUrl, aLine, aNoSwitch, aNoCaretFlag, aNoDebugFlag) {
+    let editor = DebuggerView.editor;
+
+    function set() {
+      if (!aNoCaretFlag) {
+        editor.setCaretPosition(aLine - 1);
+      }
+      if (!aNoDebugFlag) {
+        editor.setDebugLocation(aLine - 1);
+      }
     }
+
+    // Move the editor's caret to the proper url and line.
+    if (DebuggerView.Scripts.isSelected(aUrl)) {
+      return set();
+    }
+    if (!aNoSwitch && DebuggerView.Scripts.contains(aUrl)) {
+      DebuggerView.Scripts.selectScript(aUrl);
+      return set();
+    }
+    editor.setCaretPosition(-1);
+    editor.setDebugLocation(-1);
   },
 
   /**
    * Inform the debugger client whether the debuggee should be paused whenever
    * an exception is thrown.
    *
    * @param boolean aFlag
    *        The new value of the flag: true for pausing, false otherwise.
@@ -544,30 +580,19 @@ StackFrames.prototype = {
 
     let frame = this.activeThread.cachedFrames[aDepth];
     if (!frame) {
       return;
     }
 
     let url = frame.where.url;
     let line = frame.where.line;
-    let editor = DebuggerView.editor;
 
     // Move the editor's caret to the proper line.
-    if (DebuggerView.Scripts.isSelected(url) && line) {
-      editor.setCaretPosition(line - 1);
-      editor.setDebugLocation(line - 1);
-    }
-    else if (DebuggerView.Scripts.contains(url)) {
-      DebuggerView.Scripts.selectScript(url);
-      editor.setCaretPosition(line - 1);
-    }
-    else {
-      editor.setDebugLocation(-1);
-    }
+    this.updateEditorToLocation(url, line);
 
     // Start recording any added variables or properties in any scope.
     DebuggerView.Properties.createHierarchyStore();
 
     // Clear existing scopes and create each one dynamically.
     DebuggerView.Properties.empty();
 
     if (frame.environment) {
@@ -749,17 +774,17 @@ StackFrames.prototype = {
   /**
    * Adds the specified stack frame to the list.
    *
    * @param Debugger.Frame aFrame
    *        The new frame to add.
    */
   _addFrame: function SF__addFrame(aFrame) {
     let depth = aFrame.depth;
-    let label = DebuggerController.SourceScripts._getScriptLabel(aFrame.where.url);
+    let label = DebuggerController.SourceScripts.getScriptLabel(aFrame.where.url);
 
     let startText = this._getFrameTitle(aFrame);
     let endText = label + ":" + aFrame.where.line;
 
     let frame = DebuggerView.StackFrames.addFrame(depth, startText, endText);
     if (frame) {
       frame.debuggerFrame = aFrame;
     }
@@ -876,39 +901,44 @@ SourceScripts.prototype = {
    */
   _onNewScript: function SS__onNewScript(aNotification, aPacket) {
     // Ignore scripts generated from 'clientEvaluate' packets.
     if (aPacket.url == "debugger eval code") {
       return;
     }
 
     this._addScript({ url: aPacket.url, startLine: aPacket.startLine }, true);
-    // If there are any stored breakpoints for this script, display them again.
-    for each (let bp in DebuggerController.Breakpoints.store) {
-      if (bp.location.url == aPacket.url) {
-        DebuggerController.Breakpoints.displayBreakpoint(bp.location);
+
+    // If there are any stored breakpoints for this script, display them again,
+    // both in the editor and the pane.
+    for each (let breakpoint in DebuggerController.Breakpoints.store) {
+      if (breakpoint.location.url == aPacket.url) {
+        DebuggerController.Breakpoints.displayBreakpoint(breakpoint);
       }
     }
   },
 
   /**
    * Handler for the thread client's scriptsadded notification.
    */
   _onScriptsAdded: function SS__onScriptsAdded() {
     for each (let script in this.activeThread.cachedScripts) {
       this._addScript(script, false);
     }
     DebuggerView.Scripts.commitScripts();
+    DebuggerController.Breakpoints.updatePaneBreakpoints();
   },
 
   /**
    * Handler for the thread client's scriptscleared notification.
    */
   _onScriptsCleared: function SS__onScriptsCleared() {
     DebuggerView.Scripts.empty();
+    DebuggerView.Breakpoints.emptyText();
+    DebuggerView.editor.setText("");
   },
 
   /**
    * Sets the proper editor mode (JS or HTML) according to the specified
    * content type, or by determining the type from the URL.
    *
    * @param string aUrl
    *        The script URL.
@@ -961,17 +991,17 @@ SourceScripts.prototype = {
    *        The script URL.
    * @param string aLabel [optional]
    *        The resulting label at each step.
    * @param number aSeq [optional]
    *        The current iteration step.
    * @return string
    *         The resulting label at the final step.
    */
-  _trimURL: function SS__trimURL(aUrl, aLabel, aSeq) {
+  _trimUrl: function SS__trimUrl(aUrl, aLabel, aSeq) {
     if (!(aUrl instanceof Ci.nsIURL)) {
       try {
         // Use an nsIURL to parse all the url path parts.
         aUrl = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
       } catch (e) {
         // This doesn't look like a url, or nsIURL can't handle it.
         return aUrl;
       }
@@ -1006,65 +1036,65 @@ SourceScripts.prototype = {
         return aLabel;
       }
     }
 
     // Append the url query.
     if (aSeq === 1) {
       let query = aUrl.query;
       if (query) {
-        return this._trimURL(aUrl, aLabel + "?" + query, aSeq + 1);
+        return this._trimUrl(aUrl, aLabel + "?" + query, aSeq + 1);
       }
       aSeq++;
     }
     // Append the url reference.
     if (aSeq === 2) {
       let ref = aUrl.ref;
       if (ref) {
-        return this._trimURL(aUrl, aLabel + "#" + aUrl.ref, aSeq + 1);
+        return this._trimUrl(aUrl, aLabel + "#" + aUrl.ref, aSeq + 1);
       }
       aSeq++;
     }
     // Prepend the url directory.
     if (aSeq === 3) {
       let dir = aUrl.directory;
       if (dir) {
-        return this._trimURL(aUrl, dir.replace(/^\//, "") + aLabel, aSeq + 1);
+        return this._trimUrl(aUrl, dir.replace(/^\//, "") + aLabel, aSeq + 1);
       }
       aSeq++;
     }
     // Prepend the hostname and port number.
     if (aSeq === 4) {
       let host = aUrl.hostPort;
       if (host) {
-        return this._trimURL(aUrl, host + "/" + aLabel, aSeq + 1);
+        return this._trimUrl(aUrl, host + "/" + aLabel, aSeq + 1);
       }
       aSeq++;
     }
     // Use the whole url spec but ignoring the reference.
     if (aSeq === 5) {
-      return this._trimURL(aUrl, aUrl.specIgnoringRef, aSeq + 1);
+      return this._trimUrl(aUrl, aUrl.specIgnoringRef, aSeq + 1);
     }
     // Give up.
     return aUrl.spec;
   },
 
   /**
    * Gets a unique, simplified label from a script url.
    *
    * @param string aUrl
    *        The script url.
    * @param string aHref
    *        The content location href to be used. If unspecified, it will
    *        default to the script url prepath.
    * @return string
    *         The simplified label.
    */
-  _getScriptLabel: function SS__getScriptLabel(aUrl, aHref) {
-    return this._labelsCache[aUrl] || (this._labelsCache[aUrl] = this._trimURL(aUrl));
+  getScriptLabel: function SS_getScriptLabel(aUrl, aHref) {
+    return this._labelsCache[aUrl] || (this._labelsCache[aUrl] = this._trimUrl(aUrl));
   },
 
   /**
    * Clears the labels cache, populated by SS_getScriptLabel.
    * This should be done every time the content location changes.
    */
   _clearLabelsCache: function SS__clearLabelsCache() {
     this._labelsCache = {};
@@ -1075,17 +1105,17 @@ SourceScripts.prototype = {
    *
    * @param object aScript
    *        The script object coming from the active thread.
    * @param boolean aForceFlag
    *        True to force the script to be immediately added.
    */
   _addScript: function SS__addScript(aScript, aForceFlag) {
     DebuggerView.Scripts.addScript(
-      this._getScriptLabel(aScript.url), aScript, aForceFlag);
+      this.getScriptLabel(aScript.url), aScript, aForceFlag);
   },
 
   /**
    * Load the editor with the script text if available, otherwise fire an event
    * to load and display the script text.
    *
    * @param object aScript
    *        The script object coming from the active thread.
@@ -1228,16 +1258,33 @@ SourceScripts.prototype = {
     script.text = aSourceText;
     script.contentType = aContentType;
     element.setUserData("sourceScript", script, null);
 
     this.showScript(script, aOptions);
   },
 
   /**
+   * Gets the text in a source editor's specified line.
+   *
+   * @param number aLine [optional]
+   *        The line to get the text from.
+   *        If unspecified, it defaults to the current caret position line.
+   * @return string
+   *         The specified line text
+   */
+  getLineText: function SS_getLineText(aLine) {
+    let editor = DebuggerView.editor;
+    let line = aLine || editor.getCaretPosition().line;
+    let start = editor.getLineStart(line);
+    let end = editor.getLineEnd(line);
+    return editor.getText(start, end);
+  },
+
+  /**
    * Log an error message in the error console when a script fails to load.
    *
    * @param string aUrl
    *        The URL of the source script.
    * @param string aStatus
    *        The failure status code.
    */
   _logError: function SS__logError(aUrl, aStatus) {
@@ -1390,102 +1437,141 @@ Breakpoints.prototype = {
       if (breakpoint.location.url == url) {
         this.editor.addBreakpoint(breakpoint.location.line - 1);
       }
     }
     this._skipEditorBreakpointChange = false;
   },
 
   /**
+   * Update the breakpoints in the pane view. This function is invoked when the
+   * scripts are added (typically after a page navigation).
+   */
+  updatePaneBreakpoints: function BP_updatePaneBreakpoints() {
+    let url = DebuggerView.Scripts.selected;
+    if (!url) {
+      return;
+    }
+
+    this._skipEditorBreakpointChange = true;
+    for each (let breakpoint in this.store) {
+      if (DebuggerView.Scripts.contains(breakpoint.location.url)) {
+        this.displayBreakpoint(breakpoint, true);
+      }
+    }
+    this._skipEditorBreakpointChange = false;
+  },
+
+  /**
    * Add a breakpoint.
    *
    * @param object aLocation
    *        The location where you want the breakpoint. This object must have
    *        two properties:
    *          - url - the URL of the script.
    *          - line - the line number (starting from 1).
    * @param function [aCallback]
    *        Optional function to invoke once the breakpoint is added. The
    *        callback is invoked with two arguments:
    *          - aBreakpointClient - the BreakpointActor client object, if the
    *          breakpoint has been added successfully.
    *          - aResponseError - if there was any error.
    * @param boolean [aNoEditorUpdate=false]
    *        Tells if you want to skip editor updates. Typically the editor is
    *        updated to visually indicate that a breakpoint has been added.
+   * @param boolean [aNoPaneUpdate=false]
+   *        Tells if you want to skip any breakpoint pane updates.
    */
   addBreakpoint:
-  function BP_addBreakpoint(aLocation, aCallback, aNoEditorUpdate) {
+  function BP_addBreakpoint(aLocation, aCallback, aNoEditorUpdate, aNoPaneUpdate) {
     let breakpoint = this.getBreakpoint(aLocation.url, aLocation.line);
     if (breakpoint) {
       aCallback && aCallback(breakpoint);
       return;
     }
 
     this.activeThread.setBreakpoint(aLocation, function(aResponse, aBpClient) {
       this.store[aBpClient.actor] = aBpClient;
-      this.displayBreakpoint(aLocation, aNoEditorUpdate);
+      this.displayBreakpoint(aBpClient, aNoEditorUpdate, aNoPaneUpdate);
       aCallback && aCallback(aBpClient, aResponse.error);
     }.bind(this));
   },
 
   /**
    * Update the editor to display the specified breakpoint in the gutter.
    *
-   * @param object aLocation
-   *        The location where you want the breakpoint. This object must have
-   *        two properties:
-   *          - url - the URL of the script.
-   *          - line - the line number (starting from 1).
+   * @param object aBreakpoint
+   *        The breakpoint you want to display.
    * @param boolean [aNoEditorUpdate=false]
    *        Tells if you want to skip editor updates. Typically the editor is
    *        updated to visually indicate that a breakpoint has been added.
+   * @param boolean [aNoPaneUpdate=false]
+   *        Tells if you want to skip any breakpoint pane updates.
    */
-  displayBreakpoint: function BP_displayBreakpoint(aLocation, aNoEditorUpdate) {
+  displayBreakpoint:
+  function BP_displayBreakpoint(aBreakpoint, aNoEditorUpdate, aNoPaneUpdate) {
     if (!aNoEditorUpdate) {
       let url = DebuggerView.Scripts.selected;
-      if (url == aLocation.url) {
+      if (url == aBreakpoint.location.url) {
         this._skipEditorBreakpointChange = true;
-        this.editor.addBreakpoint(aLocation.line - 1);
+        this.editor.addBreakpoint(aBreakpoint.location.line - 1);
         this._skipEditorBreakpointChange = false;
       }
     }
+    if (!aNoPaneUpdate) {
+      let { url: url, line: line } = aBreakpoint.location;
+
+      if (!aBreakpoint.lineText || !aBreakpoint.lineInfo) {
+        let scripts = DebuggerController.SourceScripts;
+        aBreakpoint.lineText = scripts.getLineText(line - 1);
+        aBreakpoint.lineInfo = scripts.getScriptLabel(url) + ":" + line;
+      }
+      DebuggerView.Breakpoints.addBreakpoint(
+        aBreakpoint.actor,
+        aBreakpoint.lineInfo,
+        aBreakpoint.lineText, url, line);
+    }
   },
 
   /**
    * Remove a breakpoint.
    *
    * @param object aBreakpoint
    *        The breakpoint you want to remove.
    * @param function [aCallback]
    *        Optional function to invoke once the breakpoint is removed. The
    *        callback is invoked with one argument: the breakpoint location
    *        object which holds the url and line properties.
    * @param boolean [aNoEditorUpdate=false]
    *        Tells if you want to skip editor updates. Typically the editor is
    *        updated to visually indicate that a breakpoint has been removed.
+   * @param boolean [aNoPaneUpdate=false]
+   *        Tells if you want to skip any breakpoint pane updates.
    */
   removeBreakpoint:
-  function BP_removeBreakpoint(aBreakpoint, aCallback, aNoEditorUpdate) {
+  function BP_removeBreakpoint(aBreakpoint, aCallback, aNoEditorUpdate, aNoPaneUpdate) {
     if (!(aBreakpoint.actor in this.store)) {
       aCallback && aCallback(aBreakpoint.location);
       return;
     }
 
     aBreakpoint.remove(function() {
       delete this.store[aBreakpoint.actor];
 
       if (!aNoEditorUpdate) {
         let url = DebuggerView.Scripts.selected;
         if (url == aBreakpoint.location.url) {
           this._skipEditorBreakpointChange = true;
           this.editor.removeBreakpoint(aBreakpoint.location.line - 1);
           this._skipEditorBreakpointChange = false;
         }
       }
+      if (!aNoPaneUpdate) {
+        DebuggerView.Breakpoints.removeBreakpoint(aBreakpoint.actor);
+      }
 
       aCallback && aCallback(aBreakpoint.location);
     }.bind(this));
   },
 
   /**
    * Get the breakpoint object at the given location.
    *
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -1,33 +1,34 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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/. */
 "use strict";
 
 const PROPERTY_VIEW_FLASH_DURATION = 400; // ms
+const BREAKPOINT_LINE_TOOLTIP_MAX_SIZE = 1000;
 
 /**
  * Object mediating visual changes and event listeners between the debugger and
  * the html view.
  */
 let DebuggerView = {
 
   /**
    * An instance of SourceEditor.
    */
   editor: null,
 
   /**
    * Initializes UI properties for all the displayed panes.
    */
   initializePanes: function DV_initializePanes() {
-    let stackframes = document.getElementById("stackframes");
+    let stackframes = document.getElementById("stackframes+breakpoints");
     stackframes.setAttribute("width", Prefs.stackframesWidth);
 
     let variables = document.getElementById("variables");
     variables.setAttribute("width", Prefs.variablesWidth);
   },
 
   /**
    * Initializes the SourceEditor instance.
@@ -46,17 +47,17 @@ let DebuggerView = {
     this.editor = new SourceEditor();
     this.editor.init(placeholder, config, this._onEditorLoad.bind(this));
   },
 
   /**
    * Removes the displayed panes and saves any necessary state.
    */
   destroyPanes: function DV_destroyPanes() {
-    let stackframes = document.getElementById("stackframes");
+    let stackframes = document.getElementById("stackframes+breakpoints");
     Prefs.stackframesWidth = stackframes.getAttribute("width");
 
     let variables = document.getElementById("variables");
     Prefs.variablesWidth = variables.getAttribute("width");
   },
 
   /**
    * Removes the SourceEditor instance and added breakpoints.
@@ -84,53 +85,55 @@ let DebuggerView = {
 };
 
 /**
  * A simple way of displaying a "Connect to..." prompt.
  */
 function RemoteDebuggerPrompt() {
 
   /**
-   * The remote uri the user wants to connect to.
+   * The remote host and port the user wants to connect to.
    */
-  this.uri = null;
+  this.remote = {};
 }
 
 RemoteDebuggerPrompt.prototype = {
 
   /**
    * Shows the prompt and sets the uri using the user input.
    *
    * @param boolean aIsReconnectingFlag
    *                True to show the reconnect message instead.
    */
   show: function RDP_show(aIsReconnectingFlag) {
     let check = { value: Prefs.remoteAutoConnect };
-    let input = { value: "http://" + Prefs.remoteHost +
-                               ":" + Prefs.remotePort + "/" };
+    let input = { value: Prefs.remoteHost + ":" + Prefs.remotePort };
+    let parts;
 
     while (true) {
       let result = Services.prompt.prompt(null,
         L10N.getStr("remoteDebuggerPromptTitle"),
         L10N.getStr(aIsReconnectingFlag
           ? "remoteDebuggerReconnectMessage"
           : "remoteDebuggerPromptMessage"), input,
         L10N.getStr("remoteDebuggerPromptCheck"), check);
 
       Prefs.remoteAutoConnect = check.value;
 
-      try {
-        let uri = Services.io.newURI(input.value, null, null);
-        let url = uri.QueryInterface(Ci.nsIURL);
+      if (!result) {
+        return false;
+      }
+      if ((parts = input.value.split(":")).length === 2) {
+        let [host, port] = parts;
 
-        // If a url could be successfully retrieved, then the uri is correct.
-        this.uri = uri;
-        return result;
+        if (host.length && port.length) {
+          this.remote = { host: host, port: port };
+          return true;
+        }
       }
-      catch(e) { }
     }
   }
 };
 
 /**
  * Functions handling the scripts UI.
  */
 function ScriptsView() {
@@ -140,16 +143,18 @@ function ScriptsView() {
 }
 
 ScriptsView.prototype = {
 
   /**
    * Removes all elements from the scripts container, leaving it empty.
    */
   empty: function DVS_empty() {
+    this._scripts.selectedIndex = -1;
+
     while (this._scripts.firstChild) {
       this._scripts.removeChild(this._scripts.firstChild);
     }
   },
 
   /**
    * Removes the input in the searchbox and unhides all the scripts.
    */
@@ -410,17 +415,22 @@ ScriptsView.prototype = {
 
     return [file, line, token];
   },
 
   /**
    * The click listener for the scripts container.
    */
   _onScriptsChange: function DVS__onScriptsChange() {
-    let script = this._scripts.selectedItem.getUserData("sourceScript");
+    let selectedItem = this._scripts.selectedItem;
+    if (!selectedItem) {
+      return;
+    }
+
+    let script = selectedItem.getUserData("sourceScript");
     this._preferredScript = script;
     DebuggerController.SourceScripts.showScript(script);
   },
 
   /**
    * The search listener for the scripts search box.
    */
   _onScriptsSearch: function DVS__onScriptsSearch(e) {
@@ -454,17 +464,17 @@ ScriptsView.prototype = {
         else {
           item.hidden = true;
         }
       }
     }
     if (line > -1) {
       editor.setCaretPosition(line - 1);
     }
-    if (token) {
+    if (token.length) {
       let offset = editor.find(token, { ignoreCase: true });
       if (offset > -1) {
         editor.setSelection(offset, offset + token.length)
       }
     }
   },
 
   /**
@@ -473,16 +483,20 @@ ScriptsView.prototype = {
   _onScriptsKeyUp: function DVS__onScriptsKeyUp(e) {
     if (e.keyCode === e.DOM_VK_ESCAPE) {
       DebuggerView.editor.focus();
       return;
     }
 
     if (e.keyCode === e.DOM_VK_RETURN || e.keyCode === e.DOM_VK_ENTER) {
       let token = this._getSearchboxInfo()[2];
+      if (!token.length) {
+        return;
+      }
+
       let editor = DebuggerView.editor;
       let offset = editor.findNext(true);
       if (offset > -1) {
         editor.setSelection(offset, offset + token.length)
       }
     }
   },
 
@@ -796,16 +810,17 @@ StackFramesView.prototype = {
     stepOver.addEventListener("click", this._onStepOverClick, false);
     stepIn.addEventListener("click", this._onStepInClick, false);
     stepOut.addEventListener("click", this._onStepOutClick, false);
     frames.addEventListener("click", this._onFramesClick, false);
     frames.addEventListener("scroll", this._onFramesScroll, false);
     window.addEventListener("resize", this._onFramesScroll, false);
 
     this._frames = frames;
+    this.emptyText();
   },
 
   /**
    * Destruction function, called when the debugger is shut down.
    */
   destroy: function DVF_destroy() {
     let close = document.getElementById("close");
     let pauseOnExceptions = document.getElementById("pause-exceptions");
@@ -827,25 +842,565 @@ StackFramesView.prototype = {
     frames.removeEventListener("scroll", this._onFramesScroll, false);
     window.removeEventListener("resize", this._onFramesScroll, false);
 
     this._frames = null;
   }
 };
 
 /**
+ * Functions handling the breakpoints view.
+ */
+function BreakpointsView() {
+  this._onBreakpointClick = this._onBreakpointClick.bind(this);
+  this._onBreakpointCheckboxChange = this._onBreakpointCheckboxChange.bind(this);
+}
+
+BreakpointsView.prototype = {
+
+  /**
+   * Removes all elements from the breakpoints container, leaving it empty.
+   */
+  empty: function DVB_empty() {
+    let firstChild;
+    while (firstChild = this._breakpoints.firstChild) {
+      this._destroyContextMenu(firstChild);
+      this._breakpoints.removeChild(firstChild);
+    }
+  },
+
+  /**
+   * Removes all elements from the breakpoints container, and adds a child node
+   * with an empty text note attached.
+   */
+  emptyText: function DVB_emptyText() {
+    // Make sure the container is empty first.
+    this.empty();
+
+    let item = document.createElement("label");
+
+    // The empty node should look grayed out to avoid confusion.
+    item.className = "list-item empty";
+    item.setAttribute("value", L10N.getStr("emptyBreakpointsText"));
+
+    this._breakpoints.appendChild(item);
+  },
+
+  /**
+   * Checks whether the breakpoint with the specified script URL and line is
+   * among the breakpoints known to the debugger and shown in the list, and
+   * returns the matched result or null if nothing is found.
+   *
+   * @param string aUrl
+   *        The original breakpoint script url.
+   * @param number aLine
+   *        The original breakpoint script line.
+   * @return object | null
+   *         The queried breakpoint
+   */
+  getBreakpoint: function DVB_getBreakpoint(aUrl, aLine) {
+    return this._breakpoints.getElementsByAttribute("location", aUrl + ":" + aLine)[0];
+  },
+
+  /**
+   * Removes a breakpoint only from the breakpoints container.
+   * This doesn't remove the breakpoint from the DebuggerController!
+   *
+   * @param string aId
+   *        A breakpoint identifier specified by the debugger.
+   */
+  removeBreakpoint: function DVB_removeBreakpoint(aId) {
+    let breakpoint = document.getElementById("breakpoint-" + aId);
+
+    // Make sure we have something to remove.
+    if (!breakpoint) {
+      return;
+    }
+    this._destroyContextMenu(breakpoint);
+    this._breakpoints.removeChild(breakpoint);
+
+    if (!this.count) {
+      this.emptyText();
+    }
+  },
+
+  /**
+   * Adds a breakpoint to the breakpoints container.
+   * If the breakpoint already exists (was previously added), null is returned.
+   * If it's already added but disabled, it will be enabled and null is returned.
+   * Otherwise, the newly created element is returned.
+   *
+   * @param string aId
+   *        A breakpoint identifier specified by the debugger.
+   * @param string aLineInfo
+   *        The script line information to be displayed in the list.
+   * @param string aLineText
+   *        The script line text to be displayed in the list.
+   * @param string aUrl
+   *        The original breakpoint script url.
+   * @param number aLine
+   *        The original breakpoint script line.
+   * @return object
+   *         The newly created html node representing the added breakpoint.
+   */
+  addBreakpoint: function DVB_addBreakpoint(aId, aLineInfo, aLineText, aUrl, aLine) {
+    // Make sure we don't duplicate anything.
+    if (document.getElementById("breakpoint-" + aId)) {
+      return null;
+    }
+    // Remove the empty list text if it was there.
+    if (!this.count) {
+      this.empty();
+    }
+
+    // If the breakpoint was already added but disabled, enable it now.
+    let breakpoint = this.getBreakpoint(aUrl, aLine);
+    if (breakpoint) {
+      breakpoint.id = "breakpoint-" + aId;
+      breakpoint.breakpointActor = aId;
+      breakpoint.getElementsByTagName("checkbox")[0].setAttribute("checked", "true");
+      return;
+    }
+
+    breakpoint = document.createElement("box");
+    let bkpCheckbox = document.createElement("checkbox");
+    let bkpLineInfo = document.createElement("label");
+    let bkpLineText = document.createElement("label");
+
+    // Create a list item to be added to the stackframes container.
+    breakpoint.id = "breakpoint-" + aId;
+    breakpoint.className = "dbg-breakpoint list-item";
+    breakpoint.setAttribute("location", aUrl + ":" + aLine);
+    breakpoint.breakpointUrl = aUrl;
+    breakpoint.breakpointLine = aLine;
+    breakpoint.breakpointActor = aId;
+
+    aLineInfo = aLineInfo.trim();
+    aLineText = aLineText.trim();
+
+    // A checkbox specifies if the breakpoint is enabled or not.
+    bkpCheckbox.setAttribute("checked", "true");
+    bkpCheckbox.addEventListener("click", this._onBreakpointCheckboxChange, false);
+
+    // This list should display the line info and text for the breakpoint.
+    bkpLineInfo.className = "dbg-breakpoint-info plain";
+    bkpLineText.className = "dbg-breakpoint-text plain";
+    bkpLineInfo.setAttribute("value", aLineInfo);
+    bkpLineText.setAttribute("value", aLineText);
+    bkpLineInfo.setAttribute("crop", "end");
+    bkpLineText.setAttribute("crop", "end");
+    bkpLineText.setAttribute("tooltiptext", aLineText.substr(0, BREAKPOINT_LINE_TOOLTIP_MAX_SIZE));
+
+    // Create a context menu for the breakpoint.
+    let menupopupId = this._createContextMenu(breakpoint);
+    breakpoint.setAttribute("contextmenu", menupopupId);
+
+    let state = document.createElement("vbox");
+    state.className = "state";
+    state.appendChild(bkpCheckbox);
+
+    let content = document.createElement("vbox");
+    content.className = "content";
+    content.setAttribute("flex", "1");
+    content.appendChild(bkpLineInfo);
+    content.appendChild(bkpLineText);
+
+    breakpoint.appendChild(state);
+    breakpoint.appendChild(content);
+
+    this._breakpoints.appendChild(breakpoint);
+
+    // Return the element for later use if necessary.
+    return breakpoint;
+  },
+
+  /**
+   * Enables a breakpoint.
+   *
+   * @param object aBreakpoint
+   *        An element representing a breakpoint.
+   * @param function aCallback
+   *        Optional function to invoke once the breakpoint is enabled.
+   * @param boolean aNoCheckboxUpdate
+   *        Pass true to not update the checkbox checked state.
+   *        This is usually necessary when the checked state will be updated
+   *        automatically (e.g: on a checkbox click).
+   */
+  enableBreakpoint:
+  function DVB_enableBreakpoint(aTarget, aCallback, aNoCheckboxUpdate) {
+    let { breakpointUrl: url, breakpointLine: line } = aTarget;
+    let breakpoint = DebuggerController.Breakpoints.getBreakpoint(url, line)
+
+    if (!breakpoint) {
+      if (!aNoCheckboxUpdate) {
+        aTarget.getElementsByTagName("checkbox")[0].setAttribute("checked", "true");
+      }
+      DebuggerController.Breakpoints.
+        addBreakpoint({ url: url, line: line }, aCallback);
+
+      return true;
+    }
+    return false;
+  },
+
+  /**
+   * Disables a breakpoint.
+   *
+   * @param object aTarget
+   *        An element representing a breakpoint.
+   * @param function aCallback
+   *        Optional function to invoke once the breakpoint is disabled.
+   * @param boolean aNoCheckboxUpdate
+   *        Pass true to not update the checkbox checked state.
+   *        This is usually necessary when the checked state will be updated
+   *        automatically (e.g: on a checkbox click).
+   */
+  disableBreakpoint:
+  function DVB_disableBreakpoint(aTarget, aCallback, aNoCheckboxUpdate) {
+    let { breakpointUrl: url, breakpointLine: line } = aTarget;
+    let breakpoint = DebuggerController.Breakpoints.getBreakpoint(url, line)
+
+    if (breakpoint) {
+      if (!aNoCheckboxUpdate) {
+        aTarget.getElementsByTagName("checkbox")[0].removeAttribute("checked");
+      }
+      DebuggerController.Breakpoints.
+        removeBreakpoint(breakpoint, aCallback, false, true);
+
+      return true;
+    }
+    return false;
+  },
+
+  /**
+   * Gets the current number of added breakpoints.
+   */
+  get count() {
+    return this._breakpoints.getElementsByClassName("dbg-breakpoint").length;
+  },
+
+  /**
+   * Iterates through all the added breakpoints.
+   *
+   * @param function aCallback
+   *        Function called for each element.
+   */
+  _iterate: function DVB_iterate(aCallback) {
+    Array.forEach(Array.slice(this._breakpoints.childNodes), aCallback);
+  },
+
+  /**
+   * Gets the real breakpoint target when an event is handled.
+   * @return object
+   */
+  _getBreakpointTarget: function DVB__getBreakpointTarget(aEvent) {
+    let target = aEvent.target;
+
+    while (target) {
+      if (target.breakpointActor) {
+        return target;
+      }
+      target = target.parentNode;
+    }
+  },
+
+  /**
+   * Listener handling the breakpoint click event.
+   */
+  _onBreakpointClick: function DVB__onBreakpointClick(aEvent) {
+    let target = this._getBreakpointTarget(aEvent);
+    let { breakpointUrl: url, breakpointLine: line } = target;
+
+    DebuggerController.StackFrames.updateEditorToLocation(url, line, 0, 0, 1);
+  },
+
+  /**
+   * Listener handling the breakpoint checkbox change event.
+   */
+  _onBreakpointCheckboxChange: function DVB__onBreakpointCheckboxChange(aEvent) {
+    aEvent.stopPropagation();
+
+    let target = this._getBreakpointTarget(aEvent);
+    let { breakpointUrl: url, breakpointLine: line } = target;
+
+    if (aEvent.target.getAttribute("checked") === "true") {
+      this.disableBreakpoint(target, null, true);
+    } else {
+      this.enableBreakpoint(target, null, true);
+    }
+  },
+
+  /**
+   * Listener handling the "enableSelf" menuitem command.
+   *
+   * @param object aTarget
+   *        The corresponding breakpoint element.
+   */
+  _onEnableSelf: function DVB__onEnableSelf(aTarget) {
+    if (!aTarget) {
+      return;
+    }
+    if (this.enableBreakpoint(aTarget)) {
+      aTarget.enableSelf.menuitem.setAttribute("hidden", "true");
+      aTarget.disableSelf.menuitem.removeAttribute("hidden");
+    }
+  },
+
+  /**
+   * Listener handling the "disableSelf" menuitem command.
+   *
+   * @param object aTarget
+   *        The corresponding breakpoint element.
+   */
+  _onDisableSelf: function DVB__onDisableSelf(aTarget) {
+    if (!aTarget) {
+      return;
+    }
+    if (this.disableBreakpoint(aTarget)) {
+      aTarget.enableSelf.menuitem.removeAttribute("hidden");
+      aTarget.disableSelf.menuitem.setAttribute("hidden", "true");
+    }
+  },
+
+  /**
+   * Listener handling the "deleteSelf" menuitem command.
+   *
+   * @param object aTarget
+   *        The corresponding breakpoint element.
+   */
+  _onDeleteSelf: function DVB__onDeleteSelf(aTarget) {
+    let { breakpointUrl: url, breakpointLine: line } = aTarget;
+    let breakpoint = DebuggerController.Breakpoints.getBreakpoint(url, line)
+
+    if (aTarget) {
+      this.removeBreakpoint(aTarget.breakpointActor);
+    }
+    if (breakpoint) {
+      DebuggerController.Breakpoints.removeBreakpoint(breakpoint);
+    }
+  },
+
+  /**
+   * Listener handling the "enableOthers" menuitem command.
+   *
+   * @param object aTarget
+   *        The corresponding breakpoint element.
+   */
+  _onEnableOthers: function DVB__onEnableOthers(aTarget) {
+    this._iterate(function(element) {
+      if (element !== aTarget) {
+        this._onEnableSelf(element);
+      }
+    }.bind(this));
+  },
+
+  /**
+   * Listener handling the "disableOthers" menuitem command.
+   *
+   * @param object aTarget
+   *        The corresponding breakpoint element.
+   */
+  _onDisableOthers: function DVB__onDisableOthers(aTarget) {
+    this._iterate(function(element) {
+      if (element !== aTarget) {
+        this._onDisableSelf(element);
+      }
+    }.bind(this));
+  },
+
+  /**
+   * Listener handling the "deleteOthers" menuitem command.
+   *
+   * @param object aTarget
+   *        The corresponding breakpoint element.
+   */
+  _onDeleteOthers: function DVB__onDeleteOthers(aTarget) {
+    this._iterate(function(element) {
+      if (element !== aTarget) {
+        this._onDeleteSelf(element);
+      }
+    }.bind(this));
+  },
+
+  /**
+   * Listener handling the "disableAll" menuitem command.
+   *
+   * @param object aTarget
+   *        The corresponding breakpoint element.
+   */
+  _onEnableAll: function DVB__onEnableAll(aTarget) {
+    this._onEnableOthers(aTarget);
+    this._onEnableSelf(aTarget);
+  },
+
+  /**
+   * Listener handling the "disableAll" menuitem command.
+   *
+   * @param object aTarget
+   *        The corresponding breakpoint element.
+   */
+  _onDisableAll: function DVB__onDisableAll(aTarget) {
+    this._onDisableOthers(aTarget);
+    this._onDisableSelf(aTarget);
+  },
+
+  /**
+   * Listener handling the "deleteAll" menuitem command.
+   *
+   * @param object aTarget
+   *        The corresponding breakpoint element.
+   */
+  _onDeleteAll: function DVB__onDeleteAll(aTarget) {
+    this._onDeleteOthers(aTarget);
+    this._onDeleteSelf(aTarget);
+  },
+
+  /**
+   * The cached breakpoints container.
+   */
+  _breakpoints: null,
+
+  /**
+   * Creates a breakpoint context menu.
+   *
+   * @param object aBreakpoint
+   *        An element representing a breakpoint.
+   * @return string
+   *         The popup id.
+   */
+  _createContextMenu: function DVB_createContextMenu(aBreakpoint) {
+    let commandsetId = "breakpointMenuCommands-" + aBreakpoint.id;
+    let menupopupId = "breakpointContextMenu-" + aBreakpoint.id;
+
+    let commandsset = document.createElement("commandsset");
+    commandsset.setAttribute("id", commandsetId);
+
+    let menupopup = document.createElement("menupopup");
+    menupopup.setAttribute("id", menupopupId);
+
+    /**
+     * Creates a menu item specified by a name with the appropriate attributes
+     * (label and command handler).
+     *
+     * @param string aName
+     *        A global identifier for the menu item.
+     * @param boolean aHiddenFlag
+     *        True if this menuitem should be hidden.
+     */
+    function createMenuItem(aName, aHiddenFlag) {
+      let menuitem = document.createElement("menuitem");
+      let command = document.createElement("command");
+
+      let func = this["_on" + aName.charAt(0).toUpperCase() + aName.slice(1)];
+      let label = L10N.getStr("breakpointMenuItem." + aName);
+
+      let prefix = "bp-cMenu-";
+      let commandId = prefix + aName + "-" + aBreakpoint.id + "-command";
+      let menuitemId = prefix + aName + "-" + aBreakpoint.id + "-menuitem";
+
+      command.setAttribute("id", commandId);
+      command.setAttribute("label", label);
+      command.addEventListener("command", func.bind(this, aBreakpoint), true);
+
+      menuitem.setAttribute("id", menuitemId);
+      menuitem.setAttribute("command", commandId);
+      menuitem.setAttribute("hidden", aHiddenFlag);
+
+      commandsset.appendChild(command);
+      menupopup.appendChild(menuitem);
+
+      aBreakpoint[aName] = {
+        menuitem: menuitem,
+        command: command
+      };
+    }
+
+    /**
+     * Creates a simple menu separator element and appends it to the current
+     * menupopup hierarchy.
+     */
+    function createMenuSeparator() {
+      let menuseparator = document.createElement("menuseparator");
+      menupopup.appendChild(menuseparator);
+    }
+
+    createMenuItem.call(this, "enableSelf", true);
+    createMenuItem.call(this, "disableSelf");
+    createMenuItem.call(this, "deleteSelf");
+    createMenuSeparator();
+    createMenuItem.call(this, "enableOthers");
+    createMenuItem.call(this, "disableOthers");
+    createMenuItem.call(this, "deleteOthers");
+    createMenuSeparator();
+    createMenuItem.call(this, "enableAll");
+    createMenuItem.call(this, "disableAll");
+    createMenuSeparator();
+    createMenuItem.call(this, "deleteAll");
+
+    let popupset = document.getElementById("debugger-popups");
+    popupset.appendChild(menupopup);
+    document.documentElement.appendChild(commandsset);
+
+    return menupopupId;
+  },
+
+  /**
+   * Destroys a breakpoint context menu.
+   *
+   * @param object aBreakpoint
+   *        An element representing a breakpoint.
+   */
+  _destroyContextMenu: function DVB__destroyContextMenu(aBreakpoint) {
+    let commandsetId = "breakpointMenuCommands-" + aBreakpoint.id;
+    let menupopupId = "breakpointContextMenu-" + aBreakpoint.id;
+
+    let commandset = document.getElementById(commandsetId);
+    let menupopup = document.getElementById(menupopupId);
+
+    if (commandset) {
+      commandset.parentNode.removeChild(commandset);
+    }
+    if (menupopup) {
+      menupopup.parentNode.removeChild(menupopup);
+    }
+  },
+
+  /**
+   * Initialization function, called when the debugger is initialized.
+   */
+  initialize: function DVB_initialize() {
+    let breakpoints = document.getElementById("breakpoints");
+    breakpoints.addEventListener("click", this._onBreakpointClick, false);
+
+    this._breakpoints = breakpoints;
+    this.emptyText();
+  },
+
+  /**
+   * Destruction function, called when the debugger is shut down.
+   */
+  destroy: function DVB_destroy() {
+    let breakpoints = this._breakpoints;
+    breakpoints.removeEventListener("click", this._onBreakpointClick, false);
+
+    this._breakpoints = null;
+  }
+};
+
+/**
  * Functions handling the properties view.
  */
 function PropertiesView() {
   this.addScope = this._addScope.bind(this);
   this._addVar = this._addVar.bind(this);
   this._addProperties = this._addProperties.bind(this);
 }
 
 PropertiesView.prototype = {
+
   /**
    * A monotonically-increasing counter, that guarantees the uniqueness of scope
    * IDs.
    */
   _idCount: 1,
 
   /**
    * Adds a scope to contain any inspected variables.
@@ -1912,19 +2467,20 @@ PropertiesView.prototype = {
    * The cached variable properties container.
    */
   _vars: null,
 
   /**
    * Initialization function, called when the debugger is initialized.
    */
   initialize: function DVP_initialize() {
-    this.createHierarchyStore();
+    this._vars = document.getElementById("variables");
 
-    this._vars = document.getElementById("variables");
+    this.emptyText();
+    this.createHierarchyStore();
   },
 
   /**
    * Destruction function, called when the debugger is shut down.
    */
   destroy: function DVP_destroy() {
     this._currHierarchy = null;
     this._prevHierarchy = null;
@@ -1932,16 +2488,17 @@ PropertiesView.prototype = {
   }
 };
 
 /**
  * Preliminary setup for the DebuggerView object.
  */
 DebuggerView.Scripts = new ScriptsView();
 DebuggerView.StackFrames = new StackFramesView();
+DebuggerView.Breakpoints = new BreakpointsView();
 DebuggerView.Properties = new PropertiesView();
 
 /**
  * Export the source editor to the global scope for easier access in tests.
  */
 Object.defineProperty(window, "editor", {
   get: function() { return DebuggerView.editor; }
 });
--- a/browser/devtools/debugger/debugger.css
+++ b/browser/devtools/debugger/debugger.css
@@ -8,16 +8,30 @@
  * Stack frames
  */
 
 #stackframes {
   overflow: auto;
 }
 
 /**
+ * Breakpoints view
+ */
+
+#breakpoints {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+.dbg-breakpoint > .state,
+.dbg-breakpoint > .content {
+  overflow: hidden;
+}
+
+/**
  * Properties elements
  */
 
 #variables {
   overflow: auto;
 }
 
 /**
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -75,16 +75,20 @@
       <spacer flex="1"/>
 #ifndef XP_MACOSX
       <toolbarbutton id="close"
                      tooltiptext="&debuggerUI.closeButton.tooltip;"
                      class="devtools-closebutton"/>
 #endif
     </toolbar>
     <hbox id="dbg-content" flex="1">
-      <vbox id="stackframes"/>
-      <splitter id="stack-script-splitter" class="devtools-side-splitter"/>
+      <vbox id="stackframes+breakpoints">
+        <vbox id="stackframes" flex="1"/>
+        <splitter class="devtools-horizontal-splitter"/>
+        <vbox id="breakpoints"/>
+      </vbox>
+      <splitter class="devtools-side-splitter"/>
       <vbox id="editor" flex="1"/>
-      <splitter id="script-properties-splitter" class="devtools-side-splitter"/>
+      <splitter class="devtools-side-splitter"/>
       <vbox id="variables"/>
     </hbox>
   </vbox>
 </window>
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -37,32 +37,35 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_panesize.js \
 	browser_dbg_panesize-inner.js \
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_stack-05.js \
 	browser_dbg_location-changes.js \
+	browser_dbg_location-changes-blank.js \
 	browser_dbg_script-switching.js \
 	browser_dbg_scripts-sorting.js \
 	browser_dbg_scripts-searching-01.js \
 	browser_dbg_scripts-searching-02.js \
 	browser_dbg_pause-resume.js \
 	browser_dbg_update-editor-mode.js \
 	$(warning browser_dbg_select-line.js temporarily disabled due to oranges, see bug 726609) \
 	browser_dbg_clean-exit.js \
 	browser_dbg_bug723069_editor-breakpoints.js \
+	browser_dbg_bug723071_editor-breakpoints-pane.js \
 	browser_dbg_bug731394_editor-contextmenu.js \
 	browser_dbg_displayName.js \
 	browser_dbg_iframes.js \
 	browser_dbg_pause-exceptions.js \
 	browser_dbg_multiple-windows.js \
 	browser_dbg_menustatus.js \
 	browser_dbg_bfcache.js \
+	browser_dbg_breakpoint-new-script.js \
 	head.js \
 	$(NULL)
 
 MOCHITEST_BROWSER_PAGES = \
 	browser_dbg_tab1.html \
 	browser_dbg_tab2.html \
 	browser_dbg_debuggerstatement.html \
 	browser_dbg_stack.html \
@@ -71,13 +74,14 @@ MOCHITEST_BROWSER_PAGES = \
 	test-script-switching-02.js \
 	browser_dbg_frame-parameters.html \
 	browser_dbg_update-editor-mode.html \
 	test-editor-mode \
 	browser_dbg_displayName.html \
 	browser_dbg_iframes.html \
 	browser_dbg_with-frame.html \
 	browser_dbg_pause-exceptions.html \
+	browser_dbg_breakpoint-new-script.html \
 	$(NULL)
 
 MOCHITEST_BROWSER_FILES_PARTS = MOCHITEST_BROWSER_TESTS MOCHITEST_BROWSER_PAGES
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_breakpoint-new-script.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script type="text/javascript">
+function runDebuggerStatement() {
+  debugger;
+}
+function myFunction() {
+  var a = 1;
+  debugger;
+}
+</script>
+</head>
+<body>
+
+<button type="button" onclick="myFunction()">Run</button>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_breakpoint-new-script.js
@@ -0,0 +1,94 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Bug 771452: make sure that setting a breakpoint in an inline script doesn't
+// add it twice.
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_breakpoint-new-script.html";
+
+var gPane = null;
+var gTab = null;
+var gDebugger = null;
+var gDebuggee = null;
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    gDebuggee = aDebuggee;
+
+    testAddBreakpoint();
+  });
+}
+
+function testAddBreakpoint()
+{
+  gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
+    gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
+    executeSoon(function() {
+      var frames = gDebugger.DebuggerView.StackFrames._frames;
+
+      is(gDebugger.DebuggerController.activeThread.state, "paused",
+         "The debugger statement was reached.");
+
+      is(frames.querySelectorAll(".dbg-stackframe").length, 1,
+         "Should have one frame.");
+
+      let location = { url: TAB_URL, line: 9 };
+      gPane.addBreakpoint(location, function (aResponse, bpClient) {
+        testResume();
+      });
+    });
+  }, false);
+
+  gDebuggee.runDebuggerStatement();
+}
+
+function testResume()
+{
+  gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function test() {
+    gDebugger.DebuggerController.activeThread.addOneTimeListener("paused", function test() {
+      executeSoon(testBreakpointHit);
+    }, false);
+
+    EventUtils.sendMouseEvent({ type: "click" },
+      content.document.querySelector("button"),
+      content.window);
+
+  });
+
+  gDebugger.DebuggerController.activeThread.resume();
+}
+
+function testBreakpointHit()
+{
+  var frames = gDebugger.DebuggerView.StackFrames._frames;
+
+  is(gDebugger.DebuggerController.activeThread.state, "paused",
+    "The breakpoint was hit.");
+
+  resumeAndFinish();
+}
+
+function resumeAndFinish() {
+  let thread = gDebugger.DebuggerController.activeThread;
+  thread.addOneTimeListener("paused", function test(aEvent, aPacket) {
+    is(aPacket.why.type, "debuggerStatement", "Execution has advanced to the next line.");
+    isnot(aPacket.why.type, "breakpoint", "No ghost breakpoint was hit.");
+
+    closeDebuggerAndFinish();
+  });
+
+  thread.resume();
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebugger = null;
+  gDebuggee = null;
+});
--- a/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js
@@ -16,16 +16,17 @@ let gScripts = null;
 let gEditor = null;
 let gBreakpoints = null;
 
 function test()
 {
   let tempScope = {};
   Cu.import("resource:///modules/source-editor.jsm", tempScope);
   let SourceEditor = tempScope.SourceEditor;
+
   let scriptShown = false;
   let framesAdded = false;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_bug723071_editor-breakpoints-pane.js
@@ -0,0 +1,281 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Bug 723071: test adding a pane to display the list of breakpoints across
+ * all scripts in the debuggee.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
+
+let gPane = null;
+let gTab = null;
+let gDebuggee = null;
+let gDebugger = null;
+let gScripts = null;
+let gBreakpoints = null;
+let gBreakpointsElement = null;
+
+function test()
+{
+  let scriptShown = false;
+  let framesAdded = false;
+  let resumed = false;
+  let testStarted = false;
+
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    resumed = true;
+
+    gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
+      framesAdded = true;
+      executeSoon(startTest);
+    });
+
+    executeSoon(function() {
+      gDebuggee.firstCall();
+    });
+  });
+
+  function onScriptShown(aEvent)
+  {
+    scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
+    executeSoon(startTest);
+  }
+
+  window.addEventListener("Debugger:ScriptShown", onScriptShown);
+
+  function startTest()
+  {
+    if (scriptShown && framesAdded && resumed && !testStarted) {
+      window.removeEventListener("Debugger:ScriptShown", onScriptShown);
+      testStarted = true;
+      Services.tm.currentThread.dispatch({ run: performTest }, 0);
+    }
+  }
+
+  let breakpointsAdded = 0;
+  let breakpointsDisabled = 0;
+  let breakpointsRemoved = 0;
+
+  function performTest()
+  {
+    gScripts = gDebugger.DebuggerView.Scripts;
+
+    is(gDebugger.DebuggerController.activeThread.state, "paused",
+      "Should only be getting stack frames while paused.");
+
+    is(gScripts._scripts.itemCount, 2, "Found the expected number of scripts.");
+
+    let editor = gDebugger.editor;
+
+    isnot(editor.getText().indexOf("debugger"), -1,
+          "The correct script was loaded initially.");
+    isnot(gScripts.selected, gScripts.scriptLocations[0],
+          "the correct script is selected");
+
+    gBreakpoints = gPane.breakpoints;
+    is(Object.keys(gBreakpoints), 0, "no breakpoints");
+    ok(!gPane.getBreakpoint("chocolate", 3), "getBreakpoint('chocolate', 3) returns falsey");
+
+    is(editor.getBreakpoints().length, 0, "no breakpoints in the editor");
+
+    gBreakpointsElement = gDebugger.DebuggerView.Breakpoints._breakpoints;
+    is(gBreakpointsElement.childNodes.length, 1,
+      "The breakpoints pane should be empty, but showing a " +
+      "'no breakpoints' information message.");
+    is(gBreakpointsElement.childNodes.length,
+       gBreakpointsElement.querySelectorAll(".list-item.empty").length,
+       "Found junk in the breakpoints container.");
+
+    addBreakpoints(function() {
+      is(breakpointsAdded, 3,
+        "Should have added 3 breakpoints so far.");
+      is(breakpointsDisabled, 0,
+        "Shouldn't have disabled anything so far.");
+      is(breakpointsRemoved, 0,
+        "Shouldn't have removed anything so far.");
+
+      is(gBreakpointsElement.childNodes.length,
+         gBreakpointsElement.querySelectorAll(".dbg-breakpoint").length,
+         "Found junk in the breakpoints container.");
+
+      disableBreakpoints(function() {
+        is(breakpointsAdded, 3,
+          "Should still have 3 breakpoints added so far.");
+        is(breakpointsDisabled, 3,
+          "Should have 3 disabled breakpoints.");
+        is(breakpointsRemoved, 0,
+          "Shouldn't have removed anything so far.");
+
+        is(gBreakpointsElement.childNodes.length, breakpointsAdded,
+          "Should have the same number of breakpoints in the pane.");
+        is(gBreakpointsElement.childNodes.length, breakpointsDisabled,
+          "Should have the same number of disabled breakpoints.");
+
+        addBreakpoints(function() {
+          is(breakpointsAdded, 3,
+            "Should still have only 3 breakpoints added so far.");
+          is(breakpointsDisabled, 3,
+            "Should still have 3 disabled breakpoints.");
+          is(breakpointsRemoved, 0,
+            "Shouldn't have removed anything so far.");
+
+          is(gBreakpointsElement.childNodes.length, breakpointsAdded,
+            "Since half of the breakpoints already existed, but disabled, " +
+            "only half of the added breakpoints are actually in the pane.");
+          is(gBreakpointsElement.childNodes.length,
+             gBreakpointsElement.querySelectorAll(".dbg-breakpoint").length,
+             "Found junk in the breakpoints container.");
+
+          removeBreakpoints(function() {
+            is(breakpointsRemoved, 3,
+              "Should have 3 removed breakpoints.");
+
+            is(gBreakpointsElement.childNodes.length, 1,
+              "The breakpoints pane should be empty, but showing a " +
+              "'no breakpoints' information message.");
+            is(gBreakpointsElement.childNodes.length,
+               gBreakpointsElement.querySelectorAll(".list-item.empty").length,
+               "Found junk in the breakpoints container.");
+
+            finish();
+          });
+        });
+      });
+    }, true);
+
+    function addBreakpoints(callback, increment)
+    {
+      let line;
+
+      executeSoon(function()
+      {
+        line = 4;
+        gPane.addBreakpoint({url: gScripts.selected, line: line},
+          function(cl, err) {
+          onBreakpointAdd.call({ increment: increment, line: line }, cl, err);
+
+          line = 5;
+          gPane.addBreakpoint({url: gScripts.selected, line: line},
+            function(cl, err) {
+            onBreakpointAdd.call({ increment: increment, line: line }, cl, err);
+
+            line = 6;
+            gPane.addBreakpoint({url: gScripts.selected, line: line},
+              function(cl, err) {
+              onBreakpointAdd.call({ increment: increment, line: line }, cl, err);
+
+              executeSoon(function() {
+                callback();
+              });
+            });
+          });
+        });
+      });
+    }
+
+    function disableBreakpoints(callback)
+    {
+      let nodes = Array.slice(gBreakpointsElement.childNodes);
+      info("Nodes to disable: " + breakpointsAdded);
+      is(nodes.length, breakpointsAdded,
+        "The number of nodes to disable is incorrect.");
+
+      Array.forEach(nodes, function(bkp) {
+        info("Disabling breakpoint: " + bkp.id);
+
+        gDebugger.DebuggerView.Breakpoints.disableBreakpoint(bkp, function() {
+          if (++breakpointsDisabled !== breakpointsAdded) {
+            return;
+          }
+          executeSoon(function() {
+            callback();
+          });
+        });
+      });
+    }
+
+    function removeBreakpoints(callback)
+    {
+      let nodes = Array.slice(gBreakpointsElement.childNodes);
+      info("Nodes to remove: " + breakpointsAdded);
+      is(nodes.length, breakpointsAdded,
+        "The number of nodes to remove is incorrect.");
+
+      Array.forEach(nodes, function(bkp) {
+        info("Removing breakpoint: " + bkp.id);
+
+        let [url, line, actor] =
+          [bkp.breakpointUrl, bkp.breakpointLine, bkp.breakpointActor];
+
+        gDebugger.DebuggerView.Breakpoints.removeBreakpoint(actor);
+        gPane.removeBreakpoint(gPane.getBreakpoint(url, line), function() {
+          if (++breakpointsRemoved !== breakpointsAdded) {
+            return;
+          }
+          executeSoon(function() {
+            callback();
+          });
+        });
+      });
+    }
+
+    function onBreakpointAdd(aBreakpointClient, aResponseError)
+    {
+      if (this.increment) {
+        breakpointsAdded++;
+      }
+
+      is(gBreakpointsElement.childNodes.length, breakpointsAdded, this.increment
+        ? "Should have added a breakpoint in the pane."
+        : "Should have the same number of breakpoints in the pane.");
+
+      let id = "breakpoint-" + aBreakpointClient.actor;
+      let bkp = gDebugger.document.getElementById(id);
+      let info = bkp.getElementsByClassName("dbg-breakpoint-info")[0];
+      let text = bkp.getElementsByClassName("dbg-breakpoint-text")[0];
+      let check = bkp.querySelector("checkbox");
+
+      is(bkp.id, id,
+        "Breakpoint element " + id + " found succesfully.");
+      is(info.getAttribute("value"), getExpectedBreakpointInfo(this.line),
+        "The expected information wasn't found in the breakpoint element.");
+      is(text.getAttribute("value"), getExpectedLineText(this.line).trim(),
+        "The expected line text wasn't found in the breakpoint element.");
+      is(check.getAttribute("checked"), "true",
+        "The breakpoint enable checkbox is checked as expected.");
+    }
+
+    function getExpectedBreakpointInfo(line) {
+      let url = gDebugger.DebuggerView.Scripts.selected;
+      let label = gDebugger.DebuggerController.SourceScripts.getScriptLabel(url);
+      return label + ":" + line;
+    }
+
+    function getExpectedLineText(line) {
+      return gDebugger.DebuggerController.SourceScripts.getLineText(line - 1);
+    }
+  }
+
+  registerCleanupFunction(function() {
+    is(Object.keys(gBreakpoints).length, 0, "no breakpoint in the debugger");
+    ok(!gPane.getBreakpoint(gScripts.scriptLocations[0], 5),
+       "getBreakpoint(scriptLocations[0], 5) returns no breakpoint");
+
+    is(breakpointsAdded, 3, "correct number of breakpoints have been added");
+    is(breakpointsDisabled, 3, "correct number of breakpoints have been disabled");
+    is(breakpointsRemoved, 3, "correct number of breakpoints have been removed");
+    removeTab(gTab);
+    gPane = null;
+    gTab = null;
+    gDebuggee = null;
+    gDebugger = null;
+    gScripts = null;
+    gBreakpoints = null;
+    gBreakpointsElement = null;
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-blank.js
@@ -0,0 +1,84 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that changing the tab location URL to a page with no scripts works.
+ */
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+
+function test()
+{
+  debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+
+    testSimpleCall();
+  });
+}
+
+function testSimpleCall() {
+  gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
+    Services.tm.currentThread.dispatch({
+      run: function() {
+        var frames = gDebugger.DebuggerView.StackFrames._frames,
+            childNodes = frames.childNodes;
+
+        is(gDebugger.DebuggerController.activeThread.state, "paused",
+          "Should only be getting stack frames while paused.");
+
+        is(frames.querySelectorAll(".dbg-stackframe").length, 1,
+          "Should have only one frame.");
+
+        is(childNodes.length, frames.querySelectorAll(".dbg-stackframe").length,
+          "All children should be frames.");
+
+        isnot(gDebugger.DebuggerView.Scripts.selected, null,
+          "There should be a selected script.");
+        isnot(gDebugger.editor.getText().length, 0,
+          "The source editor should have some text displayed.");
+
+        testLocationChange();
+      }
+    }, 0);
+  });
+
+  gDebuggee.simpleCall();
+}
+
+function testLocationChange()
+{
+  gDebugger.DebuggerController.activeThread.resume(function() {
+    gDebugger.DebuggerController.client.addOneTimeListener("tabNavigated", function(aEvent, aPacket) {
+      ok(true, "tabNavigated event was fired.");
+      gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
+        ok(true, "Successfully reattached to the tab again.");
+
+        // Wait for the initial resume...
+        gDebugger.gClient.addOneTimeListener("resumed", function() {
+          is(gDebugger.DebuggerView.Scripts.selected, null,
+            "There should be no selected script.");
+          is(gDebugger.editor.getText().length, 0,
+            "The source editor not have any text displayed.");
+
+          closeDebuggerAndFinish();
+        });
+      });
+    });
+    content.location = "about:blank";
+  });
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebuggee = null;
+  gDebugger = null;
+});
--- a/browser/devtools/debugger/test/browser_dbg_panesize-inner.js
+++ b/browser/devtools/debugger/test/browser_dbg_panesize-inner.js
@@ -28,17 +28,17 @@ function test() {
     frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
       frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
 
       ok(content.Prefs.stackframesWidth,
         "The debugger preferences should have a saved stackframesWidth value.");
       ok(content.Prefs.variablesWidth,
         "The debugger preferences should have a saved variablesWidth value.");
 
-      stackframes = content.document.getElementById("stackframes");
+      stackframes = content.document.getElementById("stackframes+breakpoints");
       variables = content.document.getElementById("variables");
 
       is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
         "The stackframes pane width should be the same as the preferred value.");
       is(content.Prefs.variablesWidth, variables.getAttribute("width"),
         "The variables pane width should be the same as the preferred value.");
 
       stackframes.setAttribute("width", someWidth1);
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
@@ -63,17 +63,17 @@ function testScriptLabelShortening() {
       { href: "resource://random/", leaf: "script_t3_1.js#id?a=1&b=2" },
       { href: "resource://random/", leaf: "script_t3_2.js?a=1&b=2#id" },
       { href: "resource://random/", leaf: "script_t3_3.js&a=1&b=2#id" }
     ];
 
     urls.forEach(function(url) {
       executeSoon(function() {
         let loc = url.href + url.leaf;
-        vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true);
+        vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc }, true);
       });
     });
 
     executeSoon(function() {
       info("Script labels:");
       info(vs.scriptLabels.toSource());
 
       info("Script locations:");
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js
@@ -119,16 +119,33 @@ function testScriptSearching() {
 
     write("#__i do not exist__");
     ok(gEditor.getCaretPosition().line == 8 &&
        gEditor.getCaretPosition().col == 2 + token.length,
       "The editor didn't remain at the correct token. (12)");
 
 
     token = "debugger";
+    write("#" + token);
+    ok(gEditor.getCaretPosition().line == 2 &&
+       gEditor.getCaretPosition().col == 44 + token.length,
+      "The editor didn't jump to the correct token. (12.1)");
+
+    clear();
+    EventUtils.sendKey("RETURN");
+    ok(gEditor.getCaretPosition().line == 2 &&
+       gEditor.getCaretPosition().col == 44 + token.length,
+      "The editor shouldn't jump to another token. (12.2)");
+
+    EventUtils.sendKey("ENTER");
+    ok(gEditor.getCaretPosition().line == 2 &&
+       gEditor.getCaretPosition().col == 44 + token.length,
+      "The editor shouldn't jump to another token. (12.3)");
+
+
     write(":1:2:3:a:b:c:::12");
     ok(gEditor.getCaretPosition().line == 11 &&
        gEditor.getCaretPosition().col == 0,
       "The editor didn't jump to the correct line. (13)");
 
     write("#don't#find#me#instead#find#" + token);
     ok(gEditor.getCaretPosition().line == 2 &&
        gEditor.getCaretPosition().col == 44 + token.length,
--- a/browser/devtools/debugger/test/browser_dbg_scripts-sorting.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-sorting.js
@@ -62,41 +62,41 @@ function addScriptsAndCheckOrder(method,
   urls.sort(function(a, b) {
     return Math.random() - 0.5;
   });
 
   switch (method) {
     case 1:
       urls.forEach(function(url) {
         let loc = url.href + url.leaf;
-        vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc });
+        vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc });
       });
       vs.commitScripts();
       break;
 
     case 2:
       urls.forEach(function(url) {
         let loc = url.href + url.leaf;
-        vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true);
+        vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc }, true);
       });
       break;
 
     case 3:
       let i = 0
       for (; i < urls.length / 2; i++) {
         let url = urls[i];
         let loc = url.href + url.leaf;
-        vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc });
+        vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc });
       }
       vs.commitScripts();
 
       for (; i < urls.length; i++) {
         let url = urls[i];
         let loc = url.href + url.leaf;
-        vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true);
+        vs.addScript(ss.getScriptLabel(loc, url.href), { url: loc }, true);
       }
       break;
   }
 
   executeSoon(function() {
     checkScriptsOrder(method);
     callback();
   });
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/Jsbeautify.jsm
@@ -0,0 +1,1317 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/z