Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Wed, 18 Jul 2012 19:02:32 -0700
changeset 110161 adb60cc7b1505bc91ca1c3bb846270cfd19926cb
parent 110160 5d1128ed64af3daa90e95d18c06c06cc03dcac9f (current diff)
parent 102757 9b876829ed322df8cee0120ec5dfe0bb33670794 (diff)
child 110162 e4cf8b5d1baa6bd3579e3763ea65d24a049cab67
push idunknown
push userunknown
push dateunknown
milestone17.0a1
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/zero/1.0/ */
+
+/*
+JS Beautifier written by Einar Lielmanis, <einar@jsbeautifier.org>
+    http://jsbeautifier.org/
+
+Originally converted to javascript by Vital, <vital76@gmail.com>
+"End braces on own line" added by Chris J. Shull, <chrisjshull@gmail.com>
+
+You are free to use this in any way you want, in case you find this useful or
+working for you.
+
+Usage:
+js_beautify(js_source_text);
+js_beautify(js_source_text, options);
+
+The options are:
+indent_size (default 4)          — indentation size.
+indent_char (default space)      — character to indent with.
+preserve_newlines (default true) — whether existing line breaks should be
+                                   preserved.
+max_preserve_newlines (default unlimited) - maximum number of line breaks to be
+                                            preserved in one chunk.
+jslint_happy (default false)     — if true, then jslint-stricter mode is
+                                   enforced.
+
+    jslint_happy   !jslint_happy
+    ---------------------------------
+     function ()    function()
+
+brace_style (default "collapse") - "collapse" | "expand" | "end-expand" |
+                                   "expand-strict"
+    put braces on the same line as control statements (default), or put braces
+    on own line (Allman / ANSI style), or just put end braces on own line.
+
+    expand-strict: put brace on own line even in such cases:
+
+      var a =
+      {
+        a: 5,
+        b: 6
+      }
+    This mode may break your scripts - e.g "return { a: 1 }" will be broken into
+    two lines, so beware.
+
+space_before_conditional (default true) - should the space before conditional
+statement be added, "if(true)" vs "if (true)",
+
+unescape_strings (default false) - should printable characters in
+strings encoded in \xNN notation be unescaped, "example" vs
+"\x65\x78\x61\x6d\x70\x6c\x65"
+
+e.g
+
+js_beautify(js_source_text, {
+  'indent_size': 1,
+  'indent_char': '\t'
+});
+*/
+
+"use strict";
+
+var EXPORTED_SYMBOLS = [ "js_beautify" ];
+
+function js_beautify(js_source_text, options={}) {
+  let input, output, token_text, last_type, last_text, last_last_text,
+    last_word, flags, flag_store, indent_string, whitespace, wordchar,
+    punct, parser_pos, line_starters, digits, prefix, token_type,
+    do_block_just_closed, wanted_newline, just_added_newline, n_newlines,
+    opt_brace_style, preindent_string = '';
+
+  // compatibility
+  if (options.space_after_anon_function !== undefined &&
+      options.jslint_happy === undefined) {
+    options.jslint_happy = options.space_after_anon_function;
+  }
+  if (options.braces_on_own_line !== undefined) {
+    opt_brace_style = options.braces_on_own_line ? "expand" : "collapse";
+  }
+  opt_brace_style = options.brace_style ? options.brace_style :
+                    (opt_brace_style ? opt_brace_style : "collapse");
+
+
+  let opt_indent_size = options.indent_size ? options.indent_size : 4;
+  let opt_indent_char = options.indent_char ? options.indent_char : ' ';
+  let opt_preserve_newlines = typeof options.preserve_newlines === 'undefined' ?
+    true : options.preserve_newlines;
+  let opt_max_preserve_newlines =
+    typeof options.max_preserve_newlines === 'undefined' ?
+    false : options.max_preserve_newlines;
+  let opt_jslint_happy = options.jslint_happy === 'undefined' ?
+    false : options.jslint_happy;
+  let opt_keep_array_indentation =
+    typeof options.keep_array_indentation === 'undefined' ?
+    false : options.keep_array_indentation;
+  let opt_space_before_conditional =
+    typeof options.space_before_conditional === 'undefined' ?
+    true : options.space_before_conditional;
+  let opt_indent_case = typeof options.indent_case === 'undefined' ?
+    false : options.indent_case;
+  let opt_unescape_strings = typeof options.unescape_strings === 'undefined' ?
+    false : options.unescape_strings;
+
+  just_added_newline = false;
+
+  // cache the source's length.
+  let input_length = js_source_text.length;
+
+  function trim_output(eat_newlines) {
+    eat_newlines = typeof eat_newlines === 'undefined' ? false : eat_newlines;
+    while (output.length && (output[output.length - 1] === ' ' ||
+           output[output.length - 1] === indent_string ||
+           output[output.length - 1] === preindent_string ||
+           (eat_newlines && (output[output.length - 1] === '\n' ||
+           output[output.length - 1] === '\r')))) {
+      output.pop();
+    }
+  }
+
+  function trim(s) {
+    return s.replace(/^\s\s*|\s\s*$/, '');
+  }
+
+  function split_newlines(s)
+  {
+    return s.split(/\x0d\x0a|\x0a/);
+  }
+
+  function force_newline()
+  {
+    let old_keep_array_indentation = opt_keep_array_indentation;
+    opt_keep_array_indentation = false;
+    print_newline();
+    opt_keep_array_indentation = old_keep_array_indentation;
+  }
+
+  function print_newline(ignore_repeated) {
+
+    flags.eat_next_space = false;
+    if (opt_keep_array_indentation && is_array(flags.mode)) {
+      return;
+    }
+
+    ignore_repeated = typeof ignore_repeated === 'undefined' ? true : ignore_repeated;
+
+    flags.if_line = false;
+    trim_output();
+
+    if (!output.length) {
+      return; // no newline on start of file
+    }
+
+    if (output[output.length - 1] !== "\n" || !ignore_repeated) {
+      just_added_newline = true;
+      output.push("\n");
+    }
+    if (preindent_string) {
+      output.push(preindent_string);
+    }
+    for (let i = 0; i < flags.indentation_level; i += 1) {
+      output.push(indent_string);
+    }
+    if (flags.var_line && flags.var_line_reindented) {
+      output.push(indent_string); // skip space-stuffing, if indenting with a tab
+    }
+    if (flags.case_body) {
+      output.push(indent_string);
+    }
+  }
+
+  function print_single_space() {
+
+    if (last_type === 'TK_COMMENT') {
+      return print_newline();
+    }
+    if (flags.eat_next_space) {
+      flags.eat_next_space = false;
+      return;
+    }
+    let last_output = ' ';
+    if (output.length) {
+      last_output = output[output.length - 1];
+    }
+    if (last_output !== ' ' && last_output !== '\n' &&
+        last_output !== indent_string) { // prevent occassional duplicate space
+      output.push(' ');
+    }
+  }
+
+
+  function print_token() {
+    just_added_newline = false;
+    flags.eat_next_space = false;
+    output.push(token_text);
+  }
+
+  function indent() {
+    flags.indentation_level += 1;
+  }
+
+
+  function remove_indent() {
+    if (output.length && output[output.length - 1] === indent_string) {
+      output.pop();
+    }
+  }
+
+  function set_mode(mode) {
+    if (flags) {
+      flag_store.push(flags);
+    }
+    flags = {
+      previous_mode: flags ? flags.mode : 'BLOCK',
+      mode: mode,
+      var_line: false,
+      var_line_tainted: false,
+      var_line_reindented: false,
+      in_html_comment: false,
+      if_line: false,
+      in_case_statement: false, // switch(..){ INSIDE HERE }
+      in_case: false, // we're on the exact line with "case 0:"
+      case_body: false, // the indented case-action block
+      eat_next_space: false,
+      indentation_baseline: -1,
+      indentation_level: (flags ? flags.indentation_level +
+                         (flags.case_body ? 1 : 0) +
+                         ((flags.var_line && flags.var_line_reindented) ? 1 : 0) : 0),
+      ternary_depth: 0
+    };
+  }
+
+  function is_array(mode) {
+    return mode === '[EXPRESSION]' || mode === '[INDENTED-EXPRESSION]';
+  }
+
+  function is_expression(mode) {
+    return in_array(mode, ['[EXPRESSION]', '(EXPRESSION)',
+           '(FOR-EXPRESSION)', '(COND-EXPRESSION)']);
+  }
+
+  function restore_mode() {
+    do_block_just_closed = flags.mode === 'DO_BLOCK';
+    if (flag_store.length > 0) {
+      let mode = flags.mode;
+      flags = flag_store.pop();
+      flags.previous_mode = mode;
+    }
+  }
+
+  function all_lines_start_with(lines, c) {
+    for (let line of lines) {
+      line = trim(line);
+      if (line.charAt(0) !== c) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  function is_special_word(word) {
+    return in_array(word, ['case', 'return', 'do', 'if', 'throw', 'else']);
+  }
+
+  function in_array(what, arr) {
+    return arr.indexOf(what) != -1;
+  }
+
+  function look_up(exclude) {
+    let local_pos = parser_pos;
+    let c = input.charAt(local_pos);
+    while (in_array(c, whitespace) && c != exclude) {
+      local_pos++;
+      if (local_pos >= input_length) return 0;
+      c = input.charAt(local_pos);
+    }
+    return c;
+  }
+
+  function get_next_token() {
+    n_newlines = 0;
+
+    if (parser_pos >= input_length) {
+      return ['', 'TK_EOF'];
+    }
+
+    wanted_newline = false;
+
+    let c = input.charAt(parser_pos);
+    parser_pos += 1;
+
+    let keep_whitespace = opt_keep_array_indentation && is_array(flags.mode);
+
+    if (keep_whitespace) {
+
+      //
+      // slight mess to allow nice preservation of array indentation and
+      // reindent that correctly first time when we get to the arrays:
+      // let a = [
+      // ....'something'
+      // we make note of whitespace_count = 4 into flags.indentation_baseline so
+      // we know that 4 whitespaces in original source match indent_level of
+      // reindented source and afterwards, when we get to
+      //  'something,
+      // .......'something else'
+      // we know that this should be indented to indent_level +
+      // (7 - indentation_baseline) spaces
+      //
+      let whitespace_count = 0;
+
+      while (in_array(c, whitespace)) {
+        if (c === "\n") {
+          trim_output();
+          output.push("\n");
+          just_added_newline = true;
+          whitespace_count = 0;
+        } else {
+          if (c === '\t') {
+            whitespace_count += 4;
+          } else if (c === '\r') {
+            // nothing
+          } else {
+            whitespace_count += 1;
+          }
+        }
+
+        if (parser_pos >= input_length) {
+          return ['', 'TK_EOF'];
+        }
+
+        c = input.charAt(parser_pos);
+        parser_pos += 1;
+
+      }
+      if (flags.indentation_baseline === -1) {
+        flags.indentation_baseline = whitespace_count;
+      }
+
+      if (just_added_newline) {
+        for (let i = 0; i < flags.indentation_level + 1; i += 1) {
+          output.push(indent_string);
+        }
+        if (flags.indentation_baseline !== -1) {
+          for (let i = 0; i < whitespace_count - flags.indentation_baseline; i++) {
+            output.push(' ');
+          }
+        }
+      }
+    } else {
+      while (in_array(c, whitespace)) {
+
+        if (c === "\n") {
+          n_newlines += ( (opt_max_preserve_newlines) ?
+            (n_newlines <= opt_max_preserve_newlines) ? 1: 0: 1 );
+        }
+
+
+        if (parser_pos >= input_length) {
+          return ['', 'TK_EOF'];
+        }
+
+        c = input.charAt(parser_pos);
+        parser_pos += 1;
+      }
+
+      if (opt_preserve_newlines) {
+        if (n_newlines > 1) {
+          for (i = 0; i < n_newlines; i += 1) {
+            print_newline(i === 0);
+            just_added_newline = true;
+          }
+        }
+      }
+      wanted_newline = n_newlines > 0;
+    }
+
+    if (in_array(c, wordchar)) {
+      if (parser_pos < input_length) {
+        while (in_array(input.charAt(parser_pos), wordchar)) {
+          c += input.charAt(parser_pos);
+          parser_pos += 1;
+          if (parser_pos === input_length) {
+            break;
+          }
+        }
+      }
+
+      // small and surprisingly unugly hack for 1E-10 representation
+      if (parser_pos !== input_length && c.match(/^[0-9]+[Ee]$/) &&
+         (input.charAt(parser_pos) === '-' ||
+          input.charAt(parser_pos) === '+')) {
+        let sign = input.charAt(parser_pos);
+        parser_pos += 1;
+
+        let t = get_next_token(parser_pos);
+        c += sign + t[0];
+        return [c, 'TK_WORD'];
+      }
+
+      if (c === 'in') { // hack for 'in' operator
+        return [c, 'TK_OPERATOR'];
+      }
+      if (wanted_newline && last_type !== 'TK_OPERATOR'
+        && last_type !== 'TK_EQUALS'
+        && !flags.if_line && (opt_preserve_newlines || last_text !== 'var')) {
+        print_newline();
+      }
+      return [c, 'TK_WORD'];
+    }
+
+    if (c === '(' || c === '[') {
+      return [c, 'TK_START_EXPR'];
+    }
+
+    if (c === ')' || c === ']') {
+      return [c, 'TK_END_EXPR'];
+    }
+
+    if (c === '{') {
+      return [c, 'TK_START_BLOCK'];
+    }
+
+    if (c === '}') {
+      return [c, 'TK_END_BLOCK'];
+    }
+
+    if (c === ';') {
+      return [c, 'TK_SEMICOLON'];
+    }
+
+    if (c === '/') {
+      let comment = '';
+      // peek for comment /* ... */
+      let inline_comment = true;
+      if (input.charAt(parser_pos) === '*') {
+        parser_pos += 1;
+        if (parser_pos < input_length) {
+          while (parser_pos < input_length && ! (input.charAt(parser_pos) === '*' &&
+            input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/')) {
+
+            c = input.charAt(parser_pos);
+            comment += c;
+            if (c === "\n" || c === "\r") {
+              inline_comment = false;
+            }
+            parser_pos += 1;
+            if (parser_pos >= input_length) {
+              break;
+            }
+          }
+        }
+        parser_pos += 2;
+        if (inline_comment && n_newlines == 0) {
+          return ['/*' + comment + '*/', 'TK_INLINE_COMMENT'];
+        } else {
+          return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT'];
+        }
+      }
+      // peek for comment // ...
+      if (input.charAt(parser_pos) === '/') {
+        comment = c;
+        while (input.charAt(parser_pos) !== '\r' &&
+               input.charAt(parser_pos) !== '\n') {
+          comment += input.charAt(parser_pos);
+          parser_pos += 1;
+          if (parser_pos >= input_length) {
+            break;
+          }
+        }
+        if (wanted_newline) {
+          print_newline();
+        }
+        return [comment, 'TK_COMMENT'];
+      }
+
+    }
+
+    if (c === "'" || // string
+        c === '"' || // string
+       (c === '/' &&
+      ((last_type === 'TK_WORD' && is_special_word(last_text)) ||
+       (last_text === ')' && in_array(flags.previous_mode,
+        ['(COND-EXPRESSION)', '(FOR-EXPRESSION)'])) ||
+       (last_type === 'TK_COMMENT' || last_type === 'TK_START_EXPR' ||
+        last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' ||
+        last_type === 'TK_OPERATOR' || last_type === 'TK_EQUALS' ||
+        last_type === 'TK_EOF' || last_type === 'TK_SEMICOLON')))) { // regexp
+
+      let sep = c;
+      let esc = false;
+      let esc1 = 0;
+      let esc2 = 0;
+      let resulting_string = c;
+
+      if (parser_pos < input_length) {
+        if (sep === '/') {
+          //
+          // handle regexp separately...
+          //
+          let in_char_class = false;
+          while (esc || in_char_class || input.charAt(parser_pos) !== sep) {
+            resulting_string += input.charAt(parser_pos);
+            if (!esc) {
+              esc = input.charAt(parser_pos) === '\\';
+              if (input.charAt(parser_pos) === '[') {
+                in_char_class = true;
+              } else if (input.charAt(parser_pos) === ']') {
+                in_char_class