Merge m-c to s-c.
authorRichard Newman <rnewman@mozilla.com>
Sun, 03 Feb 2013 00:51:21 -0800
changeset 130798 c9a5a09b8c7d56c47e4b96e6a05fd7e86def85d5
parent 130797 018a9b5a299cf3ae8a5c7619536d9364b29adb08 (current diff)
parent 130482 ba515e203813b34f6feaaa4ad0d0a971f828e7f5 (diff)
child 130799 8d651840659725707b6a140bef13cac7d1c494d0
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to s-c.
browser/devtools/debugger/test/browser_dbg_propertyview-big-data.js
browser/devtools/debugger/test/browser_dbg_propertyview-edit.js
content/html/content/test/forms/test_input_number_value.html
content/svg/content/src/SVGLocatableElement.cpp
content/svg/content/src/SVGLocatableElement.h
dom/webidl/SVGLocatableElement.webidl
dom/webidl/SVGTransformableElement.webidl
js/src/jit-test/tests/auto-regress/bug566815.js
js/src/jit-test/tests/auto-regress/bug580967.js
js/src/jit-test/tests/auto-regress/bug688973.js
js/src/jit-test/tests/basic/bug583615.js
js/src/jit-test/tests/basic/testBug616119.js
js/src/jit-test/tests/basic/testInterpreterReentery8.js
js/src/jit-test/tests/e4x/bug557168-1.js
js/src/jit-test/tests/e4x/bug557168-2.js
js/src/jit-test/tests/e4x/bug557168-3.js
js/src/jit-test/tests/e4x/bug557168.js
js/src/jit-test/tests/e4x/bug569843.js
js/src/jit-test/tests/e4x/bug574280.js
js/src/jit-test/tests/e4x/bug596502-version.js
js/src/jit-test/tests/e4x/bug605200.js
js/src/jit-test/tests/e4x/bug613151.js
js/src/jit-test/tests/e4x/bug632206.js
js/src/jit-test/tests/e4x/bug651966.js
js/src/jit-test/tests/e4x/bug665812.js
js/src/jit-test/tests/e4x/bug672153.js
js/src/jit-test/tests/e4x/bug700799.js
js/src/jit-test/tests/e4x/bug716713.js
js/src/jit-test/tests/e4x/bug731724.js
js/src/jit-test/tests/e4x/bug731745.js
js/src/jit-test/tests/e4x/bug737251.js
js/src/jit-test/tests/e4x/bug753885-1.js
js/src/jit-test/tests/e4x/bug753885-2.js
js/src/jit-test/tests/e4x/defaults-e4x.js
js/src/jit-test/tests/e4x/e4x-descendants-with-arguments.js
js/src/jit-test/tests/e4x/testXMLPropertyNames.js
js/src/jit-test/tests/ion/bug758384.js
js/src/jsxml.cpp
js/src/jsxml.h
js/src/tests/e4x/Expressions/11.1.1.js
js/src/tests/e4x/Expressions/11.1.2.js
js/src/tests/e4x/Expressions/11.1.3.js
js/src/tests/e4x/Expressions/11.1.4-01.js
js/src/tests/e4x/Expressions/11.1.4-02.js
js/src/tests/e4x/Expressions/11.1.4-03.js
js/src/tests/e4x/Expressions/11.1.4-04.js
js/src/tests/e4x/Expressions/11.1.4-05.js
js/src/tests/e4x/Expressions/11.1.4-06.js
js/src/tests/e4x/Expressions/11.1.4-07.js
js/src/tests/e4x/Expressions/11.1.4-08.js
js/src/tests/e4x/Expressions/11.1.4.js
js/src/tests/e4x/Expressions/11.1.5.js
js/src/tests/e4x/Expressions/11.2.1.js
js/src/tests/e4x/Expressions/11.2.2.js
js/src/tests/e4x/Expressions/11.2.3.js
js/src/tests/e4x/Expressions/11.2.4.js
js/src/tests/e4x/Expressions/11.3.1.js
js/src/tests/e4x/Expressions/11.3.2.js
js/src/tests/e4x/Expressions/11.4.1.js
js/src/tests/e4x/Expressions/11.5.1.js
js/src/tests/e4x/Expressions/11.6.1.js
js/src/tests/e4x/Expressions/11.6.2.js
js/src/tests/e4x/Expressions/11.6.3.js
js/src/tests/e4x/Expressions/browser.js
js/src/tests/e4x/Expressions/regress-301545.js
js/src/tests/e4x/Expressions/regress-302531.js
js/src/tests/e4x/Expressions/regress-340024.js
js/src/tests/e4x/Expressions/regress-366123.js
js/src/tests/e4x/Expressions/regress-496113.js
js/src/tests/e4x/Expressions/shell.js
js/src/tests/e4x/GC/browser.js
js/src/tests/e4x/GC/regress-280844-1.js
js/src/tests/e4x/GC/regress-280844-2.js
js/src/tests/e4x/GC/regress-292455.js
js/src/tests/e4x/GC/regress-313952-01.js
js/src/tests/e4x/GC/regress-313952-02.js
js/src/tests/e4x/GC/regress-324117.js
js/src/tests/e4x/GC/regress-324278.js
js/src/tests/e4x/GC/regress-339785.js
js/src/tests/e4x/GC/regress-357063-01.js
js/src/tests/e4x/GC/regress-357063-02.js
js/src/tests/e4x/GC/shell.js
js/src/tests/e4x/Global/13.1.2.1.js
js/src/tests/e4x/Global/browser.js
js/src/tests/e4x/Global/shell.js
js/src/tests/e4x/Namespace/13.2.1.js
js/src/tests/e4x/Namespace/13.2.2.js
js/src/tests/e4x/Namespace/13.2.5.js
js/src/tests/e4x/Namespace/browser.js
js/src/tests/e4x/Namespace/regress-283972.js
js/src/tests/e4x/Namespace/regress-292863.js
js/src/tests/e4x/Namespace/regress-350442.js
js/src/tests/e4x/Namespace/regress-444608-02.js
js/src/tests/e4x/Namespace/regress-444608.js
js/src/tests/e4x/Namespace/shell.js
js/src/tests/e4x/QName/13.3.1.js
js/src/tests/e4x/QName/13.3.2.js
js/src/tests/e4x/QName/13.3.5.js
js/src/tests/e4x/QName/browser.js
js/src/tests/e4x/QName/regress-373595-01.js
js/src/tests/e4x/QName/regress-373595-02.js
js/src/tests/e4x/QName/regress-373595-03.js
js/src/tests/e4x/QName/regress-444608.js
js/src/tests/e4x/QName/regress-619529.js
js/src/tests/e4x/QName/shell.js
js/src/tests/e4x/Regress/browser.js
js/src/tests/e4x/Regress/regress-257679.js
js/src/tests/e4x/Regress/regress-263934.js
js/src/tests/e4x/Regress/regress-263935.js
js/src/tests/e4x/Regress/regress-263936.js
js/src/tests/e4x/Regress/regress-264369.js
js/src/tests/e4x/Regress/regress-271545.js
js/src/tests/e4x/Regress/regress-277650.js
js/src/tests/e4x/Regress/regress-277664.js
js/src/tests/e4x/Regress/regress-277683.js
js/src/tests/e4x/Regress/regress-277779.js
js/src/tests/e4x/Regress/regress-277935.js
js/src/tests/e4x/Regress/regress-278112.js
js/src/tests/e4x/Regress/regress-283349.js
js/src/tests/e4x/Regress/regress-290056.js
js/src/tests/e4x/Regress/regress-290499.js
js/src/tests/e4x/Regress/regress-301553.js
js/src/tests/e4x/Regress/regress-301573.js
js/src/tests/e4x/Regress/regress-301596.js
js/src/tests/e4x/Regress/regress-308111.js
js/src/tests/e4x/Regress/regress-309897.js
js/src/tests/e4x/Regress/regress-311580.js
js/src/tests/e4x/Regress/regress-313799.js
js/src/tests/e4x/Regress/regress-318922.js
js/src/tests/e4x/Regress/regress-319872.js
js/src/tests/e4x/Regress/regress-322499.js
js/src/tests/e4x/Regress/regress-323338-1.js
js/src/tests/e4x/Regress/regress-323338-2.js
js/src/tests/e4x/Regress/regress-325425.js
js/src/tests/e4x/Regress/regress-327564.js
js/src/tests/e4x/Regress/regress-327691-01.js
js/src/tests/e4x/Regress/regress-327691-02.js
js/src/tests/e4x/Regress/regress-327697.js
js/src/tests/e4x/Regress/regress-328249.js
js/src/tests/e4x/Regress/regress-329257.js
js/src/tests/e4x/Regress/regress-331664.js
js/src/tests/e4x/Regress/regress-344455.js
js/src/tests/e4x/Regress/regress-347155.js
js/src/tests/e4x/Regress/regress-350206-1.js
js/src/tests/e4x/Regress/regress-350206.js
js/src/tests/e4x/Regress/regress-350238.js
js/src/tests/e4x/Regress/regress-350629.js
js/src/tests/e4x/Regress/regress-352103.js
js/src/tests/e4x/Regress/regress-352223.js
js/src/tests/e4x/Regress/regress-354145-01.js
js/src/tests/e4x/Regress/regress-354145-02.js
js/src/tests/e4x/Regress/regress-354145-03.js
js/src/tests/e4x/Regress/regress-354145-04.js
js/src/tests/e4x/Regress/regress-354145-05.js
js/src/tests/e4x/Regress/regress-354145-07.js
js/src/tests/e4x/Regress/regress-354998.js
js/src/tests/e4x/Regress/regress-355474-02.js
js/src/tests/e4x/Regress/regress-355478.js
js/src/tests/e4x/Regress/regress-355569.js
js/src/tests/e4x/Regress/regress-356238-01.js
js/src/tests/e4x/Regress/regress-356238-02.js
js/src/tests/e4x/Regress/regress-356238-03.js
js/src/tests/e4x/Regress/regress-361451.js
js/src/tests/e4x/Regress/regress-364017.js
js/src/tests/e4x/Regress/regress-369032.js
js/src/tests/e4x/Regress/regress-369536.js
js/src/tests/e4x/Regress/regress-369740.js
js/src/tests/e4x/Regress/regress-370016.js
js/src/tests/e4x/Regress/regress-370048-01.js
js/src/tests/e4x/Regress/regress-370048-02.js
js/src/tests/e4x/Regress/regress-370372.js
js/src/tests/e4x/Regress/regress-371369.js
js/src/tests/e4x/Regress/regress-372563.js
js/src/tests/e4x/Regress/regress-372564.js
js/src/tests/e4x/Regress/regress-373082.js
js/src/tests/e4x/Regress/regress-374106.js
js/src/tests/e4x/Regress/regress-374112.js
js/src/tests/e4x/Regress/regress-374116.js
js/src/tests/e4x/Regress/regress-374160.js
js/src/tests/e4x/Regress/regress-375406.js
js/src/tests/e4x/Regress/regress-378492.js
js/src/tests/e4x/Regress/regress-380833.js
js/src/tests/e4x/Regress/regress-383255.js
js/src/tests/e4x/Regress/regress-394941.js
js/src/tests/e4x/Regress/regress-407323.js
js/src/tests/e4x/Regress/regress-426520.js
js/src/tests/e4x/Regress/regress-453915.js
js/src/tests/e4x/Regress/regress-458679-01.js
js/src/tests/e4x/Regress/regress-458679-02.js
js/src/tests/e4x/Regress/regress-460180.js
js/src/tests/e4x/Regress/regress-465063.js
js/src/tests/e4x/Regress/regress-470619.js
js/src/tests/e4x/Regress/regress-473709.js
js/src/tests/e4x/Regress/regress-474319.js
js/src/tests/e4x/Regress/regress-477053.js
js/src/tests/e4x/Regress/regress-561031.js
js/src/tests/e4x/Regress/regress-587434.js
js/src/tests/e4x/Regress/regress-677032.js
js/src/tests/e4x/Regress/shell.js
js/src/tests/e4x/Statements/12.1.js
js/src/tests/e4x/Statements/12.2.js
js/src/tests/e4x/Statements/12.3-01.js
js/src/tests/e4x/Statements/browser.js
js/src/tests/e4x/Statements/shell.js
js/src/tests/e4x/TypeConversion/10.1.1.js
js/src/tests/e4x/TypeConversion/10.1.2.js
js/src/tests/e4x/TypeConversion/10.2.1.js
js/src/tests/e4x/TypeConversion/10.3.1.js
js/src/tests/e4x/TypeConversion/10.3.js
js/src/tests/e4x/TypeConversion/10.4.1.js
js/src/tests/e4x/TypeConversion/10.4.js
js/src/tests/e4x/TypeConversion/10.5.1.js
js/src/tests/e4x/TypeConversion/10.5.js
js/src/tests/e4x/TypeConversion/10.6.1.js
js/src/tests/e4x/TypeConversion/10.6.js
js/src/tests/e4x/TypeConversion/browser.js
js/src/tests/e4x/TypeConversion/shell.js
js/src/tests/e4x/Types/9.1.1.1.js
js/src/tests/e4x/Types/9.1.1.10.js
js/src/tests/e4x/Types/9.1.1.11.js
js/src/tests/e4x/Types/9.1.1.12.js
js/src/tests/e4x/Types/9.1.1.13.js
js/src/tests/e4x/Types/9.1.1.2.js
js/src/tests/e4x/Types/9.1.1.3.js
js/src/tests/e4x/Types/9.1.1.4.js
js/src/tests/e4x/Types/9.1.1.5.js
js/src/tests/e4x/Types/9.1.1.6.js
js/src/tests/e4x/Types/9.1.1.7.js
js/src/tests/e4x/Types/9.1.1.8.js
js/src/tests/e4x/Types/9.1.1.9.js
js/src/tests/e4x/Types/9.2.1.1.js
js/src/tests/e4x/Types/9.2.1.10.js
js/src/tests/e4x/Types/9.2.1.2.js
js/src/tests/e4x/Types/9.2.1.3.js
js/src/tests/e4x/Types/9.2.1.4.js
js/src/tests/e4x/Types/9.2.1.5.js
js/src/tests/e4x/Types/9.2.1.6.js
js/src/tests/e4x/Types/9.2.1.7.js
js/src/tests/e4x/Types/9.2.1.8.js
js/src/tests/e4x/Types/9.2.1.9.js
js/src/tests/e4x/Types/browser.js
js/src/tests/e4x/Types/shell.js
js/src/tests/e4x/XML/13.4.1.js
js/src/tests/e4x/XML/13.4.2.js
js/src/tests/e4x/XML/13.4.3.10.js
js/src/tests/e4x/XML/13.4.3.js
js/src/tests/e4x/XML/13.4.4.1.js
js/src/tests/e4x/XML/13.4.4.10.js
js/src/tests/e4x/XML/13.4.4.11.js
js/src/tests/e4x/XML/13.4.4.12-1.js
js/src/tests/e4x/XML/13.4.4.12.js
js/src/tests/e4x/XML/13.4.4.13.js
js/src/tests/e4x/XML/13.4.4.14.js
js/src/tests/e4x/XML/13.4.4.15.js
js/src/tests/e4x/XML/13.4.4.16.js
js/src/tests/e4x/XML/13.4.4.17.js
js/src/tests/e4x/XML/13.4.4.18.js
js/src/tests/e4x/XML/13.4.4.19.js
js/src/tests/e4x/XML/13.4.4.2.js
js/src/tests/e4x/XML/13.4.4.20.js
js/src/tests/e4x/XML/13.4.4.21.js
js/src/tests/e4x/XML/13.4.4.22.js
js/src/tests/e4x/XML/13.4.4.23.js
js/src/tests/e4x/XML/13.4.4.24.js
js/src/tests/e4x/XML/13.4.4.25.js
js/src/tests/e4x/XML/13.4.4.26.js
js/src/tests/e4x/XML/13.4.4.27.js
js/src/tests/e4x/XML/13.4.4.28.js
js/src/tests/e4x/XML/13.4.4.29.js
js/src/tests/e4x/XML/13.4.4.3-01.js
js/src/tests/e4x/XML/13.4.4.3-02.js
js/src/tests/e4x/XML/13.4.4.3.js
js/src/tests/e4x/XML/13.4.4.30.js
js/src/tests/e4x/XML/13.4.4.31.js
js/src/tests/e4x/XML/13.4.4.32-01.js
js/src/tests/e4x/XML/13.4.4.32.js
js/src/tests/e4x/XML/13.4.4.33.js
js/src/tests/e4x/XML/13.4.4.34.js
js/src/tests/e4x/XML/13.4.4.35.js
js/src/tests/e4x/XML/13.4.4.36.js
js/src/tests/e4x/XML/13.4.4.37.js
js/src/tests/e4x/XML/13.4.4.38.js
js/src/tests/e4x/XML/13.4.4.39.js
js/src/tests/e4x/XML/13.4.4.4.js
js/src/tests/e4x/XML/13.4.4.40.js
js/src/tests/e4x/XML/13.4.4.5.js
js/src/tests/e4x/XML/13.4.4.6.js
js/src/tests/e4x/XML/13.4.4.7.js
js/src/tests/e4x/XML/13.4.4.8.js
js/src/tests/e4x/XML/13.4.4.9.js
js/src/tests/e4x/XML/browser.js
js/src/tests/e4x/XML/regress-291930.js
js/src/tests/e4x/XML/regress-324422-1.js
js/src/tests/e4x/XML/regress-324422-2.js
js/src/tests/e4x/XML/regress-324688.js
js/src/tests/e4x/XML/regress-336921.js
js/src/tests/e4x/XML/regress-376773.js
js/src/tests/e4x/XML/regress-621464.js
js/src/tests/e4x/XML/regress-638982.js
js/src/tests/e4x/XML/shell.js
js/src/tests/e4x/XMLList/13.5.1.js
js/src/tests/e4x/XMLList/13.5.2.js
js/src/tests/e4x/XMLList/13.5.4.10.js
js/src/tests/e4x/XMLList/13.5.4.11.js
js/src/tests/e4x/XMLList/13.5.4.12.js
js/src/tests/e4x/XMLList/13.5.4.13.js
js/src/tests/e4x/XMLList/13.5.4.14.js
js/src/tests/e4x/XMLList/13.5.4.15.js
js/src/tests/e4x/XMLList/13.5.4.16.js
js/src/tests/e4x/XMLList/13.5.4.17.js
js/src/tests/e4x/XMLList/13.5.4.18.js
js/src/tests/e4x/XMLList/13.5.4.19.js
js/src/tests/e4x/XMLList/13.5.4.2.js
js/src/tests/e4x/XMLList/13.5.4.20.js
js/src/tests/e4x/XMLList/13.5.4.21.js
js/src/tests/e4x/XMLList/13.5.4.22.js
js/src/tests/e4x/XMLList/13.5.4.3.js
js/src/tests/e4x/XMLList/13.5.4.4.js
js/src/tests/e4x/XMLList/13.5.4.5.js
js/src/tests/e4x/XMLList/13.5.4.6.js
js/src/tests/e4x/XMLList/13.5.4.7.js
js/src/tests/e4x/XMLList/13.5.4.8.js
js/src/tests/e4x/XMLList/13.5.4.9.js
js/src/tests/e4x/XMLList/browser.js
js/src/tests/e4x/XMLList/regress-373072.js
js/src/tests/e4x/XMLList/shell.js
js/src/tests/e4x/browser.js
js/src/tests/e4x/extensions/assign-to-xml.js
js/src/tests/e4x/extensions/browser.js
js/src/tests/e4x/extensions/extensibility.js
js/src/tests/e4x/extensions/json-stringify-dropping-xml-elements.js
js/src/tests/e4x/extensions/qualified-name-expr.js
js/src/tests/e4x/extensions/regress-305335.js
js/src/tests/e4x/extensions/regress-312196.js
js/src/tests/e4x/extensions/regress-313080.js
js/src/tests/e4x/extensions/regress-327534.js
js/src/tests/e4x/extensions/regress-327897.js
js/src/tests/e4x/extensions/regress-337226.js
js/src/tests/e4x/extensions/regress-352846-01.js
js/src/tests/e4x/extensions/regress-352846-02.js
js/src/tests/e4x/extensions/regress-352846-03.js
js/src/tests/e4x/extensions/regress-353165.js
js/src/tests/e4x/extensions/regress-354145-06.js
js/src/tests/e4x/extensions/regress-354151-01.js
js/src/tests/e4x/extensions/regress-354151-02.js
js/src/tests/e4x/extensions/regress-374025.js
js/src/tests/e4x/extensions/regress-374163.js
js/src/tests/e4x/extensions/regress-410192.js
js/src/tests/e4x/extensions/regress-450871-01.js
js/src/tests/e4x/extensions/regress-450871-02.js
js/src/tests/e4x/extensions/regress-462734-01.js
js/src/tests/e4x/extensions/regress-595207.js
js/src/tests/e4x/extensions/shell.js
js/src/tests/e4x/extensions/stringify-xml.js
js/src/tests/e4x/extensions/xml-as-proto.js
js/src/tests/e4x/shell.js
js/src/tests/e4x/template.js
js/src/tests/ecma_5/extensions/Object-keys-and-object-ids.js
js/src/tests/ecma_5/extensions/strict-e4x-ban.js
js/src/tests/js1_5/Regress/regress-309242.js
js/src/tests/js1_5/Regress/regress-407323.js
js/src/tests/js1_6/Regress/regress-301574.js
js/src/tests/js1_6/Regress/regress-314887.js
js/src/tests/js1_6/Regress/regress-378492.js
js/src/tests/js1_7/block/regress-352212.js
js/src/tests/js1_7/extensions/regress-355145.js
js/src/tests/js1_7/geniter/regress-352605.js
js/src/tests/js1_7/iterable/regress-355075-02.js
js/src/tests/js1_7/regress/regress-352797-02.js
js/src/tests/js1_7/regress/regress-352870-01.js
js/src/tests/js1_7/regress/regress-352870-03.js
js/src/tests/js1_7/regress/regress-416705.js
js/src/tests/js1_7/regress/regress-428708.js
js/src/tests/js1_7/regress/regress-470388-02.js
js/src/tests/js1_7/regress/regress-470388-03.js
js/src/tests/js1_8/extensions/regress-476871-02.js
js/src/tests/js1_8/regress/regress-472450-01.js
js/src/tests/js1_8/regress/regress-472450-02.js
js/src/tests/js1_8_5/regress/regress-546615.js
js/src/tests/js1_8_5/regress/regress-560101.js
js/src/tests/js1_8_5/regress/regress-592217.js
js/src/tests/js1_8_5/regress/regress-597870.js
js/src/tests/js1_8_5/regress/regress-618576.js
js/src/tests/js1_8_5/regress/regress-673070-3.js
js/src/tests/js1_8_5/regress/regress-675581.js
js/xpconnect/src/nsCSSPropertiesQS.h
js/xpconnect/tests/mochitest/test_bug564330.html
js/xpconnect/tests/mochitest/test_bug655297.html
mobile/android/base/resources/drawable-nodpi/tabs_tray_selected_bg.png
mobile/android/base/resources/drawable/tabs_tray_active_selector.xml
mobile/android/base/resources/drawable/tabs_tray_default_selector.xml
mobile/android/base/resources/drawable/tabs_tray_selected_bg_repeat.xml
mobile/android/base/resources/layout-v11/tabs_panel_header.xml
mobile/android/base/resources/menu/tabs_switcher_menu.xml
--- a/CLOBBER
+++ b/CLOBBER
@@ -10,9 +10,9 @@
 #                  O   <-- Users coming from both parents need to Clobber
 #               /     \
 #          O               O
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
-Bug 830231 - Remove nsIDOMDOM(Settable)TokenList (Needs clobber on at least Windows)
+Bug 788293 - Remove e4x support
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -116,19 +116,27 @@ SettingsListener.observe('language.curre
   }
 
   let intl = '';
   try {
     intl = Services.prefs.getComplexValue(prefName,
                                           Ci.nsIPrefLocalizedString).data;
   } catch(e) {}
 
+  // Bug 830782 - Homescreen is in English instead of selected locale after
+  // the first run experience.
+  // In order to ensure the current intl value is reflected on the child
+  // process let's always write a user value, even if this one match the
+  // current localized pref value.
   if (!((new RegExp('^' + value + '[^a-z-_] *[,;]?', 'i')).test(intl))) {
-    Services.prefs.setCharPref(prefName, value + ', ' + intl);
+    value = value + ', ' + intl;
+  } else {
+    value = intl;
   }
+  Services.prefs.setCharPref(prefName, value);
 
   if (shell.hasStarted() == false) {
     shell.start();
   }
 });
 
 // =================== RIL ====================
 (function RILSettingsToPrefs() {
@@ -192,23 +200,47 @@ Components.utils.import('resource://gre/
 // =================== Debugger ====================
 SettingsListener.observe('devtools.debugger.remote-enabled', false, function(value) {
   Services.prefs.setBoolPref('devtools.debugger.remote-enabled', value);
   // This preference is consulted during startup
   Services.prefs.savePrefFile(null);
   value ? RemoteDebugger.start() : RemoteDebugger.stop();
 
 #ifdef MOZ_WIDGET_GONK
+  let enableAdb = value;
+
+  if (Services.prefs.getBoolPref('marionette.defaultPrefs.enabled')) {
+    // Marionette is enabled. Force adb on, since marionette requires remote
+    // debugging to be disabled (we don't want adb to track the remote debugger
+    // setting).
+
+    enableAdb = true;
+  }
+
   // Configure adb.
   try {
-    let current = libcutils.property_get("persist.sys.usb.config");
-    let prefix = current.replace(/,adb/, "");
-    libcutils.property_set("persist.sys.usb.config",
-                           prefix + (value ? ",adb" : ""));
-    current = libcutils.property_get("persist.sys.usb.config");
+    let currentConfig = libcutils.property_get("persist.sys.usb.config");
+    let configFuncs = currentConfig.split(",");
+    let adbIndex = configFuncs.indexOf("adb");
+
+    if (enableAdb) {
+      // Add adb to the list of functions, if not already present
+      if (adbIndex < 0) {
+        configFuncs.push("adb");
+      }
+    } else {
+      // Remove adb from the list of functions, if present
+      if (adbIndex >= 0) {
+        configFuncs.splice(adbIndex,1);
+      }
+    }
+    let newConfig = configFuncs.join(",");
+    if (newConfig != currentConfig) {
+      libcutils.property_set("persist.sys.usb.config", newConfig);
+    }
   } catch(e) {
     dump("Error configuring adb: " + e);
   }
 #endif
 });
 
 SettingsListener.observe('debug.log-animations.enabled', false, function(value) {
   Services.prefs.setBoolPref('layers.offmainthreadcomposition.log-animations', value);
--- a/b2g/components/DirectoryProvider.js
+++ b/b2g/components/DirectoryProvider.js
@@ -8,16 +8,18 @@ const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 const XRE_OS_UPDATE_APPLY_TO_DIR = "OSUpdApplyToD"
 const UPDATE_ARCHIVE_DIR = "UpdArchD"
 const LOCAL_DIR = "/data/local";
+const UPDATES_DIR = "updates/0";
+const FOTA_DIR = "updates/fota";
 
 XPCOMUtils.defineLazyServiceGetter(Services, "env",
                                    "@mozilla.org/process/environment;1",
                                    "nsIEnvironment");
 
 XPCOMUtils.defineLazyServiceGetter(Services, "um",
                                    "@mozilla.org/updates/update-manager;1",
                                    "nsIUpdateManager");
@@ -59,20 +61,27 @@ DirectoryProvider.prototype = {
       return file;
     }
     if (prop == "coreAppsDir") {
       let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile)
       file.initWithPath("/system/b2g");
       persistent.value = true;
       return file;
     }
-    if (prop == XRE_OS_UPDATE_APPLY_TO_DIR ||
-        prop == UPDATE_ARCHIVE_DIR) {
-      let file = this.getUpdateDir(persistent);
-      return file;
+    if (prop == UPDATE_ARCHIVE_DIR) {
+      // getUpdateDir will set persistent to false since it may toggle between
+      // /data/local/ and /mnt/sdcard based on free space and/or availability
+      // of the sdcard.
+      return this.getUpdateDir(persistent, UPDATES_DIR);
+    }
+    if (prop == XRE_OS_UPDATE_APPLY_TO_DIR) {
+      // getUpdateDir will set persistent to false since it may toggle between
+      // /data/local/ and /mnt/sdcard based on free space and/or availability
+      // of the sdcard.
+      return this.getUpdateDir(persistent, FOTA_DIR);
     }
 #endif
     return null;
   },
 
   // The VolumeService only exists on the device, and not on desktop
   volumeHasFreeSpace: function dp_volumeHasFreeSpace(volumePath, requiredSpace) {
     if (!volumePath) {
@@ -87,45 +96,45 @@ DirectoryProvider.prototype = {
     }
     let stat = volume.getStats();
     if (!stat) {
       return false;
     }
     return requiredSpace <= stat.freeBytes;
   },
 
-  findUpdateDirWithFreeSpace: function dp_findUpdateDirWithFreeSpace(requiredSpace) {
+  findUpdateDirWithFreeSpace: function dp_findUpdateDirWithFreeSpace(requiredSpace, subdir) {
     if (!Services.volumeService) {
-      return this.createUpdatesDir(LOCAL_DIR);
+      return this.createUpdatesDir(LOCAL_DIR, subdir);
     }
     let activeUpdate = Services.um.activeUpdate;
     if (gUseSDCard) {
       if (this.volumeHasFreeSpace(gExtStorage, requiredSpace)) {
-        let extUpdateDir = this.createUpdatesDir(gExtStorage);
+        let extUpdateDir = this.createUpdatesDir(gExtStorage, subdir);
         if (extUpdateDir !== null) {
           return extUpdateDir;
         }
         log("Warning: " + gExtStorage + " has enough free space for update " +
             activeUpdate.name + ", but is not writable");
       }
     }
 
     if (this.volumeHasFreeSpace(LOCAL_DIR, requiredSpace)) {
-      let localUpdateDir = this.createUpdatesDir(LOCAL_DIR);
+      let localUpdateDir = this.createUpdatesDir(LOCAL_DIR, subdir);
       if (localUpdateDir !== null) {
         return localUpdateDir;
       }
       log("Warning: " + LOCAL_DIR + " has enough free space for update " +
           activeUpdate.name + ", but is not writable");
     }
 
     return null;
   },
 
-  getUpdateDir: function dp_getUpdateDir(persistent) {
+  getUpdateDir: function dp_getUpdateDir(persistent, subdir) {
     let defaultUpdateDir = this.getDefaultUpdateDir();
     persistent.value = false;
 
     let activeUpdate = Services.um.activeUpdate;
     if (!activeUpdate) {
       log("Warning: No active update found, using default update dir: " +
           defaultUpdateDir);
       return defaultUpdateDir;
@@ -134,47 +143,48 @@ DirectoryProvider.prototype = {
     let selectedPatch = activeUpdate.selectedPatch;
     if (!selectedPatch) {
       log("Warning: No selected patch, using default update dir: " +
           defaultUpdateDir);
       return defaultUpdateDir;
     }
 
     let requiredSpace = selectedPatch.size * 2;
-    let updateDir = this.findUpdateDirWithFreeSpace(requiredSpace, persistent);
+    let updateDir = this.findUpdateDirWithFreeSpace(requiredSpace, subdir);
     if (updateDir) {
       return updateDir;
     }
 
     // If we've gotten this far, there isn't enough free space to download the patch
     // on either external storage or /data/local. All we can do is report the
     // error and let upstream code handle it more gracefully.
     log("Error: No volume found with " + requiredSpace + " bytes for downloading"+
         " update " + activeUpdate.name);
     throw Cr.NS_ERROR_FILE_TOO_BIG;
   },
 
-  createUpdatesDir: function dp_createUpdatesDir(root) {
+  createUpdatesDir: function dp_createUpdatesDir(root, subdir) {
       let dir = Cc["@mozilla.org/file/local;1"]
                    .createInstance(Ci.nsILocalFile);
       dir.initWithPath(root);
       if (!dir.isWritable()) {
+        log("Error: " + dir.path + " isn't writable");
         return null;
       }
-      dir.appendRelativePath("updates/0");
+      dir.appendRelativePath(subdir);
       if (dir.exists()) {
         if (dir.isDirectory() && dir.isWritable()) {
           return dir;
         }
-        // updates/0 is either a file or isn't writable. In either case we
+        // subdir is either a file or isn't writable. In either case we
         // can't use it.
         log("Error: " + dir.path + " is a file or isn't writable");
         return null;
       }
-      // updates/0 doesn't exist, and the parent is writable, so try to
+      // subdir doesn't exist, and the parent is writable, so try to
       // create it. This can fail if a file named updates exists.
       try {
         dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0770);
       } catch (e) {
         // The create failed for some reason. We can't use it.
         log("Error: " + dir.path + " unable to create directory");
         return null;
       }
--- a/b2g/components/RecoveryService.js
+++ b/b2g/components/RecoveryService.js
@@ -14,17 +14,22 @@ const RECOVERYSERVICE_CID = Components.I
 const RECOVERYSERVICE_CONTRACTID = "@mozilla.org/recovery-service;1";
 
 function log(msg) {
   dump("-*- RecoveryService: " + msg + "\n");
 }
 
 #ifdef MOZ_WIDGET_GONK
 let librecovery = (function() {
-  let library = ctypes.open("librecovery.so");
+  try {
+    let library = ctypes.open("librecovery.so");
+  } catch (e) {
+    log("Unable to open librecovery.so");
+    throw Cr.NS_ERROR_FAILURE;
+  }
   let FotaUpdateStatus = new ctypes.StructType("FotaUpdateStatus", [
                                                 { result: ctypes.int },
                                                 { updatePath: ctypes.char.ptr }
                                               ]);
 
   return {
     factoryReset:        library.declare("factoryReset",
                                          ctypes.default_abi,
@@ -68,24 +73,24 @@ RecoveryService.prototype = {
 
   installFotaUpdate: function RS_installFotaUpdate(updatePath) {
 #ifdef MOZ_WIDGET_GONK
     // If this succeeds, then the device reboots and this never returns
     if (librecovery.installFotaUpdate(updatePath, updatePath.length) != 0) {
       log("Error: FOTA install failed");
     }
 #endif
-
     throw Cr.NS_ERROR_FAILURE;
   },
 
   getFotaUpdateStatus: function RS_getFotaUpdateStatus() {
     let status =  Ci.nsIRecoveryService.FOTA_UPDATE_UNKNOWN;
 #ifdef MOZ_WIDGET_GONK
     let cStatus = librecovery.FotaUpdateStatus();
+
     if (librecovery.getFotaUpdateStatus(cStatus.address()) == 0) {
       status = cStatus.result;
     }
 
 #endif
     return status;
   }
 };
--- a/b2g/components/UpdatePrompt.js
+++ b/b2g/components/UpdatePrompt.js
@@ -3,16 +3,17 @@
  */
 /* 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/. */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
+const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 const VERBOSE = 1;
 let log =
   VERBOSE ?
   function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
@@ -369,26 +370,31 @@ UpdatePrompt.prototype = {
     // NB: on Gonk, we rely on the system process manager to restart us.
     let pmService = Cc["@mozilla.org/power/powermanagerservice;1"]
                     .getService(Ci.nsIPowerManagerService);
     pmService.restart();
 #endif
   },
 
   finishOSUpdate: function UP_finishOSUpdate(aOsUpdatePath) {
-    let recoveryService = Cc["@mozilla.org/recovery-service;1"]
-                            .getService(Ci.nsIRecoveryService);
-
     log("Rebooting into recovery to apply FOTA update: " + aOsUpdatePath);
 
     try {
+      let recoveryService = Cc["@mozilla.org/recovery-service;1"]
+                            .getService(Ci.nsIRecoveryService);
       recoveryService.installFotaUpdate(aOsUpdatePath);
     } catch(e) {
       log("Error: Couldn't reboot into recovery to apply FOTA update " +
           aOsUpdatePath);
+      aUpdate = Services.um.activeUpdate;
+      if (aUpdate) {
+        aUpdate.errorCode = Cr.NS_ERROR_FAILURE;
+        aUpdate.statusText = "fota-reboot-failed";
+        this.showUpdateError(aUpdate);
+      }
     }
   },
 
   forceUpdateCheck: function UP_forceUpdateCheck() {
     log("Forcing update check");
 
     let checker = Cc["@mozilla.org/updates/update-checker;1"]
                     .createInstance(Ci.nsIUpdateChecker);
--- a/b2g/config/panda-gaia-central/config.json
+++ b/b2g/config/panda-gaia-central/config.json
@@ -15,10 +15,11 @@
     "gecko_l10n_root": "http://hg.mozilla.org/l10n-central",
     "gaia": {
         "vcs": "hgtool",
         "repo": "http://hg.mozilla.org/integration/gaia-central",
         "l10n": {
             "vcs": "hgtool",
             "root": "http://hg.mozilla.org/gaia-l10n"
         }
-    }
+    },
+    "upload_platform": "panda_gaia_central"
 }
--- 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="1358893928000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1359495205000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
                         <versionRange  minVersion="0.1" maxVersion="4.3.1.00" severity="1">
                     </versionRange>
@@ -202,16 +202,20 @@
       <emItem  blockID="i222" id="dealcabby@jetpack">
                         <versionRange  minVersion="0" maxVersion="*" severity="1">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i51" id="admin@youtubeplayer.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i258" id="helperbar@helperbar.com">
+                        <versionRange  minVersion="0" maxVersion="*" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i46" id="{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}">
                         <versionRange  minVersion="0.1" maxVersion="*">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="9.0a1" maxVersion="9.0" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i256" id="/^[0-9a-f]+@[0-9a-f]+\.info/">
@@ -297,16 +301,20 @@
       <emItem  blockID="i109" id="{392e123b-b691-4a5e-b52f-c4c1027e749c}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i76" id="crossriderapp3924@crossrider.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
+      <emItem  blockID="i262" id="{167d9323-f7cc-48f5-948a-6f012831a69f}">
+                        <versionRange  minVersion="0" maxVersion="*" severity="3">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i196" id="info@wxdownloadmanager.com">
                         <versionRange  minVersion="0" maxVersion="*" severity="3">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i67" id="youtube2@youtube2.com">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
@@ -504,17 +512,21 @@
                   </pluginItem>
       <pluginItem  blockID="p85">
                   <match name="filename" exp="JavaPlugin2_NPAPI\.plugin" />                      <versionRange  minVersion="0" maxVersion="13.6.0" severity="1"></versionRange>
                   </pluginItem>
       <pluginItem  os="Darwin" blockID="p89">
                   <match name="filename" exp="AdobePDFViewerNPAPI\.plugin" />                      <versionRange  minVersion="0" maxVersion="10.1.3" severity="1"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p94">
-                  <match name="filename" exp="Flash\ Player\.plugin" />                      <versionRange  minVersion="0" maxVersion="10.2.159.1" severity="0"></versionRange>
+                  <match name="filename" exp="Flash\ Player\.plugin" />                                    <versionRange  minVersion="0" maxVersion="10.2.159.1" severity="0">
+                                <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="0" maxVersion="17.*" />
+                          </targetApplication>
+                  </versionRange>
                   </pluginItem>
       <pluginItem  blockID="p102">
                   <match name="filename" exp="npmozax\.dll" />                      <versionRange  minVersion="0" maxVersion="*"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p113">
                   <match name="filename" exp="npuplaypc\.dll" />                      <versionRange  minVersion="0" maxVersion="1.0.0.0" severity="1"></versionRange>
                   </pluginItem>
       <pluginItem  blockID="p119">
@@ -679,16 +691,23 @@
                   </pluginItem>
       <pluginItem  blockID="p254">
                   <match name="filename" exp="PDF Browser Plugin\.plugin" />                                    <versionRange  minVersion="0" maxVersion="2.4.2" severity="1">
                                 <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="18.0a1" maxVersion="*" />
                           </targetApplication>
                   </versionRange>
                   </pluginItem>
+      <pluginItem  blockID="p260">
+                  <match name="filename" exp="(NPSWF32\.dll)|(Flash\ Player\.plugin)" />                                    <versionRange  minVersion="0" maxVersion="10.2.9999" severity="0" vulnerabilitystatus="1">
+                                <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="18.0a1" maxVersion="*" />
+                          </targetApplication>
+                  </versionRange>
+                  </pluginItem>
     </pluginItems>
 
   <gfxItems>
     <gfxBlacklistEntry  blockID="g35">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
                       <device>0x0a6c</device>
                   </devices>
             <feature>DIRECT2D</feature>      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>      <driverVersion>8.17.12.5896</driverVersion>      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>    </gfxBlacklistEntry>
     <gfxBlacklistEntry  blockID="g36">      <os>WINNT 6.1</os>      <vendor>0x10de</vendor>              <devices>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -516,19 +516,20 @@ pref("browser.gesture.pinch.in.shift", "
 #else
 // Disabled by default due to issues with track pad input.
 pref("browser.gesture.pinch.out", "");
 pref("browser.gesture.pinch.in", "");
 pref("browser.gesture.pinch.out.shift", "");
 pref("browser.gesture.pinch.in.shift", "");
 #endif
 pref("browser.gesture.twist.latched", false);
-pref("browser.gesture.twist.threshold", 25);
-pref("browser.gesture.twist.right", "");
-pref("browser.gesture.twist.left", "");
+pref("browser.gesture.twist.threshold", 0);
+pref("browser.gesture.twist.right", "cmd_gestureRotateRight");
+pref("browser.gesture.twist.left", "cmd_gestureRotateLeft");
+pref("browser.gesture.twist.end", "cmd_gestureRotateEnd");
 pref("browser.gesture.tap", "cmd_fullZoomReset");
 
 // 0: Nothing happens
 // 1: Scrolling contents
 // 2: Go back or go forward, in your history
 // 3: Zoom in or out.
 #ifdef XP_MACOSX
 // On OS X, if the wheel has one axis only, shift+wheel comes through as a
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -6,16 +6,17 @@
 <menupopup id="appmenu-popup"
            onpopupshowing="if (event.target == this) {
                              updateEditUIVisibility();
 #ifdef MOZ_SERVICES_SYNC
                              gSyncUI.updateUI();
 #endif
                              return;
                            }
+                           updateCharacterEncodingMenuState();
                            if (event.target.parentNode.parentNode.parentNode.parentNode == this)
                              this._currentPopup = event.target;">
   <hbox>
     <vbox id="appmenuPrimaryPane">
       <splitmenu id="appmenu_newTab"
                  label="&tabCmd.label;"
                  command="cmd_newNavigatorTab">
           <menupopup>
--- a/browser/base/content/browser-data-submission-info-bar.js
+++ b/browser/base/content/browser-data-submission-info-bar.js
@@ -1,34 +1,31 @@
-/* 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";
-
-Cu.import("resource://services-common/log4moz.js");
+# 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/.
 
 /**
  * Represents an info bar that shows a data submission notification.
  */
-function DataNotificationInfoBar() {
-  let log4moz = Cu.import("resource://services-common/log4moz.js", {}).Log4Moz;
-  this._log = log4moz.repository.getLogger("Services.DataReporting.InfoBar");
-
-  this._notificationBox = null;
-}
-
-DataNotificationInfoBar.prototype = {
+let gDataNotificationInfoBar = {
   _OBSERVERS: [
     "datareporting:notify-data-policy:request",
     "datareporting:notify-data-policy:close",
   ],
 
   _DATA_REPORTING_NOTIFICATION: "data-reporting",
 
+  _notificationBox: null,
+
+  get _log() {
+    let log4moz = Cu.import("resource://services-common/log4moz.js", {}).Log4Moz;
+    delete this._log;
+    return this._log = log4moz.repository.getLogger("Services.DataReporting.InfoBar");
+  },
+
   init: function() {
     window.addEventListener("unload", function onUnload() {
       window.removeEventListener("unload", onUnload, false);
 
       for (let o of this._OBSERVERS) {
         Services.obs.removeObserver(this, o);
       }
     }.bind(this), false);
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -173,17 +173,18 @@
                           oncommand="openPreferences();"/>
 #endif
 #endif
               </menupopup>
             </menu>
 
             <menu id="view-menu" label="&viewMenu.label;"
                   accesskey="&viewMenu.accesskey;">
-              <menupopup id="menu_viewPopup">
+              <menupopup id="menu_viewPopup"
+                         onpopupshowing="updateCharacterEncodingMenuState();">
                 <menu id="viewToolbarsMenu"
                       label="&viewToolbarsMenu.label;"
                       accesskey="&viewToolbarsMenu.accesskey;">
                   <menupopup onpopupshowing="onViewToolbarsPopupShowing(event);">
                     <menuseparator/>
                     <menuitem id="menu_tabsOnTop"
                               command="cmd_ToggleTabsOnTop"
                               type="checkbox"
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -79,16 +79,19 @@
     <command id="Browser:PrevTab" oncommand="gBrowser.tabContainer.advanceSelectedTab(-1, true);"/>
     <command id="Browser:ShowAllTabs" oncommand="allTabs.open();"/>
     <command id="Browser:ToggleTabView" oncommand="TabView.toggle();"/>
     <command id="Browser:FocusNextFrame" oncommand="focusNextFrame(event);"/>
     <command id="cmd_fullZoomReduce"  oncommand="FullZoom.reduce()"/>
     <command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/>
     <command id="cmd_fullZoomReset"   oncommand="FullZoom.reset()"/>
     <command id="cmd_fullZoomToggle"  oncommand="ZoomManager.toggleZoom();"/>
+    <command id="cmd_gestureRotateLeft" oncommand="gGestureSupport.rotate(event.sourceEvent)"/>
+    <command id="cmd_gestureRotateRight" oncommand="gGestureSupport.rotate(event.sourceEvent)"/>
+    <command id="cmd_gestureRotateEnd" oncommand="gGestureSupport.rotateEnd()"/>
     <command id="Browser:OpenLocation" oncommand="openLocation();"/>
     <command id="Browser:RestoreLastSession" oncommand="restoreLastSession();" disabled="true"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
     <command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/>
     <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/>
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -154,32 +154,28 @@ let gInitialPages = [
 #include browser-social.js
 #include browser-tabPreviews.js
 #include browser-tabview.js
 #include browser-thumbnails.js
 #include browser-webrtcUI.js
 
 #ifdef MOZ_DATA_REPORTING
 #include browser-data-submission-info-bar.js
-
-let gDataNotificationInfoBar = new DataNotificationInfoBar();
 #endif
 
 #ifdef MOZ_SERVICES_SYNC
 #include browser-syncui.js
 #endif
 
 XPCOMUtils.defineLazyGetter(this, "Win7Features", function () {
 #ifdef XP_WIN
   const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
   if (WINTASKBAR_CONTRACTID in Cc &&
       Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
-    let temp = {};
-    Cu.import("resource:///modules/WindowsPreviewPerTab.jsm", temp);
-    let AeroPeek = temp.AeroPeek;
+    let AeroPeek = Cu.import("resource:///modules/WindowsPreviewPerTab.jsm", {}).AeroPeek;
     return {
       onOpenWindow: function () {
         AeroPeek.onOpenWindow(window);
       },
       onCloseWindow: function () {
         AeroPeek.onCloseWindow(window);
       }
     };
@@ -735,16 +731,20 @@ const gFormSubmitObserver = {
 // infancy and we do NOT want to be forced into supporting an API that
 // will probably have to change in the future.  (The current Mac OS X
 // API is undocumented and was reverse-engineered.)  Until support is
 // implemented in the event dispatcher to keep these events as
 // chrome-only, we must listen for the simple gesture events during
 // the capturing phase and call stopPropagation on every event.
 
 let gGestureSupport = {
+  _currentRotation: 0,
+  _lastRotateDelta: 0,
+  _rotateMomentumThreshold: .75,
+
   /**
    * Add or remove mouse gesture event listeners
    *
    * @param aAddListener
    *        True to add/init listeners and false to remove/uninit
    */
   init: function GS_init(aAddListener) {
     const gestureEvents = ["SwipeGesture",
@@ -795,16 +795,20 @@ let gGestureSupport = {
       case "MozRotateGestureUpdate":
         aEvent.preventDefault();
         this._doUpdate(aEvent);
         break;
       case "MozTapGesture":
         aEvent.preventDefault();
         this._doAction(aEvent, ["tap"]);
         break;
+      case "MozRotateGesture":
+        aEvent.preventDefault();
+        this._doAction(aEvent, ["twist", "end"]);
+        break;
       /* case "MozPressTapGesture":
         break; */
     }
   },
 
   /**
    * Called at the start of "pinch" and "twist" gestures to setup all of the
    * information needed to process the gesture
@@ -911,17 +915,17 @@ let gGestureSupport = {
         continue;
 
       let node = document.getElementById(command);
       if (node) {
         if (node.getAttribute("disabled") != "true") {
           let cmdEvent = document.createEvent("xulcommandevent");
           cmdEvent.initCommandEvent("command", true, true, window, 0,
                                     aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
-                                    aEvent.metaKey, null);
+                                    aEvent.metaKey, aEvent);
           node.dispatchEvent(cmdEvent);
         }
       } else {
         goDoCommand(command);
       }
 
       break;
     }
@@ -971,16 +975,133 @@ let gGestureSupport = {
       let getFunc = "get" + (type == "boolean" ? "Bool" :
                              type == "number" ? "Int" : "Char") + "Pref";
       return gPrefService[getFunc](branch + aPref);
     }
     catch (e) {
       return aDef;
     }
   },
+
+  /**
+   * Perform rotation for ImageDocuments
+   *
+   * @param aEvent
+   *        The MozRotateGestureUpdate event triggering this call
+   */
+  rotate: function(aEvent) {
+    if (!(content.document instanceof ImageDocument))
+      return;
+
+    let contentElement = content.document.body.firstElementChild;
+    if (!contentElement)
+      return;
+
+    this.rotation = Math.round(this.rotation + aEvent.delta);
+    contentElement.style.transform = "rotate(" + this.rotation + "deg)";
+    this._lastRotateDelta = aEvent.delta;
+  },
+
+  /**
+   * Perform a rotation end for ImageDocuments
+   */
+  rotateEnd: function() {
+    if (!(content.document instanceof ImageDocument))
+      return;
+
+    let contentElement = content.document.body.firstElementChild;
+    if (!contentElement)
+      return;
+
+    let transitionRotation = 0;
+
+    // The reason that 360 is allowed here is because when rotating between
+    // 315 and 360, setting rotate(0deg) will cause it to rotate the wrong
+    // direction around--spinning wildly.
+    if (this.rotation <= 45)
+      transitionRotation = 0;
+    else if (this.rotation > 45 && this.rotation <= 135)
+      transitionRotation = 90;
+    else if (this.rotation > 135 && this.rotation <= 225)
+      transitionRotation = 180;
+    else if (this.rotation > 225 && this.rotation <= 315)
+      transitionRotation = 270;
+    else
+      transitionRotation = 360;
+
+    // If we're going fast enough, and we didn't already snap ahead of rotation,
+    // then snap ahead of rotation to simulate momentum
+    if (this._lastRotateDelta > this._rotateMomentumThreshold &&
+        this.rotation > transitionRotation)
+      transitionRotation += 90;
+    else if (this._lastRotateDelta < -1 * this._rotateMomentumThreshold &&
+             this.rotation < transitionRotation)
+      transitionRotation -= 90;
+
+    contentElement.classList.add("completeRotation");
+    contentElement.addEventListener("transitionend", this._clearCompleteRotation);
+
+    contentElement.style.transform = "rotate(" + transitionRotation + "deg)";
+    this.rotation = transitionRotation;
+  },
+
+  /**
+   * Gets the current rotation for the ImageDocument
+   */
+  get rotation() {
+    return this._currentRotation;
+  },
+
+  /**
+   * Sets the current rotation for the ImageDocument
+   *
+   * @param aVal
+   *        The new value to take.  Can be any value, but it will be bounded to
+   *        0 inclusive to 360 exclusive.
+   */
+  set rotation(aVal) {
+    this._currentRotation = aVal % 360;
+    if (this._currentRotation < 0)
+      this._currentRotation += 360;
+    return this._currentRotation;
+  },
+
+  /**
+   * When the location/tab changes, need to reload the current rotation for the
+   * image
+   */
+  restoreRotationState: function() {
+    if (!(content.document instanceof ImageDocument))
+      return;
+
+    let contentElement = content.document.body.firstElementChild;
+    let transformValue = content.window.getComputedStyle(contentElement, null)
+                                       .transform;
+
+    if (transformValue == "none") {
+      this.rotation = 0;
+      return;
+    }
+
+    // transformValue is a rotation matrix--split it and do mathemagic to
+    // obtain the real rotation value
+    transformValue = transformValue.split("(")[1]
+                                   .split(")")[0]
+                                   .split(",");
+    this.rotation = Math.round(Math.atan2(transformValue[1], transformValue[0]) *
+                               (180 / Math.PI));
+  },
+
+  /**
+   * Removes the transition rule by removing the completeRotation class
+   */
+  _clearCompleteRotation: function() {
+    this.classList.remove("completeRotation");
+    this.removeEventListener("transitionend", this._clearCompleteRotation);
+  },
 };
 
 var gBrowserInit = {
   onLoad: function() {
     // window.arguments[0]: URI to load (string), or an nsISupportsArray of
     //                      nsISupportsStrings to load, or a xul:tab of
     //                      a tabbrowser, which will be replaced by this
     //                      window (for this case, all other arguments are
@@ -1260,17 +1381,17 @@ var gBrowserInit = {
     IndexedDBPromptHelper.init();
     gFormSubmitObserver.init();
     SocialUI.init();
     AddonManager.addAddonListener(AddonsMgrListener);
     WebrtcIndicator.init();
 
     gBrowser.addEventListener("pageshow", function(event) {
       // Filter out events that are not about the document load we are interested in
-      if (event.target == content.document)
+      if (content && event.target == content.document)
         setTimeout(pageShowEventHandlers, 0, event);
     }, true);
 
     // Ensure login manager is up and running.
     Services.logins;
 
     if (mustLoadSidebar) {
       let sidebar = document.getElementById("sidebar");
@@ -1345,20 +1466,19 @@ var gBrowserInit = {
     // active downloads) and speeds up the first-load of the download manager UI.
     // If the user manually opens the download manager before the timeout, the
     // downloads will start right away, and getting the service again won't hurt.
     setTimeout(function() {
       Services.downloads;
 
 #ifdef XP_WIN
       if (Win7Features) {
-        let tempScope = {};
-        Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm",
-                  tempScope);
-        tempScope.DownloadTaskbarProgress.onBrowserWindowLoad(window);
+        let DownloadTaskbarProgress =
+          Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
+        DownloadTaskbarProgress.onBrowserWindowLoad(window);
       }
 #endif
     }, 10000);
 
     // The object handling the downloads indicator is also initialized here in the
     // delayed startup function, but the actual indicator element is not loaded
     // unless there are downloads to be displayed.
     DownloadsButton.initializeIndicator();
@@ -3763,16 +3883,54 @@ function updateEditUIVisibility()
     goSetCommandEnabled("cmd_selectAll", true);
     goSetCommandEnabled("cmd_delete", true);
     goSetCommandEnabled("cmd_switchTextDirection", true);
   }
 #endif
 }
 
 /**
+ * Makes the Character Encoding menu enabled or disabled as appropriate.
+ * To be called when the View menu or the app menu is opened.
+ */
+function updateCharacterEncodingMenuState()
+{
+  let charsetMenu = document.getElementById("charsetMenu");
+  let appCharsetMenu = document.getElementById("appmenu_charsetMenu");
+  let appDevCharsetMenu =
+    document.getElementById("appmenu_developer_charsetMenu");
+  // gBrowser is null on Mac when the menubar shows in the context of
+  // non-browser windows. The above elements may be null depending on 
+  // what parts of the menubar are present. E.g. no app menu on Mac.
+  if (gBrowser &&
+      gBrowser.docShell &&
+      gBrowser.docShell.mayEnableCharacterEncodingMenu) {
+    if (charsetMenu) {
+      charsetMenu.removeAttribute("disabled");
+    }
+    if (appCharsetMenu) {
+      appCharsetMenu.removeAttribute("disabled");
+    }
+    if (appDevCharsetMenu) {
+      appDevCharsetMenu.removeAttribute("disabled");
+    }
+  } else {
+    if (charsetMenu) {
+      charsetMenu.setAttribute("disabled", "true");
+    }
+    if (appCharsetMenu) {
+      appCharsetMenu.setAttribute("disabled", "true");
+    }
+    if (appDevCharsetMenu) {
+      appDevCharsetMenu.setAttribute("disabled", "true");
+    }
+  }
+}
+
+/**
  * Returns true if |aMimeType| is text-based, false otherwise.
  *
  * @param aMimeType
  *        The MIME type to check.
  *
  * If adding types to this function, please also check the similar
  * function in findbar.xml
  */
@@ -4184,16 +4342,18 @@ var XULBrowserWindow = {
         }
 
         // fix bug 253793 - turn off highlight when page changes
         gFindBar.getElement("highlight").checked = false;
       }
     }
     UpdateBackForwardCommands(gBrowser.webNavigation);
 
+    gGestureSupport.restoreRotationState();
+
     // See bug 358202, when tabs are switched during a drag operation,
     // timers don't fire on windows (bug 203573)
     if (aRequest)
       setTimeout(function () { XULBrowserWindow.asyncUpdateUI(); }, 0);
     else
       this.asyncUpdateUI();
   },
 
@@ -7112,25 +7272,17 @@ var TabContextMenu = {
 
 XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
                                   "resource:///modules/devtools/gDevTools.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "gDevToolsBrowser",
                                   "resource:///modules/devtools/gDevTools.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "HUDConsoleUI", function () {
-  let tempScope = {};
-  Cu.import("resource:///modules/HUDService.jsm", tempScope);
-  try {
-    return tempScope.HUDService.consoleUI;
-  }
-  catch (ex) {
-    Components.utils.reportError(ex);
-    return null;
-  }
+  return Cu.import("resource:///modules/HUDService.jsm", {}).HUDService.consoleUI;
 });
 
 // Prompt user to restart the browser in safe mode
 function safeModeRestart()
 {
   // prompt the user to confirm
   let promptTitle = gNavigatorBundle.getString("safeModeRestartPromptTitle");
   let promptMessage =
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -75,16 +75,17 @@
   pointer-events: auto;
 }
 
 html|*.highlighter-nodeinfobar-id,
 html|*.highlighter-nodeinfobar-classes,
 html|*.highlighter-nodeinfobar-pseudo-classes,
 html|*.highlighter-nodeinfobar-tagname {
   -moz-user-select: text;
+  -moz-user-focus: normal;
   cursor: text;
 }
 
 .highlighter-nodeinfobar-arrow {
   display: none;
 }
 
 .highlighter-nodeinfobar-container[position="top"]:not([hide-arrow]) > .highlighter-nodeinfobar-arrow-bottom {
--- a/browser/base/content/test/browser_gestureSupport.js
+++ b/browser/base/content/test/browser_gestureSupport.js
@@ -28,17 +28,17 @@ function test()
   // Reenable the default gestures support. The remaining tests target
   // the Firefox gesture functionality.
   gGestureSupport.init(true);
 
   // Test Firefox's gestures support.
   test_commandset = document.getElementById("mainCommandSet");
   test_swipeGestures();
   test_latchedGesture("pinch", "out", "in", "MozMagnifyGesture");
-  test_latchedGesture("twist", "right", "left", "MozRotateGesture");
+  // We don't latch the rotate event (see bug 833511)
   test_thresholdGesture("pinch", "out", "in", "MozMagnifyGesture");
   test_thresholdGesture("twist", "right", "left", "MozRotateGesture");
 }
 
 let test_eventCount = 0;
 let test_expectedType;
 let test_expectedDirection;
 let test_expectedDelta;
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -30,16 +30,19 @@ const VARIABLES_VIEW_NON_SORTABLE = [
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 Cu.import("resource:///modules/source-editor.jsm");
 Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this,
+  "Reflect", "resource://gre/modules/reflect.jsm");
+
 /**
  * Object defining the debugger controller components.
  */
 let DebuggerController = {
   /**
    * Initializes the debugger controller.
    */
   initialize: function DC_initialize() {
@@ -421,16 +424,19 @@ ThreadState.prototype = {
  * stack frame cache.
  */
 function StackFrames() {
   this._onPaused = this._onPaused.bind(this);
   this._onResumed = this._onResumed.bind(this);
   this._onFrames = this._onFrames.bind(this);
   this._onFramesCleared = this._onFramesCleared.bind(this);
   this._afterFramesCleared = this._afterFramesCleared.bind(this);
+  this._fetchScopeVariables = this._fetchScopeVariables.bind(this);
+  this._fetchVarProperties = this._fetchVarProperties.bind(this);
+  this._addVarExpander = this._addVarExpander.bind(this);
   this.evaluate = this.evaluate.bind(this);
 }
 
 StackFrames.prototype = {
   get activeThread() DebuggerController.activeThread,
   autoScopeExpand: false,
   currentFrame: null,
   syncedWatchExpressions: null,
@@ -679,17 +685,17 @@ StackFrames.prototype = {
     do {
       // Create a scope to contain all the inspected variables.
       let label = this._getScopeLabel(environment);
       let scope = DebuggerView.Variables.addScope(label);
 
       // Handle additions to the innermost scope.
       if (environment == frame.environment) {
         this._insertScopeFrameReferences(scope, frame);
-        this._fetchScopeVariables(scope, environment);
+        this._addScopeExpander(scope, environment);
         // Always expand the innermost scope by default.
         scope.expand();
       }
       // Lazily add nodes for every other environment scope.
       else {
         this._addScopeExpander(scope, environment);
         this.autoScopeExpand && scope.expand();
       }
@@ -705,47 +711,47 @@ StackFrames.prototype = {
    * the addition of new variables.
    *
    * @param Scope aScope
    *        The scope where the variables will be placed into.
    * @param object aEnv
    *        The scope's environment.
    */
   _addScopeExpander: function SF__addScopeExpander(aScope, aEnv) {
-    let callback = this._fetchScopeVariables.bind(this, aScope, aEnv);
+    aScope._sourceEnvironment = aEnv;
 
     // It's a good idea to be prepared in case of an expansion.
-    aScope.addEventListener("mouseover", callback, false);
+    aScope.addEventListener("mouseover", this._fetchScopeVariables, false);
     // Make sure that variables are always available on expansion.
-    aScope.onexpand = callback;
+    aScope.onexpand = this._fetchScopeVariables;
   },
 
   /**
    * Adds an 'onexpand' callback for a variable, lazily handling
    * the addition of new properties.
    *
    * @param Variable aVar
    *        The variable where the properties will be placed into.
    * @param any aGrip
    *        The grip of the variable.
    */
   _addVarExpander: function SF__addVarExpander(aVar, aGrip) {
     // No need for expansion for primitive values.
     if (VariablesView.isPrimitive({ value: aGrip })) {
       return;
     }
-    let callback = this._fetchVarProperties.bind(this, aVar, aGrip);
+    aVar._sourceGrip = aGrip;
 
     // Some variables are likely to contain a very large number of properties.
     // It's a good idea to be prepared in case of an expansion.
     if (aVar.name == "window" || aVar.name == "this") {
-      aVar.addEventListener("mouseover", callback, false);
+      aVar.addEventListener("mouseover", this._fetchVarProperties, false);
     }
     // Make sure that properties are always available on expansion.
-    aVar.onexpand = callback;
+    aVar.onexpand = this._fetchVarProperties;
   },
 
   /**
    * Adds the watch expressions evaluation results to a scope in the view.
    *
    * @param Scope aScope
    *        The scope where the watch expressions will be placed into.
    * @param object aExp
@@ -783,50 +789,49 @@ StackFrames.prototype = {
   },
 
   /**
    * Adds variables to a scope in the view. Triggered when a scope is
    * expanded or is hovered. It does not expand the scope.
    *
    * @param Scope aScope
    *        The scope where the variables will be placed into.
-   * @param object aEnv
-   *        The scope's environment.
    */
-  _fetchScopeVariables: function SF__fetchScopeVariables(aScope, aEnv) {
+  _fetchScopeVariables: function SF__fetchScopeVariables(aScope) {
     // Fetch the variables only once.
     if (aScope._fetched) {
       return;
     }
     aScope._fetched = true;
+    let env = aScope._sourceEnvironment;
 
-    switch (aEnv.type) {
+    switch (env.type) {
       case "with":
       case "object":
         // Add nodes for every variable in scope.
-        this.activeThread.pauseGrip(aEnv.object).getPrototypeAndProperties(function(aResponse) {
+        this.activeThread.pauseGrip(env.object).getPrototypeAndProperties(function(aResponse) {
           this._insertScopeVariables(aResponse.ownProperties, aScope);
 
           // Signal that variables have been fetched.
           window.dispatchEvent("Debugger:FetchedVariables");
           DebuggerView.Variables.commitHierarchy();
         }.bind(this));
         break;
       case "block":
       case "function":
         // Add nodes for every argument and every other variable in scope.
-        this._insertScopeArguments(aEnv.bindings.arguments, aScope);
-        this._insertScopeVariables(aEnv.bindings.variables, aScope);
+        this._insertScopeArguments(env.bindings.arguments, aScope);
+        this._insertScopeVariables(env.bindings.variables, aScope);
 
         // No need to signal that variables have been fetched, since
         // the scope arguments and variables are already attached to the
         // environment bindings, so pausing the active thread is unnecessary.
         break;
       default:
-        Cu.reportError("Unknown Debugger.Environment type: " + aEnv.type);
+        Cu.reportError("Unknown Debugger.Environment type: " + env.type);
         break;
     }
   },
 
   /**
    * Add nodes for special frame references in the innermost scope.
    *
    * @param Scope aScope
@@ -894,37 +899,37 @@ StackFrames.prototype = {
   },
 
   /**
    * Adds properties to a variable in the view. Triggered when a variable is
    * expanded or certain variables are hovered. It does not expand the variable.
    *
    * @param Variable aVar
    *        The variable where the properties will be placed into.
-   * @param any aGrip
-   *        The grip of the variable.
    */
-  _fetchVarProperties: function SF__fetchVarProperties(aVar, aGrip) {
+  _fetchVarProperties: function SF__fetchVarProperties(aVar) {
     // Fetch the properties only once.
     if (aVar._fetched) {
       return;
     }
     aVar._fetched = true;
+    let grip = aVar._sourceGrip;
 
-    this.activeThread.pauseGrip(aGrip).getPrototypeAndProperties(function(aResponse) {
+    this.activeThread.pauseGrip(grip).getPrototypeAndProperties(function(aResponse) {
       let { ownProperties, prototype } = aResponse;
-      let sortable = VARIABLES_VIEW_NON_SORTABLE.indexOf(aGrip.class) == -1;
+      let sortable = VARIABLES_VIEW_NON_SORTABLE.indexOf(grip.class) == -1;
 
       // Add all the variable properties.
       if (ownProperties) {
-        aVar.addProperties(ownProperties, { sorted: sortable });
-        // Expansion handlers must be set after the properties are added.
-        for (let name in ownProperties) {
-          this._addVarExpander(aVar.get(name), ownProperties[name].value);
-        }
+        aVar.addProperties(ownProperties, {
+          // Not all variables need to force sorted properties.
+          sorted: sortable,
+          // Expansion handlers must be set after the properties are added.
+          callback: this._addVarExpander
+        });
       }
 
       // Add the variable's __proto__.
       if (prototype && prototype.type != "null") {
         aVar.addProperty("__proto__", { value: prototype });
         // Expansion handlers must be set after the properties are added.
         this._addVarExpander(aVar.get("__proto__"), prototype);
       }
@@ -997,27 +1002,47 @@ StackFrames.prototype = {
   },
 
   /**
    * Updates a list of watch expressions to evaluate on each pause.
    */
   syncWatchExpressions: function SF_syncWatchExpressions() {
     let list = DebuggerView.WatchExpressions.getExpressions();
 
-    if (list.length) {
+    // Sanity check all watch expressions before syncing them. To avoid
+    // having the whole watch expressions array throw because of a single
+    // faulty expression, simply convert it to a string describing the error.
+    // There's no other information necessary to be offered in such cases.
+    let sanitizedExpressions = list.map(function(str) {
+      // Reflect.parse throws when encounters a syntax error.
+      try {
+        Reflect.parse(str);
+        return str; // Watch expression can be executed safely.
+      } catch (e) {
+        return "\"" + e.name + ": " + e.message + "\""; // Syntax error.
+      }
+    });
+
+    if (sanitizedExpressions.length) {
       this.syncedWatchExpressions =
-        this.currentWatchExpressions = "[" + list.map(function(str)
-          // Avoid yielding an empty pseudo-array when evaluating `arguments`,
-          // since they're overridden by the expression's closure scope.
-          "(function(arguments) {" +
-            // Make sure all the quotes are escaped in the expression's syntax.
-            "try { return eval(\"" + str.replace(/"/g, "\\$&") + "\"); }" +
-            "catch(e) { return e.name + ': ' + e.message; }" +
-          "})(arguments)"
-        ).join(",") + "]";
+        this.currentWatchExpressions =
+          "[" +
+            sanitizedExpressions.map(function(str)
+              "eval(\"" +
+                "try {" +
+                  // Make sure all quotes are escaped in the expression's syntax,
+                  // and add a newline after the statement to avoid comments
+                  // breaking the code integrity inside the eval block.
+                  str.replace(/"/g, "\\$&") + "\" + " + "'\\n'" + " + \"" +
+                "} catch (e) {" +
+                  "e.name + ': ' + e.message;" + // FIXME: bug 812765, 812764
+                "}" +
+              "\")"
+            ).join(",") +
+          "]";
     } else {
       this.syncedWatchExpressions =
         this.currentWatchExpressions = null;
     }
     this.currentFrame = null;
     this._onFrames();
   },
 
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -947,18 +947,16 @@ function WatchExpressionsView() {
   MenuContainer.call(this);
   this.switchExpression = this.switchExpression.bind(this);
   this.deleteExpression = this.deleteExpression.bind(this);
   this._createItemView = this._createItemView.bind(this);
   this._onClick = this._onClick.bind(this);
   this._onClose = this._onClose.bind(this);
   this._onBlur = this._onBlur.bind(this);
   this._onKeyPress = this._onKeyPress.bind(this);
-  this._onMouseOver = this._onMouseOver.bind(this);
-  this._onMouseOut = this._onMouseOut.bind(this);
 }
 
 create({ constructor: WatchExpressionsView, proto: MenuContainer.prototype }, {
   /**
    * Initialization function, called when the debugger is started.
    */
   initialize: function DVWE_initialize() {
     dumpn("Initializing the WatchExpressionsView");
@@ -992,17 +990,17 @@ create({ constructor: WatchExpressionsVi
     DebuggerView.showPanesSoon();
 
     // Append a watch expression item to this container.
     let expressionItem = this.push("", aExpression, {
       forced: { atIndex: 0 },
       unsorted: true,
       relaxed: true,
       attachment: {
-        expression: "",
+        currentExpression: "",
         initialExpression: aExpression,
         id: this._generateId()
       }
     });
 
     // Check if watch expression was already appended.
     if (!expressionItem) {
       return;
@@ -1041,41 +1039,41 @@ create({ constructor: WatchExpressionsVi
    *
    * @param Variable aVar
    *        The variable representing the watch expression evaluation.
    * @param string aExpression
    *        The new watch expression text.
    */
   switchExpression: function DVWE_switchExpression(aVar, aExpression) {
     let expressionItem =
-      [i for (i of this._cache) if (i.attachment.expression == aVar.name)][0];
+      [i for (i of this._cache) if (i.attachment.currentExpression == aVar.name)][0];
 
     // Remove the watch expression if it's going to be a duplicate.
     if (!aExpression || this.getExpressions().indexOf(aExpression) != -1) {
       this.deleteExpression(aVar);
       return;
     }
 
     // Save the watch expression code string.
-    expressionItem.attachment.expression = aExpression;
+    expressionItem.attachment.currentExpression = aExpression;
     expressionItem.target.inputNode.value = aExpression;
 
     // Synchronize with the controller's watch expressions store.
     DebuggerController.StackFrames.syncWatchExpressions();
   },
 
   /**
    * Removes the watch expression corresponding to the specified variable item.
    *
    * @param Variable aVar
    *        The variable representing the watch expression evaluation.
    */
   deleteExpression: function DVWE_deleteExpression(aVar) {
     let expressionItem =
-      [i for (i of this._cache) if (i.attachment.expression == aVar.name)][0];
+      [i for (i of this._cache) if (i.attachment.currentExpression == aVar.name)][0];
 
     // Remove the watch expression at its respective index.
     this.removeExpressionAt(this._cache.indexOf(expressionItem));
 
     // Synchronize with the controller's watch expressions store.
     DebuggerController.StackFrames.syncWatchExpressions();
   },
 
@@ -1083,27 +1081,27 @@ create({ constructor: WatchExpressionsVi
    * Gets the watch expression code string for an item in this container.
    *
    * @param number aIndex
    *        The index used to identify the watch expression.
    * @return string
    *         The watch expression code string.
    */
   getExpression: function DVWE_getExpression(aIndex) {
-    return this._cache[aIndex].attachment.expression;
+    return this._cache[aIndex].attachment.currentExpression;
   },
 
   /**
    * Gets the watch expressions code strings for all items in this container.
    *
    * @return array
    *         The watch expressions code strings.
    */
   getExpressions: function DVWE_getExpressions() {
-    return [item.attachment.expression for (item of this._cache)];
+    return [item.attachment.currentExpression for (item of this._cache)];
   },
 
   /**
    * Customization function for creating an item's UI.
    *
    * @param nsIDOMNode aElementNode
    *        The element associated with the displayed item.
    * @param string aExpression
@@ -1115,18 +1113,16 @@ create({ constructor: WatchExpressionsVi
     let closeNode = document.createElement("toolbarbutton");
 
     inputNode.setAttribute("value", aExpression);
     inputNode.setAttribute("flex", "1");
 
     closeNode.addEventListener("click", this._onClose, false);
     inputNode.addEventListener("blur", this._onBlur, false);
     inputNode.addEventListener("keypress", this._onKeyPress, false);
-    aElementNode.addEventListener("mouseover", this._onMouseOver, false);
-    aElementNode.addEventListener("mouseout", this._onMouseOut, false);
 
     aElementNode.appendChild(arrowNode);
     aElementNode.appendChild(inputNode);
     aElementNode.appendChild(closeNode);
     aElementNode.arrowNode = arrowNode;
     aElementNode.inputNode = inputNode;
     aElementNode.closeNode = closeNode;
   },
@@ -1182,33 +1178,30 @@ create({ constructor: WatchExpressionsVi
     e.stopPropagation();
   },
 
   /**
    * The blur listener for a watch expression's textbox.
    */
   _onBlur: function DVWE__onBlur({ target: textbox }) {
     let expressionItem = this.getItemForElement(textbox);
-    let oldExpression = expressionItem.attachment.expression;
+    let oldExpression = expressionItem.attachment.currentExpression;
     let newExpression = textbox.value.trim();
 
     // Remove the watch expression if it's empty.
     if (!newExpression) {
       this.removeExpressionAt(this._cache.indexOf(expressionItem));
     }
     // Remove the watch expression if it's a duplicate.
     else if (!oldExpression && this.getExpressions().indexOf(newExpression) != -1) {
       this.removeExpressionAt(this._cache.indexOf(expressionItem));
     }
     // Expression is eligible.
     else {
-      // Save the watch expression code string.
-      expressionItem.attachment.expression = newExpression;
-      // Make sure the close button is hidden when the textbox is unfocused.
-      expressionItem.target.closeNode.hidden = true;
+      expressionItem.attachment.currentExpression = newExpression;
     }
 
     // Synchronize with the controller's watch expressions store.
     DebuggerController.StackFrames.syncWatchExpressions();
   },
 
   /**
    * The keypress listener for a watch expression's textbox.
@@ -1219,30 +1212,16 @@ create({ constructor: WatchExpressionsVi
       case e.DOM_VK_ENTER:
       case e.DOM_VK_ESCAPE:
         DebuggerView.editor.focus();
         return;
     }
   },
 
   /**
-   * The mouse over listener for a watch expression.
-   */
-  _onMouseOver: function DVWE__onMouseOver({ target: element }) {
-    this.getItemForElement(element).target.closeNode.hidden = false;
-  },
-
-  /**
-   * The mouse out listener for a watch expression.
-   */
-  _onMouseOut: function DVWE__onMouseOut({ target: element }) {
-    this.getItemForElement(element).target.closeNode.hidden = true;
-  },
-
-  /**
    * Gets an identifier for a new watch expression item in the current cache.
    * @return string
    */
   _generateId: (function() {
     let count = 0;
     return function DVWE__generateId() {
       return (++count) + "";
     };
--- a/browser/devtools/debugger/debugger-toolbar.js
+++ b/browser/devtools/debugger/debugger-toolbar.js
@@ -1013,16 +1013,24 @@ FilterView.prototype = {
    * Called when the variable search filter key sequence was pressed.
    */
   _doVariableSearch: function DVF__doVariableSearch() {
     DebuggerView.Variables.performSearch("");
     this._doSearch(SEARCH_VARIABLE_FLAG);
     this._searchboxPanel.hidePopup();
   },
 
+  /**
+   * Called when the variables focus key sequence was pressed.
+   */
+  _doVariablesFocus: function DVG__doVariablesFocus() {
+    DebuggerView.showPanesSoon();
+    DebuggerView.Variables.focusFirstVisibleNode();
+  },
+
   _searchbox: null,
   _searchboxPanel: null,
   _globalOperatorButton: null,
   _globalOperatorLabel: null,
   _tokenOperatorButton: null,
   _tokenOperatorLabel: null,
   _lineOperatorButton: null,
   _lineOperatorLabel: null,
--- a/browser/devtools/debugger/debugger.css
+++ b/browser/devtools/debugger/debugger.css
@@ -35,43 +35,51 @@
 }
 
 .dbg-breakpoint > .state,
 .dbg-breakpoint > .content {
   overflow: hidden;
 }
 
 /**
+ * Watch expressions view
+ */
+
+#expressions {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+/**
  * Variables view
  */
 
 #variables {
   overflow-x: hidden;
   overflow-y: auto;
 }
 
 /**
  * Scope, variable and property elements
  */
 
-#variables .details:not([open]) {
+.details:not([open]) {
   display: none;
 }
 
+.scope,
+.variable,
+.property {
+  -moz-user-focus: normal;
+}
+
 .scope[non-header] > .title,
 .variable[non-header] > .title,
-.property[non-header] > .title {
-  display: none;
-}
-
-/**
- * Variables and properties searching
- */
-
 .variable[non-match] > .title,
+.property[non-header] > .title,
 .property[non-match] > .title {
   display: none;
 }
 
 /**
  * Toolbar
  */
 
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -38,16 +38,18 @@
     <command id="globalSearchCommand"
              oncommand="DebuggerView.Filtering._doGlobalSearch()"/>
     <command id="tokenSearchCommand"
              oncommand="DebuggerView.Filtering._doTokenSearch()"/>
     <command id="lineSearchCommand"
              oncommand="DebuggerView.Filtering._doLineSearch()"/>
     <command id="variableSearchCommand"
              oncommand="DebuggerView.Filtering._doVariableSearch()"/>
+    <command id="variablesFocusCommand"
+             oncommand="DebuggerView.Filtering._doVariablesFocus()"/>
     <command id="addBreakpointCommand"
              oncommand="DebuggerView.Breakpoints._onCmdAddBreakpoint()"/>
     <command id="addConditionalBreakpointCommand"
              oncommand="DebuggerView.Breakpoints._onCmdAddConditionalBreakpoint()"/>
     <command id="addWatchExpressionCommand"
              oncommand="DebuggerView.WatchExpressions._onCmdAddExpression()"/>
     <command id="removeAllWatchExpressionsCommand"
              oncommand="DebuggerView.WatchExpressions._onCmdRemoveAllExpressions()"/>
@@ -103,16 +105,21 @@
                 key="lineSearchKey"
                 command="lineSearchCommand"/>
       <menuseparator/>
       <menuitem id="se-dbg-cMenu-findVariable"
                 label="&debuggerUI.searchVariable;"
                 accesskey="&debuggerUI.searchVariable.key;"
                 key="variableSearchKey"
                 command="variableSearchCommand"/>
+      <menuitem id="se-dbg-cMenu-focusVariables"
+                label="&debuggerUI.focusVariables;"
+                accesskey="&debuggerUI.focusVariables.key;"
+                key="variablesFocusKey"
+                command="variablesFocusCommand"/>
     </menupopup>
 
     <menupopup id="debuggerWatchExpressionsContextMenu">
       <menuitem id="add-watch-expression"
                 label="&debuggerUI.addWatch;"
                 accesskey="&debuggerUI.addWatch.key;"
                 key="addWatchExpressionKey"
                 command="addWatchExpressionCommand"/>
@@ -179,16 +186,20 @@
     <key id="lineSearchKey"
          key="&debuggerUI.searchLine.key;"
          modifiers="accel"
          command="lineSearchCommand"/>
     <key id="variableSearchKey"
          key="&debuggerUI.searchVariable.key;"
          modifiers="accel alt"
          command="variableSearchCommand"/>
+    <key id="variablesFocusKey"
+         key="&debuggerUI.focusVariables.key;"
+         modifiers="accel shift"
+         command="variablesFocusCommand"/>
     <key id="addBreakpointKey"
          key="&debuggerUI.seMenuBreak.key;"
          modifiers="accel"
          command="addBreakpointCommand"/>
     <key id="addConditionalBreakpointKey"
          key="&debuggerUI.seMenuCondBreak.key;"
          modifiers="accel shift"
          command="addConditionalBreakpointCommand"/>
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -27,19 +27,21 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_propertyview-03.js \
 	browser_dbg_propertyview-04.js \
 	browser_dbg_propertyview-05.js \
 	browser_dbg_propertyview-06.js \
 	browser_dbg_propertyview-07.js \
 	browser_dbg_propertyview-08.js \
 	browser_dbg_propertyview-09.js \
 	browser_dbg_propertyview-10.js \
-	browser_dbg_propertyview-edit.js \
+	browser_dbg_propertyview-edit-value.js \
 	browser_dbg_propertyview-edit-watch.js \
-	browser_dbg_propertyview-big-data.js \
+	browser_dbg_propertyview-data-big.js \
+	browser_dbg_propertyview-data-getset-01.js \
+	browser_dbg_propertyview-data-getset-02.js \
 	browser_dbg_propertyview-data.js \
 	browser_dbg_propertyview-filter-01.js \
 	browser_dbg_propertyview-filter-02.js \
 	browser_dbg_propertyview-filter-03.js \
 	browser_dbg_propertyview-filter-04.js \
 	browser_dbg_propertyview-filter-05.js \
 	browser_dbg_propertyview-filter-06.js \
 	browser_dbg_propertyview-filter-07.js \
--- a/browser/devtools/debugger/test/browser_dbg_bug727429_watch-expressions-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug727429_watch-expressions-01.js
@@ -18,20 +18,17 @@ function test()
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
     gDebugger = gPane.panelWin;
     gWatch = gDebugger.DebuggerView.WatchExpressions;
 
     gDebugger.DebuggerView.togglePanes({ visible: true, animated: false });
-
-    executeSoon(function() {
-      performTest();
-    });
+    performTest();
   });
 
   function performTest()
   {
     is(gWatch.getExpressions().length, 0,
       "There should initially be no watch expressions");
 
     addAndCheckExpressions(1, 0, "a");
@@ -124,19 +121,19 @@ function test()
     let id = gWatch.getItemAtIndex(index).attachment.id;
     let element = gDebugger.document.getElementById("expression-" + id);
 
     is(gWatch.getItemAtIndex(index).attachment.initialExpression, "",
       "The initial expression at index " + index + " should be correct (1)");
     is(gWatch.getItemForElement(element).attachment.initialExpression, "",
       "The initial expression at index " + index + " should be correct (2)");
 
-    is(gWatch.getItemAtIndex(index).attachment.expression, string,
+    is(gWatch.getItemAtIndex(index).attachment.currentExpression, string,
       "The expression at index " + index + " should be correct (1)");
-    is(gWatch.getItemForElement(element).attachment.expression, string,
+    is(gWatch.getItemForElement(element).attachment.currentExpression, string,
       "The expression at index " + index + " should be correct (2)");
 
     is(gWatch.getExpression(index), string,
       "The expression at index " + index + " should be correct (3)");
     is(gWatch.getExpressions()[index], string,
       "The expression at index " + index + " should be correct (4)");
   }
 
@@ -190,19 +187,19 @@ function test()
     if (!noBlur) {
       gDebugger.editor.focus();
 
       is(gWatch.getItemAtIndex(index).attachment.initialExpression, string,
         "The initial expression at index " + index + " should be correct (1)");
       is(gWatch.getItemForElement(element).attachment.initialExpression, string,
         "The initial expression at index " + index + " should be correct (2)");
 
-      is(gWatch.getItemAtIndex(index).attachment.expression, string,
+      is(gWatch.getItemAtIndex(index).attachment.currentExpression, string,
         "The expression at index " + index + " should be correct (1)");
-      is(gWatch.getItemForElement(element).attachment.expression, string,
+      is(gWatch.getItemForElement(element).attachment.currentExpression, string,
         "The expression at index " + index + " should be correct (2)");
 
       is(gWatch.getExpression(index), string,
         "The expression at index " + index + " should be correct (3)");
       is(gWatch.getExpressions()[index], string,
         "The expression at index " + index + " should be correct (4)");
     }
   }
@@ -225,19 +222,19 @@ function test()
     let id = gWatch.getItemAtIndex(index).attachment.id;
     let element = gDebugger.document.getElementById("expression-" + id);
 
     is(gWatch.getItemAtIndex(index).attachment.initialExpression, string,
       "The initial expression at index " + index + " should be correct (1)");
     is(gWatch.getItemForElement(element).attachment.initialExpression, string,
       "The initial expression at index " + index + " should be correct (2)");
 
-    is(gWatch.getItemAtIndex(index).attachment.expression, string,
+    is(gWatch.getItemAtIndex(index).attachment.currentExpression, string,
       "The expression at index " + index + " should be correct (1)");
-    is(gWatch.getItemForElement(element).attachment.expression, string,
+    is(gWatch.getItemForElement(element).attachment.currentExpression, string,
       "The expression at index " + index + " should be correct (2)");
 
     is(gWatch.getExpression(index), string,
       "The expression at index " + index + " should be correct (3)");
     is(gWatch.getExpressions()[index], string,
       "The expression at index " + index + " should be correct (4)");
   }
 
--- a/browser/devtools/debugger/test/browser_dbg_bug727429_watch-expressions-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug727429_watch-expressions-02.js
@@ -32,32 +32,45 @@ function test()
   function addExpressions()
   {
     gWatch.addExpression("'a'");
     gWatch.addExpression("\"a\"");
     gWatch.addExpression("'a\"\"'");
     gWatch.addExpression("\"a''\"");
     gWatch.addExpression("?");
     gWatch.addExpression("a");
+    gWatch.addExpression("this");
+    gWatch.addExpression("this.canada");
     gWatch.addExpression("[1, 2, 3]");
     gWatch.addExpression("x = [1, 2, 3]");
     gWatch.addExpression("y = [1, 2, 3]; y.test = 4");
     gWatch.addExpression("z = [1, 2, 3]; z.test = 4; z");
     gWatch.addExpression("t = [1, 2, 3]; t.test = 4; !t");
     gWatch.addExpression("arguments[0]");
     gWatch.addExpression("encodeURI(\"\\\")");
     gWatch.addExpression("decodeURI(\"\\\")");
+    gWatch.addExpression("decodeURIComponent(\"%\")");
+    gWatch.addExpression("//");
+    gWatch.addExpression("// 42");
+    gWatch.addExpression("{}.foo");
+    gWatch.addExpression("{}.foo()");
+    gWatch.addExpression("({}).foo()");
+    gWatch.addExpression("new Array(-1)");
+    gWatch.addExpression("4.2.toExponential(-4.2)");
+    gWatch.addExpression("throw new Error(\"bazinga\")");
+    gWatch.addExpression("({ get error() { throw new Error(\"bazinga\") } }).error");
+    gWatch.addExpression("throw { get name() { throw \"bazinga\" } }");
   }
 
   function performTest()
   {
     is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
       "There should be 0 hidden nodes in the watch expressions container");
-    is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 14,
-      "There should be 14 visible nodes in the watch expressions container");
+    is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 27,
+      "There should be 27 visible nodes in the watch expressions container");
 
     test1(function() {
       test2(function() {
         test3(function() {
           test4(function() {
             test5(function() {
               test6(function() {
                 test7(function() {
@@ -74,107 +87,139 @@ function test()
       });
     });
   }
 
   function finishTest()
   {
     is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
       "There should be 0 hidden nodes in the watch expressions container");
-    is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 13,
-      "There should be 13 visible nodes in the watch expressions container");
+    is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 27,
+      "There should be 27 visible nodes in the watch expressions container");
 
     closeDebuggerAndFinish();
   }
 
   function test1(callback) {
     waitForWatchExpressions(function() {
       info("Performing test1");
-      checkWatchExpressions("ReferenceError: a is not defined", undefined);
+      checkWatchExpressions("ReferenceError: a is not defined",
+                            { type: "object", class: "Object" },
+                            { type: "object", class: "String" },
+                            undefined,
+                            26);
       callback();
     });
     executeSoon(function() {
-      gDebuggee.ermahgerd(); // ermahgerd!!
+      gDebuggee.test(); // ermahgerd!!
     });
   }
 
   function test2(callback) {
     waitForWatchExpressions(function() {
       info("Performing test2");
-      checkWatchExpressions(undefined, "sensational");
+      checkWatchExpressions(undefined,
+                            { type: "object", class: "Proxy" },
+                            undefined,
+                            "sensational",
+                            26);
       callback();
     });
     EventUtils.sendMouseEvent({ type: "mousedown" },
       gDebugger.document.getElementById("resume"),
       gDebugger);
   }
 
   function test3(callback) {
     waitForWatchExpressions(function() {
       info("Performing test3");
-      checkWatchExpressions({ type: "object", class: "Object" }, "sensational");
+      checkWatchExpressions({ type: "object", class: "Object" },
+                            { type: "object", class: "Proxy" },
+                            undefined,
+                            "sensational",
+                            26);
       callback();
     });
     EventUtils.sendMouseEvent({ type: "mousedown" },
       gDebugger.document.getElementById("resume"),
       gDebugger);
   }
 
   function test4(callback) {
     waitForWatchExpressions(function() {
       info("Performing test4");
-      checkWatchExpressions(5, "sensational", 13);
+      checkWatchExpressions(5,
+                            { type: "object", class: "Proxy" },
+                            undefined,
+                            "sensational",
+                            27);
       callback();
     });
     executeSoon(function() {
       gWatch.addExpression("a = 5");
       EventUtils.sendKey("RETURN", gDebugger);
     });
   }
 
   function test5(callback) {
     waitForWatchExpressions(function() {
       info("Performing test5");
-      checkWatchExpressions(5, "sensational", 13);
+      checkWatchExpressions(5,
+                            { type: "object", class: "Proxy" },
+                            undefined,
+                            "sensational",
+                            27);
       callback();
     });
     executeSoon(function() {
       gWatch.addExpression("encodeURI(\"\\\")");
       EventUtils.sendKey("RETURN", gDebugger);
     });
   }
 
   function test6(callback) {
     waitForWatchExpressions(function() {
       info("Performing test6");
-      checkWatchExpressions(5, "sensational", 13);
+      checkWatchExpressions(5,
+                            { type: "object", class: "Proxy" },
+                            undefined,
+                            "sensational",
+                            27);
       callback();
     })
     executeSoon(function() {
       gWatch.addExpression("decodeURI(\"\\\")");
       EventUtils.sendKey("RETURN", gDebugger);
     });
   }
 
   function test7(callback) {
     waitForWatchExpressions(function() {
       info("Performing test7");
-      checkWatchExpressions(5, "sensational", 13);
+      checkWatchExpressions(5,
+                            { type: "object", class: "Proxy" },
+                            undefined,
+                            "sensational",
+                            27);
       callback();
     });
     executeSoon(function() {
       gWatch.addExpression("?");
       EventUtils.sendKey("RETURN", gDebugger);
     });
   }
 
   function test8(callback) {
     waitForWatchExpressions(function() {
       info("Performing test8");
-      checkWatchExpressions(5, "sensational", 13);
+      checkWatchExpressions(5,
+                            { type: "object", class: "Proxy" },
+                            undefined,
+                            "sensational",
+                            27);
       callback();
     });
     executeSoon(function() {
       gWatch.addExpression("a");
       EventUtils.sendKey("RETURN", gDebugger);
     });
   }
 
@@ -197,17 +242,22 @@ function test()
 
   function waitForWatchExpressions(callback) {
     gDebugger.addEventListener("Debugger:FetchedWatchExpressions", function onFetch() {
       gDebugger.removeEventListener("Debugger:FetchedWatchExpressions", onFetch, false);
       executeSoon(callback);
     }, false);
   }
 
-  function checkWatchExpressions(expected_a, expected_arguments, total = 12) {
+  function checkWatchExpressions(expected_a,
+                                 expected_this,
+                                 expected_prop,
+                                 expected_arguments,
+                                 total)
+  {
     is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, total,
       "There should be " + total + " hidden nodes in the watch expressions container");
     is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
       "There should be 0 visible nodes in the watch expressions container");
 
     let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
     let scope = gVars._currHierarchy.get(label);
 
@@ -215,58 +265,115 @@ function test()
     is(scope._store.size, total, "There should be " + total + " evaluations availalble");
 
     let w1 = scope.get("'a'");
     let w2 = scope.get("\"a\"");
     let w3 = scope.get("'a\"\"'");
     let w4 = scope.get("\"a''\"");
     let w5 = scope.get("?");
     let w6 = scope.get("a");
-    let w7 = scope.get("x = [1, 2, 3]");
-    let w8 = scope.get("y = [1, 2, 3]; y.test = 4");
-    let w9 = scope.get("z = [1, 2, 3]; z.test = 4; z");
-    let w10 = scope.get("t = [1, 2, 3]; t.test = 4; !t");
-    let w11 = scope.get("arguments[0]");
-    let w12 = scope.get("encodeURI(\"\\\")");
-    let w13 = scope.get("decodeURI(\"\\\")");
+    let w7 = scope.get("this");
+    let w8 = scope.get("this.canada");
+    let w9 = scope.get("[1, 2, 3]");
+    let w10 = scope.get("x = [1, 2, 3]");
+    let w11 = scope.get("y = [1, 2, 3]; y.test = 4");
+    let w12 = scope.get("z = [1, 2, 3]; z.test = 4; z");
+    let w13 = scope.get("t = [1, 2, 3]; t.test = 4; !t");
+    let w14 = scope.get("arguments[0]");
+    let w15 = scope.get("encodeURI(\"\\\")");
+    let w16 = scope.get("decodeURI(\"\\\")");
+    let w17 = scope.get("decodeURIComponent(\"%\")");
+    let w18 = scope.get("//");
+    let w19 = scope.get("// 42");
+    let w20 = scope.get("{}.foo");
+    let w21 = scope.get("{}.foo()");
+    let w22 = scope.get("({}).foo()");
+    let w23 = scope.get("new Array(-1)");
+    let w24 = scope.get("4.2.toExponential(-4.2)");
+    let w25 = scope.get("throw new Error(\"bazinga\")");
+    let w26 = scope.get("({ get error() { throw new Error(\"bazinga\") } }).error");
+    let w27 = scope.get("throw { get name() { throw \"bazinga\" } }");
 
     ok(w1, "The first watch expression should be present in the scope");
     ok(w2, "The second watch expression should be present in the scope");
     ok(w3, "The third watch expression should be present in the scope");
     ok(w4, "The fourth watch expression should be present in the scope");
     ok(w5, "The fifth watch expression should be present in the scope");
     ok(w6, "The sixth watch expression should be present in the scope");
     ok(w7, "The seventh watch expression should be present in the scope");
     ok(w8, "The eight watch expression should be present in the scope");
     ok(w9, "The ninth watch expression should be present in the scope");
     ok(w10, "The tenth watch expression should be present in the scope");
     ok(w11, "The eleventh watch expression should be present in the scope");
-    ok(!w12, "The twelveth watch expression should not be present in the scope");
-    ok(!w13, "The thirteenth watch expression should not be present in the scope");
+    ok(w12, "The twelfth watch expression should be present in the scope");
+    ok(w13, "The 13th watch expression should be present in the scope");
+    ok(w14, "The 14th watch expression should be present in the scope");
+    ok(w15, "The 15th watch expression should be present in the scope");
+    ok(w16, "The 16th watch expression should be present in the scope");
+    ok(w17, "The 17th watch expression should be present in the scope");
+    ok(w18, "The 18th watch expression should be present in the scope");
+    ok(w19, "The 19th watch expression should be present in the scope");
+    ok(w20, "The 20th watch expression should be present in the scope");
+    ok(w21, "The 21st watch expression should be present in the scope");
+    ok(w22, "The 22nd watch expression should be present in the scope");
+    ok(w23, "The 23nd watch expression should be present in the scope");
+    ok(w24, "The 24th watch expression should be present in the scope");
+    ok(w25, "The 25th watch expression should be present in the scope");
+    ok(w26, "The 26th watch expression should be present in the scope");
+    ok(!w27, "The 27th watch expression should not be present in the scope");
 
     is(w1.value, "a", "The first value is correct");
     is(w2.value, "a", "The second value is correct");
     is(w3.value, "a\"\"", "The third value is correct");
     is(w4.value, "a''", "The fourth value is correct");
     is(w5.value, "SyntaxError: syntax error", "The fifth value is correct");
 
     if (typeof expected_a == "object") {
       is(w6.value.type, expected_a.type, "The sixth value type is correct");
       is(w6.value.class, expected_a.class, "The sixth value class is correct");
     } else {
       is(w6.value, expected_a, "The sixth value is correct");
     }
 
-    is(w7.value.type, "object", "The seventh value type is correct");
-    is(w7.value.class, "Array", "The seventh value class is correct");
-    is(w8.value, "4", "The eight value is correct");
+    if (typeof expected_this == "object") {
+      is(w7.value.type, expected_this.type, "The seventh value type is correct");
+      is(w7.value.class, expected_this.class, "The seventh value class is correct");
+    } else {
+      is(w7.value, expected_this, "The seventh value is correct");
+    }
+
+    if (typeof expected_prop == "object") {
+      is(w8.value.type, expected_prop.type, "The eighth value type is correct");
+      is(w8.value.class, expected_prop.class, "The eighth value class is correct");
+    } else {
+      is(w8.value, expected_prop, "The eighth value is correct");
+    }
+
     is(w9.value.type, "object", "The ninth value type is correct");
     is(w9.value.class, "Array", "The ninth value class is correct");
-    is(w10.value, false, "The tenth value is correct");
-    is(w11.value, expected_arguments, "The eleventh value is correct");
+    is(w10.value.type, "object", "The tenth value type is correct");
+    is(w10.value.class, "Array", "The tenth value class is correct");
+    is(w11.value, "4", "The eleventh value is correct");
+    is(w12.value.type, "object", "The eleventh value type is correct");
+    is(w12.value.class, "Array", "The twelfth value class is correct");
+    is(w13.value, false, "The 13th value is correct");
+    is(w14.value, expected_arguments, "The 14th value is correct");
+
+    is(w15.value, "SyntaxError: unterminated string literal", "The 15th value is correct");
+    is(w16.value, "SyntaxError: unterminated string literal", "The 16th value is correct");
+    is(w17.value, "URIError: malformed URI sequence", "The 17th value is correct");
+    is(w18.value, undefined, "The 18th value is correct");
+    is(w19.value, undefined, "The 19th value is correct");
+    is(w20.value, "SyntaxError: syntax error", "The 20th value is correct");
+    is(w21.value, "SyntaxError: syntax error", "The 21th value is correct");
+    is(w22.value, "TypeError: (intermediate value).foo is not a function", "The 22th value is correct");
+    is(w23.value, "RangeError: invalid array length", "The 23th value is correct");
+    is(w24.value, "RangeError: precision -4 out of range", "The 24st value is correct");
+    is(w25.value, "Error: bazinga", "The 25nd value is correct");
+    is(w26.value, "Error: bazinga", "The 26rd value is correct");
   }
 
   registerCleanupFunction(function() {
     removeTab(gTab);
     gPane = null;
     gTab = null;
     gDebuggee = null;
     gDebugger = null;
--- a/browser/devtools/debugger/test/browser_dbg_frame-parameters.html
+++ b/browser/devtools/debugger/test/browser_dbg_frame-parameters.html
@@ -6,16 +6,21 @@
     <!-- Any copyright is dedicated to the Public Domain.
          http://creativecommons.org/publicdomain/zero/1.0/ -->
     <script type="text/javascript">
       window.addEventListener("load", function() {
         function test(aArg, bArg, cArg, dArg, eArg, fArg) {
           var a = 1;
           var b = { a: a };
           var c = { a: 1, b: "beta", c: true, d: b };
+          var myVar = {
+            _prop: 42,
+            get prop() { return this._prop; },
+            set prop(val) { this._prop = val; }
+          };
 
           debugger;
         }
         function load() {
           var a = { a: 1, b: "beta", c: true };
           var e = eval("test(a, 'beta', 3, false, null)");
         }
         var button = document.querySelector("button");
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-03.js
@@ -134,18 +134,18 @@ function testSimpleCall() {
       ok(!testVar.expanded,
         "Clicking again the testVar arrow should collapse it.");
 
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
         testVar.target.querySelector(".title"),
         gDebugger);
 
-      ok(!testVar.expanded,
-        "Clicking the testVar title div shouldn't expand it.");
+      ok(testVar.expanded,
+        "Clicking the testVar title div should expand it again.");
 
 
       testScope.show();
       testScope.expand();
       testVar.show();
       testVar.expand();
 
       ok(!testVar.get("child").expanded,
@@ -180,18 +180,18 @@ function testSimpleCall() {
       ok(!testVar.get("child").expanded,
         "Clicking again the testVar child property arrow should collapse it.");
 
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
         testVar.get("child").target.querySelector(".title"),
         gDebugger);
 
-      ok(!testVar.get("child").expanded,
-        "Clicking the testVar child property title div shouldn't expand it.");
+      ok(testVar.get("child").expanded,
+        "Clicking the testVar child property title div should expand it again.");
 
 
       gDebugger.DebuggerView.Variables.empty();
       is(gDebugger.DebuggerView.Variables._list.childNodes.length, 0,
         "The scopes should have been removed from the parent container tree.");
 
       gDebugger.DebuggerController.activeThread.resume(function() {
         closeDebuggerAndFinish();
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-07.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-07.js
@@ -35,17 +35,17 @@ function testFrameParameters()
           localNodes = localScope.querySelector(".details").childNodes;
 
       is(gDebugger.DebuggerController.activeThread.state, "paused",
         "Should only be getting stack frames while paused.");
 
       is(frames.querySelectorAll(".dbg-stackframe").length, 3,
         "Should have three frames.");
 
-      is(localNodes.length, 11,
+      is(localNodes.length, 12,
         "The localScope should contain all the created variable elements.");
 
       is(localNodes[0].querySelector(".value").getAttribute("value"), "[object Proxy]",
         "Should have the right property value for 'this'.");
 
       is(localNodes[1].querySelector(".value").getAttribute("value"), "[object Object]",
         "Should have the right property value for 'aArg'.");
 
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-08.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-08.js
@@ -35,17 +35,17 @@ function testFrameParameters()
           localNonEnums = localScope.querySelector(".nonenum").childNodes;
 
       is(gDebugger.DebuggerController.activeThread.state, "paused",
         "Should only be getting stack frames while paused.");
 
       is(frames.querySelectorAll(".dbg-stackframe").length, 3,
         "Should have three frames.");
 
-      is(localNodes.length + localNonEnums.length, 11,
+      is(localNodes.length + localNonEnums.length, 12,
         "The localScope and localNonEnums should contain all the created variable elements.");
 
       is(localNodes[0].querySelector(".value").getAttribute("value"), "[object Proxy]",
         "Should have the right property value for 'this'.");
       is(localNodes[8].querySelector(".value").getAttribute("value"), "[object Arguments]",
         "Should have the right property value for 'arguments'.");
       is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Object]",
         "Should have the right property value for 'c'.");
@@ -69,19 +69,19 @@ function testFrameParameters()
       is(gVars.getScopeForNode(gVars._list.querySelectorAll(".scope")[0]).expanded, true,
         "The local scope should be expanded by default.");
       is(gVars.getScopeForNode(gVars._list.querySelectorAll(".scope")[1]).expanded, false,
         "The block scope should be collapsed by default.");
       is(gVars.getScopeForNode(gVars._list.querySelectorAll(".scope")[2]).expanded, false,
         "The global scope should be collapsed by default.");
 
 
-      let thisNode = gVars.getVariableOrPropertyForNode(localNodes[0]);
-      let argumentsNode = gVars.getVariableOrPropertyForNode(localNodes[8]);
-      let cNode = gVars.getVariableOrPropertyForNode(localNodes[10]);
+      let thisNode = gVars.getItemForNode(localNodes[0]);
+      let argumentsNode = gVars.getItemForNode(localNodes[8]);
+      let cNode = gVars.getItemForNode(localNodes[10]);
 
       is(thisNode.expanded, false,
         "The thisNode should not be expanded at this point.");
       is(argumentsNode.expanded, false,
         "The argumentsNode should not be expanded at this point.");
       is(cNode.expanded, false,
         "The cNode should not be expanded at this point.");
 
@@ -175,30 +175,30 @@ function testFrameParameters()
         is(cNode.target.querySelectorAll(".property > .title > .name")[2]
            .getAttribute("value"), "c",
           "Should have the right property name for 'c.c'.");
         is(cNode.target.querySelectorAll(".property > .title > .value")[2]
            .getAttribute("value"), "true",
           "Should have the right value for 'c.c'.");
 
 
-        is(gVars.getVariableOrPropertyForNode(
+        is(gVars.getItemForNode(
            cNode.target.querySelectorAll(".property")[0]).target,
            cNode.target.querySelectorAll(".property")[0],
-          "getVariableOrPropertyForNode([0]) didn't return the expected property.");
+          "getItemForNode([0]) didn't return the expected property.");
 
-        is(gVars.getVariableOrPropertyForNode(
+        is(gVars.getItemForNode(
            cNode.target.querySelectorAll(".property")[1]).target,
            cNode.target.querySelectorAll(".property")[1],
-          "getVariableOrPropertyForNode([1]) didn't return the expected property.");
+          "getItemForNode([1]) didn't return the expected property.");
 
-        is(gVars.getVariableOrPropertyForNode(
+        is(gVars.getItemForNode(
            cNode.target.querySelectorAll(".property")[2]).target,
            cNode.target.querySelectorAll(".property")[2],
-          "getVariableOrPropertyForNode([2]) didn't return the expected property.");
+          "getItemForNode([2]) didn't return the expected property.");
 
 
         is(cNode.find(
            cNode.target.querySelectorAll(".property")[0]).target,
            cNode.target.querySelectorAll(".property")[0],
           "find([0]) didn't return the expected property.");
 
         is(cNode.find(
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-09.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-09.js
@@ -48,17 +48,17 @@ function testFrameParameters()
         "Should only be getting stack frames while paused.");
 
       is(frames.querySelectorAll(".dbg-stackframe").length, 3,
         "Should have three frames.");
 
       is(globalNodes[0].querySelector(".name").getAttribute("value"), "InstallTrigger",
         "Should have the right property name for |InstallTrigger|.");
 
-      is(globalNodes[0].querySelector(".value").getAttribute("value"), "undefined",
+      is(globalNodes[0].querySelector(".value").getAttribute("value"), "",
         "Should have the right property value for |InstallTrigger|.");
 
       is(globalNodes[1].querySelector(".name").getAttribute("value"), "SpecialPowers",
         "Should have the right property name for |SpecialPowers|.");
 
       is(globalNodes[1].querySelector(".value").getAttribute("value"), "[object Proxy]",
         "Should have the right property value for |SpecialPowers|.");
 
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-10.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-10.js
@@ -59,17 +59,17 @@ function testWithFrame()
         "Should have the right property name for |one|.");
 
       is(innerNodes[1].querySelector(".value").getAttribute("value"), "1",
         "Should have the right property value for |one|.");
 
       is(globalNodes[0].querySelector(".name").getAttribute("value"), "InstallTrigger",
         "Should have the right property name for |InstallTrigger|.");
 
-      is(globalNodes[0].querySelector(".value").getAttribute("value"), "undefined",
+      is(globalNodes[0].querySelector(".value").getAttribute("value"), "",
         "Should have the right property value for |InstallTrigger|.");
 
       let len = globalNodes.length - 1;
       is(globalNodes[len].querySelector(".name").getAttribute("value"), "window",
         "Should have the right property name for |window|.");
 
       is(globalNodes[len].querySelector(".value").getAttribute("value"), "[object Proxy]",
         "Should have the right property value for |window|.");
rename from browser/devtools/debugger/test/browser_dbg_propertyview-big-data.js
rename to browser/devtools/debugger/test/browser_dbg_propertyview-data-big.js
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-data-getset-01.js
@@ -0,0 +1,343 @@
+/* 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 the property view knows how to edit getters and setters.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
+
+var gPane = null;
+var gTab = null;
+var gDebugger = null;
+var gVars = null;
+var gWatch = null;
+
+requestLongerTimeout(2);
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gPane = aPane;
+    gDebugger = gPane.panelWin;
+    gVars = gDebugger.DebuggerView.Variables;
+    gWatch = gDebugger.DebuggerView.WatchExpressions;
+
+    gVars.switch = function() {};
+    gVars.delete = function() {};
+
+    prepareVariablesView();
+  });
+}
+
+function prepareVariablesView() {
+  gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
+    gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      testVariablesView();
+
+    }}, 0);
+  }, false);
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    content.document.querySelector("button"),
+    content.window);
+}
+
+function testVariablesView()
+{
+  executeSoon(function() {
+    addWatchExpressions(function() {
+      testEdit("set", "this._prop = value + ' BEER CAN'", function() {
+        testEdit("set", "{ this._prop = value + ' BEACON' }", function() {
+          testEdit("set", "{ this._prop = value + ' BEACON;'; }", function() {
+            testEdit("set", "{ return this._prop = value + ' BEACON;;'; }", function() {
+              testEdit("set", "function(value) { this._prop = value + ' BACON' }", function() {
+                testEdit("get", "'brelx BEER CAN'", function() {
+                  testEdit("get", "{ 'brelx BEACON' }", function() {
+                    testEdit("get", "{ 'brelx BEACON;'; }", function() {
+                      testEdit("get", "{ return 'brelx BEACON;;'; }", function() {
+                        testEdit("get", "function() { return 'brelx BACON'; }", function() {
+                          testEdit("get", "bogus", function() {
+                            testEdit("set", "sugob", function() {
+                              testEdit("get", "", function() {
+                                testEdit("set", "", function() {
+                                  waitForWatchExpressions(function() {
+                                    testEdit("self", "2507", function() {
+                                      closeDebuggerAndFinish();
+                                    }, {
+                                      "myVar.prop": 2507,
+                                      "myVar.prop + 42": "250742"
+                                    });
+                                  })
+                                  gWatch.deleteExpression({ name: "myVar.prop = 'xlerb'" });
+                                }, {
+                                  "myVar.prop": "xlerb",
+                                  "myVar.prop + 42": NaN,
+                                  "myVar.prop = 'xlerb'": "xlerb"
+                                });
+                              }, {
+                                "myVar.prop": undefined,
+                                "myVar.prop + 42": NaN,
+                                "myVar.prop = 'xlerb'": "ReferenceError: sugob is not defined"
+                              });
+                            }, {
+                              "myVar.prop": "ReferenceError: bogus is not defined",
+                              "myVar.prop + 42": "ReferenceError: bogus is not defined",
+                              "myVar.prop = 'xlerb'": "ReferenceError: sugob is not defined"
+                            });
+                          }, {
+                            "myVar.prop": "ReferenceError: bogus is not defined",
+                            "myVar.prop + 42": "ReferenceError: bogus is not defined",
+                            "myVar.prop = 'xlerb'": "xlerb"
+                          });
+                        }, {
+                          "myVar.prop": "brelx BACON",
+                          "myVar.prop + 42": "brelx BACON42",
+                          "myVar.prop = 'xlerb'": "xlerb"
+                        });
+                      }, {
+                        "myVar.prop": "brelx BEACON;;",
+                        "myVar.prop + 42": "brelx BEACON;;42",
+                        "myVar.prop = 'xlerb'": "xlerb"
+                      });
+                    }, {
+                      "myVar.prop": undefined,
+                      "myVar.prop + 42": NaN,
+                      "myVar.prop = 'xlerb'": "xlerb"
+                    });
+                  }, {
+                    "myVar.prop": undefined,
+                    "myVar.prop + 42": NaN,
+                    "myVar.prop = 'xlerb'": "xlerb"
+                  });
+                }, {
+                  "myVar.prop": "brelx BEER CAN",
+                  "myVar.prop + 42": "brelx BEER CAN42",
+                  "myVar.prop = 'xlerb'": "xlerb"
+                });
+              }, {
+                "myVar.prop": "xlerb BACON",
+                "myVar.prop + 42": "xlerb BACON42",
+                "myVar.prop = 'xlerb'": "xlerb"
+              });
+            }, {
+              "myVar.prop": "xlerb BEACON;;",
+              "myVar.prop + 42": "xlerb BEACON;;42",
+              "myVar.prop = 'xlerb'": "xlerb"
+            });
+          }, {
+            "myVar.prop": "xlerb BEACON;",
+            "myVar.prop + 42": "xlerb BEACON;42",
+            "myVar.prop = 'xlerb'": "xlerb"
+          });
+        }, {
+          "myVar.prop": "xlerb BEACON",
+          "myVar.prop + 42": "xlerb BEACON42",
+          "myVar.prop = 'xlerb'": "xlerb"
+        });
+      }, {
+        "myVar.prop": "xlerb BEER CAN",
+        "myVar.prop + 42": "xlerb BEER CAN42",
+        "myVar.prop = 'xlerb'": "xlerb"
+      });
+    });
+  });
+}
+
+function addWatchExpressions(callback)
+{
+  waitForWatchExpressions(function() {
+    let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
+    let scope = gVars._currHierarchy.get(label);
+
+    ok(scope, "There should be a wach expressions scope in the variables view");
+    is(scope._store.size, 1, "There should be 1 evaluation availalble");
+
+    let w1 = scope.get("myVar.prop");
+    let w2 = scope.get("myVar.prop + 42");
+    let w3 = scope.get("myVar.prop = 'xlerb'");
+
+    ok(w1, "The first watch expression should be present in the scope");
+    ok(!w2, "The second watch expression should not be present in the scope");
+    ok(!w3, "The third watch expression should not be present in the scope");
+
+    is(w1.value, 42, "The first value is correct.");
+
+
+    waitForWatchExpressions(function() {
+      let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
+      let scope = gVars._currHierarchy.get(label);
+
+      ok(scope, "There should be a wach expressions scope in the variables view");
+      is(scope._store.size, 2, "There should be 2 evaluations availalble");
+
+      let w1 = scope.get("myVar.prop");
+      let w2 = scope.get("myVar.prop + 42");
+      let w3 = scope.get("myVar.prop = 'xlerb'");
+
+      ok(w1, "The first watch expression should be present in the scope");
+      ok(w2, "The second watch expression should be present in the scope");
+      ok(!w3, "The third watch expression should not be present in the scope");
+
+      is(w1.value, "42", "The first expression value is correct.");
+      is(w2.value, "84", "The second expression value is correct.");
+
+
+      waitForWatchExpressions(function() {
+        let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
+        let scope = gVars._currHierarchy.get(label);
+
+        ok(scope, "There should be a wach expressions scope in the variables view");
+        is(scope._store.size, 3, "There should be 3 evaluations availalble");
+
+        let w1 = scope.get("myVar.prop");
+        let w2 = scope.get("myVar.prop + 42");
+        let w3 = scope.get("myVar.prop = 'xlerb'");
+
+        ok(w1, "The first watch expression should be present in the scope");
+        ok(w2, "The second watch expression should be present in the scope");
+        ok(w3, "The third watch expression should be present in the scope");
+
+        is(w1.value, "xlerb", "The first expression value is correct.");
+        is(w2.value, "xlerb42", "The second expression value is correct.");
+        is(w3.value, "xlerb", "The third expression value is correct.");
+
+        callback();
+      });
+
+      gWatch.addExpression("myVar.prop = 'xlerb'");
+      gDebugger.editor.focus();
+    });
+
+    gWatch.addExpression("myVar.prop + 42");
+    gDebugger.editor.focus();
+  });
+
+  gWatch.addExpression("myVar.prop");
+  gDebugger.editor.focus();
+}
+
+function testEdit(what, string, callback, expected)
+{
+  let localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[1],
+      localNodes = localScope.querySelector(".details").childNodes,
+      myVar = gVars.getItemForNode(localNodes[11]);
+
+  waitForProperties(function() {
+    let prop = myVar.get("prop");
+    let getterOrSetter = (what != "self" ? prop.get(what) : prop);
+
+    EventUtils.sendMouseEvent({ type: "mousedown" },
+      getterOrSetter._target.querySelector(".title > .value"),
+      gDebugger);
+
+    waitForElement(".element-value-input", true, function() {
+      waitForWatchExpressions(function() {
+        let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
+        let scope = gVars._currHierarchy.get(label);
+
+        let w1 = scope.get(Object.keys(expected)[0]);
+        let w2 = scope.get(Object.keys(expected)[1]);
+        let w3 = scope.get(Object.keys(expected)[2]);
+
+        if (w1) {
+          if (isNaN(expected[w1.name]) && typeof expected[w1.name] == "number") {
+            ok(isNaN(w1.value),
+              "The first expression value is correct after the edit (NaN).");
+          } else {
+            is(w1.value, expected[w1.name],
+              "The first expression value is correct after the edit.");
+          }
+          info(w1.value + " is equal to " + expected[w1.name]);
+        }
+        if (w2) {
+          if (isNaN(expected[w2.name]) && typeof expected[w2.name] == "number") {
+            ok(isNaN(w2.value),
+              "The second expression value is correct after the edit (NaN).");
+          } else {
+            is(w2.value, expected[w2.name],
+              "The second expression value is correct after the edit.");
+          }
+          info(w2.value + " is equal to " + expected[w2.name]);
+        }
+        if (w3) {
+          if (isNaN(expected[w3.name]) && typeof expected[w3.name] == "number") {
+            ok(isNaN(w3.value),
+              "The third expression value is correct after the edit (NaN).");
+          } else {
+            is(w3.value, expected[w3.name],
+              "The third expression value is correct after the edit.");
+          }
+          info(w3.value + " is equal to " + expected[w3.name]);
+        }
+
+        callback();
+      });
+
+      info("Changing the " + what + "ter with '" + string + "'.");
+
+      write(string);
+      EventUtils.sendKey("RETURN", gDebugger);
+    });
+  });
+
+  myVar.expand();
+  gVars.clearHierarchy();
+}
+
+function waitForWatchExpressions(callback) {
+  gDebugger.addEventListener("Debugger:FetchedWatchExpressions", function onFetch() {
+    gDebugger.removeEventListener("Debugger:FetchedWatchExpressions", onFetch, false);
+    executeSoon(callback);
+  }, false);
+}
+
+function waitForProperties(callback) {
+  gDebugger.addEventListener("Debugger:FetchedProperties", function onFetch() {
+    gDebugger.removeEventListener("Debugger:FetchedProperties", onFetch, false);
+    executeSoon(callback);
+  }, false);
+}
+
+function waitForElement(selector, exists, callback)
+{
+  // Poll every few milliseconds until the element are retrieved.
+  let count = 0;
+  let intervalID = window.setInterval(function() {
+    info("count: " + count + " ");
+    if (++count > 50) {
+      ok(false, "Timed out while polling for the element.");
+      window.clearInterval(intervalID);
+      return closeDebuggerAndFinish();
+    }
+    if (!!gVars._list.querySelector(selector) != exists) {
+      return;
+    }
+    // We got the element, it's safe to callback.
+    window.clearInterval(intervalID);
+    callback();
+  }, 100);
+}
+
+function write(text) {
+  if (!text) {
+    EventUtils.sendKey("BACK_SPACE", gDebugger);
+    return;
+  }
+  for (let i = 0; i < text.length; i++) {
+    EventUtils.sendChar(text[i], gDebugger);
+  }
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebugger = null;
+  gVars = null;
+  gWatch = null;
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-data-getset-02.js
@@ -0,0 +1,185 @@
+/* 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 the property view is able to override getter properties
+ * to plain value properties.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_frame-parameters.html";
+
+var gPane = null;
+var gTab = null;
+var gDebugger = null;
+var gVars = null;
+var gWatch = null;
+
+requestLongerTimeout(2);
+
+function test()
+{
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gPane = aPane;
+    gDebugger = gPane.panelWin;
+    gVars = gDebugger.DebuggerView.Variables;
+    gWatch = gDebugger.DebuggerView.WatchExpressions;
+
+    gVars.switch = function() {};
+    gVars.delete = function() {};
+
+    prepareVariablesView();
+  });
+}
+
+function prepareVariablesView() {
+  gDebugger.addEventListener("Debugger:FetchedVariables", function test() {
+    gDebugger.removeEventListener("Debugger:FetchedVariables", test, false);
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      testVariablesView();
+
+    }}, 0);
+  }, false);
+
+  EventUtils.sendMouseEvent({ type: "click" },
+    content.document.querySelector("button"),
+    content.window);
+}
+
+function testVariablesView()
+{
+  executeSoon(function() {
+    addWatchExpressions(function() {
+      testEdit("\"xlerb\"", "xlerb", function() {
+        closeDebuggerAndFinish();
+      });
+    });
+  });
+}
+
+function addWatchExpressions(callback)
+{
+  waitForWatchExpressions(function() {
+    let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
+    let scope = gVars._currHierarchy.get(label);
+
+    ok(scope, "There should be a wach expressions scope in the variables view");
+    is(scope._store.size, 1, "There should be 1 evaluation availalble");
+
+    let expr = scope.get("myVar.prop");
+    ok(expr, "The watch expression should be present in the scope");
+    is(expr.value, 42, "The value is correct.");
+
+    callback();
+  });
+
+  gWatch.addExpression("myVar.prop");
+  gDebugger.editor.focus();
+}
+
+function testEdit(string, expected, callback)
+{
+  let localScope = gDebugger.DebuggerView.Variables._list.querySelectorAll(".scope")[1],
+      localNodes = localScope.querySelector(".details").childNodes,
+      myVar = gVars.getItemForNode(localNodes[11]);
+
+  waitForProperties(function() {
+    let prop = myVar.get("prop");
+
+    is(prop.ownerView.name, "myVar",
+      "The right owner property name wasn't found.");
+    is(prop.name, "prop",
+      "The right property name wasn't found.");
+
+    is(prop.ownerView.value.type, "object",
+      "The right owner property value type wasn't found.");
+    is(prop.ownerView.value.class, "Object",
+      "The right owner property value class wasn't found.");
+
+    is(prop.name, "prop",
+      "The right property name wasn't found.");
+    is(prop.value, undefined,
+      "The right property value wasn't found.");
+    ok(prop.getter,
+      "The right property getter wasn't found.");
+    ok(prop.setter,
+      "The right property setter wasn't found.");
+
+    EventUtils.sendMouseEvent({ type: "mousedown" },
+      prop._target.querySelector(".dbg-variable-edit"),
+      gDebugger);
+
+    waitForElement(".element-value-input", true, function() {
+      waitForWatchExpressions(function() {
+        let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
+        let scope = gVars._currHierarchy.get(label);
+
+        let expr = scope.get("myVar.prop");
+        is(expr.value, expected, "The value is correct.");
+
+        callback();
+      });
+
+      write(string);
+      EventUtils.sendKey("RETURN", gDebugger);
+    });
+  });
+
+  myVar.expand();
+  gVars.clearHierarchy();
+}
+
+function waitForWatchExpressions(callback) {
+  gDebugger.addEventListener("Debugger:FetchedWatchExpressions", function onFetch() {
+    gDebugger.removeEventListener("Debugger:FetchedWatchExpressions", onFetch, false);
+    executeSoon(callback);
+  }, false);
+}
+
+function waitForProperties(callback) {
+  gDebugger.addEventListener("Debugger:FetchedProperties", function onFetch() {
+    gDebugger.removeEventListener("Debugger:FetchedProperties", onFetch, false);
+    executeSoon(callback);
+  }, false);
+}
+
+function waitForElement(selector, exists, callback)
+{
+  // Poll every few milliseconds until the element are retrieved.
+  let count = 0;
+  let intervalID = window.setInterval(function() {
+    info("count: " + count + " ");
+    if (++count > 50) {
+      ok(false, "Timed out while polling for the element.");
+      window.clearInterval(intervalID);
+      return closeDebuggerAndFinish();
+    }
+    if (!!gVars._list.querySelector(selector) != exists) {
+      return;
+    }
+    // We got the element, it's safe to callback.
+    window.clearInterval(intervalID);
+    callback();
+  }, 100);
+}
+
+function write(text) {
+  if (!text) {
+    EventUtils.sendKey("BACK_SPACE", gDebugger);
+    return;
+  }
+  for (let i = 0; i < text.length; i++) {
+    EventUtils.sendChar(text[i], gDebugger);
+  }
+}
+
+registerCleanupFunction(function() {
+  removeTab(gTab);
+  gPane = null;
+  gTab = null;
+  gDebugger = null;
+  gVars = null;
+  gWatch = null;
+});
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-data.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-data.js
@@ -16,16 +16,17 @@ var gVariable = null;
 function test()
 {
   debug_tab_pane(TAB1_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
     gDebugger = gPane.panelWin;
     gVariablesView = gDebugger.DebuggerView.Variables;
 
+    gDebugger.DebuggerView.togglePanes({ visible: true, animated: false });
     testVariablesView();
   });
 }
 
 function testVariablesView()
 {
   let arr = [
     42,
@@ -56,41 +57,45 @@ function testVariablesView()
     someProp3: undefined,
     someProp4: null,
     someProp5: arr,
     someProp6: obj,
     get someProp7() { return arr; },
     set someProp7(value) { arr[0] = value }
   };
 
+  gVariablesView.eval = function() {};
+  gVariablesView.switch = function() {};
+  gVariablesView.delete = function() {};
   gVariablesView.rawObject = test;
 
   testHierarchy();
   testHeader();
   testFirstLevelContents();
   testSecondLevelContents();
   testThirdLevelContents();
   testIntegrity(arr, obj);
 
-  gVariablesView.eval = function() {};
-  gVariablesView.switch = function() {};
-  gVariablesView.delete = function() {};
-
   let fooScope = gVariablesView.addScope("foo");
   let anonymousVar = fooScope.addVar();
 
   let anonymousScope = gVariablesView.addScope();
   let barVar = anonymousScope.addVar("bar");
   let bazProperty = barVar.addProperty("baz");
 
   testAnonymousHeaders(fooScope, anonymousVar, anonymousScope, barVar, bazProperty);
   testPropertyInheritance(fooScope, anonymousVar, anonymousScope, barVar, bazProperty);
-  testClearHierarchy();
 
-  closeDebuggerAndFinish();
+  executeSoon(function() {
+    testKeyboardAccessibility(function() {
+      testClearHierarchy();
+
+      closeDebuggerAndFinish();
+    });
+  });
 }
 
 function testHierarchy() {
   is(gVariablesView._currHierarchy.size, 13,
     "There should be 1 scope, 1 var, 1 proto, 8 props, 1 getter and 1 setter.");
 
   gScope = gVariablesView._currHierarchy.get("");
   gVariable = gVariablesView._currHierarchy.get("[\"\"]");
@@ -577,21 +582,278 @@ function testPropertyInheritance(fooScop
   is(bazProperty.delete, gVariablesView.delete,
     "The delete property should persist from the view to all properties.");
   isnot(bazProperty.eval, bazProperty.switch,
     "The eval and switch functions got mixed up in the property.");
   isnot(bazProperty.switch, bazProperty.delete,
     "The eval and switch functions got mixed up in the property.");
 }
 
+function testKeyboardAccessibility(callback) {
+  gDebugger.DebuggerView.Filtering._doVariablesFocus();
+  gDebugger.DebuggerView.Variables.pageSize = 5;
+
+  is(gVariablesView.getFocusedItem().name, "someProp0",
+    "The someProp0 item should be focused.");
+
+  gVariablesView.focusNextItem();
+  is(gVariablesView.getFocusedItem().name, "someProp1",
+    "The someProp1 item should be focused.");
+
+  gVariablesView.focusPrevItem();
+  is(gVariablesView.getFocusedItem().name, "someProp0",
+    "The someProp0 item should be focused again.");
+
+
+  ok(!gVariablesView._list.querySelector(".element-value-input"),
+    "There shouldn't be a value input element created.");
+
+  EventUtils.synthesizeKey("VK_ENTER", {}, gDebugger);
+  waitForElement(".element-value-input", true, function() {
+
+    ok(gVariablesView._list.querySelector(".element-value-input"),
+      "There should be a value input element created.");
+
+    EventUtils.sendKey("ESCAPE", gDebugger);
+    waitForElement(".element-value-input", false, function() {
+
+      ok(!gVariablesView._list.querySelector(".element-value-input"),
+        "There shouldn't be a value input element anymore.");
+
+      ok(!gVariablesView._list.querySelector(".element-name-input"),
+        "There shouldn't be a name input element created.");
+
+      EventUtils.synthesizeKey("VK_ENTER", { shiftKey: true }, gDebugger);
+      waitForElement(".element-name-input", true, function() {
+
+        ok(gVariablesView._list.querySelector(".element-name-input"),
+          "There should be a name input element created.");
+
+        EventUtils.sendKey("ESCAPE", gDebugger);
+        waitForElement(".element-name-input", false, function() {
+
+          ok(!gVariablesView._list.querySelector(".element-name-input"),
+            "There shouldn't be a name input element anymore.");
+
+
+          EventUtils.sendKey("DOWN", gDebugger);
+          executeSoon(function() {
+            is(gVariablesView._parent.scrollTop, 0,
+              "The variables view shouldn't scroll when pressing the DOWN key.");
+
+            EventUtils.sendKey("UP", gDebugger);
+            executeSoon(function() {
+              is(gVariablesView._parent.scrollTop, 0,
+                "The variables view shouldn't scroll when pressing the UP key.");
+
+
+              EventUtils.sendKey("PAGE_DOWN", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp5",
+                "The someProp5 item should be focused now.");
+
+              EventUtils.sendKey("DOWN", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "0",
+                "The 0 item should be focused now.");
+
+              EventUtils.sendKey("END", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "foo",
+                "The foo item should be focused now.");
+
+              EventUtils.sendKey("DOWN", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "foo",
+                "The foo item should still be focused now.");
+
+              EventUtils.sendKey("RIGHT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "bar",
+                "The bar item should still be focused now.");
+
+              EventUtils.sendKey("PAGE_DOWN", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "foo",
+                "The foo item should still be focused now.");
+
+
+              EventUtils.sendKey("PAGE_UP", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "__proto__",
+                "The __proto__ item should be focused now.");
+
+              EventUtils.sendKey("UP", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "set",
+                "The set item should be focused now.");
+
+              EventUtils.sendKey("UP", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "get",
+                "The get item should be focused now.");
+
+              EventUtils.sendKey("UP", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "p8",
+                "The p8 item should be focused now.");
+
+              EventUtils.sendKey("HOME", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp0",
+                "The someProp0 item should be focused now.");
+
+              EventUtils.sendKey("UP", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp0",
+                "The someProp0 item should still be focused now.");
+
+              EventUtils.sendKey("LEFT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp0",
+                "The someProp0 item should still be focused now.");
+
+              EventUtils.sendKey("PAGE_UP", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp0",
+                "The someProp0 item should still be focused now.");
+
+
+              for (let i = 0; i < 16; i++) {
+                // Advance to the first collapsed __proto__ property.
+                EventUtils.sendKey("RIGHT", gDebugger);
+              }
+              is(gVariablesView.getFocusedItem().name, "__proto__",
+                "The __proto__ item should be focused now.");
+              is(gVariablesView.getFocusedItem().expanded, false,
+                "The __proto__ item shouldn't be expanded yet.");
+
+              EventUtils.sendKey("RIGHT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "__proto__",
+                "The __proto__ item should still be focused.");
+              is(gVariablesView.getFocusedItem().expanded, true,
+                "The __proto__ item should be expanded now.");
+
+              for (let i = 0; i < 2; i++) {
+                // Advance to the fifth top-level someProp5 property.
+                EventUtils.sendKey("LEFT", gDebugger);
+              }
+              is(gVariablesView.getFocusedItem().name, "5",
+                "The fifth array item should be focused.");
+              is(gVariablesView.getFocusedItem().expanded, false,
+                "The fifth array item should not be expanded now.");
+
+              for (let i = 0; i < 6; i++) {
+                // Advance to the fifth top-level someProp5 property.
+                EventUtils.sendKey("UP", gDebugger);
+              }
+              is(gVariablesView.getFocusedItem().name, "someProp5",
+                "The someProp5 item should be focused now.");
+              is(gVariablesView.getFocusedItem().expanded, true,
+                "The someProp5 item should already be expanded.");
+
+              EventUtils.sendKey("LEFT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp5",
+                "The someProp5 item should still be focused.");
+              is(gVariablesView.getFocusedItem().expanded, false,
+                "The someProp5 item should not be expanded now.");
+
+              EventUtils.sendKey("LEFT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp4",
+                "The someProp4 item should be focused.");
+
+              EventUtils.sendKey("LEFT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp3",
+                "The someProp3 item should be focused.");
+
+              EventUtils.sendKey("LEFT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp2",
+                "The someProp2 item should be focused.");
+
+              EventUtils.sendKey("LEFT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp1",
+                "The someProp1 item should be focused.");
+
+              EventUtils.sendKey("LEFT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp0",
+                "The someProp0 item should be focused.");
+
+              EventUtils.sendKey("LEFT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "someProp0",
+                "The someProp0 item should still be focused.");
+
+              for (let i = 0; i < 32; i++) {
+                // Advance to the last property in this scope.
+                EventUtils.sendKey("DOWN", gDebugger);
+              }
+              is(gVariablesView.getFocusedItem().name, "__proto__",
+                "The top-level __proto__ item should be focused.");
+
+              EventUtils.sendKey("DOWN", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "foo",
+                "The foo scope should be focused now.");
+              is(gVariablesView.getFocusedItem().expanded, true,
+                "The foo scope should already be expanded yet.");
+
+              EventUtils.sendKey("LEFT", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "foo",
+                "The foo scope should be focused now.");
+              is(gVariablesView.getFocusedItem().expanded, false,
+                "The foo scope shouldn't be expanded now.");
+
+              EventUtils.sendKey("DOWN", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "foo",
+                "The foo scope should still be focused.");
+              is(gVariablesView.getFocusedItem().expanded, true,
+                "The foo scope should be expanded now.");
+
+              EventUtils.sendKey("DOWN", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "bar",
+                "The bar variable should still be focused.");
+              is(gVariablesView.getFocusedItem().expanded, false,
+                "The bar variable shouldn't be expanded.");
+              is(gVariablesView.getFocusedItem().visible, true,
+                "The bar variable shouldn't be hidden.");
+
+              EventUtils.sendKey("BACK_SPACE", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "bar",
+                "The bar variable should still be focused.");
+              is(gVariablesView.getFocusedItem().expanded, false,
+                "The bar variable should still not be expanded.");
+              is(gVariablesView.getFocusedItem().visible, false,
+                "The bar variable should be hidden.");
+
+              EventUtils.sendKey("UP", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "foo",
+                "The foo scope should be focused.");
+
+              EventUtils.sendKey("UP", gDebugger);
+              is(gVariablesView.getFocusedItem().name, "__proto__",
+                "The top-level __proto__ item should be focused.");
+
+              executeSoon(callback);
+            });
+          });
+        });
+      });
+    });
+  });
+}
+
+function waitForElement(selector, exists, callback)
+{
+  // Poll every few milliseconds until the element are retrieved.
+  let count = 0;
+  let intervalID = window.setInterval(function() {
+    info("count: " + count + " ");
+    if (++count > 50) {
+      ok(false, "Timed out while polling for the element.");
+      window.clearInterval(intervalID);
+      return closeDebuggerAndFinish();
+    }
+    if (!!gVariablesView._list.querySelector(selector) != exists) {
+      return;
+    }
+    // We got the element, it's safe to callback.
+    window.clearInterval(intervalID);
+    callback();
+  }, 100);
+}
+
 function testClearHierarchy() {
   gVariablesView.clearHierarchy();
-  is (gVariablesView._prevHierarchy.size, 0,
+  ok(!gVariablesView._prevHierarchy.size,
     "The previous hierarchy should have been cleared.");
-  is (gVariablesView._currHierarchy.size, 0,
+  ok(!gVariablesView._currHierarchy.size,
     "The current hierarchy should have been cleared.");
 }
 
 registerCleanupFunction(function() {
   removeTab(gTab);
   gPane = null;
   gTab = null;
   gDebugger = null;
rename from browser/devtools/debugger/test/browser_dbg_propertyview-edit.js
rename to browser/devtools/debugger/test/browser_dbg_propertyview-edit-value.js
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-edit.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-edit-value.js
@@ -64,17 +64,17 @@ function testFrameEval() {
 }
 
 function testModification(aVar, aCallback, aNewValue, aNewResult) {
   function makeChangesAndExitInputMode() {
     EventUtils.sendString(aNewValue, gDebugger);
     EventUtils.sendKey("RETURN", gDebugger);
   }
 
-  EventUtils.sendMouseEvent({ type: "click" },
+  EventUtils.sendMouseEvent({ type: "mousedown" },
     aVar.querySelector(".value"),
     gDebugger);
 
   executeSoon(function() {
     ok(aVar.querySelector(".element-value-input"),
       "There should be an input element created.");
 
     let count = 0;
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-edit-watch.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-edit-watch.js
@@ -63,59 +63,59 @@ function testFrameEval() {
         "There should be 0 visible nodes in the watch expressions container");
 
       let label = gDebugger.L10N.getStr("watchExpressionsScopeLabel");
       let scope = gVars._currHierarchy.get(label);
 
       ok(scope, "There should be a wach expressions scope in the variables view");
       is(scope._store.size, 5, "There should be 5 evaluations availalble");
 
-      is(scope.get("this")._isShown, true,
+      is(scope.get("this")._isContentVisible, true,
         "Should have the right visibility state for 'this'.");
       is(scope.get("this").target.querySelectorAll(".dbg-variable-delete").length, 1,
         "Should have the one close button visible for 'this'.");
       is(scope.get("this").name, "this",
         "Should have the right name for 'this'.");
       is(scope.get("this").value.type, "object",
         "Should have the right value type for 'this'.");
       is(scope.get("this").value.class, "Proxy",
         "Should have the right value type for 'this'.");
 
-      is(scope.get("ermahgerd")._isShown, true,
+      is(scope.get("ermahgerd")._isContentVisible, true,
         "Should have the right visibility state for 'ermahgerd'.");
       is(scope.get("ermahgerd").target.querySelectorAll(".dbg-variable-delete").length, 1,
         "Should have the one close button visible for 'ermahgerd'.");
       is(scope.get("ermahgerd").name, "ermahgerd",
         "Should have the right name for 'ermahgerd'.");
       is(scope.get("ermahgerd").value.type, "object",
         "Should have the right value type for 'ermahgerd'.");
       is(scope.get("ermahgerd").value.class, "Function",
         "Should have the right value type for 'ermahgerd'.");
 
-      is(scope.get("aArg")._isShown, true,
+      is(scope.get("aArg")._isContentVisible, true,
         "Should have the right visibility state for 'aArg'.");
       is(scope.get("aArg").target.querySelectorAll(".dbg-variable-delete").length, 1,
         "Should have the one close button visible for 'aArg'.");
       is(scope.get("aArg").name, "aArg",
         "Should have the right name for 'aArg'.");
       is(scope.get("aArg").value, undefined,
         "Should have the right value for 'aArg'.");
 
-      is(scope.get("document.title")._isShown, true,
+      is(scope.get("document.title")._isContentVisible, true,
         "Should have the right visibility state for 'document.title'.");
       is(scope.get("document.title").target.querySelectorAll(".dbg-variable-delete").length, 1,
         "Should have the one close button visible for 'document.title'.");
       is(scope.get("document.title").name, "document.title",
         "Should have the right name for 'document.title'.");
       is(scope.get("document.title").value, "42",
         "Should have the right value for 'document.title'.");
       is(typeof scope.get("document.title").value, "string",
         "Should have the right value type for 'document.title'.");
 
-      is(scope.get("document.title = 42")._isShown, true,
+      is(scope.get("document.title = 42")._isContentVisible, true,
         "Should have the right visibility state for 'document.title = 42'.");
       is(scope.get("document.title = 42").target.querySelectorAll(".dbg-variable-delete").length, 1,
         "Should have the one close button visible for 'document.title = 42'.");
       is(scope.get("document.title = 42").name, "document.title = 42",
         "Should have the right name for 'document.title = 42'.");
       is(scope.get("document.title = 42").value, 42,
         "Should have the right value for 'document.title = 42'.");
       is(typeof scope.get("document.title = 42").value, "number",
@@ -335,148 +335,148 @@ function test1(scope) {
   is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
     "There should be 0 visible nodes in the watch expressions container");
 
   ok(scope, "There should be a wach expressions scope in the variables view");
   is(scope._store.size, 5, "There should be 5 evaluations availalble");
 
   is(gWatch._cache[0].target.inputNode.value, "document.title = 43",
     "The first textbox input value is not the correct one");
-  is(gWatch._cache[0].attachment.expression, "document.title = 43",
+  is(gWatch._cache[0].attachment.currentExpression, "document.title = 43",
     "The first textbox input value is not the correct one");
   is(gWatch._cache[1].target.inputNode.value, "document.title",
     "The second textbox input value is not the correct one");
-  is(gWatch._cache[1].attachment.expression, "document.title",
+  is(gWatch._cache[1].attachment.currentExpression, "document.title",
     "The second textbox input value is not the correct one");
   is(gWatch._cache[2].target.inputNode.value, "aArg",
     "The third textbox input value is not the correct one");
-  is(gWatch._cache[2].attachment.expression, "aArg",
+  is(gWatch._cache[2].attachment.currentExpression, "aArg",
     "The third textbox input value is not the correct one");
   is(gWatch._cache[3].target.inputNode.value, "ermahgerd",
     "The fourth textbox input value is not the correct one");
-  is(gWatch._cache[3].attachment.expression, "ermahgerd",
+  is(gWatch._cache[3].attachment.currentExpression, "ermahgerd",
     "The fourth textbox input value is not the correct one");
   is(gWatch._cache[4].target.inputNode.value, "this",
     "The fifth textbox input value is not the correct one");
-  is(gWatch._cache[4].attachment.expression, "this",
+  is(gWatch._cache[4].attachment.currentExpression, "this",
     "The fifth textbox input value is not the correct one");
 }
 
 function test2(scope) {
   is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 5,
     "There should be 5 hidden nodes in the watch expressions container");
   is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
     "There should be 0 visible nodes in the watch expressions container");
 
   ok(scope, "There should be a wach expressions scope in the variables view");
   is(scope._store.size, 5, "There should be 5 evaluations availalble");
 
   is(gWatch._cache[0].target.inputNode.value, "document.title = 43",
     "The first textbox input value is not the correct one");
-  is(gWatch._cache[0].attachment.expression, "document.title = 43",
+  is(gWatch._cache[0].attachment.currentExpression, "document.title = 43",
     "The first textbox input value is not the correct one");
   is(gWatch._cache[1].target.inputNode.value, "document.title",
     "The second textbox input value is not the correct one");
-  is(gWatch._cache[1].attachment.expression, "document.title",
+  is(gWatch._cache[1].attachment.currentExpression, "document.title",
     "The second textbox input value is not the correct one");
   is(gWatch._cache[2].target.inputNode.value, "aArg = 44",
     "The third textbox input value is not the correct one");
-  is(gWatch._cache[2].attachment.expression, "aArg = 44",
+  is(gWatch._cache[2].attachment.currentExpression, "aArg = 44",
     "The third textbox input value is not the correct one");
   is(gWatch._cache[3].target.inputNode.value, "ermahgerd",
     "The fourth textbox input value is not the correct one");
-  is(gWatch._cache[3].attachment.expression, "ermahgerd",
+  is(gWatch._cache[3].attachment.currentExpression, "ermahgerd",
     "The fourth textbox input value is not the correct one");
   is(gWatch._cache[4].target.inputNode.value, "this",
     "The fifth textbox input value is not the correct one");
-  is(gWatch._cache[4].attachment.expression, "this",
+  is(gWatch._cache[4].attachment.currentExpression, "this",
     "The fifth textbox input value is not the correct one");
 }
 
 function test3(scope) {
   is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 4,
     "There should be 4 hidden nodes in the watch expressions container");
   is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
     "There should be 0 visible nodes in the watch expressions container");
 
   ok(scope, "There should be a wach expressions scope in the variables view");
   is(scope._store.size, 4, "There should be 4 evaluations availalble");
 
   is(gWatch._cache[0].target.inputNode.value, "document.title = 43",
     "The first textbox input value is not the correct one");
-  is(gWatch._cache[0].attachment.expression, "document.title = 43",
+  is(gWatch._cache[0].attachment.currentExpression, "document.title = 43",
     "The first textbox input value is not the correct one");
   is(gWatch._cache[1].target.inputNode.value, "document.title",
     "The second textbox input value is not the correct one");
-  is(gWatch._cache[1].attachment.expression, "document.title",
+  is(gWatch._cache[1].attachment.currentExpression, "document.title",
     "The second textbox input value is not the correct one");
   is(gWatch._cache[2].target.inputNode.value, "ermahgerd",
     "The third textbox input value is not the correct one");
-  is(gWatch._cache[2].attachment.expression, "ermahgerd",
+  is(gWatch._cache[2].attachment.currentExpression, "ermahgerd",
     "The third textbox input value is not the correct one");
   is(gWatch._cache[3].target.inputNode.value, "this",
     "The fourth textbox input value is not the correct one");
-  is(gWatch._cache[3].attachment.expression, "this",
+  is(gWatch._cache[3].attachment.currentExpression, "this",
     "The fourth textbox input value is not the correct one");
 }
 
 function test4(scope) {
   is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 3,
     "There should be 3 hidden nodes in the watch expressions container");
   is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
     "There should be 0 visible nodes in the watch expressions container");
 
   ok(scope, "There should be a wach expressions scope in the variables view");
   is(scope._store.size, 3, "There should be 3 evaluations availalble");
 
   is(gWatch._cache[0].target.inputNode.value, "document.title",
     "The first textbox input value is not the correct one");
-  is(gWatch._cache[0].attachment.expression, "document.title",
+  is(gWatch._cache[0].attachment.currentExpression, "document.title",
     "The first textbox input value is not the correct one");
   is(gWatch._cache[1].target.inputNode.value, "ermahgerd",
     "The second textbox input value is not the correct one");
-  is(gWatch._cache[1].attachment.expression, "ermahgerd",
+  is(gWatch._cache[1].attachment.currentExpression, "ermahgerd",
     "The second textbox input value is not the correct one");
   is(gWatch._cache[2].target.inputNode.value, "this",
     "The third textbox input value is not the correct one");
-  is(gWatch._cache[2].attachment.expression, "this",
+  is(gWatch._cache[2].attachment.currentExpression, "this",
     "The third textbox input value is not the correct one");
 }
 
 function test5(scope) {
   is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 2,
     "There should be 2 hidden nodes in the watch expressions container");
   is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
     "There should be 0 visible nodes in the watch expressions container");
 
   ok(scope, "There should be a wach expressions scope in the variables view");
   is(scope._store.size, 2, "There should be 2 evaluations availalble");
 
   is(gWatch._cache[0].target.inputNode.value, "ermahgerd",
     "The second textbox input value is not the correct one");
-  is(gWatch._cache[0].attachment.expression, "ermahgerd",
+  is(gWatch._cache[0].attachment.currentExpression, "ermahgerd",
     "The second textbox input value is not the correct one");
   is(gWatch._cache[1].target.inputNode.value, "this",
     "The third textbox input value is not the correct one");
-  is(gWatch._cache[1].attachment.expression, "this",
+  is(gWatch._cache[1].attachment.currentExpression, "this",
     "The third textbox input value is not the correct one");
 }
 
 function test6(scope) {
   is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 1,
     "There should be 1 hidden nodes in the watch expressions container");
   is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
     "There should be 0 visible nodes in the watch expressions container");
 
   ok(scope, "There should be a wach expressions scope in the variables view");
   is(scope._store.size, 1, "There should be 1 evaluation availalble");
 
   is(gWatch._cache[0].target.inputNode.value, "ermahgerd",
     "The third textbox input value is not the correct one");
-  is(gWatch._cache[0].attachment.expression, "ermahgerd",
+  is(gWatch._cache[0].attachment.currentExpression, "ermahgerd",
     "The third textbox input value is not the correct one");
 }
 
 function test7(scope) {
   is(gWatch._container._parent.querySelectorAll(".dbg-expression[hidden=true]").length, 0,
     "There should be 0 hidden nodes in the watch expressions container");
   is(gWatch._container._parent.querySelectorAll(".dbg-expression:not([hidden=true])").length, 0,
     "There should be 0 visible nodes in the watch expressions container");
--- a/browser/devtools/debugger/test/browser_dbg_watch-expressions.html
+++ b/browser/devtools/debugger/test/browser_dbg_watch-expressions.html
@@ -1,23 +1,27 @@
 <!DOCTYPE HTML>
 <html>
   <head>
     <meta charset='utf-8'/>
     <title>Browser Debugger Watch Expressions Test</title>
     <!-- Any copyright is dedicated to the Public Domain.
          http://creativecommons.org/publicdomain/zero/1.0/ -->
     <script type="text/javascript">
+      function test() {
+        ermahgerd.call({ canada: new String("eh") });
+      }
       function ermahgerd(aArg) {
         var t = document.title;
         debugger;
         (function() {
           var a = undefined;
           debugger;
           var a = {};
           debugger;
         }("sensational"));
       }
     </script>
+
   </head>
   <body>
   </body>
 </html>
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -28,16 +28,17 @@ browser.jar:
     content/browser/debugger-toolbar.js           (debugger/debugger-toolbar.js)
     content/browser/debugger-panes.js             (debugger/debugger-panes.js)
     content/browser/profiler.xul                  (profiler/profiler.xul)
     content/browser/profiler.css                  (profiler/profiler.css)
     content/browser/devtools/cleopatra.html       (profiler/cleopatra/cleopatra.html)
     content/browser/devtools/profiler/cleopatra/css/ui.css              (profiler/cleopatra/css/ui.css)
     content/browser/devtools/profiler/cleopatra/css/tree.css            (profiler/cleopatra/css/tree.css)
     content/browser/devtools/profiler/cleopatra/css/devtools.css        (profiler/cleopatra/css/devtools.css)
+    content/browser/devtools/profiler/cleopatra/js/strings.js           (profiler/cleopatra/js/strings.js)
     content/browser/devtools/profiler/cleopatra/js/parser.js            (profiler/cleopatra/js/parser.js)
     content/browser/devtools/profiler/cleopatra/js/parserWorker.js      (profiler/cleopatra/js/parserWorker.js)
     content/browser/devtools/profiler/cleopatra/js/tree.js              (profiler/cleopatra/js/tree.js)
     content/browser/devtools/profiler/cleopatra/js/ui.js                (profiler/cleopatra/js/ui.js)
     content/browser/devtools/profiler/cleopatra/js/ProgressReporter.js  (profiler/cleopatra/js/ProgressReporter.js)
     content/browser/devtools/profiler/cleopatra/js/devtools.js          (profiler/cleopatra/js/devtools.js)
     content/browser/devtools/profiler/cleopatra/images/circlearrow.svg  (profiler/cleopatra/images/circlearrow.svg)
     content/browser/devtools/profiler/cleopatra/images/noise.png        (profiler/cleopatra/images/noise.png)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/profiler/ProfilerHelpers.jsm
@@ -0,0 +1,43 @@
+/* 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 Cu = Components.utils;
+const ProfilerProps = "chrome://browser/locale/devtools/profiler.properties";
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+this.EXPORTED_SYMBOLS = ["L10N"];
+
+/**
+ * Localization helper methods.
+ */
+let L10N = {
+  /**
+   * Returns a simple localized string.
+   *
+   * @param string name
+   * @return string
+   */
+  getStr: function L10N_getStr(name) {
+    return this.stringBundle.GetStringFromName(name);
+  },
+
+  /**
+   * Returns formatted localized string.
+   *
+   * @param string name
+   * @param array params
+   * @return string
+   */
+  getFormatStr: function L10N_getFormatStr(name, params) {
+    return this.stringBundle.formatStringFromName(name, params, params.length);
+  }
+};
+
+XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function () {
+  return Services.strings.createBundle(ProfilerProps);
+});
\ No newline at end of file
--- a/browser/devtools/profiler/ProfilerPanel.jsm
+++ b/browser/devtools/profiler/ProfilerPanel.jsm
@@ -2,16 +2,17 @@
  * 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 Cu = Components.utils;
 
 Cu.import("resource:///modules/devtools/ProfilerController.jsm");
+Cu.import("resource:///modules/devtools/ProfilerHelpers.jsm");
 Cu.import("resource://gre/modules/commonjs/promise/core.js");
 Cu.import("resource:///modules/devtools/EventEmitter.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 this.EXPORTED_SYMBOLS = ["ProfilerPanel"];
 
 XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function () {
   Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
@@ -244,22 +245,21 @@ ProfilerPanel.prototype = {
     let uid  = ++this._uid;
     let list = this.document.getElementById("profiles-list");
     let item = this.document.createElement("li");
     let wrap = this.document.createElement("h1");
 
     item.setAttribute("id", "profile-" + uid);
     item.setAttribute("data-uid", uid);
     item.addEventListener("click", function (ev) {
-      let uid = parseInt(ev.target.getAttribute("data-uid"), 10);
       this.switchToProfile(this.profiles.get(uid));
     }.bind(this), false);
 
     wrap.className = "profile-name";
-    wrap.textContent = "Profile " + uid;
+    wrap.textContent = L10N.getFormatStr("profiler.profileName", [uid]);
 
     item.appendChild(wrap);
     list.appendChild(item);
 
     let profile = new ProfileUI(uid, this);
     this.profiles.set(uid, profile);
 
     this.emit("profileCreated", uid);
--- a/browser/devtools/profiler/cleopatra/cleopatra.html
+++ b/browser/devtools/profiler/cleopatra/cleopatra.html
@@ -7,16 +7,17 @@
   <head>
     <title>Firefox Profiler (SPS)</title>
     <meta charset="utf-8">
 
     <link rel="stylesheet" type="text/css" href="profiler/cleopatra/css/ui.css">
     <link rel="stylesheet" type="text/css" href="profiler/cleopatra/css/tree.css">
     <link rel="stylesheet" type="text/css" href="profiler/cleopatra/css/devtools.css">
 
+    <script src="profiler/cleopatra/js/strings.js"></script>
     <script src="profiler/cleopatra/js/parser.js"></script>
     <script src="profiler/cleopatra/js/tree.js"></script>
     <script src="profiler/cleopatra/js/ui.js"></script>
     <script src="profiler/cleopatra/js/ProgressReporter.js"></script>
     <script src="profiler/cleopatra/js/devtools.js"></script>
   </head>
 
   <body onload="notifyParent('loaded');">
--- a/browser/devtools/profiler/cleopatra/js/devtools.js
+++ b/browser/devtools/profiler/cleopatra/js/devtools.js
@@ -80,34 +80,39 @@ function initUI() {
 
   gMainArea = document.createElement("div");
   gMainArea.id = "mainarea";
 
   container.appendChild(gMainArea);
   document.body.appendChild(container);
 
   var startButton = document.createElement("button");
-  startButton.innerHTML = "Start";
+  startButton.innerHTML = gStrings.getStr("profiler.start");
   startButton.addEventListener("click", function (event) {
     event.target.setAttribute("disabled", true);
     notifyParent("start");
   }, false);
 
   var stopButton = document.createElement("button");
-  stopButton.innerHTML = "Stop";
+  stopButton.innerHTML = gStrings.getStr("profiler.stop");
   stopButton.addEventListener("click", function (event) {
     event.target.setAttribute("disabled", true);
     notifyParent("stop");
   }, false);
 
   var controlPane = document.createElement("div");
+  var startProfiling = gStrings.getFormatStr("profiler.startProfiling",
+    ["<span class='btn'></span>"]);
+  var stopProfiling = gStrings.getFormatStr("profiler.stopProfiling",
+    ["<span class='btn'></span>"]);
+
   controlPane.className = "controlPane";
   controlPane.innerHTML =
-    "<p id='startWrapper'>Click <span class='btn'></span> to start profiling.</p>" +
-    "<p id='stopWrapper'>Click <span class='btn'></span> to stop profiling.</p>";
+    "<p id='startWrapper'>" + startProfiling + "</p>" +
+    "<p id='stopWrapper'>" + stopProfiling + "</p>";
 
   controlPane.querySelector("#startWrapper > span.btn").appendChild(startButton);
   controlPane.querySelector("#stopWrapper > span.btn").appendChild(stopButton);
 
   gMainArea.appendChild(controlPane);
 }
 
 /**
@@ -148,19 +153,19 @@ function enterFinishedProfileUI() {
 
   var tree = document.createElement("div");
   tree.className = "treeContainer";
   tree.style.width = "100%";
   tree.style.height = "100%";
 
   gTreeManager = new ProfileTreeManager();
   gTreeManager.treeView.setColumns([
-    { name: "sampleCount", title: "Running time" },
-    { name: "selfSampleCount", title: "Self" },
-    { name: "resource", title: "" },
+    { name: "sampleCount", title: gStrings["Running Time"] },
+    { name: "selfSampleCount", title: gStrings["Self"] },
+    { name: "resource", title: "" }
   ]);
 
   currRow = pane.insertRow(rowIndex++);
   currRow.style.height = "100%";
 
   var cell = currRow.insertCell(0);
   cell.appendChild(tree);
   tree.appendChild(gTreeManager.getContainer());
new file mode 100644
--- /dev/null
+++ b/browser/devtools/profiler/cleopatra/js/strings.js
@@ -0,0 +1,23 @@
+const Cu = Components.utils;
+Cu.import("resource:///modules/devtools/ProfilerHelpers.jsm");
+
+/**
+ * Shortcuts for the L10N helper functions. Used in Cleopatra.
+ */
+var gStrings = {
+  // This strings are here so that Cleopatra code could use a simple object
+  // lookup. This makes it easier to merge upstream changes.
+  "Complete Profile": L10N.getStr("profiler.completeProfile"),
+  "Sample Range": L10N.getStr("profiler.sampleRange"),
+  "Running Time": L10N.getStr("profiler.runningTime"),
+  "Self": L10N.getStr("profiler.self"),
+  "Symbol Name": L10N.getStr("profiler.symbolName"),
+
+  getStr: function (name) {
+    return L10N.getStr(name);
+  },
+
+  getFormatStr: function (name, params) {
+    return L10N.getFormatStr(name, params);
+  }
+};
\ No newline at end of file
--- a/browser/devtools/profiler/cleopatra/js/ui.js
+++ b/browser/devtools/profiler/cleopatra/js/ui.js
@@ -148,20 +148,20 @@ FileList.prototype = {
 
 function treeObjSort(a, b) {
   return b.counter - a.counter;
 }
 
 function ProfileTreeManager() {
   this.treeView = new TreeView();
   this.treeView.setColumns([
-    { name: "sampleCount", title: "Running time" },
-    { name: "selfSampleCount", title: "Self" },
+    { name: "sampleCount", title: gStrings["Running Time"] },
+    { name: "selfSampleCount", title: gStrings["Self"] },
     { name: "resource", title: "" },
-    { name: "symbolName", title: "Symbol Name"}
+    { name: "symbolName", title: gStrings["Symbol Name"] }
   ]);
   var self = this;
   this.treeView.addEventListener("select", function (frameData) {
     self.highlightFrame(frameData);
     if (window.comparator_setSelection) {
       window.comparator_setSelection(gTreeManager.serializeCurrentSelectionSnapshot(), frameData);
     }
   });
@@ -747,17 +747,17 @@ RangeSelector.prototype = {
     if (this._transientRestrictionEnteringAffordance) {
       this._transientRestrictionEnteringAffordance.discard();
     }
   },
   _finishSelection: function RangeSelector__finishSelection(start, end) {
     var newFilterChain = gSampleFilters.concat({ type: "RangeSampleFilter", start: start, end: end });
     var self = this;
     self._transientRestrictionEnteringAffordance = gBreadcrumbTrail.add({
-      title: "Sample Range [" + start + ", " + (end + 1) + "]",
+      title: gStrings["Sample Range"] + " [" + start + ", " + (end + 1) + "]",
       enterCallback: function () {
         gSampleFilters = newFilterChain;
         self.collapseHistogramSelection();
         filtersChanged();
       }
     });
   },
   finishHistogramSelection: function RangeSelector_finishHistgramSelection(isSomethingSelected) {
@@ -1769,17 +1769,17 @@ function enterFinishedProfileUI() {
   //currRow = finishedProfilePane.insertRow(4);
   treeContainerDiv.appendChild(gPluginView.getContainer());
 
   gMainArea.appendChild(finishedProfilePaneBackgroundCover);
   gMainArea.appendChild(finishedProfilePane);
 
   var currentBreadcrumb = gSampleFilters;
   gBreadcrumbTrail.add({
-    title: "Complete Profile",
+    title: gStrings["Complete Profile"],
     enterCallback: function () {
       gSampleFilters = [];
       filtersChanged();
     }
   });
   if (currentBreadcrumb == null || currentBreadcrumb.length == 0) {
     gTreeManager.restoreSerializedSelectionSnapshot(gRestoreSelection);
     viewOptionsChanged();
--- a/browser/devtools/profiler/profiler.xul
+++ b/browser/devtools/profiler/profiler.xul
@@ -5,16 +5,21 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <?xml-stylesheet href="chrome://global/skin/global.css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/splitview.css"?>
 <?xml-stylesheet href="chrome://browser/content/splitview.css"?>
 <?xml-stylesheet href="chrome://browser/content/profiler.css"?>
 
+<!DOCTYPE window [
+<!ENTITY % profilerDTD SYSTEM "chrome://browser/locale/devtools/profiler.dtd">
+  %profilerDTD;
+]>
+
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <box flex="1" id="profiler-chrome" class="splitview-root">
     <box class="splitview-controller" width="180px">
       <box class="splitview-main"></box>
 
       <box class="splitview-nav-container">
         <ol class="splitview-nav" id="profiles-list">
           <!-- Example:
@@ -24,17 +29,17 @@
           -->
         </ol>
 
         <spacer flex="1"/>
 
         <toolbar class="devtools-toolbar" mode="full">
           <toolbarbutton id="profiler-create"
                          class="devtools-toolbarbutton"
-                         label="New"
+                         label="&profilerNew.label;"
                          disabled="true"/>
         </toolbar>
       </box> <!-- splitview-nav-container -->
     </box> <!-- splitview-controller -->
 
     <box flex="1">
       <vbox flex="1" id="profiler-report">
         <!-- Example:
--- a/browser/devtools/shared/VariablesView.jsm
+++ b/browser/devtools/shared/VariablesView.jsm
@@ -1,24 +1,31 @@
 /* -*- 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 Ci = Components.interfaces;
+const Cu = Components.utils;
+
 const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
 const LAZY_EMPTY_DELAY = 150; // ms
 const LAZY_EXPAND_DELAY = 50; // ms
 const LAZY_APPEND_DELAY = 100; // ms
 const LAZY_APPEND_BATCH = 100; // nodes
+const PAGE_SIZE_SCROLL_HEIGHT_RATIO = 100;
+const PAGE_SIZE_MAX_JUMPS = 30;
 const SEARCH_ACTION_MAX_DELAY = 1000; // ms
+const ELEMENT_INPUT_DEFAULT_WIDTH = 100; // px
+const ELEMENT_INPUT_EXTRA_SPACE = 4; // px
 
-Components.utils.import("resource://gre/modules/Services.jsm");
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this,
   "WebConsoleUtils", "resource://gre/modules/devtools/WebConsoleUtils.jsm");
 
 this.EXPORTED_SYMBOLS = ["VariablesView", "create"];
 
 /**
  * Debugger localization strings.
@@ -35,27 +42,31 @@ const STR = Services.strings.createBundl
  * provide a "switch" function. To handle deleting variables or properties,
  * provide a "delete" function.
  *
  * @param nsIDOMNode aParentNode
  *        The parent node to hold this view.
  */
 this.VariablesView = function VariablesView(aParentNode) {
   this._store = new Map();
+  this._itemsByElement = new WeakMap();
   this._prevHierarchy = new Map();
   this._currHierarchy = new Map();
 
   this._parent = aParentNode;
   this._appendEmptyNotice();
 
   this._onSearchboxInput = this._onSearchboxInput.bind(this);
   this._onSearchboxKeyPress = this._onSearchboxKeyPress.bind(this);
+  this._onViewKeyPress = this._onViewKeyPress.bind(this);
 
   // Create an internal list container.
-  this._list = this.document.createElement("vbox");
+  this._list = this.document.createElement("scrollbox");
+  this._list.setAttribute("orient", "vertical");
+  this._list.addEventListener("keypress", this._onViewKeyPress, false);
   this._parent.appendChild(this._list);
 };
 
 VariablesView.prototype = {
   /**
    * Helper setter for populating this container with a raw object.
    *
    * @param object aData
@@ -77,16 +88,17 @@ VariablesView.prototype = {
    */
   addScope: function VV_addScope(aName = "") {
     this._removeEmptyNotice();
     this._toggleSearchVisibility(true);
 
     let scope = new Scope(this, aName);
     this._store.set(scope.id, scope);
     this._currHierarchy.set(aName, scope);
+    this._itemsByElement.set(scope._target, scope);
     scope.header = !!aName;
     return scope;
   },
 
   /**
    * Removes all items from this container.
    *
    * @param number aTimeout [optional]
@@ -107,16 +119,18 @@ VariablesView.prototype = {
     let list = this._list;
     let firstChild;
 
     while (firstChild = list.firstChild) {
       list.removeChild(firstChild);
     }
 
     this._store = new Map();
+    this._itemsByElement = new WeakMap();
+
     this._appendEmptyNotice();
     this._toggleSearchVisibility(false);
   },
 
   /**
    * Emptying this container and rebuilding it immediately afterwards would
    * result in a brief redraw flicker, because the previously expanded nodes
    * may get asynchronously re-expanded, after fetching the prototype and
@@ -128,22 +142,28 @@ VariablesView.prototype = {
    * data fetching delay. In the meantime, any operations can be executed
    * normally.
    *
    * @see VariablesView.empty
    * @see VariablesView.commitHierarchy
    */
   _emptySoon: function VV__emptySoon(aTimeout) {
     let prevList = this._list;
-    let currList = this._list = this.document.createElement("vbox");
+    let currList = this._list = this.document.createElement("scrollbox");
+
     this._store = new Map();
+    this._itemsByElement = new WeakMap();
 
     this._emptyTimeout = this.window.setTimeout(function() {
       this._emptyTimeout = null;
 
+      prevList.removeEventListener("keypress", this._onViewKeyPress, false);
+      currList.addEventListener("keypress", this._onViewKeyPress, false);
+      currList.setAttribute("orient", "vertical");
+
       this._parent.removeChild(prevList);
       this._parent.appendChild(currList);
 
       if (!this._store.size) {
         this._appendEmptyNotice();
         this._toggleSearchVisibility(false);
       }
     }.bind(this), aTimeout);
@@ -202,16 +222,26 @@ VariablesView.prototype = {
    * function is provided, in order to change the variable or property's name.
    *
    * This flag is applied recursively onto each scope in this view and
    * affects only the child nodes when they're created.
    */
   editableNameTooltip: STR.GetStringFromName("variablesEditableNameTooltip"),
 
   /**
+   * The tooltip text shown on a variable or property's edit button if an
+   * |eval| function is provided and a getter/setter descriptor is present,
+   * in order to change the variable or property to a plain value.
+   *
+   * This flag is applied recursively onto each scope in this view and
+   * affects only the child nodes when they're created.
+   */
+  editButtonTooltip: STR.GetStringFromName("variablesEditButtonTooltip"),
+
+  /**
    * The tooltip text shown on a variable or property's delete button if a
    * |delete| function is provided, in order to delete the variable or property.
    *
    * This flag is applied recursively onto each scope in this view and
    * affects only the child nodes when they're created.
    */
   deleteButtonTooltip: STR.GetStringFromName("variablesCloseButtonTooltip"),
 
@@ -463,62 +493,338 @@ VariablesView.prototype = {
     }
   },
 
   /**
    * Expands the first search results in this container.
    */
   expandFirstSearchResults: function VV_expandFirstSearchResults() {
     for (let [, scope] of this._store) {
-      for (let [, variable] of scope._store) {
-        if (variable._isMatch) {
-          variable.expand();
-          break;
-        }
+      let match = scope._firstMatch;
+      if (match) {
+        match.expand();
+      }
+    }
+  },
+
+  /**
+   * Focuses the first visible variable or property in this container.
+   */
+  focusFirstVisibleNode: function VV_focusFirstVisibleNode() {
+    let property, variable, scope;
+
+    for (let [, item] of this._currHierarchy) {
+      if (!item.focusable) {
+        continue;
+      }
+      if (item instanceof Property) {
+        property = item;
+        break;
+      } else if (item instanceof Variable) {
+        variable = item;
+        break;
+      } else if (item instanceof Scope) {
+        scope = item;
+        break;
       }
     }
+    if (scope) {
+      this._focusItem(scope);
+    } else if (variable) {
+      this._focusItem(variable);
+    } else if (property) {
+      this._focusItem(property);
+    }
+    this._parent.scrollTop = 0;
+    this._parent.scrollLeft = 0;
+  },
+
+  /**
+   * Focuses the last visible variable or property in this container.
+   */
+  focusLastVisibleNode: function VV_focusLastVisibleNode() {
+    let property, variable, scope;
+
+    for (let [, item] of this._currHierarchy) {
+      if (!item.focusable) {
+        continue;
+      }
+      if (item instanceof Property) {
+        property = item;
+      } else if (item instanceof Variable) {
+        variable = item;
+      } else if (item instanceof Scope) {
+        scope = item;
+      }
+    }
+    if (property && (!variable || property.isDescendantOf(variable))) {
+      this._focusItem(property);
+    } else if (variable && (!scope || variable.isDescendantOf(scope))) {
+      this._focusItem(variable);
+    } else if (scope) {
+      this._focusItem(scope);
+      this._parent.scrollTop = this._parent.scrollHeight;
+      this._parent.scrollLeft = 0;
+    }
   },
 
   /**
    * Searches for the scope in this container displayed by the specified node.
    *
    * @param nsIDOMNode aNode
    *        The node to search for.
    * @return Scope
    *         The matched scope, or null if nothing is found.
    */
   getScopeForNode: function VV_getScopeForNode(aNode) {
-    for (let [, scope] of this._store) {
-      if (scope._target == aNode) {
-        return scope;
-      }
+    let item = this._itemsByElement.get(aNode);
+    if (item && !(item instanceof Variable) && !(item instanceof Property)) {
+      return item;
     }
     return null;
   },
 
   /**
-   * Recursively searches all the scopes for the variable or property
+   * Recursively searches this container for the scope, variable or property
    * displayed by the specified node.
    *
    * @param nsIDOMNode aNode
    *        The node to search for.
-   * @return Variable | Property
-   *         The matched variable or property, or null if nothing is found.
+   * @return Scope | Variable | Property
+   *         The matched scope, variable or property, or null if nothing is found.
+   */
+  getItemForNode: function VV_getItemForNode(aNode) {
+    return this._itemsByElement.get(aNode);
+  },
+
+  /**
+   * Gets the currently focused scope, variable or property in this view.
+   *
+   * @return Scope | Variable | Property
+   *         The focused scope, variable or property, or null if nothing is found.
+   */
+  getFocusedItem: function VV_getFocusedItem() {
+    let focused = this.document.commandDispatcher.focusedElement;
+    return this.getItemForNode(focused);
+  },
+
+  /**
+   * Focuses the next scope, variable or property in this view.
+   * @see VariablesView.prototype._focusChange
+   */
+  focusNextItem: function VV_focusNextItem(aMaintainViewFocusedFlag)
+    this._focusChange("advanceFocus", aMaintainViewFocusedFlag),
+
+  /**
+   * Focuses the previous scope, variable or property in this view.
+   * @see VariablesView.prototype._focusChange
+   */
+  focusPrevItem: function VV_focusPrevItem(aMaintainViewFocusedFlag)
+    this._focusChange("rewindFocus", aMaintainViewFocusedFlag),
+
+  /**
+   * Focuses the next or previous scope, variable or property in this view.
+   *
+   * @param string aDirection
+   *        Either "advanceFocus" or "rewindFocus".
+   * @param boolean aMaintainViewFocusedFlag
+   *        True too keep this view focused if the element is out of bounds.
+   * @return boolean
+   *         True if the focus went out of bounds and the first or last element
+   *         in this view was focused instead.
+   */
+  _focusChange: function VV__changeFocus(aDirection, aMaintainViewFocusedFlag) {
+    let commandDispatcher = this.document.commandDispatcher;
+    let item;
+
+    do {
+      commandDispatcher[aDirection]();
+
+      // If maintaining this view focused is not mandatory, a simple
+      // "advanceFocus" or "rewindFocus" command dispatch is sufficient.
+      if (!aMaintainViewFocusedFlag) {
+        return false;
+      }
+
+      // Make sure the newly focused target is a part of this view.
+      item = this.getFocusedItem();
+      if (!item) {
+        if (aDirection == "advanceFocus") {
+          this.focusLastVisibleNode();
+        } else {
+          this.focusFirstVisibleNode();
+        }
+        // Focus went out of bounds so the first or last element in this view
+        // was focused instead.
+        return true;
+      }
+    } while (!item.focusable);
+
+    // Focus remained within bounds.
+    return false;
+  },
+
+  /**
+   * Focuses a scope, variable or property and makes sure it's visible.
+   *
+   * @param aItem Scope | Variable | Property
+   *        The item to focus.
+   * @param boolean aCollapseFlag
+   *        True if the focused item should also be collapsed.
+   * @return boolean
+   *         True if the item was successfully focused.
+   */
+  _focusItem: function VV__focusItem(aItem, aCollapseFlag) {
+    if (!aItem.focusable) {
+      return false;
+    }
+    if (aCollapseFlag) {
+      aItem.collapse();
+    }
+    aItem._target.focus();
+
+    let boxObject = this._list.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
+    boxObject.ensureElementIsVisible(aItem._title);
+    boxObject.scrollBy(-this._list.clientWidth, 0);
+    return true;
+  },
+
+  /**
+   * Listener handling a key press event on the view.
    */
-  getVariableOrPropertyForNode: function VV_getVariableOrPropertyForNode(aNode) {
-    for (let [, scope] of this._store) {
-      let match = scope.find(aNode);
-      if (match) {
-        return match;
-      }
+  _onViewKeyPress: function VV__onViewKeyPress(e) {
+    let item = this.getFocusedItem();
+
+    switch (e.keyCode) {
+      case e.DOM_VK_UP:
+      case e.DOM_VK_DOWN:
+      case e.DOM_VK_LEFT:
+      case e.DOM_VK_RIGHT:
+      case e.DOM_VK_PAGE_UP:
+      case e.DOM_VK_PAGE_DOWN:
+      case e.DOM_VK_HOME:
+      case e.DOM_VK_END:
+        // Prevent scrolling when pressing navigation keys.
+        e.preventDefault();
+        e.stopPropagation();
     }
-    return null;
+
+    switch (e.keyCode) {
+      case e.DOM_VK_UP:
+        // Always rewind focus.
+        this.focusPrevItem(true);
+        return;
+
+      case e.DOM_VK_DOWN:
+        // Only expand scopes before advancing focus.
+        if (!(item instanceof Variable) &&
+            !(item instanceof Property) &&
+            !item._isExpanded && item._isArrowVisible) {
+          item.expand();
+        } else {
+          this.focusNextItem(true);
+        }
+        return;
+
+      case e.DOM_VK_LEFT:
+        // If this is a collapsed or un-expandable item that has an expandable
+        // variable or property parent, collapse and focus the owner view.
+        if (!item._isExpanded || !item._isArrowVisible) {
+          let ownerView = item.ownerView;
+          if ((ownerView instanceof Variable ||
+               ownerView instanceof Property) &&
+               ownerView._isExpanded && ownerView._isArrowVisible) {
+            if (this._focusItem(ownerView, true)) {
+              return;
+            }
+          }
+        }
+        // Collapse scopes, variables and properties before rewinding focus.
+        if (item._isExpanded && item._isArrowVisible) {
+          item.collapse();
+        } else {
+          this.focusPrevItem(true);
+        }
+        return;
+
+      case e.DOM_VK_RIGHT:
+        // Expand scopes, variables and properties before advancing focus.
+        if (!item._isExpanded && item._isArrowVisible) {
+          item.expand();
+        } else {
+          this.focusNextItem(true);
+        }
+        return;
+
+      case e.DOM_VK_PAGE_UP:
+        // Rewind a certain number of elements based on the container height.
+        var jumps = this.pageSize || Math.min(Math.floor(this._list.scrollHeight /
+          PAGE_SIZE_SCROLL_HEIGHT_RATIO),
+          PAGE_SIZE_MAX_JUMPS);
+
+        while (jumps--) {
+          if (this.focusPrevItem(true)) {
+            return;
+          }
+        }
+        return;
+
+      case e.DOM_VK_PAGE_DOWN:
+        // Advance a certain number of elements based on the container height.
+        var jumps = this.pageSize || Math.min(Math.floor(this._list.scrollHeight /
+          PAGE_SIZE_SCROLL_HEIGHT_RATIO),
+          PAGE_SIZE_MAX_JUMPS);
+
+        while (jumps--) {
+          if (this.focusNextItem(true)) {
+            return;
+          }
+        }
+        return;
+
+      case e.DOM_VK_HOME:
+        this.focusFirstVisibleNode();
+        return;
+
+      case e.DOM_VK_END:
+        this.focusLastVisibleNode();
+        return;
+
+      case e.DOM_VK_RETURN:
+      case e.DOM_VK_ENTER:
+        // Start editing the value or name of the variable or property.
+        if (item instanceof Variable ||
+            item instanceof Property) {
+          if (e.metaKey || e.altKey || e.shiftKey) {
+            item._activateNameInput();
+          } else {
+            item._activateValueInput();
+          }
+        }
+        return;
+
+      case e.DOM_VK_DELETE:
+      case e.DOM_VK_BACK_SPACE:
+        // Delete the variable or property if allowed.
+        if (item instanceof Variable ||
+            item instanceof Property) {
+          item._onDelete(e);
+        }
+        return;
+    }
   },
 
   /**
+   * The number of elements in this container to jump when Page Up or Page Down
+   * keys are pressed. If falsy, then the page size will be based on the
+   * container height.
+   */
+  pageSize: 0,
+
+  /**
    * Sets the text displayed in this container when there are no available items.
    * @param string aValue
    */
   set emptyText(aValue) {
     if (this._emptyTextNode) {
       this._emptyTextNode.setAttribute("value", aValue);
     }
     this._emptyTextValue = aValue;
@@ -586,43 +892,170 @@ VariablesView.prototype = {
   _searchboxNode: null,
   _searchboxContainer: null,
   _searchboxPlaceholder: "",
   _emptyTextNode: null,
   _emptyTextValue: ""
 };
 
 /**
+ * Generates the string evaluated when performing simple value changes.
+ *
+ * @param Variable | Property aItem
+ *        The current variable or property.
+ * @param string aCurrentString
+ *        The trimmed user inputted string.
+ * @return string
+ *         The string to be evaluated.
+ */
+VariablesView.simpleValueEvalMacro = function(aItem, aCurrentString) {
+  return aItem._symbolicName + "=" + aCurrentString;
+};
+
+/**
+ * Generates the string evaluated when overriding getters and setters with
+ * plain values.
+ *
+ * @param Property aItem
+ *        The current getter or setter property.
+ * @param string aCurrentString
+ *        The trimmed user inputted string.
+ * @return string
+ *         The string to be evaluated.
+ */
+VariablesView.overrideValueEvalMacro = function(aItem, aCurrentString) {
+  let property = "\"" + aItem._nameString + "\"";
+  let parent = aItem.ownerView._symbolicName || "this";
+
+  return "Object.defineProperty(" + parent + "," + property + "," +
+    "{ value: " + aCurrentString +
+    ", enumerable: " + parent + ".propertyIsEnumerable(" + property + ")" +
+    ", configurable: true" +
+    ", writable: true" +
+    "})";
+};
+
+/**
+ * Generates the string evaluated when performing getters and setters changes.
+ *
+ * @param Property aItem
+ *        The current getter or setter property.
+ * @param string aCurrentString
+ *        The trimmed user inputted string.
+ * @return string
+ *         The string to be evaluated.
+ */
+VariablesView.getterOrSetterEvalMacro = function(aItem, aCurrentString) {
+  let type = aItem._nameString;
+  let propertyObject = aItem.ownerView;
+  let parentObject = propertyObject.ownerView;
+  let property = "\"" + propertyObject._nameString + "\"";
+  let parent = parentObject._symbolicName || "this";
+
+  switch (aCurrentString) {
+    case "":
+    case "null":
+    case "undefined":
+      let mirrorType = type == "get" ? "set" : "get";
+      let mirrorLookup = type == "get" ? "__lookupSetter__" : "__lookupGetter__";
+
+      // If the parent object will end up without any getter or setter,
+      // morph it into a plain value.
+      if ((type == "set" && propertyObject.getter.type == "undefined") ||
+          (type == "get" && propertyObject.setter.type == "undefined")) {
+        return VariablesView.overrideValueEvalMacro(propertyObject, "undefined");
+      }
+
+      // Construct and return the getter/setter removal evaluation string.
+      // e.g: Object.defineProperty(foo, "bar", {
+      //   get: foo.__lookupGetter__("bar"),
+      //   set: undefined,
+      //   enumerable: true,
+      //   configurable: true
+      // })
+      return "Object.defineProperty(" + parent + "," + property + "," +
+        "{" + mirrorType + ":" + parent + "." + mirrorLookup + "(" + property + ")" +
+        "," + type + ":" + undefined +
+        ", enumerable: " + parent + ".propertyIsEnumerable(" + property + ")" +
+        ", configurable: true" +
+        "})";
+
+    default:
+      // Wrap statements inside a function declaration if not already wrapped.
+      if (aCurrentString.indexOf("function") != 0) {
+        let header = "function(" + (type == "set" ? "value" : "") + ")";
+        let body = "";
+        // If there's a return statement explicitly written, always use the
+        // standard function definition syntax
+        if (aCurrentString.indexOf("return ") != -1) {
+          body = "{" + aCurrentString + "}";
+        }
+        // If block syntax is used, use the whole string as the function body.
+        else if (aCurrentString.indexOf("{") == 0) {
+          body = aCurrentString;
+        }
+        // Prefer an expression closure.
+        else {
+          body = "(" + aCurrentString + ")";
+        }
+        aCurrentString = header + body;
+      }
+
+      // Determine if a new getter or setter should be defined.
+      let defineType = type == "get" ? "__defineGetter__" : "__defineSetter__";
+
+      // Make sure all quotes are escaped in the expression's syntax,
+      let defineFunc = "eval(\"(" + aCurrentString.replace(/"/g, "\\$&") + ")\")";
+
+      // Construct and return the getter/setter evaluation string.
+      // e.g: foo.__defineGetter__("bar", eval("(function() { return 42; })"))
+      return parent + "." + defineType + "(" + property + "," + defineFunc + ")";
+  }
+};
+
+/**
+ * Function invoked when a getter or setter is deleted.
+ *
+ * @param Property aItem
+ *        The current getter or setter property.
+ */
+VariablesView.getterOrSetterDeleteCallback = function(aItem) {
+  aItem._disable();
+  aItem.ownerView.eval(VariablesView.getterOrSetterEvalMacro(aItem, ""));
+  return true; // Don't hide the element.
+};
+
+/**
  * A Scope is an object holding Variable instances.
  * Iterable via "for (let [name, variable] in instance) { }".
  *
  * @param VariablesView aView
  *        The view to contain this scope.
  * @param string aName
  *        The scope's name.
  * @param object aFlags [optional]
  *        Additional options or flags for this scope.
  */
 function Scope(aView, aName, aFlags = {}) {
   this.ownerView = aView;
 
-  this.expand = this.expand.bind(this);
-  this.toggle = this.toggle.bind(this);
+  this._onClick = this._onClick.bind(this);
   this._openEnum = this._openEnum.bind(this);
   this._openNonEnum = this._openNonEnum.bind(this);
   this._batchAppend = this._batchAppend.bind(this);
   this._batchItems = [];
 
   // Inherit properties and flags from the parent view. You can override
   // each of these directly onto any scope, variable or property instance.
   this.eval = aView.eval;
   this.switch = aView.switch;
   this.delete = aView.delete;
   this.editableValueTooltip = aView.editableValueTooltip;
   this.editableNameTooltip = aView.editableNameTooltip;
+  this.editButtonTooltip = aView.editButtonTooltip;
   this.deleteButtonTooltip = aView.deleteButtonTooltip;
   this.descriptorTooltip = aView.descriptorTooltip;
   this.contextMenuId = aView.contextMenuId;
   this.separatorStr = aView.separatorStr;
 
   this._store = new Map();
   this._init(aName.trim(), aFlags);
 }
@@ -651,16 +1084,17 @@ Scope.prototype = {
   addVar: function S_addVar(aName = "", aDescriptor = {}) {
     if (this._store.has(aName)) {
       return null;
     }
 
     let variable = new Variable(this, aName, aDescriptor);
     this._store.set(aName, variable);
     this._variablesView._currHierarchy.set(variable._absoluteName, variable);
+    this._variablesView._itemsByElement.set(variable._target, variable);
     variable.header = !!aName;
     return variable;
   },
 
   /**
    * Gets the variable in this container having the specified name.
    *
    * @param string aName
@@ -692,33 +1126,66 @@ Scope.prototype = {
       if (match) {
         return match;
       }
     }
     return null;
   },
 
   /**
+   * Determines if this scope is a direct child of a parent variables view,
+   * scope, variable or property.
+   *
+   * @param VariablesView | Scope | Variable | Property
+   *        The parent to check.
+   * @return boolean
+   *         True if the specified item is a direct child, false otherwise.
+   */
+  isChildOf: function S_isChildOf(aParent) {
+    return this.ownerView == aParent;
+  },
+
+  /**
+   * Determines if this scope is a descendant of a parent variables view,
+   * scope, variable or property.
+   *
+   * @param VariablesView | Scope | Variable | Property
+   *        The parent to check.
+   * @return boolean
+   *         True if the specified item is a descendant, false otherwise.
+   */
+  isDescendantOf: function S_isDescendantOf(aParent) {
+    if (this.isChildOf(aParent)) {
+      return true;
+    }
+    if (this.ownerView instanceof Scope ||
+        this.ownerView instanceof Variable ||
+        this.ownerView instanceof Property) {
+      return this.ownerView.isDescendantOf(aParent);
+    }
+  },
+
+  /**
    * Shows the scope.
    */
   show: function S_show() {
     this._target.hidden = false;
-    this._isShown = true;
+    this._isContentVisible = true;
 
     if (this.onshow) {
       this.onshow(this);
     }
   },
 
   /**
    * Hides the scope.
    */
   hide: function S_hide() {
     this._target.hidden = true;
-    this._isShown = false;
+    this._isContentVisible = false;
 
     if (this.onhide) {
       this.onhide(this);
     }
   },
 
   /**
    * Expands the scope, showing all the added details.
@@ -733,17 +1200,17 @@ Scope.prototype = {
     // to suggest that this scope is expanding.
     if (!this._isExpanding &&
          this._variablesView.lazyAppend && this._store.size > LAZY_APPEND_BATCH) {
       this._isExpanding = true;
 
       // Start spinning a throbber in this scope's title and allow a few
       // milliseconds for it to be painted.
       this._startThrobber();
-      this.window.setTimeout(this.expand, LAZY_EXPAND_DELAY);
+      this.window.setTimeout(this.expand.bind(this), LAZY_EXPAND_DELAY);
       return;
     }
 
     if (this._variablesView._enumVisible) {
       this._openEnum();
     }
     if (this._variablesView._nonEnumVisible) {
       Services.tm.currentThread.dispatch({ run: this._openNonEnum }, 0);
@@ -782,17 +1249,17 @@ Scope.prototype = {
       return;
     }
     this._wasToggled = true;
     this.expanded ^= 1;
 
     // Make sure the scope and its contents are visibile.
     for (let [, variable] of this._store) {
       variable.header = true;
-      variable._match = true;
+      variable._matched = true;
     }
     if (this.ontoggle) {
       this.ontoggle(this);
     }
   },
 
   /**
    * Shows the scope's title header.
@@ -839,17 +1306,17 @@ Scope.prototype = {
     this._arrow.setAttribute("invisible", "");
     this._isArrowVisible = false;
   },
 
   /**
    * Gets the visibility state.
    * @return boolean
    */
-  get visible() this._isShown,
+  get visible() this._isContentVisible,
 
   /**
    * Gets the expanded state.
    * @return boolean
    */
   get expanded() this._isExpanded,
 
   /**
@@ -860,16 +1327,22 @@ Scope.prototype = {
 
   /**
    * Gets the twisty visibility state.
    * @return boolean
    */
   get twisty() this._isArrowVisible,
 
   /**
+   * Gets the expand lock state.
+   * @return boolean
+   */
+  get locked() this._locked,
+
+  /**
    * Sets the visibility state.
    * @param boolean aFlag
    */
   set visible(aFlag) aFlag ? this.show() : this.hide(),
 
   /**
    * Sets the expanded state.
    * @param boolean aFlag
@@ -884,28 +1357,47 @@ Scope.prototype = {
 
   /**
    * Sets the twisty visibility state.
    * @param boolean aFlag
    */
   set twisty(aFlag) aFlag ? this.showArrow() : this.hideArrow(),
 
   /**
-   * Gets the expand lock state.
-   * @return boolean
-   */
-  get locked() this._locked,
-
-  /**
    * Sets the expand lock state.
    * @param boolean aFlag
    */
   set locked(aFlag) this._locked = aFlag,
 
   /**
+   * Specifies if this target node may be focused.
+   * @return boolean
+   */
+  get focusable() {
+    // Check if this target node is actually visibile.
+    if (!this._nameString ||
+        !this._isContentVisible ||
+        !this._isHeaderVisible ||
+        !this._isMatch) {
+      return false;
+    }
+    // Check if all parent objects are expanded.
+    let item = this;
+    while ((item = item.ownerView) &&  /* Parent object exists. */
+           (item instanceof Scope ||
+            item instanceof Variable ||
+            item instanceof Property)) {
+      if (!item._isExpanded) {
+        return false;
+      }
+    }
+    return true;
+  },
+
+  /**
    * Adds an event listener for a certain event on this scope's title.
    * @param string aName
    * @param function aCallback
    * @param boolean aCapture
    */
   addEventListener: function S_addEventListener(aName, aCallback, aCapture) {
     this._title.addEventListener(aName, aCallback, aCapture);
   },
@@ -993,17 +1485,28 @@ Scope.prototype = {
     element.appendChild(enumerable);
     element.appendChild(nonenum);
   },
 
   /**
    * Adds the necessary event listeners for this scope.
    */
   _addEventListeners: function S__addEventListeners() {
-    this._title.addEventListener("mousedown", this.toggle, false);
+    this._title.addEventListener("mousedown", this._onClick, false);
+  },
+
+  /**
+   * The click listener for this scope's title.
+   */
+  _onClick: function S__onClick(e) {
+    if (e.target == this._inputNode) {
+      return;
+    }
+    this.toggle();
+    this._variablesView._focusItem(this);
   },
 
   /**
    * Lazily appends a node to this scope's enumerable or non-enumerable
    * container. Once a certain number of nodes have been batched, they
    * will be appended.
    *
    * @param boolean aImmediateFlag
@@ -1152,21 +1655,21 @@ Scope.prototype = {
     for (let [, variable] of this._store) {
       let currentObject = variable;
       let lowerCaseName = variable._nameString.toLowerCase();
       let lowerCaseValue = variable._valueString.toLowerCase();
 
       // Non-matched variables or properties require a corresponding attribute.
       if (!lowerCaseName.contains(aLowerCaseQuery) &&
           !lowerCaseValue.contains(aLowerCaseQuery)) {
-        variable._match = false;
+        variable._matched = false;
       }
       // Variable or property is matched.
       else {
-        variable._match = true;
+        variable._matched = true;
 
         // If the variable was ever expanded, there's a possibility it may
         // contain some matched properties, so make sure they're visible
         // ("expand downwards").
 
         if (variable._wasToggled && aLowerCaseQuery) {
           variable.expand();
         }
@@ -1179,48 +1682,67 @@ Scope.prototype = {
         // ("expand upwards").
 
         while ((variable = variable.ownerView) &&  /* Parent object exists. */
                (variable instanceof Scope ||
                 variable instanceof Variable ||
                 variable instanceof Property)) {
 
           // Show and expand the parent, as it is certainly accessible.
-          variable._match = true;
+          variable._matched = true;
           aLowerCaseQuery && variable.expand();
         }
       }
 
       // Proceed with the search recursively inside this variable or property.
       if (currentObject._wasToggled ||
           currentObject.getter ||
           currentObject.setter) {
         currentObject._performSearch(aLowerCaseQuery);
       }
     }
   },
 
   /**
-   * Sets if this object instance is a match or non-match.
+   * Sets if this object instance is a matched or non-matched item.
    * @param boolean aStatus
    */
-  set _match(aStatus) {
+  set _matched(aStatus) {
     if (this._isMatch == aStatus) {
       return;
     }
     if (aStatus) {
       this._isMatch = true;
       this.target.removeAttribute("non-match");
     } else {
       this._isMatch = false;
       this.target.setAttribute("non-match", "");
     }
   },
 
   /**
+   * Gets the first search results match in this scope.
+   * @return Variable | Property
+   */
+  get _firstMatch() {
+    for (let [, variable] of this._store) {
+      let match;
+      if (variable._isMatch) {
+        match = variable;
+      } else {
+        match = variable._firstMatch;
+      }
+      if (match) {
+        return match;
+      }
+    }
+    return null;
+  },
+
+  /**
    * Gets top level variables view instance.
    * @return VariablesView
    */
   get _variablesView() this._topView || (this._topView = (function(self) {
     let parentView = self.ownerView;
     let topView;
 
     while (topView = parentView.ownerView) {
@@ -1252,32 +1774,33 @@ Scope.prototype = {
   _window: null,
 
   ownerView: null,
   eval: null,
   switch: null,
   delete: null,
   editableValueTooltip: "",
   editableNameTooltip: "",
+  editButtonTooltip: "",
   deleteButtonTooltip: "",
   descriptorTooltip: true,
   contextMenuId: "",
   separatorStr: "",
 
   _store: null,
   _fetched: false,
   _retrieved: false,
   _committed: false,
   _batchItems: null,
   _batchTimeout: null,
   _locked: false,
-  _isShown: true,
   _isExpanding: false,
   _isExpanded: false,
   _wasToggled: false,
+  _isContentVisible: true,
   _isHeaderVisible: true,
   _isArrowVisible: true,
   _isMatch: true,
   _idString: "",
   _nameString: "",
   _target: null,
   _arrow: null,
   _name: null,
@@ -1297,20 +1820,16 @@ Scope.prototype = {
  *        The variable's name.
  * @param object aDescriptor
  *        The variable's descriptor.
  */
 function Variable(aScope, aName, aDescriptor) {
   this._displayTooltip = this._displayTooltip.bind(this);
   this._activateNameInput = this._activateNameInput.bind(this);
   this._activateValueInput = this._activateValueInput.bind(this);
-  this._deactivateNameInput = this._deactivateNameInput.bind(this);
-  this._deactivateValueInput = this._deactivateValueInput.bind(this);
-  this._onNameInputKeyPress = this._onNameInputKeyPress.bind(this);
-  this._onValueInputKeyPress = this._onValueInputKeyPress.bind(this);
 
   Scope.call(this, aScope, aName, this._initialDescriptor = aDescriptor);
   this.setGrip(aDescriptor.value);
   this._symbolicName = aName;
   this._absoluteName = aScope.name + "[\"" + aName + "\"]";
 }
 
 create({ constructor: Variable, proto: Scope.prototype }, {
@@ -1337,16 +1856,17 @@ create({ constructor: Variable, proto: S
   addProperty: function V_addProperty(aName = "", aDescriptor = {}) {
     if (this._store.has(aName)) {
       return null;
     }
 
     let property = new Property(this, aName, aDescriptor);
     this._store.set(aName, property);
     this._variablesView._currHierarchy.set(property._absoluteName, property);
+    this._variablesView._itemsByElement.set(property._target, property);
     property.header = !!aName;
     return property;
   },
 
   /**
    * Adds properties for this variable.
    *
    * @param object aProperties
@@ -1360,27 +1880,33 @@ create({ constructor: Variable, proto: S
    *                 someProp3: { value: { type: "undefined" } },
    *                 someProp4: { value: { type: "null" } },
    *                 someProp5: { value: { type: "object", class: "Object" } },
    *                 someProp6: { get: { type: "object", class: "Function" },
    *                              set: { type: "undefined" } }
    * @param object aOptions [optional]
    *        Additional options for adding the properties. Supported options:
    *        - sorted: true to sort all the properties before adding them
+   *        - callback: function invoked after each property is added
    */
   addProperties: function V_addProperties(aProperties, aOptions = {}) {
     let propertyNames = Object.keys(aProperties);
 
     // Sort all of the properties before adding them, if preferred.
     if (aOptions.sorted) {
       propertyNames.sort();
     }
     // Add the properties to the current scope.
     for (let name of propertyNames) {
-      this.addProperty(name, aProperties[name]);
+      let descriptor = aProperties[name];
+      let property = this.addProperty(name, descriptor);
+
+      if (aOptions.callback) {
+        aOptions.callback(property, descriptor.value);
+      }
     }
   },
 
   /**
    * Populates this variable to contain all the properties of an object.
    *
    * @param object aObject
    *        The raw object you want to display.
@@ -1413,36 +1939,51 @@ create({ constructor: Variable, proto: S
     }
     // Add the variable's __proto__.
     if (prototype) {
       this._addRawValueProperty("__proto__", {}, prototype);
     }
   },
 
   /**
+   * Populates a specific variable or property instance to contain all the
+   * properties of an object
+   *
+   * @param Variable | Property aVar
+   *        The target variable to populate.
+   * @param object aObject [optional]
+   *        The raw object you want to display. If unspecified, the object is
+   *        assumed to be defined in a _sourceValue property on the target.
+   */
+  _populateTarget: function V__populateTarget(aVar, aObject = aVar._sourceValue) {
+    aVar.populate(aObject);
+  },
+
+  /**
    * Adds a property for this variable based on a raw value descriptor.
    *
    * @param string aName
    *        The property's name.
    * @param object aDescriptor
    *        Specifies the exact property descriptor as returned by a call to
    *        Object.getOwnPropertyDescriptor.
    * @param object aValue
    *        The raw property value you want to display.
    */
   _addRawValueProperty: function V__addRawValueProperty(aName, aDescriptor, aValue) {
     let descriptor = Object.create(aDescriptor);
     descriptor.value = VariablesView.getGrip(aValue);
 
     let propertyItem = this.addProperty(aName, descriptor);
+    propertyItem._sourceValue = aValue;
 
     // Add an 'onexpand' callback for the property, lazily handling
     // the addition of new child properties.
     if (!VariablesView.isPrimitive(descriptor)) {
-      propertyItem.onexpand = this.populate.bind(propertyItem, aValue);
+      propertyItem.onexpand = this._populateTarget;
     }
   },
 
   /**
    * Adds a property for this variable based on a getter/setter descriptor.
    *
    * @param string aName
    *        The property's name.
@@ -1450,18 +1991,17 @@ create({ constructor: Variable, proto: S
    *        Specifies the exact property descriptor as returned by a call to
    *        Object.getOwnPropertyDescriptor.
    */
   _addRawNonValueProperty: function V__addRawNonValueProperty(aName, aDescriptor) {
     let descriptor = Object.create(aDescriptor);
     descriptor.get = VariablesView.getGrip(aDescriptor.get);
     descriptor.set = VariablesView.getGrip(aDescriptor.set);
 
-    let propertyItem = this.addProperty(aName, descriptor);
-    return propertyItem;
+    this.addProperty(aName, descriptor);
   },
 
   /**
    * Gets this variable's path to the topmost scope.
    * For example, a symbolic name may look like "arguments['0']['foo']['bar']".
    * @return string
    */
   get symbolicName() this._symbolicName,
@@ -1501,16 +2041,21 @@ create({ constructor: Variable, proto: S
    *             - { type: "null" }
    *             - { type: "object", class: "Object" }
    */
   setGrip: function V_setGrip(aGrip) {
     // Don't allow displaying grip information if there's no name available.
     if (!this._nameString) {
       return;
     }
+    // Getters and setters should display grip information in sub-properties.
+    if (!this._isUndefined && (this.getter || this.setter)) {
+      this._valueLabel.setAttribute("value", "");
+      return;
+    }
 
     if (aGrip === undefined) {
       aGrip = { type: "undefined" };
     }
     if (aGrip === null) {
       aGrip = { type: "null" };
     }
 
@@ -1531,17 +2076,17 @@ create({ constructor: Variable, proto: S
    *
    * @param string aName
    *        The variable's name.
    * @param object aDescriptor
    *        The variable's descriptor.
    */
   _init: function V__init(aName, aDescriptor) {
     this._idString = generateId(this._nameString = aName);
-    this._displayScope(aName, "variable");
+    this._displayScope(aName, "variable variable-or-property");
 
     // Don't allow displaying variable information there's no name available.
     if (this._nameString) {
       this._displayVariable();
       this._customizeVariable();
       this._prepareTooltip();
       this._setAttributes();
       this._addEventListeners();
@@ -1580,42 +2125,59 @@ create({ constructor: Variable, proto: S
 
     let valueLabel = this._valueLabel = document.createElement("label");
     valueLabel.className = "plain value";
     valueLabel.setAttribute("crop", "center");
 
     this._title.appendChild(separatorLabel);
     this._title.appendChild(valueLabel);
 
-    let isPrimitive = VariablesView.isPrimitive(descriptor);
-    let isUndefined = VariablesView.isUndefined(descriptor);
+    let isPrimitive = this._isPrimitive = VariablesView.isPrimitive(descriptor);
+    let isUndefined = this._isUndefined = VariablesView.isUndefined(descriptor);
 
     if (isPrimitive || isUndefined) {
       this.hideArrow();
     }
     if (!isUndefined && (descriptor.get || descriptor.set)) {
-      // FIXME: editing getters and setters is not allowed yet. Bug 831794.
-      this.eval = null;
-      this.addProperty("get", { value: descriptor.get });
-      this.addProperty("set", { value: descriptor.set });
-      this.expand();
       separatorLabel.hidden = true;
       valueLabel.hidden = true;
+
+      this.delete = VariablesView.getterOrSetterDeleteCallback;
+      this.evaluationMacro = VariablesView.overrideValueEvalMacro;
+
+      let getter = this.addProperty("get", { value: descriptor.get });
+      let setter = this.addProperty("set", { value: descriptor.set });
+      getter.evaluationMacro = VariablesView.getterOrSetterEvalMacro;
+      setter.evaluationMacro = VariablesView.getterOrSetterEvalMacro;
+
+      getter.hideArrow();
+      setter.hideArrow();
+      this.expand();
     }
   },
 
   /**
    * Adds specific nodes for this variable based on custom flags.
    */
   _customizeVariable: function V__customizeVariable() {
+    if (this.ownerView.eval) {
+      if (!this._isUndefined && (this.getter || this.setter)) {
+        let editNode = this._editNode = this.document.createElement("toolbarbutton");
+        editNode.className = "plain dbg-variable-edit";
+        editNode.addEventListener("mousedown", this._onEdit.bind(this), false);
+        this._title.appendChild(editNode);
+      }
+    }
     if (this.ownerView.delete) {
-      let deleteNode = this._deleteNode = this.document.createElement("toolbarbutton");
-      deleteNode.className = "plain dbg-variable-delete devtools-closebutton";
-      deleteNode.addEventListener("click", this._onDelete.bind(this), false);
-      this._title.appendChild(deleteNode);
+      if (!this._isUndefined || !(this.ownerView.getter && this.ownerView.setter)) {
+        let deleteNode = this._deleteNode = this.document.createElement("toolbarbutton");
+        deleteNode.className = "plain dbg-variable-delete devtools-closebutton";
+        deleteNode.addEventListener("click", this._onDelete.bind(this), false);
+        this._title.appendChild(deleteNode);
+      }
     }
     if (this.ownerView.contextMenuId) {
       this._title.setAttribute("context", this.ownerView.contextMenuId);
     }
   },
 
   /**
    * Prepares a tooltip for this variable.
@@ -1646,16 +2208,19 @@ create({ constructor: Variable, proto: S
       tooltip.setAttribute("orient", "horizontal");
       tooltip.appendChild(configurableLabel);
       tooltip.appendChild(enumerableLabel);
       tooltip.appendChild(writableLabel);
 
       this._target.appendChild(tooltip);
       this._target.setAttribute("tooltip", tooltip.id);
     }
+    if (this.ownerView.eval && !this._isUndefined && (this.getter || this.setter)) {
+      this._editNode.setAttribute("tooltiptext", this.ownerView.editButtonTooltip);
+    }
     if (this.ownerView.eval) {
       this._valueLabel.setAttribute("tooltiptext", this.ownerView.editableValueTooltip);
     }
     if (this.ownerView.switch) {
       this._name.setAttribute("tooltiptext", this.ownerView.editableNameTooltip);
     }
     if (this.ownerView.delete) {
       this._deleteNode.setAttribute("tooltiptext", this.ownerView.deleteButtonTooltip);
@@ -1665,23 +2230,26 @@ create({ constructor: Variable, proto: S
   /**
    * Sets a variable's configurable, enumerable and writable attributes,
    * and specifies if it's a 'this', '<exception>' or '__proto__' reference.
    */
   _setAttributes: function V__setAttributes() {
     let descriptor = this._initialDescriptor;
     let name = this._nameString;
 
+    if (this.ownerView.eval) {
+      this._target.setAttribute("editable", "");
+    }
     if (!descriptor.configurable) {
       this._target.setAttribute("non-configurable", "");
     }
     if (!descriptor.enumerable) {
       this._target.setAttribute("non-enumerable", "");
     }
-    if (!descriptor.writable) {
+    if (!descriptor.writable && !this.ownerView.get && !this.ownerView.set) {
       this._target.setAttribute("non-writable", "");
     }
     if (name == "this") {
       this._target.setAttribute("self", "");
     }
     else if (name == "<exception>") {
       this._target.setAttribute("exception", "");
     }
@@ -1689,20 +2257,19 @@ create({ constructor: Variable, proto: S
       this._target.setAttribute("proto", "");
     }
   },
 
   /**
    * Adds the necessary event listeners for this variable.
    */
   _addEventListeners: function V__addEventListeners() {
-    this._arrow.addEventListener("mousedown", this.toggle, false);
-    this._name.addEventListener("mousedown", this.toggle, false);
     this._name.addEventListener("dblclick", this._activateNameInput, false);
-    this._valueLabel.addEventListener("click", this._activateValueInput, false);
+    this._valueLabel.addEventListener("mousedown", this._activateValueInput, false);
+    this._title.addEventListener("mousedown", this._onClick, false);
   },
 
   /**
    * Creates a textbox node in place of a label.
    *
    * @param nsIDOMNode aLabel
    *        The label to be replaced with a textbox.
    * @param string aClassName
@@ -1713,18 +2280,24 @@ create({ constructor: Variable, proto: S
   _activateInput: function V__activateInput(aLabel, aClassName, aCallbacks) {
     let initialString = aLabel.getAttribute("value");
 
     // Create a texbox input element which will be shown in the current
     // element's specified label location.
     let input = this.document.createElement("textbox");
     input.setAttribute("value", initialString);
     input.className = "plain " + aClassName;
-    input.width = this._target.clientWidth;
 
+    // Can't use clientWidth because labels may have extra unnecessary padding.
+    let style = this.window.getComputedStyle(aLabel);
+    input.width = (parseInt(style.getPropertyValue("width")) ||
+      ELEMENT_INPUT_DEFAULT_WIDTH) + // If no content was previously available.
+      ELEMENT_INPUT_EXTRA_SPACE; // Extra space added for editing.
+
+    // Replace the specified label with a textbox input element.
     aLabel.parentNode.replaceChild(input, aLabel);
     input.select();
 
     // When the value is a string (displayed as "value"), then we probably want
     // to change it to another string in the textbox, so to avoid typing the ""
     // again, tackle with the selection bounds just a bit.
     if (aLabel.getAttribute("value").match(/^"[^"]*"$/)) {
       input.selectionEnd--;
@@ -1735,16 +2308,17 @@ create({ constructor: Variable, proto: S
     input.addEventListener("blur", aCallbacks.onBlur, false);
 
     this._prevExpandable = this.twisty;
     this._prevExpanded = this.expanded;
     this.collapse();
     this.hideArrow();
     this._locked = true;
 
+    this._inputNode = input;
     this._stopThrobber();
   },
 
   /**
    * Removes the textbox node in place of a label.
    *
    * @param nsIDOMNode aLabel
    *        The label which was replaced with a textbox.
@@ -1755,30 +2329,39 @@ create({ constructor: Variable, proto: S
     aInput.parentNode.replaceChild(aLabel, aInput);
     aInput.removeEventListener("keypress", aCallbacks.onKeypress, false);
     aInput.removeEventListener("blur", aCallbacks.onBlur, false);
 
     this._locked = false;
     this.twisty = this._prevExpandable;
     this.expanded = this._prevExpanded;
 
+    this._inputNode = null;
     this._stopThrobber();
   },
 
   /**
    * Makes this variable's name editable.
    */
   _activateNameInput: function V__activateNameInput(e) {
     if (e && e.button != 0) {
       // Only allow left-click to trigger this event.
       return;
     }
     if (!this.ownerView.switch) {
       return;
     }
+    if (e) {
+      e.preventDefault();
+      e.stopPropagation();
+    }
+
+    this._onNameInputKeyPress = this._onNameInputKeyPress.bind(this);
+    this._deactivateNameInput = this._deactivateNameInput.bind(this);
+
     this._activateInput(this._name, "element-name-input", {
       onKeypress: this._onNameInputKeyPress,
       onBlur: this._deactivateNameInput
     });
     this._separatorLabel.hidden = true;
     this._valueLabel.hidden = true;
   },
 
@@ -1800,16 +2383,24 @@ create({ constructor: Variable, proto: S
   _activateValueInput: function V__activateValueInput(e) {
     if (e && e.button != 0) {
       // Only allow left-click to trigger this event.
       return;
     }
     if (!this.ownerView.eval) {
       return;
     }
+    if (e) {
+      e.preventDefault();
+      e.stopPropagation();
+    }
+
+    this._onValueInputKeyPress = this._onValueInputKeyPress.bind(this);
+    this._deactivateValueInput = this._deactivateValueInput.bind(this);
+
     this._activateInput(this._valueLabel, "element-value-input", {
       onKeypress: this._onValueInputKeyPress,
       onBlur: this._deactivateValueInput
     });
   },
 
   /**
    * Deactivates this variable's editable value mode.
@@ -1820,21 +2411,28 @@ create({ constructor: Variable, proto: S
       onBlur: this._deactivateValueInput
     });
   },
 
   /**
    * Disables this variable prior to a new name switch or value evaluation.
    */
   _disable: function V__disable() {
-    this.twisty = false;
+    this.hideArrow();
     this._separatorLabel.hidden = true;
     this._valueLabel.hidden = true;
     this._enum.hidden = true;
     this._nonenum.hidden = true;
+
+    if (this._editNode) {
+      this._editNode.hidden = true;
+    }
+    if (this._deleteNode) {
+      this._deleteNode.hidden = true;
+    }
   },
 
   /**
    * Deactivates this variable's editable mode and callbacks the new name.
    */
   _saveNameInput: function V__saveNameInput(e) {
     let input = e.target;
     let initialString = this._name.getAttribute("value");
@@ -1854,66 +2452,96 @@ create({ constructor: Variable, proto: S
   _saveValueInput: function V__saveValueInput(e) {
     let input = e.target;
     let initialString = this._valueLabel.getAttribute("value");
     let currentString = input.value.trim();
     this._deactivateValueInput(e);
 
     if (initialString != currentString) {
       this._disable();
-      this.ownerView.eval(this._symbolicName + "=" + currentString);
+      this.ownerView.eval(this.evaluationMacro(this, currentString.trim()));
     }
   },
 
   /**
+   * The current macro used to generate the string evaluated when performing
+   * a variable or property value change.
+   */
+  evaluationMacro: VariablesView.simpleValueEvalMacro,
+
+  /**
    * The key press listener for this variable's editable name textbox.
    */
   _onNameInputKeyPress: function V__onNameInputKeyPress(e) {
+    e.stopPropagation();
+
     switch(e.keyCode) {
       case e.DOM_VK_RETURN:
       case e.DOM_VK_ENTER:
         this._saveNameInput(e);
+        this._variablesView._focusItem(this);
         return;
       case e.DOM_VK_ESCAPE:
         this._deactivateNameInput(e);
+        this._variablesView._focusItem(this);
         return;
     }
   },
 
   /**
    * The key press listener for this variable's editable value textbox.
    */
   _onValueInputKeyPress: function V__onValueInputKeyPress(e) {
+    e.stopPropagation();
+
     switch(e.keyCode) {
       case e.DOM_VK_RETURN:
       case e.DOM_VK_ENTER:
         this._saveValueInput(e);
+        this._variablesView._focusItem(this);
         return;
       case e.DOM_VK_ESCAPE:
         this._deactivateValueInput(e);
+        this._variablesView._focusItem(this);
         return;
     }
   },
 
   /**
+   * The click listener for the edit button.
+   */
+  _onEdit: function V__onEdit(e) {
+    e.preventDefault();
+    e.stopPropagation();
+    this._activateValueInput();
+  },
+
+  /**
    * The click listener for the delete button.
    */
-  _onDelete: function V__onDelete() {
-    this.hide();
+  _onDelete: function V__onDelete(e) {
+    e.preventDefault();
+    e.stopPropagation();
 
     if (this.ownerView.delete) {
-      this.ownerView.delete(this);
+      if (!this.ownerView.delete(this)) {
+        this.hide();
+      }
     }
   },
 
   _symbolicName: "",
   _absoluteName: "",
   _initialDescriptor: null,
+  _isPrimitive: false,
+  _isUndefined: false,
   _separatorLabel: null,
   _valueLabel: null,
+  _inputNode: null,
+  _editNode: null,
   _deleteNode: null,
   _tooltip: null,
   _valueGrip: null,
   _valueString: "",
   _valueClassName: "",
   _prevExpandable: false,
   _prevExpanded: false
 });
@@ -1941,17 +2569,17 @@ create({ constructor: Property, proto: V
    *
    * @param string aName
    *        The property's name.
    * @param object aDescriptor
    *        The property's descriptor.
    */
   _init: function P__init(aName, aDescriptor) {
     this._idString = generateId(this._nameString = aName);
-    this._displayScope(aName, "property");
+    this._displayScope(aName, "property variable-or-property");
 
     // Don't allow displaying property information there's no name available.
     if (this._nameString) {
       this._displayVariable();
       this._customizeVariable();
       this._prepareTooltip();
       this._setAttributes();
       this._addEventListeners();
--- a/browser/devtools/styleeditor/test/Makefile.in
+++ b/browser/devtools/styleeditor/test/Makefile.in
@@ -19,17 +19,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_styleeditor_import.js \
                  browser_styleeditor_init.js \
                  $(filter disabled-temporarily--bug-817294, browser_styleeditor_loading.js) \
                  browser_styleeditor_new.js \
                  browser_styleeditor_passedinsheet.js \
                  browser_styleeditor_pretty.js \
                  browser_styleeditor_private_perwindowpb.js \
                  browser_styleeditor_readonly.js \
-                 $(filter disabled-for-intermittent-failures--bug-707891, browser_styleeditor_reopen.js) \
+                 browser_styleeditor_reopen.js \
                  browser_styleeditor_sv_keynav.js \
                  browser_styleeditor_sv_resize.js \
                  head.js \
                  helpers.js \
                  four.html \
                  head.js \
                  helpers.js \
                  media.html \
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -884,16 +884,17 @@ xpicleanup@BIN_SUFFIX@
   components/addonManager.js
   components/amContentHandler.js
   components/amWebInstallListener.js
   components/binary.manifest
   components/browser.xpt
   components/BrowserElementParent.js
   components/BrowserElementParent.manifest
   components/BrowserElementPromptService.jsm
+  components/BrowserElementParent.jsm
   components/contentAreaDropListener.js
   components/contentSecurityPolicy.js
   components/crypto-SDR.js
   components/FeedConverter.js
   components/FeedProcessor.js
   components/FeedWriter.js
   components/fuelApplication.js
   components/GPSDGeolocationProvider.js
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
@@ -89,16 +89,21 @@
 <!ENTITY debuggerUI.searchLine          "Jump to line…">
 <!ENTITY debuggerUI.searchLine.key      "J">
 
 <!-- LOCALIZATION NOTE (debuggerUI.searchVariable): This is the text that appears
   -  in the source editor's context menu for the variables search operation. -->
 <!ENTITY debuggerUI.searchVariable      "Filter variables">
 <!ENTITY debuggerUI.searchVariable.key  "V">
 
+<!-- LOCALIZATION NOTE (debuggerUI.focusVariables): This is the text that appears
+  -  in the source editor's context menu for the variables focus operation. -->
+<!ENTITY debuggerUI.focusVariables      "Focus variables tree">
+<!ENTITY debuggerUI.focusVariables.key  "V">
+
 <!-- LOCALIZATION NOTE (debuggerUI.condBreakPanelTitle): This is the text that
   -  appears in the conditional breakpoint panel popup as a description. -->
 <!ENTITY debuggerUI.condBreakPanelTitle "This breakpoint will stop execution only if the following expression is true">
 
 <!-- LOCALIZATION NOTE (debuggerUI.seMenuBreak): This is the text that
   -  appears in the source editor context menu for adding a breakpoint. -->
 <!ENTITY debuggerUI.seMenuBreak         "Add breakpoint">
 <!ENTITY debuggerUI.seMenuBreak.key     "B">
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.properties
@@ -191,22 +191,26 @@ ToolboxDebugger.label=Debugger
 # displayed inside the developer tools window..
 ToolboxDebugger.tooltip=JavaScript Debugger
 
 # LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed
 # in the variables list on an item with an editable name.
 variablesEditableNameTooltip=Double click to edit
 
 # LOCALIZATION NOTE (variablesEditableValueTooltip): The text that is displayed
-# in the variables list on an item with an editable name.
+# in the variables list on an item with an editable value.
 variablesEditableValueTooltip=Click to change value
 
 # LOCALIZATION NOTE (variablesCloseButtonTooltip): The text that is displayed
-# in the variables list on an item with which can be removed.
+# in the variables list on an item which can be removed.
 variablesCloseButtonTooltip=Click to remove
 
+# LOCALIZATION NOTE (variablesEditButtonTooltip): The text that is displayed
+# in the variables list on a getter or setter which can be edited.
+variablesEditButtonTooltip=Click to set value
+
 # LOCALIZATION NOTE (variablesSeparatorLabel): The text that is displayed
 # in the variables list as a separator between the name and value.
 variablesSeparatorLabel=:
 
 # LOCALIZATION NOTE (watchExpressionsSeparatorLabel): The text that is displayed
 # in the watch expressions list as a separator between the code and evaluation.
 watchExpressionsSeparatorLabel=\ →
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/devtools/profiler.dtd
@@ -0,0 +1,15 @@
+<!-- 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/. -->
+
+<!-- LOCALIZATION NOTE : FILE This file contains the Profiler strings -->
+
+<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
+  - keep it in English, or another language commonly spoken among web developers.
+  - You want to make that choice consistent across the developer tools.
+  - A good criteria is the language in which you'd find the best
+  - documentation on web development on the web. -->
+
+<!-- LOCALIZATION NOTE (profilerNew.label): This is the label for the
+  -  button that creates a new profile. -->
+<!ENTITY profilerNew.label "New">
--- a/browser/locales/en-US/chrome/browser/devtools/profiler.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/profiler.properties
@@ -14,8 +14,53 @@
 # This string is displayed in the title of the tab when the profiler is
 # displayed inside the developer tools window and in the Developer Tools Menu.
 profiler.label=Profiler
 
 # LOCALIZATION NOTE (profiler.tooltip):
 # This string is displayed in the tooltip of the tab when the profiler is
 # displayed inside the developer tools window.
 profiler.tooltip=Profiler
+
+# LOCALIZATION NOTE (profiler.profileName):
+# This string is the default name for new profiles. Its parameter is a number.
+# For example: "Profile 1", "Profile 2", etc.
+profiler.profileName=Profile %S
+
+# LOCALIZATION NOTE (profiler.completeProfile):
+# This string is displayed as a tab in the profiler UI. Clicking on it
+# displays everything that the profiler has generated so far.
+profiler.completeProfile=Complete Profile
+
+# LOCALIZATION NOTE (profiler.sampleRange):
+# This string is displayed as a tab in the profiler UI. Clicking on it
+# displays a sample range of data selected by user themselves.
+profiler.sampleRange=Sample Range
+
+# LOCALIZATION NOTE (profiler.runningTime):
+# This string is displayed as a table header in the profiler UI.
+profiler.runningTime=Running Time
+
+# LOCALIZATION NOTE (profiler.self):
+# This string is displayed as a table header in the profiler UI.
+profiler.self=Self
+
+# LOCALIZATION NOTE (profiler.symbolName)
+# This string is displayed as a table header in the profiler UI.
+profiler.symbolName=Symbol Name
+
+# LOCALIZATION NOTE (profiler.startProfiling)
+# This string is displayed around the button that starts the profiler.
+# String argument will be replaced with a Start button.
+profiler.startProfiling=Click here %S to start profiling
+
+# LOCALIZATION NOTE (profiler.stopProfiling)
+# This string is displayed around the button that stops the profiler.
+# String argument will be replaced with a Stop button.
+profiler.stopProfiling = Click here %S to stop profiling
+
+# LOCALIZATION NOTE (profiler.start)
+# This string is displayed on the button that starts the profiler.
+profiler.start=Start
+
+# LOCALIZATION NOTE (profiler.stop)
+# This string is displayed on the button that stops the profiler.
+profiler.stop=Stop
\ No newline at end of file
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -33,16 +33,17 @@
     locale/browser/devtools/scratchpad.dtd            (%chrome/browser/devtools/scratchpad.dtd)
     locale/browser/devtools/styleeditor.properties    (%chrome/browser/devtools/styleeditor.properties)
     locale/browser/devtools/styleeditor.dtd           (%chrome/browser/devtools/styleeditor.dtd)
     locale/browser/devtools/styleinspector.properties (%chrome/browser/devtools/styleinspector.properties)
     locale/browser/devtools/styleinspector.dtd        (%chrome/browser/devtools/styleinspector.dtd)
     locale/browser/devtools/webConsole.dtd            (%chrome/browser/devtools/webConsole.dtd)
     locale/browser/devtools/sourceeditor.properties   (%chrome/browser/devtools/sourceeditor.properties)
     locale/browser/devtools/sourceeditor.dtd          (%chrome/browser/devtools/sourceeditor.dtd)
+    locale/browser/devtools/profiler.dtd              (%chrome/browser/devtools/profiler.dtd)
     locale/browser/devtools/profiler.properties       (%chrome/browser/devtools/profiler.properties)
     locale/browser/devtools/layoutview.dtd            (%chrome/browser/devtools/layoutview.dtd)
     locale/browser/devtools/responsiveUI.properties   (%chrome/browser/devtools/responsiveUI.properties)
     locale/browser/devtools/toolbox.dtd            (%chrome/browser/devtools/toolbox.dtd)
     locale/browser/devtools/toolbox.properties     (%chrome/browser/devtools/toolbox.properties)
     locale/browser/devtools/inspector.dtd          (%chrome/browser/devtools/inspector.dtd)
     locale/browser/devtools/connection-screen.dtd  (%chrome/browser/devtools/connection-screen.dtd)
     locale/browser/devtools/connection-screen.properties (%chrome/browser/devtools/connection-screen.properties)
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -115,17 +115,16 @@ this.Social = {
       currentProvider = this._getProviderFromOrigin(this._currentProviderPref);
     } else {
       // Migrate data from previous single-provider builds where we used
       // social.active to indicate that the first available provider should be
       // used.
       try {
         let active = Services.prefs.getBoolPref("social.active");
         if (active) {
-          Services.prefs.clearUserPref("social.active");
           currentProvider = providers[0];
           currentProvider.active = true;
         }
       } catch(ex) {}
     }
     this._setProvider(currentProvider, notifyProviderChange);
   },
 
--- a/browser/themes/gnomestripe/devtools/debugger.css
+++ b/browser/themes/gnomestripe/devtools/debugger.css
@@ -170,43 +170,40 @@
   color: #888;
 }
 
 /**
  * Stack frames and breakpoints pane
  */
 
 #stackframes\+breakpoints {
-  background-color: white;
   min-width: 50px;
 }
 
 #stackframes\+breakpoints[animated] {
   transition: margin 0.25s ease-in-out;
 }
 
 /**
  * Variables and watch expressions pane
  */
 
 #variables\+expressions {
-  background-color: white;
   min-width: 50px;
 }
 
 #variables\+expressions[animated] {
   transition: margin 0.25s ease-in-out;
 }
 
 /**
  * Stack frames view
  */
 
 #stackframes {
-  background-color: white;
   min-height: 10px;
 }
 
 .dbg-stackframe {
   -moz-padding-start: 4px;
   -moz-padding-end: 4px;
 }
 
@@ -218,17 +215,16 @@
   -moz-padding-start: 4px;
 }
 
 /**
  * Breakpoints view
  */
 
 #breakpoints {
-  background-color: white;
   min-height: 10px;
 }
 
 #breakpoints > vbox:not(:empty) {
   min-height: 10px;
   max-height: 200px;
 }
 
@@ -252,18 +248,18 @@
   margin: 0 0 -2px 0;
 }
 
 /**
  * Watch expressions view
  */
 
 #expressions {
-  background-color: white;
   min-height: 10px;
+  max-height: 125px;
 }
 
 .dbg-expression {
   height: 20px;
   -moz-padding-start: 8px;
 }
 
 .dbg-expression-arrow {
@@ -271,117 +267,168 @@
   height: auto;
   background: url("chrome://browser/skin/devtools/commandline.png") 0px 4px no-repeat;
 }
 
 .dbg-expression-input {
   font: 9pt monospace;
 }
 
-.dbg-expression-delete:not(:hover) {
+.dbg-expression-delete {
+  opacity: 0;
+}
+
+.dbg-expression-delete:hover {
+  opacity: 1;
+}
+
+.dbg-expression:hover > .dbg-expression-delete:not(:hover) {
   opacity: 0.5;
+  transition: opacity 0.2s ease-in-out;
 }
 
 /**
  * Variables view
  */
 
 #variables {
-  background-color: white;
   min-height: 10px;
 }
 
-.dbg-variable-delete:not(:hover) {
+.dbg-variable-delete {
+  opacity: 0;
+}
+
+.dbg-variable-delete:hover {
+  opacity: 1;
+}
+
+.variable-or-property:hover > .title > .dbg-variable-delete:not(:hover),
+.variable-or-property:focus > .title > .dbg-variable-delete:not(:hover) {
   opacity: 0.5;
+  transition: opacity 0.2s ease-in-out;
+}
+
+.dbg-variable-edit {
+  background: url("chrome://browser/skin/tabview/edit-light.png") center no-repeat;
+  width: 20px;
+  height: 16px;
+  cursor: pointer;
 }
 
 .dbg-variable-throbber {
-  background: url("chrome://global/skin/icons/loading_16.png");
+  background: url("chrome://global/skin/icons/loading_16.png") center no-repeat;
   width: 16px;
   height: 16px;
 }
 
 /**
  * Scope element
  */
 
+.scope:focus > .title {
+  background: Highlight;
+  color: HighlightText;
+}
+
 .scope > .title {
   text-shadow: 0 1px #222;
   color: #fff;
 }
 
 .scope > .details {
   -moz-margin-start: 2px;
-  -moz-margin-end: 2px;
+  -moz-margin-end: 1px;
 }
 
 .scope > .details.nonenum:not(:empty) {
   border-top: 1px solid #ddd;
 }
 
 /**
  * Variable element
  */
 
 .variable {
   -moz-margin-start: 1px;
   -moz-margin-end: 1px;
   border-bottom: 1px solid #eee;
-  background: #fff;
   transition: background 1s ease-in-out;
 }
 
 .variable[changed] {
   background: rgba(255, 255, 0, 0.65);
   transition-duration: 0.4s;
 }
 
+.variable:focus > .title {
+  background: Highlight;
+  color: HighlightText;
+  border-radius: 4px;
+}
+
 .variable > .title > .name {
+  font-weight: 600;
+}
+
+.variable:not(:focus) > .title > .name {
   color: #048;
-  font-weight: 600;
 }
 
 .variable > .title > .value {
   -moz-padding-start: 6px;
   -moz-padding-end: 4px;
 }
 
+.variable[editable] > .title > .value {
+  cursor: text;
+}
+
 .variable:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
  * Property element
  */
 
 .property {
-  background: #fff;
   transition: background 1s ease-in-out;
 }
 
 .property[changed] {
   background: rgba(255, 255, 0, 0.65);
   transition-duration: 0.4s;
 }
 
-.property > .title > .name {
+.property:focus > .title {
+  background: Highlight;
+  color: HighlightText;
+  border-radius: 4px;
+}
+
+.property:not(:focus) > .title > .name {
   color: #881090;
 }
 
 .property > .title > .value {
   -moz-padding-start: 6px;
   -moz-padding-end: 4px;
 }
 
+.property[editable] > .title > .value {
+  cursor: text;
+}
+
 .property:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
- * Non enumerable, configurable and writable variables and properties.
+ * Non enumerable, configurable and writable variables and properties
  */
 
 .variable[proto] > .title > .name,
 .property[proto] > .title > .name,
 .variable[non-enumerable]:not([self]):not([exception]) > .title > .name,
 .property[non-enumerable]:not([self]):not([exception]) > .title > .name {
   opacity: 0.5;
 }
@@ -409,18 +456,18 @@
 @media (min-resolution: 2dppx) {
   .variable[non-writable] > .title:after,
   .property[non-writable] > .title:after {
     background-image: url("chrome://browser/skin/identity-icons-https@2x.png");
     background-size: 32px;
   }
 }
 
-.variable[exception] > .title > .name,
-.property[exception] > .title > .name {
+.variable[exception]:not(:focus) > .title > .name,
+.property[exception]:not(:focus) > .title > .name {
   color: #a00;
   text-shadow: 0 0 8px #fcc;
 }
 
 .variable > tooltip > label,
 .property > tooltip > label {
   margin: 0 2px 0 2px;
 }
@@ -433,28 +480,33 @@
 .property[non-writable] > tooltip > label[value="writable"] {
   text-decoration: line-through;
 }
 
 /**
  * Variables and properties editing
  */
 
-#variables .element-value-input {
-  overflow: hidden;
-  max-width: 30em;
-  -moz-margin-start: 5px !important;
+.element-value-input {
+  -moz-margin-start: 4px !important;
 }
 
-#variables .element-name-input {
-  -moz-margin-start: -1px !important;
+.element-name-input {
+  -moz-margin-start: -2px !important;
   color: #048;
   font-weight: 600;
 }
 
+.element-value-input,
+.element-name-input {
+  max-width: 30em;
+  border: 1px solid #999 !important;
+  box-shadow: 1px 2px 4px #aaa;
+}
+
 /**
  * Variables and properties searching
  */
 
 .variables-searchinput.devtools-searchinput {
   min-height: 24px;
 }
 
@@ -463,38 +515,38 @@
   border: none;
   margin: 0;
 }
 
 /**
  * Token value colors
  */
 
-.token-undefined {
+.variable-or-property:not(:focus) > .title > .token-undefined {
   color: #bbb;
 }
 
-.token-null {
+.variable-or-property:not(:focus) > .title > .token-null {
   color: #999;
 }
 
-.token-boolean {
+.variable-or-property:not(:focus) > .title > .token-boolean {
   color: #777;
 }
 
-.token-number {
+.variable-or-property:not(:focus) > .title > .token-number {
   color: #c40a16;
 }
 
-.token-string {
+.variable-or-property:not(:focus) > .title > .token-string {
   max-width: 30em;
   color: #1c00cf;
 }
 
-.token-other {
+.variable-or-property:not(:focus) > .title > .token-other {
   color: #333;
 }
 
 /**
  * Expand/collapse arrow
  */
 
 .arrow {
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -1040,17 +1040,17 @@ toolbar[mode="icons"] #forward-button:-m
 }
 
 @media (min-resolution: 2dppx) {
   #zoom-out-button {
     -moz-image-region: rect(0, 800px, 40px, 760px);
   }
 
   #zoom-in-button {
-    -moz-image-region: rect(0, 480px, 40px, 440px);
+    -moz-image-region: rect(0, 840px, 40px, 800px);
   }
 }
 
 toolbar[mode="icons"] #zoom-out-button {
   -moz-margin-end: 0;
 }
 
 toolbar[mode="icons"] #zoom-in-button {
--- a/browser/themes/pinstripe/devtools/debugger.css
+++ b/browser/themes/pinstripe/devtools/debugger.css
@@ -172,43 +172,40 @@
   color: #888;
 }
 
 /**
  * Stack frames and breakpoints pane
  */
 
 #stackframes\+breakpoints {
-  background-color: white;
   min-width: 50px;
 }
 
 #stackframes\+breakpoints[animated] {
   transition: margin 0.25s ease-in-out;
 }
 
 /**
  * Variables and watch expressions pane
  */
 
 #variables\+expressions {
-  background-color: white;
   min-width: 50px;
 }
 
 #variables\+expressions[animated] {
   transition: margin 0.25s ease-in-out;
 }
 
 /**
  * Stack frames view
  */
 
 #stackframes {
-  background-color: white;
   min-height: 10px;
 }
 
 .dbg-stackframe {
   -moz-padding-start: 4px;
   -moz-padding-end: 4px;
 }
 
@@ -220,17 +217,16 @@
   -moz-padding-start: 4px;
 }
 
 /**
  * Breakpoints view
  */
 
 #breakpoints {
-  background-color: white;
   min-height: 10px;
 }
 
 #breakpoints > vbox:not(:empty) {
   min-height: 10px;
   max-height: 200px;
 }
 
@@ -254,18 +250,18 @@
   margin: 0 0 -2px 0;
 }
 
 /**
  * Watch expressions view
  */
 
 #expressions {
-  background-color: white;
   min-height: 10px;
+  max-height: 125px;
 }
 
 .dbg-expression {
   height: 20px;
   -moz-padding-start: 8px;
 }
 
 .dbg-expression-arrow {
@@ -274,121 +270,175 @@
   background: url("chrome://browser/skin/devtools/commandline.png") 0px 4px no-repeat;
 }
 
 .dbg-expression-input {
   font: 9pt monospace;
 }
 
 .dbg-expression-delete {
+  opacity: 0;
+}
+
+.dbg-expression-delete:not(:hover) {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
-.dbg-expression-delete:not(:hover) {
+.dbg-expression-delete:hover {
+  opacity: 1;
+}
+
+.dbg-expression:hover > .dbg-expression-delete:not(:hover) {
   opacity: 0.5;
+  transition: opacity 0.2s ease-in-out;
 }
 
 /**
  * Variables view
  */
 
 #variables {
-  background-color: white;
   min-height: 10px;
 }
 
+.dbg-variable-delete {
+  opacity: 0;
+}
+
 .dbg-variable-delete:not(:hover) {
   -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+.dbg-variable-delete:hover {
+  opacity: 1;
+}
+
+.variable-or-property:hover > .title > .dbg-variable-delete:not(:hover),
+.variable-or-property:focus > .title > .dbg-variable-delete:not(:hover) {
   opacity: 0.5;
+  transition: opacity 0.2s ease-in-out;
+}
+
+.dbg-variable-edit {
+  background: url("chrome://browser/skin/tabview/edit-light.png") center no-repeat;
+  width: 20px;
+  height: 16px;
+  cursor: pointer;
 }
 
 .dbg-variable-throbber {
-  background: url("chrome://global/skin/icons/loading_16.png");
+  background: url("chrome://global/skin/icons/loading_16.png") center no-repeat;
   width: 16px;
   height: 16px;
 }
 
 /**
  * Scope element
  */
 
+.scope:focus > .title {
+  background: Highlight;
+  color: HighlightText;
+}
+
 .scope > .title {
   text-shadow: 0 1px #222;
   color: #fff;
 }
 
 .scope > .details {
   -moz-margin-start: 2px;
-  -moz-margin-end: 2px;
+  -moz-margin-end: 1px;
 }
 
 .scope > .details.nonenum:not(:empty) {
   border-top: 1px solid #ddd;
 }
 
 /**
  * Variable element
  */
 
 .variable {
   -moz-margin-start: 1px;
   -moz-margin-end: 1px;
   border-bottom: 1px solid #eee;
-  background: #fff;
   transition: background 1s ease-in-out;
 }
 
 .variable[changed] {
   background: rgba(255, 255, 0, 0.65);
   transition-duration: 0.4s;
 }
 
+.variable:focus > .title {
+  background: Highlight;
+  color: HighlightText;
+  border-radius: 4px;
+}
+
 .variable > .title > .name {
+  font-weight: 600;
+}
+
+.variable:not(:focus) > .title > .name {
   color: #048;
-  font-weight: 600;
 }
 
 .variable > .title > .value {
   -moz-padding-start: 6px;
   -moz-padding-end: 4px;
 }
 
+.variable[editable] > .title > .value {
+  cursor: text;
+}
+
 .variable:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
  * Property element
  */
 
 .property {
-  background: #fff;
   transition: background 1s ease-in-out;
 }
 
 .property[changed] {
   background: rgba(255, 255, 0, 0.65);
   transition-duration: 0.4s;
 }
 
-.property > .title > .name {
+.property:focus > .title {
+  background: Highlight;
+  color: HighlightText;
+  border-radius: 4px;
+}
+
+.property:not(:focus) > .title > .name {
   color: #881090;
 }
 
 .property > .title > .value {
   -moz-padding-start: 6px;
   -moz-padding-end: 4px;
 }
 
+.property[editable] > .title > .value {
+  cursor: text;
+}
+
 .property:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
- * Non enumerable, configurable and writable variables and properties.
+ * Non enumerable, configurable and writable variables and properties
  */
 
 .variable[proto] > .title > .name,
 .property[proto] > .title > .name,
 .variable[non-enumerable]:not([self]):not([exception]) > .title > .name,
 .property[non-enumerable]:not([self]):not([exception]) > .title > .name {
   opacity: 0.5;
 }
@@ -416,18 +466,18 @@
 @media (min-resolution: 2dppx) {
   .variable[non-writable] > .title:after,
   .property[non-writable] > .title:after {
     background-image: url("chrome://browser/skin/identity-icons-https@2x.png");
     background-size: 32px;
   }
 }
 
-.variable[exception] > .title > .name,
-.property[exception] > .title > .name {
+.variable[exception]:not(:focus) > .title > .name,
+.property[exception]:not(:focus) > .title > .name {
   color: #a00;
   text-shadow: 0 0 8px #fcc;
 }
 
 .variable > tooltip > label,
 .property > tooltip > label {
   margin: 0 2px 0 2px;
 }
@@ -440,28 +490,33 @@
 .property[non-writable] > tooltip > label[value="writable"] {
   text-decoration: line-through;
 }
 
 /**
  * Variables and properties editing
  */
 
-#variables .element-value-input {
-  overflow: hidden;
-  max-width: 30em;
-  -moz-margin-start: 5px !important;
+.element-value-input {
+  -moz-margin-start: 4px !important;
 }
 
-#variables .element-name-input {
-  -moz-margin-start: -1px !important;
+.element-name-input {
+  -moz-margin-start: -2px !important;
   color: #048;
   font-weight: 600;
 }
 
+.element-value-input,
+.element-name-input {
+  max-width: 30em;
+  border: 1px solid #999 !important;
+  box-shadow: 1px 2px 4px #aaa;
+}
+
 /**
  * Variables and properties searching
  */
 
 .variables-searchinput.devtools-searchinput {
   min-height: 24px;
 }
 
@@ -470,38 +525,38 @@
   border: none;
   margin: 0;
 }
 
 /**
  * Token value colors
  */
 
-.token-undefined {
+.variable-or-property:not(:focus) > .title > .token-undefined {
   color: #bbb;
 }
 
-.token-null {
+.variable-or-property:not(:focus) > .title > .token-null {
   color: #999;
 }
 
-.token-boolean {
+.variable-or-property:not(:focus) > .title > .token-boolean {
   color: #777;
 }
 
-.token-number {
+.variable-or-property:not(:focus) > .title > .token-number {
   color: #c40a16;
 }
 
-.token-string {
+.variable-or-property:not(:focus) > .title > .token-string {
   max-width: 30em;
   color: #1c00cf;
 }
 
-.token-other {
+.variable-or-property:not(:focus) > .title > .token-other {
   color: #333;
 }
 
 /**
  * Expand/collapse arrow
  */
 
 .arrow {
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -1247,21 +1247,16 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
   padding: 0 3px;
 }
 
 .searchbar-engine-button,
 .search-go-container {
   padding: 2px 2px;
 }
 
-.urlbar-icon:-moz-system-metric(touch-enabled) {
-  -moz-margin-end: 1px !important;
-  padding: 0 3px !important;
-}
-
 .urlbar-icon:hover {
   background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.3), hsla(200,100%,70%,0));
 }
 
 .urlbar-icon[open="true"],
 .urlbar-icon:hover:active {
   background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.1), hsla(200,100%,70%,0));
 }
@@ -1378,20 +1373,16 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
   padding: 0 3px;
   background-color: transparent;
   border: none;
   width: auto;
   list-style-image: url("chrome://browser/skin/urlbar-history-dropmarker.png");
   -moz-image-region: rect(0px, 11px, 14px, 0px);
 }
 
-.urlbar-history-dropmarker:-moz-system-metric(touch-enabled) {
-  min-width: 6.4mozmm;
-}
-
 .urlbar-history-dropmarker:hover {
   background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
   -moz-image-region: rect(0px, 22px, 14px, 11px);
 }
 
 .urlbar-history-dropmarker:hover:active,
 .urlbar-history-dropmarker[open="true"] {
   background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.1), hsla(205,100%,70%,0));
@@ -1923,52 +1914,32 @@ richlistitem[type~="action"][actiontype=
 .tab-close-button {
   -moz-appearance: none;
   -moz-image-region: rect(0, 64px, 16px, 48px);
   border: none;
   padding: 0px;
   list-style-image: url("chrome://global/skin/icons/close.png");
 }
 
-.tab-close-button:-moz-system-metric(touch-enabled) {
-  transform: scale(1.2);
-}
-
 .tab-close-button:hover,
 .tab-close-button:hover[selected="true"] {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
 .tab-close-button:hover:active,
 .tab-close-button:hover:active[selected="true"] {
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 .tab-close-button[selected="true"] {
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 /* Tab scrollbox arrow, tabstrip new tab and all-tabs buttons */
 
-@media (-moz-touch-enabled) {
-  .tabbrowser-arrowscrollbox > .scrollbutton-up,
-  .tabbrowser-arrowscrollbox > .scrollbutton-down,
-  #TabsToolbar .toolbarbutton-1 {
-    min-width: 8.1mozmm;
-  }
-
-  .tabs-newtab-button {
-    min-width: 10mozmm;
-  }
-
-  .tab-content {
-    min-height: calc(6.8mozmm - 7px); /* subtract borders from the desired height */
-  }
-}
-
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-left.png");
   margin: 0;
   padding-right: 2px;
   border-right: 2px solid transparent;
   background-origin: border-box;
 }
--- a/browser/themes/winstripe/devtools/debugger.css
+++ b/browser/themes/winstripe/devtools/debugger.css
@@ -178,43 +178,40 @@
   color: #888;
 }
 
 /**
  * Stack frames and breakpoints pane
  */
 
 #stackframes\+breakpoints {
-  background-color: white;
   min-width: 50px;
 }
 
 #stackframes\+breakpoints[animated] {
   transition: margin 0.25s ease-in-out;
 }
 
 /**
  * Variables and watch expressions pane
  */
 
 #variables\+expressions {
-  background-color: white;
   min-width: 50px;
 }
 
 #variables\+expressions[animated] {
   transition: margin 0.25s ease-in-out;
 }
 
 /**
  * Stack frames view
  */
 
 #stackframes {
-  background-color: white;
   min-height: 10px;
 }
 
 .dbg-stackframe {
   -moz-padding-start: 4px;
   -moz-padding-end: 4px;
 }
 
@@ -226,17 +223,16 @@
   -moz-padding-start: 4px;
 }
 
 /**
  * Breakpoints view
  */
 
 #breakpoints {
-  background-color: white;
   min-height: 10px;
 }
 
 #breakpoints > vbox:not(:empty) {
   min-height: 10px;
   max-height: 200px;
 }
 
@@ -260,18 +256,18 @@
   margin: 0 0 -2px 0;
 }
 
 /**
  * Watch expressions view
  */
 
 #expressions {
-  background-color: white;
   min-height: 10px;
+  max-height: 125px;
 }
 
 .dbg-expression {
   height: 20px;
   -moz-padding-start: 8px;
 }
 
 .dbg-expression-arrow {
@@ -280,121 +276,176 @@
   background: url("chrome://browser/skin/devtools/commandline.png") 0px 4px no-repeat;
 }
 
 .dbg-expression-input {
   font: 9pt monospace;
 }
 
 .dbg-expression-delete {
+  opacity: 0;
+}
+
+.dbg-expression-delete:not(:hover) {
   -moz-image-region: rect(0, 32px, 16px, 16px);
 }
 
-.dbg-expression-delete:not(:hover) {
+.dbg-expression-delete:hover {
+  opacity: 1;
+}
+
+.dbg-expression:hover > .dbg-expression-delete:not(:hover) {
   opacity: 0.5;
+  transition: opacity 0.2s ease-in-out;
 }
 
 /**
  * Variables view
  */
 
 #variables {
-  background-color: white;
   min-height: 10px;
 }
 
+.dbg-variable-delete {
+  opacity: 0;
+}
+
 .dbg-variable-delete:not(:hover) {
   -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+.dbg-variable-delete:hover {
+  opacity: 1;
+}
+
+.variable-or-property:hover > .title > .dbg-variable-delete:not(:hover),
+.variable-or-property:focus > .title > .dbg-variable-delete:not(:hover) {
   opacity: 0.5;
+  transition: opacity 0.2s ease-in-out;
+}
+
+.dbg-variable-edit {
+  background: url("chrome://browser/skin/tabview/edit-light.png") center no-repeat;
+  width: 20px;
+  height: 16px;
+  cursor: pointer;
 }
 
 .dbg-variable-throbber {
-  background: url("chrome://global/skin/icons/loading_16.png");
+  background: url("chrome://global/skin/icons/loading_16.png") center no-repeat;
   width: 16px;
   height: 16px;
 }
 
 /**
  * Scope element
  */
 
+.scope:focus > .title {
+  background: Highlight;
+  color: HighlightText;
+}
+
 .scope > .title {
   text-shadow: 0 1px #222;
   color: #fff;
 }
 
 .scope > .details {
   -moz-margin-start: 2px;
-  -moz-margin-end: 2px;
+  -moz-margin-end: 1px;
 }
 
 .scope > .details.nonenum:not(:empty) {
   border-top: 1px solid #ddd;
 }
 
 /**
  * Variable element
  */
 
 .variable {
   -moz-margin-start: 1px;
   -moz-margin-end: 1px;
   border-bottom: 1px solid #eee;
-  background: #fff;
   transition: background 1s ease-in-out;
 }
 
 .variable[changed] {
   background: rgba(255, 255, 0, 0.65);
   transition-duration: 0.4s;
 }
 
+.variable:focus > .title {
+  background: Highlight;
+  color: HighlightText;
+  border-radius: 4px;
+}
+
 .variable > .title > .name {
+  font-weight: 600;
+}
+
+.variable:not(:focus) > .title > .name {
   color: #048;
-  font-weight: 600;
 }
 
 .variable > .title > .value {
   -moz-padding-start: 6px;
   -moz-padding-end: 4px;
 }
 
+.variable[editable] > .title > .value {
+  cursor: text;
+}
+
 .variable:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
  * Property element
  */
 
 .property {
-  background: #fff;
   transition: background 1s ease-in-out;
 }
 
 .property[changed] {
   background: rgba(255, 255, 0, 0.65);
   transition-duration: 0.4s;
 }
 
-.property > .title > .name {
+.property:focus > .title {
+  background: Highlight;
+  color: HighlightText;
+  border-radius: 4px;
+}
+
+.property:not(:focus) > .title > .name {
   color: #881090;
 }
 
 .property > .title > .value {
   -moz-padding-start: 6px;
   -moz-padding-end: 4px;
+  cursor: text;
+}
+
+.property[editable] > .title > .value {
+  cursor: text;
 }
 
 .property:not([non-header]) > .details {
   -moz-margin-start: 10px;
 }
 
 /**
- * Non enumerable, configurable and writable variables and properties.
+ * Non enumerable, configurable and writable variables and properties
  */
 
 .variable[proto] > .title > .name,
 .property[proto] > .title > .name,
 .variable[non-enumerable]:not([self]):not([exception]) > .title > .name,
 .property[non-enumerable]:not([self]):not([exception]) > .title > .name {
   opacity: 0.5;
 }
@@ -422,18 +473,18 @@
 @media (min-resolution: 2dppx) {
   .variable[non-writable] > .title:after,
   .property[non-writable] > .title:after {
     background-image: url("chrome://browser/skin/identity-icons-https@2x.png");
     background-size: 32px;
   }
 }
 
-.variable[exception] > .title > .name,
-.property[exception] > .title > .name {
+.variable[exception]:not(:focus) > .title > .name,
+.property[exception]:not(:focus) > .title > .name {
   color: #a00;
   text-shadow: 0 0 8px #fcc;
 }
 
 .variable > tooltip > label,
 .property > tooltip > label {
   margin: 0 2px 0 2px;
 }
@@ -446,28 +497,33 @@
 .property[non-writable] > tooltip > label[value="writable"] {
   text-decoration: line-through;
 }
 
 /**
  * Variables and properties editing
  */
 
-#variables .element-value-input {
-  overflow: hidden;
-  max-width: 30em;
-  -moz-margin-start: 5px !important;
+.element-value-input {
+  -moz-margin-start: 4px !important;
 }
 
-#variables .element-name-input {
-  -moz-margin-start: -1px !important;
+.element-name-input {
+  -moz-margin-start: -2px !important;
   color: #048;
   font-weight: 600;
 }
 
+.element-value-input,
+.element-name-input {
+  max-width: 30em;
+  border: 1px solid #999 !important;
+  box-shadow: 1px 2px 4px #aaa;
+}
+
 /**
  * Variables and properties searching
  */
 
 .variables-searchinput.devtools-searchinput {
   min-height: 24px;
 }
 
@@ -476,38 +532,38 @@
   border: none;
   margin: 0;
 }
 
 /**
  * Token value colors
  */
 
-.token-undefined {
+.variable-or-property:not(:focus) > .title > .token-undefined {
   color: #bbb;
 }
 
-.token-null {
+.variable-or-property:not(:focus) > .title > .token-null {
   color: #999;
 }
 
-.token-boolean {
+.variable-or-property:not(:focus) > .title > .token-boolean {
   color: #777;
 }
 
-.token-number {
+.variable-or-property:not(:focus) > .title > .token-number {
   color: #c40a16;
 }
 
-.token-string {
+.variable-or-property:not(:focus) > .title > .token-string {
   max-width: 30em;
   color: #1c00cf;
 }
 
-.token-other {
+.variable-or-property:not(:focus) > .title > .token-other {
   color: #333;
 }
 
 /**
  * Expand/collapse arrow
  */
 
 .arrow {
--- a/browser/themes/winstripe/searchbar.css
+++ b/browser/themes/winstripe/searchbar.css
@@ -59,21 +59,16 @@
 }
 
 .search-go-button {
   padding: 1px;
   list-style-image: url("chrome://global/skin/icons/Search-glass.png");
   -moz-image-region: rect(0px 16px 16px 0px);
 }
 
-.search-go-button:-moz-system-metric(touch-enabled) {
-  -moz-padding-start: 5px;
-  -moz-padding-end: 3px;
-}
-
 .search-go-button:-moz-locale-dir(rtl) {
   transform: scaleX(-1);
 }
 
 .search-go-button:hover {
   -moz-image-region: rect(0px 32px 16px 16px);
 }
 
--- a/build/autoconf/toolchain.m4
+++ b/build/autoconf/toolchain.m4
@@ -12,23 +12,23 @@ CC_VERSION='N/A'
 CXX_VERSION='N/A'
 if test "$GCC" = "yes"; then
     GNU_CC=1
     CC_VERSION=`$CC -v 2>&1 | grep 'gcc version'`
 fi
 if test "$GXX" = "yes"; then
     GNU_CXX=1
     CXX_VERSION=`$CXX -v 2>&1 | grep 'gcc version'`
-    changequote(,)
-    GCC_VERSION_FULL=`echo "$CXX_VERSION" | $PERL -pe 's/^.*gcc version ([^ ]*).*/$1/'`
-    GCC_VERSION=`echo "$GCC_VERSION_FULL" | $PERL -pe '(split(/\./))[0]>=4&&s/(^\d*\.\d*).*/$1/;'`
+    changequote(<<,>>)
+    GCC_VERSION_FULL=`echo "$CXX_VERSION" | $PERL -pe 's/^.*gcc version ([^ ]*).*/<<$>>1/'`
+    GCC_VERSION=`echo "$GCC_VERSION_FULL" | $PERL -pe '(split(/\./))[0]>=4&&s/(^\d*\.\d*).*/<<$>>1/;'`
+
+    GCC_MAJOR_VERSION=`echo ${GCC_VERSION} | $AWK -F\. '{ print <<$>>1 }'`
+    GCC_MINOR_VERSION=`echo ${GCC_VERSION} | $AWK -F\. '{ print <<$>>2 }'`
     changequote([,])
-
-    GCC_MAJOR_VERSION=`echo ${GCC_VERSION} | $AWK -F\. '{ print $1 }'`
-    GCC_MINOR_VERSION=`echo ${GCC_VERSION} | $AWK -F\. '{ print $2 }'`
 fi
 
 if test "`echo | $AS -o conftest.out -v 2>&1 | grep -c GNU`" != "0"; then
     GNU_AS=1
 fi
 rm -f conftest.out
 if test "`echo | $LD -v 2>&1 | grep -c GNU`" != "0"; then
     GNU_LD=1
--- a/config/makefiles/autotargets.mk
+++ b/config/makefiles/autotargets.mk
@@ -33,17 +33,17 @@ space = $(NULL) $(NULL)
 getPathPrefix =$(if $(filter /%,$(1)),/)
 
 # Squeeze '//' from the path, easily created by string functions
 _slashSqueeze =$(foreach val,$(getargv),$(call getPathPrefix,$(val))$(subst $(space),/,$(strip $(subst /,$(space),$(val)))))
 
 # Squeeze extraneous directory slashes from the path
 #  o protect embedded spaces within the path
 #  o replace //+ sequences with /
-slash_strip =\
+slash_strip = \
   $(strip \
     $(subst <--[**]-->,$(space),\
 	$(call _slashSqueeze,\
     $(subst $(space),<--[**]-->,$(1))\
   )))
 
 # Extract directory path from a dependency file.
 mkdir_stem =$(foreach val,$(getargv),$(subst /.mkdir.done,$(NULL),$(val)))
@@ -57,37 +57,31 @@ mkdir_deps =$(foreach dir,$(getargv),$(c
 
 %/.mkdir.done: # mkdir -p -p => mkdir -p
 	$(subst $(space)-p,$(null),$(MKDIR)) -p "$(dir $@)"
 # Make the timestamp old enough for not being a problem with symbolic links
 # targets depending on it. Use Jan 3, 1980 to accomodate any timezone where
 # 198001010000 would translate to something older than FAT epoch.
 	@$(TOUCH) -t 198001030000 "$@"
 
-# A handful of makefiles are attempting "mkdir dot".  Likely not intended
-# or stale logic so add a stub target to handle the request and warn for now.
-.mkdir.done:
-ifndef NOWARN_AUTOTARGETS # {
-	@echo "WARNING: $(MKDIR) -dot- requested by $(MAKE) -C $(CURDIR) $(MAKECMDGOALS)"
-	@$(TOUCH) -t 198001030000 $@
-endif #}
-
 INCLUDED_AUTOTARGETS_MK = 1
 endif #}
 
 
 ## Accumulate deps and cleanup
 ifneq (,$(GENERATED_DIRS))
+  GENERATED_DIRS := $(strip $(sort $(GENERATED_DIRS)))
   tmpauto :=$(call mkdir_deps,GENERATED_DIRS)
   GENERATED_DIRS_DEPS +=$(tmpauto)
   GARBAGE_DIRS        +=$(GENERATED_DIRS)
 endif
 
 #################################################################
 # One ring/dep to rule them all:
 #   config/rules.mk::all target is available by default
 #   Add $(AUTO_DEPS) as an explicit target dependency when needed.
 #################################################################
 
 AUTO_DEPS +=$(GENERATED_DIRS_DEPS)
+AUTO_DEPS := $(strip $(sort $(AUTO_DEPS)))
 
 # Complain loudly if deps have not loaded so getargv != $(NULL)
 $(call requiredfunction,getargv)
--- a/config/makefiles/makeutils.mk
+++ b/config/makefiles/makeutils.mk
@@ -40,21 +40,21 @@ subargv =$(wordlist $(1),$(words $(getar
 # Debug:
 #   target-preqs = \
 #     $(call banner,target-preqs-BEGIN) \
 #     foo bar tans \
 #     $(call banner,target-preqs-END) \
 #     $(NULL)
 #   target: $(target-preqs)
 
-banner =\
-$(info )\
-$(info ***************************************************************************)\
-$(info ** $(getargv))\
-$(info ***************************************************************************)\
+banner = \
+$(info ) \
+$(info ***************************************************************************) \
+$(info ** $(getargv)) \
+$(info ***************************************************************************) \
 $(NULL)
 
 #####################################################################
 # Intent: Determine if a string or pattern is contained in a list
 # Usage: strcmp  - $(call if_XinY,clean,$(MAKECMDGOALS))
 #      : pattern - $(call if_XinY,clean%,$(MAKECMDGOALS))
 is_XinY =$(filter $(1),$(call subargv,3,$(getargv)))
 
--- a/config/makefiles/test/check-autotargets.mk
+++ b/config/makefiles/test/check-autotargets.mk
@@ -6,31 +6,29 @@
 
 ifdef VERBOSE
   $(warning loading test)
 endif
 
 space=$(null) $(null)
 GENERATED_DIRS = bogus # test data
 
-NOWARN_AUTOTARGETS = 1 # Unit test includes makefile twice.
-
 undefine USE_AUTOTARGETS_MK
 undefine INCLUDED_AUTOTARGETS_MK
 include $(topsrcdir)/config/makefiles/autotargets.mk
 
 ifndef INCLUDED_AUTOTARGETS_MK
   $(error autotargets.mk was not included
 endif
 
 $(call requiredfunction,mkdir_deps)
 
 
 # Verify test data populated makefile vars correctly
-vars = AUTO_DEPS GARBAGE_DIRS GENERATED_DIRS_DEPS 
+vars = AUTO_DEPS GARBAGE_DIRS GENERATED_DIRS_DEPS
 $(foreach var,$(vars),$(call errorIfEmpty,$(var)))
 
 # Data should also be valid
 ifneq (bogus,$(findstring bogus,$(AUTO_DEPS)))
   $(error AUTO_DEPS=[$(AUTO_DEPS)] is not set correctly)
 endif
 
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -111,17 +111,17 @@ check::
 cppunittests-remote: DM_TRANS?=adb
 cppunittests-remote:
 	@if [ "${TEST_DEVICE}" != "" -o "$(DM_TRANS)" = "adb" ]; then \
 		$(PYTHON) -u $(topsrcdir)/testing/remotecppunittests.py \
 			--xre-path=$(DEPTH)/dist/bin \
 			--localLib=$(DEPTH)/dist/$(MOZ_APP_NAME) \
 			--dm_trans=$(DM_TRANS) \
 			--deviceIP=${TEST_DEVICE} \
- 			$(subst .cpp,$(BIN_SUFFIX),$(CPP_UNIT_TESTS)) $(EXTRA_TEST_ARGS); \
+			$(subst .cpp,$(BIN_SUFFIX),$(CPP_UNIT_TESTS)) $(EXTRA_TEST_ARGS); \
 	else \
 		echo "please prepare your host with environment variables for TEST_DEVICE"; \
 	fi
 
 endif # CPP_UNIT_TESTS
 
 .PHONY: check
 
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -42,32 +42,32 @@
 #include "mozilla/ErrorResult.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDOMAttr.h"
 #include "nsISMILAttr.h"
 #include "nsClientRect.h"
 #include "nsEvent.h"
 #include "nsAttrValue.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "nsIHTMLCollection.h"
 
 class nsIDOMEventListener;
 class nsIFrame;
 class nsIDOMNamedNodeMap;
 class nsIDOMCSSStyleDeclaration;
 class nsIURI;
 class nsINodeInfo;
 class nsIControllers;
 class nsEventChainVisitor;
 class nsEventListenerManager;
 class nsIScrollableFrame;
 class nsAttrValueOrString;
 class ContentUnbinder;
 class nsClientRect;
 class nsClientRectList;
-class nsIHTMLCollection;
 class nsContentList;
 class nsDOMTokenList;
 struct nsRect;
 class nsEventStateManager;
 class nsFocusManager;
 class nsGlobalWindow;
 class nsICSSDeclaration;
 class nsISMILAttr;
@@ -116,18 +116,18 @@ enum {
 namespace mozilla {
 namespace dom {
 
 class Link;
 class UndoManager;
 
 // IID for the dom::Element interface
 #define NS_ELEMENT_IID \
-{ 0xc6c049a1, 0x96e8, 0x4580, \
-  { 0xa6, 0x93, 0xb9, 0x5f, 0x53, 0xbe, 0xe8, 0x1c } }
+{ 0xcae9f7e7, 0x6163, 0x47b5, \
+ { 0xa1, 0x63, 0x30, 0xc8, 0x1d, 0x2d, 0x79, 0x39 } }
 
 class Element : public FragmentOrElement
 {
 public:
 #ifdef MOZILLA_INTERNAL_API
   Element(already_AddRefed<nsINodeInfo> aNodeInfo) :
     FragmentOrElement(aNodeInfo),
     mState(NS_EVENT_STATE_MOZ_READONLY)
@@ -442,41 +442,34 @@ public:
                              const nsAttrValueOrString& aValue,
                              bool aNotify, nsAttrValue& aOldValue,
                              uint8_t* aModType, bool* aHasListeners);
 
   bool OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
                               nsIAtom* aPrefix,
                               const nsAttrValueOrString& aValue,
                               bool aNotify, nsAttrValue& aOldValue,
-                              uint8_t* aModType, bool* aHasListeners)
-  {
-    if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
-                              aOldValue, aModType, aHasListeners)) {
-      nsAutoScriptBlocker scriptBlocker;
-      nsNodeUtils::AttributeSetToCurrentValue(this, aNamespaceID, aName);
-      return true;
-    }
-    return false;
-  }
+                              uint8_t* aModType, bool* aHasListeners);
 
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
                            const nsAString& aValue, bool aNotify);
   nsresult SetParsedAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
                          nsAttrValue& aParsedValue, bool aNotify);
-  virtual bool GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
-                       nsAString& aResult) const;
-  virtual bool HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const;
+  // GetAttr is not inlined on purpose, to keep down codesize from all
+  // the inlined nsAttrValue bits for C++ callers.
+  bool GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+               nsAString& aResult) const;
+  inline bool HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const;
   // aCaseSensitive == eIgnoreCaase means ASCII case-insensitive matching.
-  virtual bool AttrValueIs(int32_t aNameSpaceID, nsIAtom* aName,
-                             const nsAString& aValue,
-                             nsCaseTreatment aCaseSensitive) const;
-  virtual bool AttrValueIs(int32_t aNameSpaceID, nsIAtom* aName,
-                             nsIAtom* aValue,
-                             nsCaseTreatment aCaseSensitive) const;
+  inline bool AttrValueIs(int32_t aNameSpaceID, nsIAtom* aName,
+                          const nsAString& aValue,
+                          nsCaseTreatment aCaseSensitive) const;
+  inline bool AttrValueIs(int32_t aNameSpaceID, nsIAtom* aName,
+                          nsIAtom* aValue,
+                          nsCaseTreatment aCaseSensitive) const;
   virtual int32_t FindAttrValueIn(int32_t aNameSpaceID,
                                   nsIAtom* aName,
                                   AttrValuesArray* aValues,
                                   nsCaseTreatment aCaseSensitive) const;
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify);
   virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const;
   virtual uint32_t GetAttrCount() const;
@@ -1159,16 +1152,53 @@ private:
   nsresult GetMarkup(bool aIncludeSelf, nsAString& aMarkup);
 
   // Data members
   nsEventStates mState;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(Element, NS_ELEMENT_IID)
 
+inline bool
+Element::HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const
+{
+  NS_ASSERTION(nullptr != aName, "must have attribute name");
+  NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
+               "must have a real namespace ID!");
+
+  return mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID) >= 0;
+}
+
+inline bool
+Element::AttrValueIs(int32_t aNameSpaceID,
+                     nsIAtom* aName,
+                     const nsAString& aValue,
+                     nsCaseTreatment aCaseSensitive) const
+{
+  NS_ASSERTION(aName, "Must have attr name");
+  NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
+
+  const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
+  return val && val->Equals(aValue, aCaseSensitive);
+}
+
+inline bool
+Element::AttrValueIs(int32_t aNameSpaceID,
+                     nsIAtom* aName,
+                     nsIAtom* aValue,
+                     nsCaseTreatment aCaseSensitive) const
+{
+  NS_ASSERTION(aName, "Must have attr name");
+  NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
+  NS_ASSERTION(aValue, "Null value atom");
+
+  const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
+  return val && val->Equals(aValue, aCaseSensitive);
+}
+
 } // namespace dom
 } // namespace mozilla
 
 inline mozilla::dom::Element* nsINode::AsElement()
 {
   MOZ_ASSERT(IsElement());
   return static_cast<mozilla::dom::Element*>(this);
 }
--- a/content/base/public/nsIContent.h
+++ b/content/base/public/nsIContent.h
@@ -29,18 +29,18 @@ struct IMEState;
 enum nsLinkState {
   eLinkState_Unvisited  = 1,
   eLinkState_Visited    = 2,
   eLinkState_NotLink    = 3 
 };
 
 // IID for the nsIContent interface
 #define NS_ICONTENT_IID \
-{ 0xe2985850, 0x81ca, 0x4b5d, \
-  { 0xb0, 0xf3, 0xe3, 0x95, 0xd5, 0x0d, 0x85, 0x64 } }
+{ 0x8a8b4b1d, 0x72d8, 0x428e, \
+ { 0x95, 0x75, 0xf9, 0x18, 0xba, 0xf6, 0x9e, 0xa1 } }
 
 /**
  * A node of content in a document's content model. This interface
  * is supported by all content objects.
  */
 class nsIContent : public nsINode {
 public:
   typedef mozilla::widget::IMEState IMEState;
@@ -367,63 +367,57 @@ public:
    * suitable for passing back into SetAttr.
    *
    * @param aNameSpaceID the namespace of the attr
    * @param aName the name of the attr
    * @param aResult the value (may legitimately be the empty string) [OUT]
    * @returns true if the attribute was set (even when set to empty string)
    *          false when not set.
    */
-  virtual bool GetAttr(int32_t aNameSpaceID, nsIAtom* aName, 
-                         nsAString& aResult) const = 0;
+  bool GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+               nsAString& aResult) const;
 
   /**
    * Determine if an attribute has been set (empty string or otherwise).
    *
    * @param aNameSpaceId the namespace id of the attribute
    * @param aAttr the attribute name
    * @return whether an attribute exists
    */
-  virtual bool HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const = 0;
+  bool HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const;
 
   /**
    * Test whether this content node's given attribute has the given value.  If
    * the attribute is not set at all, this will return false.
    *
    * @param aNameSpaceID The namespace ID of the attribute.  Must not
    *                     be kNameSpaceID_Unknown.
    * @param aName The name atom of the attribute.  Must not be null.
    * @param aValue The value to compare to.
    * @param aCaseSensitive Whether to do a case-sensitive compare on the value.
    */
-  virtual bool AttrValueIs(int32_t aNameSpaceID,
-                             nsIAtom* aName,
-                             const nsAString& aValue,
-                             nsCaseTreatment aCaseSensitive) const
-  {
-    return false;
-  }
+  bool AttrValueIs(int32_t aNameSpaceID,
+                   nsIAtom* aName,
+                   const nsAString& aValue,
+                   nsCaseTreatment aCaseSensitive) const;
   
   /**
    * Test whether this content node's given attribute has the given value.  If
    * the attribute is not set at all, this will return false.
    *
    * @param aNameSpaceID The namespace ID of the attribute.  Must not
    *                     be kNameSpaceID_Unknown.
    * @param aName The name atom of the attribute.  Must not be null.
    * @param aValue The value to compare to.  Must not be null.
    * @param aCaseSensitive Whether to do a case-sensitive compare on the value.
    */
-  virtual bool AttrValueIs(int32_t aNameSpaceID,
-                             nsIAtom* aName,
-                             nsIAtom* aValue,
-                             nsCaseTreatment aCaseSensitive) const
-  {
-    return false;
-  }
+  bool AttrValueIs(int32_t aNameSpaceID,
+                   nsIAtom* aName,
+                   nsIAtom* aValue,
+                   nsCaseTreatment aCaseSensitive) const;
   
   enum {
     ATTR_MISSING = -1,
     ATTR_VALUE_NO_MATCH = -2
   };
   /**
    * Check whether this content node's given attribute has one of a given
    * list of values. If there is a match, we return the index in the list
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -383,16 +383,17 @@ protected:
   /**
    * WrapNode is called from WrapObject to actually wrap this node, WrapObject
    * does some additional checks and fix-up that's common to all nodes. WrapNode
    * should just call the DOM binding's Wrap function.
    */
   virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
                              bool *aTriedToWrap)
   {
+    MOZ_ASSERT(!IsDOMBinding(), "Someone forgot to override WrapNode");
     *aTriedToWrap = false;
     return nullptr;
   }
 
 public:
   nsIDocument* GetParentObject() const
   {
     // Make sure that we get the owner document of the content node, in case
--- a/content/base/public/nsViewportInfo.h
+++ b/content/base/public/nsViewportInfo.h
@@ -1,16 +1,17 @@
 /* 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/. */
 
 #ifndef nsViewportInfo_h___
 #define nsViewportInfo_h___
 
-#include "nsContentUtils.h"
+#include "mozilla/StandardInteger.h"
+#include "nscore.h"
 
 /**
  * Default values for the nsViewportInfo class.
  */
 static const double   kViewportMinScale = 0.0;
 static const double   kViewportMaxScale = 10.0;
 static const uint32_t kViewportMinWidth = 200;
 static const uint32_t kViewportMaxWidth = 10000;
--- a/content/base/src/DocumentFragment.h
+++ b/content/base/src/DocumentFragment.h
@@ -57,25 +57,16 @@ public:
     return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
   }
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify)
   {
     return NS_OK;
   }
-  virtual bool GetAttr(int32_t aNameSpaceID, nsIAtom* aName, 
-                       nsAString& aResult) const
-  {
-    return false;
-  }
-  virtual bool HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const
-  {
-    return false;
-  }
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute, 
                              bool aNotify)
   {
     return NS_OK;
   }
   virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const
   {
     return nullptr;
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -1723,16 +1723,33 @@ Element::MaybeCheckSameAttrVal(int32_t a
     }
   }
   *aModType = modification ?
     static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) :
     static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
   return false;
 }
 
+bool
+Element::OnlyNotifySameValueSet(int32_t aNamespaceID, nsIAtom* aName,
+                                nsIAtom* aPrefix,
+                                const nsAttrValueOrString& aValue,
+                                bool aNotify, nsAttrValue& aOldValue,
+                                uint8_t* aModType, bool* aHasListeners)
+{
+  if (!MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
+                             aOldValue, aModType, aHasListeners)) {
+    return false;
+  }
+
+  nsAutoScriptBlocker scriptBlocker;
+  nsNodeUtils::AttributeSetToCurrentValue(this, aNamespaceID, aName);
+  return true;
+}
+
 nsresult
 Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
                  nsIAtom* aPrefix, const nsAString& aValue,
                  bool aNotify)
 {
   // Keep this in sync with SetParsedAttr below
 
   NS_ENSURE_ARG_POINTER(aName);
@@ -1962,53 +1979,16 @@ Element::GetAttr(int32_t aNameSpaceID, n
                  nsAString& aResult) const
 {
   DOMString str;
   bool haveAttr = GetAttr(aNameSpaceID, aName, str);
   str.ToString(aResult);
   return haveAttr;
 }
 
-bool
-Element::HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const
-{
-  NS_ASSERTION(nullptr != aName, "must have attribute name");
-  NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
-               "must have a real namespace ID!");
-
-  return mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID) >= 0;
-}
-
-bool
-Element::AttrValueIs(int32_t aNameSpaceID,
-                     nsIAtom* aName,
-                     const nsAString& aValue,
-                     nsCaseTreatment aCaseSensitive) const
-{
-  NS_ASSERTION(aName, "Must have attr name");
-  NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
-
-  const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
-  return val && val->Equals(aValue, aCaseSensitive);
-}
-
-bool
-Element::AttrValueIs(int32_t aNameSpaceID,
-                     nsIAtom* aName,
-                     nsIAtom* aValue,
-                     nsCaseTreatment aCaseSensitive) const
-{
-  NS_ASSERTION(aName, "Must have attr name");
-  NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
-  NS_ASSERTION(aValue, "Null value atom");
-
-  const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
-  return val && val->Equals(aValue, aCaseSensitive);
-}
-
 int32_t
 Element::FindAttrValueIn(int32_t aNameSpaceID,
                          nsIAtom* aName,
                          AttrValuesArray* aValues,
                          nsCaseTreatment aCaseSensitive) const
 {
   NS_ASSERTION(aName, "Must have attr name");
   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -838,16 +838,53 @@ nsIContent::PreHandleEvent(nsEventChainP
   if (parent) {
     aVisitor.mParentTarget = parent;
   } else {
     aVisitor.mParentTarget = GetCurrentDoc();
   }
   return NS_OK;
 }
 
+bool
+nsIContent::GetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+                    nsAString& aResult) const
+{
+  if (IsElement()) {
+    return AsElement()->GetAttr(aNameSpaceID, aName, aResult);
+  }
+  aResult.Truncate();
+  return false;
+}
+
+bool
+nsIContent::HasAttr(int32_t aNameSpaceID, nsIAtom* aName) const
+{
+  return IsElement() && AsElement()->HasAttr(aNameSpaceID, aName);
+}
+
+bool
+nsIContent::AttrValueIs(int32_t aNameSpaceID,
+                        nsIAtom* aName,
+                        const nsAString& aValue,
+                        nsCaseTreatment aCaseSensitive) const
+{
+  return IsElement() &&
+    AsElement()->AttrValueIs(aNameSpaceID, aName, aValue, aCaseSensitive);
+}
+
+bool
+nsIContent::AttrValueIs(int32_t aNameSpaceID,
+                        nsIAtom* aName,
+                        nsIAtom* aValue,
+                        nsCaseTreatment aCaseSensitive) const
+{
+  return IsElement() &&
+    AsElement()->AttrValueIs(aNameSpaceID, aName, aValue, aCaseSensitive);
+}
+
 const nsAttrValue*
 FragmentOrElement::DoGetClasses() const
 {
   NS_NOTREACHED("Shouldn't ever be called");
   return nullptr;
 }
 
 NS_IMETHODIMP
--- a/content/base/src/mozAutoDocUpdate.h
+++ b/content/base/src/mozAutoDocUpdate.h
@@ -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/. */
 
 #ifndef mozAutoDocUpdate_h_
 #define mozAutoDocUpdate_h_
 
-#include "nsContentUtils.h"
+#include "nsContentUtils.h" // For AddScriptBlocker() and RemoveScriptBlocker().
 #include "nsIDocument.h"
 #include "nsIDocumentObserver.h"
 
 /**
  * Helper class to automatically handle batching of document updates.  This
  * class will call BeginUpdate on construction and EndUpdate on destruction on
  * the given document with the given update type.  The document could be null,
  * in which case no updates will be called.  The constructor also takes a
--- a/content/base/src/nsFormData.cpp
+++ b/content/base/src/nsFormData.cpp
@@ -4,16 +4,17 @@
 
 #include "nsFormData.h"
 #include "nsIVariant.h"
 #include "nsIInputStream.h"
 #include "nsIDOMFile.h"
 #include "nsHTMLFormElement.h"
 #include "mozilla/dom/FormDataBinding.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsFormData::nsFormData(nsISupports* aOwner)
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
   , mOwner(aOwner)
 {
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -81,16 +81,17 @@
 #include "ContentParent.h"
 #include "TabParent.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "nsIAppsService.h"
+#include "sampler.h"
 
 #include "jsapi.h"
 #include "nsHTMLIFrameElement.h"
 #include "nsSandboxFlags.h"
 
 #include "mozilla/dom/StructuredCloneUtils.h"
 
 #ifdef MOZ_XUL
@@ -406,16 +407,18 @@ nsFrameLoader::ReallyStartLoading()
   return rv;
 }
 
 nsresult
 nsFrameLoader::ReallyStartLoadingInternal()
 {
   NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInDoc());
 
+  SAMPLE_LABEL("nsFrameLoader", "ReallyStartLoading");
+
   nsresult rv = MaybeCreateDocShell();
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (mRemoteFrame) {
     if (!mRemoteBrowser) {
       TryRemoteBrowser();
@@ -2025,16 +2028,18 @@ nsFrameLoader::TryRemoteBrowser()
   nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
   if (!window) {
     return false;
   }
   if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
     return false;
   }
 
+  SAMPLE_LABEL("nsFrameLoader", "CreateRemoteBrowser");
+
   MutableTabContext context;
   nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
   nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
   ScrollingBehavior scrollingBehavior = DEFAULT_SCROLLING;
   if (mOwnerContent->AttrValueIs(kNameSpaceID_None,
                                  nsGkAtoms::mozasyncpanzoom,
                                  nsGkAtoms::_true,
                                  eCaseMatters)) {
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1124,20 +1124,17 @@ nsFrameScriptExecutor::InitTabChildGloba
 
   JSContext* cx = JS_NewContext(rt, 8192);
   NS_ENSURE_TRUE(cx, false);
 
   mCx = cx;
 
   nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
 
-  bool allowXML = Preferences::GetBool("javascript.options.xml.chrome");
-  JS_SetOptions(cx, JS_GetOptions(cx) |
-                    JSOPTION_PRIVATE_IS_NSISUPPORTS |
-                    (allowXML ? JSOPTION_ALLOW_XML : 0));
+  JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_PRIVATE_IS_NSISUPPORTS);
   JS_SetVersion(cx, JSVERSION_LATEST);
   JS_SetErrorReporter(cx, ContentScriptErrorReporter);
 
   xpc_LocalizeContext(cx);
 
   JSAutoRequest ar(cx);
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES;
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -572,31 +572,16 @@ nsGenericDOMDataNode::SetAttr(int32_t aN
 
 nsresult
 nsGenericDOMDataNode::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
                                 bool aNotify)
 {
   return NS_OK;
 }
 
-bool
-nsGenericDOMDataNode::GetAttr(int32_t aNameSpaceID, nsIAtom *aAttr,
-                              nsAString& aResult) const
-{
-  aResult.Truncate();
-
-  return false;
-}
-
-bool
-nsGenericDOMDataNode::HasAttr(int32_t aNameSpaceID, nsIAtom *aAttribute) const
-{
-  return false;
-}
-
 const nsAttrName*
 nsGenericDOMDataNode::GetAttrNameAt(uint32_t aIndex) const
 {
   return nullptr;
 }
 
 uint32_t
 nsGenericDOMDataNode::GetAttrCount() const
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -110,19 +110,16 @@ public:
   {
     return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
   }
   virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            bool aNotify);
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                              bool aNotify);
-  virtual bool GetAttr(int32_t aNameSpaceID, nsIAtom *aAttribute,
-                         nsAString& aResult) const;
-  virtual bool HasAttr(int32_t aNameSpaceID, nsIAtom *aAttribute) const;
   virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const;
   virtual uint32_t GetAttrCount() const;
   virtual const nsTextFragment *GetText();
   virtual uint32_t TextLength() const;
   virtual nsresult SetText(const PRUnichar* aBuffer, uint32_t aLength,
                            bool aNotify);
   // Need to implement this here too to avoid hiding.
   nsresult SetText(const nsAString& aStr, bool aNotify)
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -1240,8 +1240,21 @@ nsImageLoadingContent::CreateStaticImage
   aDest->mSuppressed = mSuppressed;
 }
 
 CORSMode
 nsImageLoadingContent::GetCORSMode()
 {
   return CORS_NONE;
 }
+
+nsImageLoadingContent::ImageObserver::ImageObserver(imgINotificationObserver* aObserver)
+  : mObserver(aObserver)
+  , mNext(nullptr)
+{
+  MOZ_COUNT_CTOR(ImageObserver);
+}
+
+nsImageLoadingContent::ImageObserver::~ImageObserver()
+{
+  MOZ_COUNT_DTOR(ImageObserver);
+  NS_CONTENT_DELETE_LIST_MEMBER(ImageObserver, this, mNext);
+}
--- a/content/base/src/nsImageLoadingContent.h
+++ b/content/base/src/nsImageLoadingContent.h
@@ -12,25 +12,29 @@
 
 #ifndef nsImageLoadingContent_h__
 #define nsImageLoadingContent_h__
 
 #include "imgINotificationObserver.h"
 #include "imgIOnloadBlocker.h"
 #include "mozilla/CORSMode.h"
 #include "nsCOMPtr.h"
-#include "nsContentUtils.h" // NS_CONTENT_DELETE_LIST_MEMBER
 #include "nsEventStates.h"
 #include "nsIImageLoadingContent.h"
 #include "nsIRequest.h"
+#include "mozilla/ErrorResult.h"
+#include "nsAutoPtr.h"
 
 class nsIURI;
 class nsIDocument;
 class imgILoader;
 class nsIIOService;
+class nsPresContext;
+class nsIContent;
+class imgRequestProxy;
 
 class nsImageLoadingContent : public nsIImageLoadingContent,
                               public imgIOnloadBlocker
 {
   /* METHODS */
 public:
   nsImageLoadingContent();
   virtual ~nsImageLoadingContent();
@@ -181,27 +185,18 @@ protected:
   nsresult OnStopRequest(imgIRequest* aRequest, nsresult aStatus);
   nsresult OnImageIsAnimated(imgIRequest *aRequest);
 
 private:
   /**
    * Struct used to manage the image observers.
    */
   struct ImageObserver {
-    ImageObserver(imgINotificationObserver* aObserver) :
-      mObserver(aObserver),
-      mNext(nullptr)
-    {
-      MOZ_COUNT_CTOR(ImageObserver);
-    }
-    ~ImageObserver()
-    {
-      MOZ_COUNT_DTOR(ImageObserver);
-      NS_CONTENT_DELETE_LIST_MEMBER(ImageObserver, this, mNext);
-    }
+    ImageObserver(imgINotificationObserver* aObserver);
+    ~ImageObserver();
 
     nsCOMPtr<imgINotificationObserver> mObserver;
     ImageObserver* mNext;
   };
 
   /**
    * Struct to report state changes
    */
--- a/content/base/src/nsMixedContentBlocker.cpp
+++ b/content/base/src/nsMixedContentBlocker.cpp
@@ -79,30 +79,46 @@ public:
        if (rootDoc->GetHasMixedActiveContentLoaded()) {
          return NS_OK;
        }
        rootDoc->SetHasMixedActiveContentLoaded(true);
 
       // Update the security UI in the tab with the allowed mixed active content
       nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell);
       if (eventSink) {
-        eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN | nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
+        // If mixed display content is loaded, make sure to include that in the state.
+        if (rootDoc->GetHasMixedDisplayContentLoaded()) {
+          eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN |
+          nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
+          nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
+        } else {
+          eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN |
+          nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
+        }
       }
 
     } else if (mType == eMixedDisplay) {
       // See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
       if (rootDoc->GetHasMixedDisplayContentLoaded()) {
         return NS_OK;
       }
       rootDoc->SetHasMixedDisplayContentLoaded(true);
 
       // Update the security UI in the tab with the allowed mixed display content.
       nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell);
       if (eventSink) {
-        eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN | nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
+        // If mixed active content is loaded, make sure to include that in the state.
+        if (rootDoc->GetHasMixedActiveContentLoaded()) {
+          eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN |
+          nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT |
+          nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
+        } else {
+          eventSink->OnSecurityChange(mContext, (nsIWebProgressListener::STATE_IS_BROKEN |
+          nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
+        }
       }
     }
 
     return NS_OK;
   }
 private:
   // The requesting context for the content load. Generally, a DOM node from
   // the document that caused the load.
@@ -155,17 +171,20 @@ nsMixedContentBlocker::ShouldLoad(uint32
   //
   // TYPE_FONT: The TrueType hinting mechanism is basically a scripting
   // language that gets interpreted by the operating system's font rasterizer.
   // Mixed content web fonts are relatively uncommon, and we can can fall back
   // to built-in fonts with minimal disruption in almost all cases.
   //
   // TYPE_OBJECT_SUBREQUEST could actually be either active content (e.g. a
   // script that a plugin will execute) or display content (e.g. Flash video
-  // content).
+  // content).  Until we have a way to determine active vs passive content
+  // from plugin requests (bug 836352), we will treat this as passive content.
+  // This is to prevent false positives from causing users to become
+  // desensitized to the mixed content blocker.
   //
   // TYPE_CSP_REPORT: High-risk because they directly leak information about
   // the content of the page, and because blocking them does not have any
   // negative effect on the page loading.
   //
   // TYPE_PING: Ping requests are POSTS, not GETs like images and media.
   // Also, PING requests have no bearing on the rendering or operation of
   // the page when used as designed, so even though they are lower risk than
@@ -215,28 +234,28 @@ nsMixedContentBlocker::ShouldLoad(uint32
       *aDecision = ACCEPT;
       return NS_OK;
 
 
     // Static display content is considered moderate risk for mixed content so
     // these will be blocked according to the mixed display preference
     case TYPE_IMAGE:
     case TYPE_MEDIA:
+    case TYPE_OBJECT_SUBREQUEST:
     case TYPE_PING:
       classification = eMixedDisplay;
       break;
 
     // Active content (or content with a low value/risk-of-blocking ratio)
     // that has been explicitly evaluated; listed here for documentation
     // purposes and to avoid the assertion and warning for the default case.
     case TYPE_CSP_REPORT:
     case TYPE_DTD:
     case TYPE_FONT:
     case TYPE_OBJECT:
-    case TYPE_OBJECT_SUBREQUEST:
     case TYPE_SCRIPT:
     case TYPE_STYLESHEET:
     case TYPE_SUBDOCUMENT:
     case TYPE_XBL:
     case TYPE_XMLHTTPREQUEST:
     case TYPE_OTHER:
       break;
 
@@ -359,20 +378,25 @@ nsMixedContentBlocker::ShouldLoad(uint32
   NS_ASSERTION(rootDoc, "No root document from document shell root tree item.");
 
   // Get eventSink and the current security state from the docShell
   nsCOMPtr<nsISecurityEventSink> eventSink = do_Query