Merge the last PGO-green inbound changeset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 01 Feb 2013 15:48:59 -0500
changeset 130476 4e7c92906a795f721806e19aa86566bfd2c89018
parent 130354 b546bd987ed4007bcf9006b21f3234157ce7d71a (current diff)
parent 130475 f3271987974111cb3c0629908417b45bf42049d7 (diff)
child 130477 0ffbc0f69476ad7a1800c40275281ac0b572535d
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
4e7c92906a79 / 21.0a1 / 20130202030955 / files
nightly linux64
4e7c92906a79 / 21.0a1 / 20130202030955 / files
nightly mac
4e7c92906a79 / 21.0a1 / 20130202030955 / files
nightly win32
4e7c92906a79 / 21.0a1 / 20130202030955 / files
nightly win64
4e7c92906a79 / 21.0a1 / 20130202030955 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge the last PGO-green inbound changeset to m-c.
content/html/content/test/forms/test_input_number_value.html
content/svg/content/src/SVGLocatableElement.cpp
content/svg/content/src/SVGLocatableElement.h
docshell/test/bug94514-postpage.html
docshell/test/test_bug94514.html
dom/browser-element/BrowserElementParent.js
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/tests/mochitest/test_bug564330.html
--- 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
@@ -200,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/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-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
@@ -731,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",
@@ -791,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
@@ -907,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;
     }
@@ -967,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
@@ -3758,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
  */
@@ -4179,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();
   },
 
--- 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/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/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/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;
@@ -442,26 +442,17 @@ 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);
   // 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,
--- 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/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);
--- 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/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/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_QueryInterface(docShell);
   NS_ASSERTION(eventSink, "No eventSink from docShell.");
   nsCOMPtr<nsIDocShell> rootShell = do_GetInterface(sameTypeRoot);
   NS_ASSERTION(rootShell, "No root docshell from document shell root tree item.");
   uint32_t State = nsIWebProgressListener::STATE_IS_BROKEN;
-  nsCOMPtr<nsISecureBrowserUI> SecurityUI;
-  rootShell->GetSecurityUI(getter_AddRefs(SecurityUI));
-  NS_ASSERTION(SecurityUI, "No SecurityUI from the root docShell.");
-  nsresult stateRV = SecurityUI->GetState(&State);
+  nsCOMPtr<nsISecureBrowserUI> securityUI;
+  rootShell->GetSecurityUI(getter_AddRefs(securityUI));
+  // If there is no securityUI, document doesn't have a security state.
+  // Allow load and return early.
+  if (!securityUI) {
+    *aDecision = nsIContentPolicy::ACCEPT;
+    return NS_OK;
+  }
+  nsresult stateRV = securityUI->GetState(&State);
 
   // If the content is display content, and the pref says display content should be blocked, block it.
   if (sBlockMixedDisplay && classification == eMixedDisplay) {
     if (allowMixedContent) {
       *aDecision = nsIContentPolicy::ACCEPT;
       rootDoc->SetHasMixedActiveContentLoaded(true);
       if (!rootDoc->GetHasMixedDisplayContentLoaded() && NS_SUCCEEDED(stateRV)) {
         eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
@@ -395,19 +419,22 @@ nsMixedContentBlocker::ShouldLoad(uint32
          return NS_OK;
        }
        rootDoc->SetHasMixedActiveContentLoaded(true);
 
        if (rootHasSecureConnection) {
          // User has decided to override the pref and the root is https, so change the Security State.
          if (rootDoc->GetHasMixedDisplayContentLoaded()) {
            // If mixed display content is loaded, make sure to include that in the state.
-           eventSink->OnSecurityChange(aRequestingContext, (nsIWebProgressListener::STATE_IS_BROKEN | nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT | nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
+           eventSink->OnSecurityChange(aRequestingContext, (nsIWebProgressListener::STATE_IS_BROKEN |
+           nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT |
+           nsIWebProgressListener::STATE_LOADED_MIXED_DISPLAY_CONTENT));
          } else {
-           eventSink->OnSecurityChange(aRequestingContext, (nsIWebProgressListener::STATE_IS_BROKEN | nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
+           eventSink->OnSecurityChange(aRequestingContext, (nsIWebProgressListener::STATE_IS_BROKEN |
+           nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
          }
          return NS_OK;
        } else {
          // User has already overriden the pref and the root is not https;
          // mixed content was allowed on an https subframe.
          if (NS_SUCCEEDED(stateRV)) {
            eventSink->OnSecurityChange(aRequestingContext, (State | nsIWebProgressListener::STATE_LOADED_MIXED_ACTIVE_CONTENT));
          }
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -10,31 +10,32 @@
  * loading functionality (eg <embed>, <object>, <applet>, etc).
  */
 
 #ifndef NSOBJECTLOADINGCONTENT_H_
 #define NSOBJECTLOADINGCONTENT_H_
 
 #include "nsImageLoadingContent.h"
 #include "nsIStreamListener.h"
-#include "nsFrameLoader.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsIRunnable.h"
 #include "nsPluginInstanceOwner.h"
 #include "nsIThreadInternal.h"
 #include "nsIFrame.h"
+#include "nsIFrameLoader.h"
 
 class nsAsyncInstantiateEvent;
 class nsStopPluginRunnable;
 class AutoNotifier;
 class AutoFallback;
 class AutoSetInstantiatingToFalse;
 class nsObjectFrame;
+class nsFrameLoader;
 
 class nsObjectLoadingContent : public nsImageLoadingContent
                              , public nsIStreamListener
                              , public nsIFrameLoaderOwner
                              , public nsIObjectLoadingContent
                              , public nsIInterfaceRequestor
                              , public nsIChannelEventSink
 {
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -393,30 +393,16 @@ ParseTypeAttribute(const nsAString& aTyp
   rv = parser.GetParameter("version", versionName);
 
   if (NS_SUCCEEDED(rv)) {
     *aVersion = nsContentUtils::ParseJavascriptVersion(versionName);
   } else if (rv != NS_ERROR_INVALID_ARG) {
     return false;
   }
 
-  nsAutoString value;
-  rv = parser.GetParameter("e4x", value);
-  if (NS_SUCCEEDED(rv)) {
-    if (value.Length() == 1 && value[0] == '1') {
-      // This happens in about 2 web pages. Enable E4X no matter what JS
-      // version number was selected.  We do this by turning on the "moar
-      // XML" version bit.  This is OK even if version has
-      // JSVERSION_UNKNOWN (-1).
-      *aVersion = js::VersionSetMoarXML(*aVersion, true);
-    }
-  } else if (rv != NS_ERROR_INVALID_ARG) {
-    return false;
-  }
-
   return true;
 }
 
 bool
 nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
 {
   // We need a document to evaluate scripts.
   NS_ENSURE_TRUE(mDocument, false);
--- a/content/base/src/nsViewportInfo.cpp
+++ b/content/base/src/nsViewportInfo.cpp
@@ -1,13 +1,14 @@
 /* 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/. */
 
 #include "nsViewportInfo.h"
+#include "mozilla/Assertions.h"
 #include <algorithm>
 
 void
 nsViewportInfo::SetDefaultZoom(const double aDefaultZoom)
 {
   MOZ_ASSERT(aDefaultZoom >= 0.0f);
   mDefaultZoom = aDefaultZoom;
 }
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -26,17 +26,16 @@
 #include "nsCOMArray.h"
 #include "nsJSUtils.h"
 #include "nsTArray.h"
 #include "nsIJSNativeInitializer.h"
 #include "nsIDOMLSProgressEvent.h"
 #include "nsITimer.h"
 #include "nsIDOMProgressEvent.h"
 #include "nsDOMEventTargetHelper.h"
-#include "nsContentUtils.h"
 #include "nsDOMFile.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsISizeOfEventTarget.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/BindingUtils.h"
--- a/content/canvas/src/WebGLBuffer.cpp
+++ b/content/canvas/src/WebGLBuffer.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "WebGLBuffer.h"
 #include "WebGLContext.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 
 WebGLBuffer::WebGLBuffer(WebGLContext *context)
     : WebGLContextBoundObject(context)
     , mHasEverBeenBound(false)
     , mByteLength(0)
     , mTarget(LOCAL_GL_NONE)
--- a/content/canvas/src/WebGLExtensionBase.cpp
+++ b/content/canvas/src/WebGLExtensionBase.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "WebGLContext.h"
 #include "WebGLExtensions.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 
 WebGLExtensionBase::WebGLExtensionBase(WebGLContext* context)
     : WebGLContextBoundObject(context)
 {
     SetIsDOMBinding();
 }
--- a/content/canvas/src/WebGLFramebuffer.cpp
+++ b/content/canvas/src/WebGLFramebuffer.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "WebGLContext.h"
 #include "WebGLFramebuffer.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 
 JSObject*
 WebGLFramebuffer::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap) {
     return dom::WebGLFramebufferBinding::Wrap(cx, scope, this, triedToWrap);
 }
 
--- a/content/canvas/src/WebGLProgram.cpp
+++ b/content/canvas/src/WebGLProgram.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "WebGLContext.h"
 #include "WebGLProgram.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 
 /** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart
   * 
   * \param string input/output: the string to split, becomes the string without the bracket part
   * \param bracketPart output: gets the bracket part.
   * 
--- a/content/canvas/src/WebGLRenderbuffer.cpp
+++ b/content/canvas/src/WebGLRenderbuffer.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "WebGLContext.h"
 #include "WebGLRenderbuffer.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 
 JSObject*
 WebGLRenderbuffer::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap) {
     return dom::WebGLRenderbufferBinding::Wrap(cx, scope, this, triedToWrap);
 }
 
--- a/content/canvas/src/WebGLShader.cpp
+++ b/content/canvas/src/WebGLShader.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #include "WebGLShader.h"
 #include "WebGLContext.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 
 JSObject*
 WebGLShader::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap) {
     return dom::WebGLShaderBinding::Wrap(cx, scope, this, triedToWrap);
 }
 
--- a/content/canvas/src/WebGLTexture.cpp
+++ b/content/canvas/src/WebGLTexture.cpp
@@ -2,16 +2,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/. */
 
 #include "WebGLContext.h"
 #include "WebGLTexture.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include <algorithm>
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 
 JSObject*
 WebGLTexture::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap) {
     return dom::WebGLTextureBinding::Wrap(cx, scope, this, triedToWrap);
 }
 
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -3897,16 +3897,28 @@ public:
                            &aVisitor.mEventStatus);
       }
     }
   }
 
   nsCOMPtr<nsIContent> mTarget;
 };
 
+/*static*/ bool
+nsEventStateManager::IsHandlingUserInput()
+{
+  if (sUserInputEventDepth <= 0) {
+    return false;
+  }
+
+  TimeDuration timeout = nsContentUtils::HandlingUserInputTimeout();
+  return timeout <= TimeDuration(0) ||
+         (TimeStamp::Now() - sHandlingInputStart) <= timeout;
+}
+
 nsIFrame*
 nsEventStateManager::DispatchMouseEvent(nsGUIEvent* aEvent, uint32_t aMessage,
                                         nsIContent* aTargetContent,
                                         nsIContent* aRelatedContent)
 {
   // http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html#methods
   // "[When the mouse is locked on an element...e]vents that require the concept
   // of a mouse cursor must not be dispatched (for example: mouseover, mouseout).
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -21,17 +21,16 @@
 #include "nsIFrameLoader.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsIScrollableFrame.h"
 #include "nsFocusManager.h"
 #include "nsIDocument.h"
 #include "nsEventStates.h"
 #include "mozilla/TimeStamp.h"
-#include "nsContentUtils.h"
 #include "nsIFrame.h"
 
 class nsIPresShell;
 class nsIDocShell;
 class nsIDocShellTreeNode;
 class nsIDocShellTreeItem;
 class imgIContainer;
 class nsDOMDataTransfer;
@@ -170,25 +169,17 @@ public:
    * This includes timers or anything else that is initiated from user input.
    * However, mouse over events are not counted as user input, nor are
    * page load events. If this method is called from asynchronously executed code,
    * such as during layout reflows, it will return false. If more time has elapsed
    * since the user input than is specified by the
    * dom.event.handling-user-input-time-limit pref (default 1 second), this
    * function also returns false.
    */
-  static bool IsHandlingUserInput()
-  {
-    if (sUserInputEventDepth <= 0) {
-      return false;
-    }
-    TimeDuration timeout = nsContentUtils::HandlingUserInputTimeout();
-    return timeout <= TimeDuration(0) ||
-           (TimeStamp::Now() - sHandlingInputStart) <= timeout;
-  }
+  static bool IsHandlingUserInput();
 
   nsPresContext* GetPresContext() { return mPresContext; }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsEventStateManager,
                                            nsIObserver)
 
   static nsIDocument* sMouseOverDocument;
 
--- a/content/html/content/src/HTMLFontElement.cpp
+++ b/content/html/content/src/HTMLFontElement.cpp
@@ -5,16 +5,17 @@
 
 #include "mozilla/Util.h"
 
 #include "HTMLFontElement.h"
 #include "mozilla/dom/HTMLFontElementBinding.h"
 #include "nsAttrValueInlines.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
+#include "nsContentUtils.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Font)
 DOMCI_NODE_DATA(HTMLFontElement, mozilla::dom::HTMLFontElement)
 
 namespace mozilla {
 namespace dom {
 
 HTMLFontElement::~HTMLFontElement()
--- a/content/html/content/src/HTMLObjectElement.cpp
+++ b/content/html/content/src/HTMLObjectElement.cpp
@@ -18,16 +18,17 @@
 #include "nsIDOMSVGDocument.h"
 #include "nsIDOMGetSVGDocument.h"
 #include "nsIDOMHTMLObjectElement.h"
 #include "nsFormSubmission.h"
 #include "nsIObjectFrame.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsIConstraintValidation.h"
 #include "nsIWidget.h"
+#include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 class HTMLObjectElement MOZ_FINAL : public nsGenericHTMLFormElement
                                   , public nsObjectLoadingContent
                                   , public nsIDOMHTMLObjectElement
                                   , public nsIConstraintValidation
@@ -101,18 +102,18 @@ public:
   virtual uint32_t GetCapabilities() const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   nsresult CopyInnerTo(Element* aDest);
 
   void StartObjectLoad() { StartObjectLoad(true); }
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(HTMLObjectElement,
-                                                     nsGenericHTMLFormElement)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLObjectElement,
+                                           nsGenericHTMLFormElement)
 
   virtual nsXPCClassInfo* GetClassInfo();
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
 private:
   /**
    * Calls LoadObject with the correct arguments to start the plugin load.
    */
@@ -166,18 +167,23 @@ HTMLObjectElement::DoneAddingChildren(bo
   // Otherwise, BindToTree takes care of that.
   if (IsInDoc()) {
     StartObjectLoad(aHaveNotified);
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLObjectElement,
                                                   nsGenericHTMLFormElement)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
   nsObjectLoadingContent::Traverse(tmp, cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLObjectElement,
+                                                nsGenericHTMLFormElement)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(HTMLObjectElement, Element)
 NS_IMPL_RELEASE_INHERITED(HTMLObjectElement, Element)
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLObjectElement)
   NS_HTML_CONTENT_INTERFACE_TABLE_BEGIN(HTMLObjectElement)
     NS_INTERFACE_TABLE_ENTRY(HTMLObjectElement, nsIDOMHTMLObjectElement)
     NS_INTERFACE_TABLE_ENTRY(HTMLObjectElement, imgINotificationObserver)
--- a/content/html/content/src/HTMLTableElement.cpp
+++ b/content/html/content/src/HTMLTableElement.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/dom/HTMLTableElement.h"
 #include "nsIDOMHTMLTableSectionElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsRuleData.h"
 #include "nsHTMLStyleSheet.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/dom/HTMLTableElementBinding.h"
+#include "nsContentUtils.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Table)
 DOMCI_NODE_DATA(HTMLTableElement, mozilla::dom::HTMLTableElement)
 
 namespace mozilla {
 namespace dom {
 
 /* ------------------------------ TableRowsCollection -------------------------------- */
--- a/content/html/content/src/HTMLTableRowElement.cpp
+++ b/content/html/content/src/HTMLTableRowElement.cpp
@@ -7,16 +7,18 @@
 
 #include "mozilla/dom/HTMLTableRowElement.h"
 #include "mozilla/dom/HTMLTableElement.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
 #include "nsRuleData.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/HTMLTableRowElementBinding.h"
+#include "nsContentList.h"
+#include "nsContentUtils.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(TableRow)
 DOMCI_NODE_DATA(HTMLTableRowElement, mozilla::dom::HTMLTableRowElement)
 
 namespace mozilla {
 namespace dom {
 
 JSObject*
--- a/content/html/content/src/HTMLTableRowElement.h
+++ b/content/html/content/src/HTMLTableRowElement.h
@@ -5,16 +5,17 @@
 #ifndef mozilla_dom_HTMLTableRowElement_h
 #define mozilla_dom_HTMLTableRowElement_h
 
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLTableRowElement.h"
 
 class nsIDOMHTMLTableElement;
 class nsIDOMHTMLTableSectionElement;
+class nsContentList;
 
 namespace mozilla {
 namespace dom {
 
 class HTMLTableRowElement : public nsGenericHTMLElement,
                             public nsIDOMHTMLTableRowElement
 {
 public:
--- a/content/html/content/src/HTMLTableSectionElement.cpp
+++ b/content/html/content/src/HTMLTableSectionElement.cpp
@@ -6,16 +6,17 @@
 #include "mozilla/Util.h"
 
 #include "mozilla/dom/HTMLTableSectionElement.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
 #include "nsRuleData.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/HTMLTableSectionElementBinding.h"
+#include "nsContentUtils.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(TableSection)
 DOMCI_NODE_DATA(HTMLTableSectionElement, mozilla::dom::HTMLTableSectionElement)
 
 namespace mozilla {
 namespace dom {
 
 // you will see the phrases "rowgroup" and "section" used interchangably
--- a/content/html/content/src/HTMLTableSectionElement.h
+++ b/content/html/content/src/HTMLTableSectionElement.h
@@ -2,16 +2,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 mozilla_dom_HTMLTableSectionElement_h
 #define mozilla_dom_HTMLTableSectionElement_h
 
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLTableSectionElement.h"
+#include "nsContentList.h" // For ctor.
 
 namespace mozilla {
 namespace dom {
 
 class HTMLTableSectionElement : public nsGenericHTMLElement,
                                 public nsIDOMHTMLTableSectionElement
 {
 public:
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -8,17 +8,16 @@
 
 #include "nsMappedAttributeElement.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsINameSpaceManager.h"  // for kNameSpaceID_None
 #include "nsIFormControl.h"
 #include "nsGkAtoms.h"
 #include "nsContentCreatorFunctions.h"
 #include "mozilla/ErrorResult.h"
-#include "nsContentUtils.h"
 #include "nsIDOMHTMLMenuElement.h"
 #include "mozilla/dom/ValidityState.h"
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIDOMNodeList;
 class nsIFrame;
 class nsIStyleRule;
--- a/content/html/content/src/nsHTMLIFrameElement.cpp
+++ b/content/html/content/src/nsHTMLIFrameElement.cpp
@@ -7,16 +7,17 @@
 
 #include "nsHTMLIFrameElement.h"
 #include "nsIDOMSVGDocument.h"
 #include "nsMappedAttributes.h"
 #include "nsAttrValueInlines.h"
 #include "nsError.h"
 #include "nsRuleData.h"
 #include "nsStyleConsts.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
 
 nsHTMLIFrameElement::nsHTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                                          FromParser aFromParser)
@@ -228,10 +229,22 @@ nsHTMLIFrameElement::AfterSetAttr(int32_
             strValue);
         }   
         docshell->SetSandboxFlags(newFlags);
       }
     }
   }
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
                                             aNotify);
+}
 
+uint32_t
+nsHTMLIFrameElement::GetSandboxFlags()
+{
+  nsAutoString sandboxAttr;
+
+  if (GetAttr(kNameSpaceID_None, nsGkAtoms::sandbox, sandboxAttr)) {
+    return nsContentUtils::ParseSandboxAttributeToFlags(sandboxAttr);
+  }
+
+  // No sandbox attribute, no sandbox flags.
+  return 0;
 }
--- a/content/html/content/src/nsHTMLIFrameElement.h
+++ b/content/html/content/src/nsHTMLIFrameElement.h
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "nsGenericHTMLFrameElement.h"
 #include "nsIDOMHTMLIFrameElement.h"
 #include "nsIDOMGetSVGDocument.h"
-#include "nsContentUtils.h"
 
 class nsHTMLIFrameElement : public nsGenericHTMLFrameElement
                           , public nsIDOMHTMLIFrameElement
                           , public nsIDOMGetSVGDocument
 {
 public:
   nsHTMLIFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                       mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER);
@@ -48,24 +47,14 @@ public:
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
   virtual nsXPCClassInfo* GetClassInfo();
   virtual nsIDOMNode* AsDOMNode() { return this; }
 
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue,
                                 bool aNotify);
 
-  uint32_t GetSandboxFlags()
-  {
-    nsAutoString sandboxAttr;
-
-    if (GetAttr(kNameSpaceID_None, nsGkAtoms::sandbox, sandboxAttr)) {
-      return nsContentUtils::ParseSandboxAttributeToFlags(sandboxAttr);
-    }
-
-    // No sandbox attribute, no sandbox flags.
-    return 0;
-  }
+  uint32_t GetSandboxFlags();
 
 protected:
   virtual void GetItemValueText(nsAString& text);
   virtual void SetItemValueText(const nsAString& text);
 };
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -1002,18 +1002,18 @@ nsHTMLInputElement::SetWidth(uint32_t aW
   return nsGenericHTMLElement::SetUnsignedIntAttr(nsGkAtoms::width, aWidth);
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::GetValue(nsAString& aValue)
 {
   nsresult rv = GetValueInternal(aValue);
 
-  // Don't return non-sanitized value for number inputs.
-  if (mType == NS_FORM_INPUT_NUMBER) {
+  // Don't return non-sanitized value for types that are experimental on mobile.
+  if (IsExperimentalMobileType(mType)) {
     SanitizeValue(aValue);
   }
 
   return rv;
 }
 
 nsresult
 nsHTMLInputElement::GetValueInternal(nsAString& aValue) const
@@ -1277,17 +1277,17 @@ nsHTMLInputElement::ConvertNumberToStrin
             MOZ_DOUBLE_IS_NaN(month.toNumber()) ||
             MOZ_DOUBLE_IS_NaN(day.toNumber())) {
           return false;
         }
 
         aResultString.AppendPrintf("%04.0f-%02.0f-%02.0f", year.toNumber(),
                                    month.toNumber() + 1, day.toNumber());
 
-	return true;
+        return true;
       }
     case NS_FORM_INPUT_TIME:
       {
         // Per spec, we need to truncate |aValue| and we should only represent
         // times inside a day [00:00, 24:00[, which means that we should do a
         // modulo on |aValue| using the number of milliseconds in a day (86400000).
         uint32_t value = NS_floorModulo(floor(aValue), 86400000);
 
@@ -1306,17 +1306,17 @@ nsHTMLInputElement::ConvertNumberToStrin
           aResultString.AppendPrintf("%02d:%02d:%02d.%03d",
                                      hours, minutes, seconds, milliseconds);
         } else if (seconds != 0) {
           aResultString.AppendPrintf("%02d:%02d:%02d",
                                      hours, minutes, seconds);
         } else {
           aResultString.AppendPrintf("%02d:%02d", hours, minutes);
         }
-      
+
         return true;
       }
     default:
       MOZ_NOT_REACHED();
       return false;
   }
 }
 
@@ -1440,18 +1440,18 @@ nsHTMLInputElement::SetValueAsNumber(dou
 
   SetValue(aValueAsNumber);
   return NS_OK;
 }
 
 double
 nsHTMLInputElement::GetMinimum() const
 {
-  // Should only be used for <input type='number'/'date'> for the moment.
-  MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE);
+  MOZ_ASSERT(DoesValueAsNumberApply(),
+             "GetMinAsDouble() should only be used for types that allow .valueAsNumber");
 
   // Once we add support for types that have a default minimum/maximum, take
   // account of the default minimum here.
 
   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::min)) {
     return MOZ_DOUBLE_NaN();
   }
 
@@ -1460,18 +1460,18 @@ nsHTMLInputElement::GetMinimum() const
 
   double min;
   return ConvertStringToNumber(minStr, min) ? min : MOZ_DOUBLE_NaN();
 }
 
 double
 nsHTMLInputElement::GetMaximum() const
 {
-  // Should only be used for <input type='number'/'date'> for the moment.
-  MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE);
+  MOZ_ASSERT(DoesValueAsNumberApply(),
+             "GetMaxAsDouble() should only be used for types that allow .valueAsNumber");
 
   // Once we add support for types that have a default minimum/maximum, take
   // account of the default maximum here.
 
   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::max)) {
     return MOZ_DOUBLE_NaN();
   }
 
@@ -1675,18 +1675,17 @@ nsHTMLInputElement::MozSetFileNameArray(
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::MozIsTextField(bool aExcludePassword, bool* aResult)
 {
   // TODO: temporary until bug 635240 and 773205 are fixed.
-  if (mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE ||
-      mType == NS_FORM_INPUT_TIME) {
+  if (IsExperimentalMobileType(mType)) {
     *aResult = false;
     return NS_OK;
   }
 
   *aResult = IsSingleLineTextControl(aExcludePassword);
 
   return NS_OK;
 }
@@ -2478,18 +2477,20 @@ nsHTMLInputElement::PreHandleEvent(nsEve
     aVisitor.mEvent->mFlags.mNoContentDispatch = false;
   }
 
   // We must cache type because mType may change during JS event (bug 2369)
   aVisitor.mItemFlags |= mType;
 
   // Fire onchange (if necessary), before we do the blur, bug 357684.
   if (aVisitor.mEvent->message == NS_BLUR_CONTENT) {
-    // In number inputs we can't allow the user to set an invalid value.
-    if (mType == NS_FORM_INPUT_NUMBER) {
+    // Experimental mobile types rely on the system UI to prevent users to not
+    // set invalid values but we have to be extra-careful. Especially if the
+    // option has been enabled on desktop.
+    if (IsExperimentalMobileType(mType)) {
       nsAutoString aValue;
       GetValueInternal(aValue);
       SetValueInternal(aValue, false, false);
     }
     FireChangeEventIfNeeded();
   }
 
   return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
@@ -2768,20 +2769,18 @@ nsHTMLInputElement::PostHandleEvent(nsEv
            * (c) if there is more than one text input and no submit buttons, do
            *     not submit, period.
            */
 
           if (aVisitor.mEvent->message == NS_KEY_PRESS &&
               (keyEvent->keyCode == NS_VK_RETURN ||
                keyEvent->keyCode == NS_VK_ENTER) &&
                (IsSingleLineTextControl(false, mType) ||
-                mType == NS_FORM_INPUT_NUMBER ||
-                mType == NS_FORM_INPUT_TIME ||
-                mType == NS_FORM_INPUT_DATE)) {
-            FireChangeEventIfNeeded();   
+                IsExperimentalMobileType(mType))) {
+            FireChangeEventIfNeeded();
             rv = MaybeSubmitForm(aVisitor.mPresContext);
             NS_ENSURE_SUCCESS(rv, rv);
           }
 
         } break; // NS_KEY_PRESS || NS_KEY_UP
 
         case NS_MOUSE_BUTTON_DOWN:
         case NS_MOUSE_BUTTON_UP:
@@ -3283,19 +3282,17 @@ nsHTMLInputElement::ParseAttribute(int32
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::type) {
       // XXX ARG!! This is major evilness. ParseAttribute
       // shouldn't set members. Override SetAttr instead
       int32_t newType;
       bool success = aResult.ParseEnumValue(aValue, kInputTypeTable, false);
       if (success) {
         newType = aResult.GetEnumValue();
-        if ((newType == NS_FORM_INPUT_NUMBER ||
-             newType == NS_FORM_INPUT_TIME ||
-             newType == NS_FORM_INPUT_DATE) && 
+        if (IsExperimentalMobileType(newType) &&
             !Preferences::GetBool("dom.experimental_forms", false)) {
           newType = kInputDefaultType->value;
           aResult.SetTo(newType, &aValue);
         }
         if (newType == NS_FORM_INPUT_FILE &&
             Preferences::GetBool("dom.disable_input_file", false)) {
           newType = kInputDefaultType->value;
           aResult.SetTo(newType, &aValue);
@@ -4440,31 +4437,31 @@ nsHTMLInputElement::PlaceholderApplies()
 
   return IsSingleLineTextControl(false);
 }
 
 bool
 nsHTMLInputElement::DoesPatternApply() const
 {
   // TODO: temporary until bug 635240 and bug 773205 are fixed.
-  if (mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE ||
-      mType == NS_FORM_INPUT_TIME) {
+  if (IsExperimentalMobileType(mType)) {
     return false;
   }
 
   return IsSingleLineTextControl(false);
 }
 
 bool
 nsHTMLInputElement::DoesMinMaxApply() const
 {
   switch (mType)
   {
     case NS_FORM_INPUT_NUMBER:
     case NS_FORM_INPUT_DATE:
+    case NS_FORM_INPUT_TIME:
     // TODO:
     // case NS_FORM_INPUT_RANGE:
     // All date/time types.
       return true;
 #ifdef DEBUG
     case NS_FORM_INPUT_RESET:
     case NS_FORM_INPUT_SUBMIT:
     case NS_FORM_INPUT_IMAGE:
@@ -4474,34 +4471,31 @@ nsHTMLInputElement::DoesMinMaxApply() co
     case NS_FORM_INPUT_CHECKBOX:
     case NS_FORM_INPUT_FILE:
     case NS_FORM_INPUT_TEXT:
     case NS_FORM_INPUT_PASSWORD:
     case NS_FORM_INPUT_SEARCH:
     case NS_FORM_INPUT_TEL:
     case NS_FORM_INPUT_EMAIL:
     case NS_FORM_INPUT_URL:
-    // TODO: temp until bug 781572 is fixed.
-    case NS_FORM_INPUT_TIME:
       return false;
     default:
       NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
       return false;
 #else // DEBUG
     default:
       return false;
 #endif // DEBUG
   }
 }
 
 double
 nsHTMLInputElement::GetStep() const
 {
-  MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER || mType == NS_FORM_INPUT_DATE,
-             "We can't be there if type!=number or date!");
+  MOZ_ASSERT(DoesStepApply(), "GetStep() can only be called if @step applies");
 
   // NOTE: should be defaultStep, which is 1 for type=number and date.
   double step = 1;
 
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::step)) {
     nsAutoString stepStr;
     GetAttr(kNameSpaceID_None, nsGkAtoms::step, stepStr);
 
@@ -4651,18 +4645,17 @@ nsHTMLInputElement::HasPatternMismatch()
   nsIDocument* doc = OwnerDoc();
 
   return !nsContentUtils::IsPatternMatching(value, pattern, doc);
 }
 
 bool
 nsHTMLInputElement::IsRangeOverflow() const
 {
-  // Ignore type=time until bug 781572 is fixed.
-  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_TIME) {
+  if (!DoesMinMaxApply()) {
     return false;
   }
 
   double maximum = GetMaximum();
   if (MOZ_DOUBLE_IS_NaN(maximum)) {
     return false;
   }
 
@@ -4945,17 +4938,17 @@ nsHTMLInputElement::GetValidationMessage
 
       nsAutoString maxStr;
       if (mType == NS_FORM_INPUT_NUMBER) {
         //We want to show the value as parsed when it's a number
         double maximum = GetMaximum();
         MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(maximum));
 
         maxStr.AppendFloat(maximum);
-      } else if (mType == NS_FORM_INPUT_DATE) {
+      } else if (mType == NS_FORM_INPUT_DATE || mType == NS_FORM_INPUT_TIME) {
         GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
       } else {
         NS_NOTREACHED("Unexpected input type");
       }
 
       const PRUnichar* params[] = { maxStr.get() };
       rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                  "FormValidationRangeOverflow",
@@ -4968,17 +4961,17 @@ nsHTMLInputElement::GetValidationMessage
       nsXPIDLString message;
 
       nsAutoString minStr;
       if (mType == NS_FORM_INPUT_NUMBER) {
         double minimum = GetMinimum();
         MOZ_ASSERT(!MOZ_DOUBLE_IS_NaN(minimum));
 
         minStr.AppendFloat(minimum);
-      } else if (mType == NS_FORM_INPUT_DATE) {
+      } else if (mType == NS_FORM_INPUT_DATE || mType == NS_FORM_INPUT_TIME) {
         GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
       } else {
         NS_NOTREACHED("Unexpected input type");
       }
 
       const PRUnichar* params[] = { minStr.get() };
       rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                  "FormValidationRangeUnderflow",
@@ -5472,24 +5465,27 @@ nsHTMLInputElement::UpdateValidityUIBits
     mCanShowInvalidUI = true;
     mCanShowValidUI = true;
   }
 }
 
 void
 nsHTMLInputElement::UpdateHasRange()
 {
+  /*
+   * There is a range if min/max applies for the type and if the element
+   * currently have a valid min or max.
+   */
+
   mHasRange = false;
 
-  if (mType != NS_FORM_INPUT_NUMBER && mType != NS_FORM_INPUT_DATE) {
+  if (!DoesMinMaxApply()) {
     return;
   }
 
-  // <input type=number> has a range if min or max is a valid double.
-
   double minimum = GetMinimum();
   if (!MOZ_DOUBLE_IS_NaN(minimum)) {
     mHasRange = true;
     return;
   }
 
   double maximum = GetMaximum();
   if (!MOZ_DOUBLE_IS_NaN(maximum)) {
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -481,27 +481,27 @@ protected:
   /**
    * Returns if the min and max attributes apply for the current type.
    */
   bool DoesMinMaxApply() const;
 
   /**
    * Returns if the step attribute apply for the current type.
    */
-  bool DoesStepApply() const { return DoesMinMaxApply(); }
+  bool DoesStepApply() const { return DoesMinMaxApply() && mType != NS_FORM_INPUT_TIME; }
 
   /**
    * Returns if stepDown and stepUp methods apply for the current type.
    */
   bool DoStepDownStepUpApply() const { return DoesStepApply(); }
 
   /**
    * Returns if valueAsNumber attribute applies for the current type.
    */
-  bool DoesValueAsNumberApply() const { return DoesMinMaxApply() || mType == NS_FORM_INPUT_TIME; }
+  bool DoesValueAsNumberApply() const { return DoesMinMaxApply(); }
 
   /**
    * Returns if the maxlength attribute applies for the current type.
    */
   bool MaxLengthApplies() const { return IsSingleLineTextControl(false, mType); }
 
   void FreeData();
   nsTextEditorState *GetEditorState() const;
@@ -706,16 +706,25 @@ protected:
   /**
    * Apply a step change from stepUp or stepDown by multiplying aStep by the
    * current step value.
    *
    * @param aStep The value used to be multiplied against the step value.
    */
   nsresult ApplyStep(int32_t aStep);
 
+  /**
+   * Returns if the current type is an experimental mobile type.
+   */
+  static bool IsExperimentalMobileType(uint8_t aType)
+  {
+    return aType == NS_FORM_INPUT_NUMBER || aType == NS_FORM_INPUT_DATE ||
+           aType == NS_FORM_INPUT_TIME;
+  }
+
   nsCOMPtr<nsIControllers> mControllers;
 
   /*
    * In mInputData, the mState field is used if IsSingleLineTextControl returns
    * true and mValue is used otherwise.  We have to be careful when handling it
    * on a type change.
    *
    * Accessing the mState member should be done using the GetEditorState function,
--- a/content/html/content/src/nsHTMLSharedObjectElement.cpp
+++ b/content/html/content/src/nsHTMLSharedObjectElement.cpp
@@ -15,16 +15,17 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLAppletElement.h"
 #include "nsIDOMHTMLEmbedElement.h"
 #include "nsThreadUtils.h"
 #include "nsIDOMGetSVGDocument.h"
 #include "nsIDOMSVGDocument.h"
 #include "nsIScriptError.h"
 #include "nsIWidget.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 class nsHTMLSharedObjectElement : public nsGenericHTMLElement
                                 , public nsObjectLoadingContent
                                 , public nsIDOMHTMLAppletElement
                                 , public nsIDOMHTMLEmbedElement
--- a/content/html/content/test/forms/Makefile.in
+++ b/content/html/content/test/forms/Makefile.in
@@ -43,16 +43,16 @@ MOCHITEST_FILES = \
 		test_meter_element.html \
 		test_meter_pseudo-classes.html \
 		test_max_attribute.html \
 		test_min_attribute.html \
 		test_step_attribute.html \
 		test_stepup_stepdown.html \
 		test_valueasnumber_attribute.html \
 		test_experimental_forms_pref.html \
-		test_input_number_value.html \
+		test_input_typing_sanitization.html \
 		test_input_sanitization.html \
 		test_valueasdate_attribute.html \
 		test_input_file_b2g_disabled.html \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
rename from content/html/content/test/forms/test_input_number_value.html
rename to content/html/content/test/forms/test_input_typing_sanitization.html
--- a/content/html/content/test/forms/test_input_number_value.html
+++ b/content/html/content/test/forms/test_input_typing_sanitization.html
@@ -15,121 +15,212 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <iframe name="submit_frame" style="visibility: hidden;"></iframe>
 <div id="content">
   <form id='f' target="submit_frame" action="foo">
     <input name=i id="i" step='any' >
   </form>
 </div>
 <pre id="test">
-<script type="application/javascript">
+<script type="application/javascript;version=1.7">
+
+/*
+ * This test checks that when a user types in some input types, it will not be
+ * in a state where the value will be un-sanitized and usable (by a script).
+ */
 
 var input = document.getElementById('i');
 var form = document.getElementById('f');
 var submitFrame = document.getElementsByTagName('iframe')[0];
 var testData = [];
-var validData =
-[
-  "42",
-  "-42", // should work for negative values
-  "42.1234",
-  "123.12345678912345",  // double precision
-  "1e2", // e should be usable
-  "2e1",
-  "1e-1", // value after e can be negative
-  "1E2", // E can be used instead of e
-];
-var invalidData =
-[
-  "e",
-  "e2",
-  "1e0.1",
-  "foo",
-  "42,13", // comma can't be used as a decimal separator
-];
+var gValidData = [];
+var gInvalidData = [];
 
 function submitForm() {
   form.submit();
 }
 
 function sendKeyEventToSubmitForm() {
   sendKey("return");
 }
 
+function urlify(aStr) {
+  return aStr.replace(':', '%3A', 'g');
+}
+
 function checkValueSubmittedIsValid()
 {
   is(frames['submit_frame'].location.href,
      'http://mochi.test:8888/tests/content/html/content/test/forms/foo?i='
-     + validData[valueIndex++],
+     + urlify(gValidData[valueIndex++]),
      "The submitted value should not have been sanitized");
 
   input.value = "";
 
-  if (valueIndex >= validData.length) {
+  if (valueIndex >= gValidData.length) {
     valueIndex = 0;
     submitFrame.onload = checkValueSubmittedIsInvalid;
-    testData = invalidData;
+    testData = gInvalidData;
   }
-  submitNextValue();
+  testSubmissions();
 }
 
 function checkValueSubmittedIsInvalid()
 {
   is(frames['submit_frame'].location.href,
-        'http://mochi.test:8888/tests/content/html/content/test/forms/foo?i=',
-        "The submitted value should have been sanitized");
+     'http://mochi.test:8888/tests/content/html/content/test/forms/foo?i=',
+     "The submitted value should have been sanitized");
 
   valueIndex++;
   input.value = "";
 
-  if (valueIndex >= invalidData.length) {
+  if (valueIndex >= gInvalidData.length) {
     if (submitMethod == sendKeyEventToSubmitForm) {
-      SimpleTest.finish();
+      try {
+        testRunner.next();
+      } catch (e) {
+        if (e.toString() == '[object StopIteration]') {
+          SimpleTest.finish();
+        } else {
+          throw StopIteration;
+        }
+      }
       return;
     }
     valueIndex = 0;
     submitMethod = sendKeyEventToSubmitForm;
     submitFrame.onload = checkValueSubmittedIsValid;
-    testData = validData;
+    testData = gValidData;
   }
-  submitNextValue();
+  testSubmissions();
 }
 
-function submitNextValue() {
+function testSubmissions() {
   SpecialPowers.focus(input);
   sendString(testData[valueIndex]);
   submitMethod();
 }
 
 var valueIndex = 0;
 var submitMethod = submitForm;
 
 SimpleTest.waitForExplicitFinish();
-addLoadEvent(function () {
-  SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
-    input.type = "number";
 
-    for (data of validData) {
+function runTest()
+{
+  var data = [
+    {
+      type: 'number',
+      validData: [
+        "42",
+        "-42", // should work for negative values
+        "42.1234",
+        "123.12345678912345",  // double precision
+        "1e2", // e should be usable
+        "2e1",
+        "1e-1", // value after e can be negative
+        "1E2", // E can be used instead of e
+      ],
+      invalidData: [
+        "e",
+        "e2",
+        "1e0.1",
+        "foo",
+        "42,13", // comma can't be used as a decimal separator
+      ]
+    },
+    {
+      type: 'date',
+      validData: [
+        '0001-01-01',
+        '2012-12-21',
+        '2013-01-28',
+        '100000-01-01',
+      ],
+      invalidData: [
+        '1-01-01',
+        'a',
+        '-',
+        '2012-01',
+        '2013-01-1',
+        '1011-23-21',
+        '1000-12-99',
+      ]
+    },
+    {
+      type: 'time',
+      validData: [
+        '00:00',
+        '09:09:00',
+        '08:23:23.1',
+        '21:43:56.12',
+        '23:12:45.100',
+      ],
+      invalidData: [
+        '00:',
+        '00:00:',
+        '25:00',
+        '-00:00',
+        '00:00:00.',
+        '00:60',
+        '10:58:99',
+        ':19:10',
+        '23:08:09.1012',
+      ]
+    },
+    { type: 'week', todo: true },
+    { type: 'month', todo: true },
+    { type: 'datetime', todo: true },
+    { type: 'datetime-local', todo: true },
+    { type: 'color', todo: true },
+  ];
+
+  for (test of data) {
+    if (test.todo) {
+      input.type = test.type;
+      todo_is(input.type, test.type, test.type + " is not implemented");
+      continue;
+    }
+
+    input.type = test.type;
+    gValidData = test.validData;
+    gInvalidData = test.invalidData;
+
+    for (data of gValidData) {
       input.value = "";
       SpecialPowers.focus(input);
       sendString(data);
       input.blur();
       is(input.value, data, "valid user input should not be sanitized");
     }
 
-    for (data of invalidData) {
+    for (data of gInvalidData) {
       input.value = "";
       SpecialPowers.focus(input);
       sendString(data);
       input.blur();
       is(input.value, "", "invalid user input should be sanitized");
     }
 
-    testData = validData;
+    input.value = '';
+
+    testData = gValidData;
+    valueIndex = 0;
     submitFrame.onload = checkValueSubmittedIsValid;
-    submitNextValue();
-  });
+    testSubmissions();
+    yield;
+  }
+}
+
+var testRunner = runTest();
+
+addLoadEvent(function () {
+  SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]},
+    function() {
+      testRunner.next();
+    }
+  );
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/forms/test_max_attribute.html
+++ b/content/html/content/test/forms/test_max_attribute.html
@@ -14,40 +14,40 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 635499 **/
 
-var types = [
-  [ 'hidden',         false ],
-  [ 'text',           false ],
-  [ 'search',         false ],
-  [ 'tel',            false ],
-  [ 'url',            false ],
-  [ 'email',          false ],
-  [ 'password',       false ],
-  [ 'datetime',       true,  true ],
-  [ 'date',           true ],
-  [ 'month',          true,  true ],
-  [ 'week',           true,  true ],
-  [ 'time',           true ],
-  [ 'datetime-local', true,  true ],
-  [ 'number',         true ],
-  [ 'range',          true,  true ],
-  [ 'color',          false, true ],
-  [ 'checkbox',       false ],
-  [ 'radio',          false ],
-  [ 'file',           false ],
-  [ 'submit',         false ],
-  [ 'image',          false ],
-  [ 'reset',          false ],
-  [ 'button',         false ],
+var data = [
+  { type: 'hidden', apply: false },
+  { type: 'text', apply: false },
+  { type: 'search', apply: false },
+  { type: 'tel', apply: false },
+  { type: 'url', apply: false },
+  { type: 'email', apply: false },
+  { type: 'password', apply: false },
+  { type: 'datetime', apply: true, todo: true },
+  { type: 'date', apply: true },
+  { type: 'month', apply: true, todo: true },
+  { type: 'week', apply: true, todo: true },
+  { type: 'time', apply: true },
+  { type: 'datetime-local', apply: true, todo: true },
+  { type: 'number', apply: true },
+  { type: 'range', apply: true, todo: true },
+  { type: 'color', apply: false, todo: true },
+  { type: 'checkbox', apply: false },
+  { type: 'radio', apply: false },
+  { type: 'file', apply: false },
+  { type: 'submit', apply: false },
+  { type: 'image', apply: false },
+  { type: 'reset', apply: false },
+  { type: 'button', apply: false },
 ];
 
 var input = document.createElement("input");
 document.getElementById('content').appendChild(input);
 
 function checkValidity(aElement, aValidity, aApply, aRangeApply)
 {
   aValidity = aApply ? aValidity : true;
@@ -74,127 +74,215 @@ function checkValidity(aElement, aValidi
        ":in-range matches status should be " + aValidity);
     is(aElement.mozMatchesSelector(":out-of-range"), !aValidity,
        ":out-of-range matches status should be " + !aValidity);
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
-for (var data of types) {
-  input.type = data[0];
-  var apply = data[1];
+for (var test of data) {
+  input.type = test.type;
+  var apply = test.apply;
 
-  if (data[2]) {
-    todo_is(input.type, data[0], data[0] + " isn't implemented yet");
-    continue;
-  }
-
-  if (input.type == 'time') {
+  if (test.todo) {
+    todo_is(input.type, test.type, test.type + " isn't implemented yet");
     continue;
   }
 
   checkValidity(input, true, apply, false);
 
-  if (input.type == 'date') {
-    input.max = '2012-06-27';
-  } else {
-    input.max = '2';
+  switch (input.type) {
+    case 'hidden':
+    case 'text':
+    case 'search':
+    case 'password':
+    case 'url':
+    case 'tel':
+    case 'email':
+    case 'number':
+    case 'checkbox':
+    case 'radio':
+    case 'file':
+    case 'submit':
+    case 'reset':
+    case 'button':
+    case 'image':
+      input.max = '-1';
+      break;
+    case 'date':
+      input.max = '2012-06-27';
+      break;
+    case 'time':
+      input.max = '02:20';
+      break;
+    default:
+      ok(false, 'please, add a case for this new type (' + input.type + ')');
   }
 
   checkValidity(input, true, apply, apply);
 
-  if (input.type == 'url') {
-    input.value = 'http://mozilla.org';
-    checkValidity(input, true, apply, apply);
-  } else if (input.type == 'email') {
-    input.value = 'foo@bar.com';
-    checkValidity(input, true, apply, apply);
-  } else if (input.type == 'file') {
-    // Need privileges to set a filename with .value.
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  switch (input.type) {
+    case 'text':
+    case 'hidden':
+    case 'search':
+    case 'password':
+    case 'tel':
+    case 'radio':
+    case 'checkbox':
+    case 'reset':
+    case 'button':
+    case 'submit':
+    case 'image':
+      input.value = '0';
+      checkValidity(input, true, apply, apply);
+      break;
+    case 'url':
+      input.value = 'http://mozilla.org';
+      checkValidity(input, true, apply, apply);
+      break;
+    case 'email':
+      input.value = 'foo@bar.com';
+      checkValidity(input, true, apply, apply);
+      break;
+    case 'file':
+      // Need privileges to set a filename with .value.
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
-    var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
-                           .getService(Components.interfaces.nsIProperties);
-    var file = dirSvc.get("ProfD", Components.interfaces.nsIFile);
-    file.append('635499_file');
-    var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
-                    createInstance(Components.interfaces.nsIFileOutputStream);
-    outStream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
-                   0666, 0);
-    outStream.write("foo", 3);
-    outStream.close();
+      var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
+                             .getService(Components.interfaces.nsIProperties);
+      var file = dirSvc.get("ProfD", Components.interfaces.nsIFile);
+      file.append('635499_file');
+      var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
+                      createInstance(Components.interfaces.nsIFileOutputStream);
+      outStream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
+                     0666, 0);
+      outStream.write("foo", 3);
+      outStream.close();
 
-    input.value = file.path;
-    checkValidity(input, true, apply, apply);
+      input.value = file.path;
+      checkValidity(input, true, apply, apply);
 
-    file.remove(false);
-  } else if (input.type == 'date') {
-    input.value = '2012-06-26';
-    checkValidity(input, true, apply, apply);
+      file.remove(false);
+      break;
+    case 'date':
+      input.max = '2012-06-27';
+      input.value = '2012-06-26';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '2012-06-27';
-    checkValidity(input, true, apply, apply);
+      input.value = '2012-06-27';
+      checkValidity(input, true, apply, apply);
+
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2012-06-28';
+      checkValidity(input, false, apply, apply);
 
-    input.value = 'foo';
-    checkValidity(input, true, apply, apply);
+      input.max = '2012-06-30';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '2012-06-28';
-    checkValidity(input, false, apply, apply);
+      input.value = '2012-07-05';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '1000-01-01';
+      checkValidity(input, true, apply, apply);
 
-    input.max = '2012-06-30';
-    checkValidity(input, true, apply, apply);
+      input.value = '20120-01-01';
+      checkValidity(input, false, apply, apply);
+
+      input.max = '0050-01-01';
+      checkValidity(input, false, apply, apply);
 
-    input.value = '2012-07-05';
-    checkValidity(input, false, apply, apply);
+      input.value = '0049-01-01';
+      checkValidity(input, true, apply, apply);
+
+      input.max = '';
+      checkValidity(input, true, apply, false);
 
-    input.value = '1000-01-01';
-    checkValidity(input, true, apply, apply);
+      input.max = 'foo';
+      checkValidity(input, true, apply, false);
+
+      break;
+    case 'number':
+      input.max = '2';
+      input.value = '1';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '20120-01-01';
-    checkValidity(input, false, apply, apply);
+      input.value = '2';
+      checkValidity(input, true, apply, apply);
 
-    input.max = '0050-01-01';
-    checkValidity(input, false, apply, apply);
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '3';
+      checkValidity(input, false, apply, apply);
 
-    input.value = '0049-01-01';
-    checkValidity(input, true, apply, apply);
-  } else {
-    input.value = '1';
-    checkValidity(input, true, apply, apply);
+      input.max = '5';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '42';
+      checkValidity(input, false, apply, apply);
+
+      input.max = '';
+      checkValidity(input, true, apply, false);
 
-    input.value = '2';
-    checkValidity(input, true, apply, apply);
+      input.max = 'foo';
+      checkValidity(input, true, apply, false);
 
-    input.value = 'foo';
-    checkValidity(input, true, apply, apply);
+      // Check that we correctly convert input.max to a double in validationMessage.
+      if (input.type == 'number') {
+        input.max = "4.333333333333333333333333333333333331";
+        input.value = "5";
+        is(input.validationMessage,
+           "Please select a value that is lower than 4.33333333333333.",
+           "validation message");
+      }
 
-    input.value = '3';
-    checkValidity(input, false, apply, apply);
+      break;
+    case 'time':
+      input.max = '10:10';
+      input.value = '10:09';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '10:10';
+      checkValidity(input, true, apply, apply);
 
-    input.max = '5';
-    checkValidity(input, true, apply, apply);
+      input.value = '10:10:00';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '10:10:00.000';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '42';
-    checkValidity(input, false, apply, apply);
-  }
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '10:11';
+      checkValidity(input, false, apply, apply);
 
-  input.max = '';
-  checkValidity(input, true, apply, false);
+      input.value = '10:10:00.001';
+      checkValidity(input, false, apply, apply);
 
-  input.max = 'foo';
-  checkValidity(input, true, apply, false);
+      input.max = '01:00:00.01';
+      input.value = '01:00:00.001';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '01:00:00';
+      checkValidity(input, true, apply, apply);
 
-  // Check that we correctly convert input.max to a double in validationMessage.
-  if (input.type == 'number') {
-    input.max = "4.333333333333333333333333333333333331";
-    input.value = "5";
-    is(input.validationMessage,
-       "Please select a value that is lower than 4.33333333333333.",
-       "validation message");
+      input.value = '01:00:00.1';
+      checkValidity(input, false, apply, apply);
+
+      input.max = '';
+      checkValidity(input, true, apply, false);
+
+      input.max = 'foo';
+      checkValidity(input, true, apply, false);
+
+      break;
   }
 
   // Cleaning up,
   input.removeAttribute('max');
   input.value = '';
 }
 
 SimpleTest.finish();
--- a/content/html/content/test/forms/test_min_attribute.html
+++ b/content/html/content/test/forms/test_min_attribute.html
@@ -14,40 +14,40 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 635553 **/
 
-var types = [
-  [ 'hidden',         false ],
-  [ 'text',           false ],
-  [ 'search',         false ],
-  [ 'tel',            false ],
-  [ 'url',            false ],
-  [ 'email',          false ],
-  [ 'password',       false ],
-  [ 'datetime',       true,  true ],
-  [ 'date',           true ],
-  [ 'month',          true,  true ],
-  [ 'week',           true,  true ],
-  [ 'time',           true ],
-  [ 'datetime-local', true,  true ],
-  [ 'number',         true ],
-  [ 'range',          true,  true ],
-  [ 'color',          false, true ],
-  [ 'checkbox',       false ],
-  [ 'radio',          false ],
-  [ 'file',           false ],
-  [ 'submit',         false ],
-  [ 'image',          false ],
-  [ 'reset',          false ],
-  [ 'button',         false ],
+var data = [
+  { type: 'hidden', apply: false },
+  { type: 'text', apply: false },
+  { type: 'search', apply: false },
+  { type: 'tel', apply: false },
+  { type: 'url', apply: false },
+  { type: 'email', apply: false },
+  { type: 'password', apply: false },
+  { type: 'datetime', apply: true, todo: true },
+  { type: 'date', apply: true },
+  { type: 'month', apply: true, todo: true },
+  { type: 'week', apply: true, todo: true },
+  { type: 'time', apply: true },
+  { type: 'datetime-local', apply: true, todo: true },
+  { type: 'number', apply: true },
+  { type: 'range', apply: true, todo: true },
+  { type: 'color', apply: false, todo: true },
+  { type: 'checkbox', apply: false },
+  { type: 'radio', apply: false },
+  { type: 'file', apply: false },
+  { type: 'submit', apply: false },
+  { type: 'image', apply: false },
+  { type: 'reset', apply: false },
+  { type: 'button', apply: false },
 ];
 
 var input = document.createElement("input");
 document.getElementById('content').appendChild(input);
 
 function checkValidity(aElement, aValidity, aApply, aRangeApply)
 {
   aValidity = aApply ? aValidity : true;
@@ -74,127 +74,221 @@ function checkValidity(aElement, aValidi
        ":in-range matches status should be " + aValidity);
     is(aElement.mozMatchesSelector(":out-of-range"), !aValidity,
        ":out-of-range matches status should be " + !aValidity);
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", true]]}, function() {
-for (var data of types) {
-  input.type = data[0];
-  var apply = data[1];
+for (var test of data) {
+  input.type = test.type;
+  var apply = test.apply;
 
-  if (data[2]) {
-    todo_is(input.type, data[0], data[0] + " isn't implemented yet");
-    continue;
-  }
-
-  if (input.type == 'time') {
+  if (test.todo) {
+    todo_is(input.type, test.type, test.type + " isn't implemented yet");
     continue;
   }
 
+  // The element should be valid. Range should not apply.
   checkValidity(input, true, apply, false);
 
-  if (input.type == 'date') {
-    input.min = '2012-06-27';
-  } else {
-    input.min = '0';
+  switch (input.type) {
+    case 'hidden':
+    case 'text':
+    case 'search':
+    case 'password':
+    case 'url':
+    case 'tel':
+    case 'email':
+    case 'number':
+    case 'checkbox':
+    case 'radio':
+    case 'file':
+    case 'submit':
+    case 'reset':
+    case 'button':
+    case 'image':
+      input.min = '999';
+      break;
+    case 'date':
+      input.min = '2012-06-27';
+      break;
+    case 'time':
+      input.min = '20:20';
+      break;
+    default:
+      ok(false, 'please, add a case for this new type (' + input.type + ')');
   }
 
+  // The element should still be valid and range should apply if it can.
   checkValidity(input, true, apply, apply);
 
-  if (input.type == 'url') {
-    input.value = 'http://mozilla.org';
-    checkValidity(input, true, apply, apply);
-  } else if (input.type == 'email') {
-    input.value = 'foo@bar.com';
-    checkValidity(input, true, apply, apply);
-  } else if (input.type == 'file') {
-    // Need privileges to set a filename with .value.
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  switch (input.type) {
+    case 'text':
+    case 'hidden':
+    case 'search':
+    case 'password':
+    case 'tel':
+    case 'radio':
+    case 'checkbox':
+    case 'reset':
+    case 'button':
+    case 'submit':
+    case 'image':
+      input.value = '0';
+      checkValidity(input, true, apply, apply);
+      break;
+    case 'url':
+      input.value = 'http://mozilla.org';
+      checkValidity(input, true, apply, apply);
+      break;
+    case 'email':
+      input.value = 'foo@bar.com';
+      checkValidity(input, true, apply, apply);
+      break;
+    case 'file':
+      // Need privileges to set a filename with .value.
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
-    var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
-                           .getService(Components.interfaces.nsIProperties);
-    var file = dirSvc.get("ProfD", Components.interfaces.nsIFile);
-    file.append('635499_file');
-    var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
-                    createInstance(Components.interfaces.nsIFileOutputStream);
-    outStream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
-                   0666, 0);
-    outStream.write("foo", 3);
-    outStream.close();
+      var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
+                             .getService(Components.interfaces.nsIProperties);
+      var file = dirSvc.get("ProfD", Components.interfaces.nsIFile);
+      file.append('635499_file');
+      var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"].
+                      createInstance(Components.interfaces.nsIFileOutputStream);
+      outStream.init(file, 0x02 | 0x08 | 0x20, // write, create, truncate
+                     0666, 0);
+      outStream.write("foo", 3);
+      outStream.close();
 
-    input.value = file.path;
-    checkValidity(input, true, apply, apply);
+      input.value = file.path;
+      checkValidity(input, true, apply, apply);
+
+      file.remove(false);
+      break;
+    case 'date':
+      input.value = '2012-06-28';
+      checkValidity(input, true, apply, apply);
 
-    file.remove(false);
-  } else if (input.type == 'date') {
-    input.value = '2012-06-28';
-    checkValidity(input, true, apply, apply);
+      input.value = '2012-06-27';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '2012-06-27';
-    checkValidity(input, true, apply, apply);
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2012-06-26';
+      checkValidity(input, false, apply, apply);
 
-    input.value = 'foo';
-    checkValidity(input, true, apply, apply);
+      input.min = '2012-02-29';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '2012-06-26';
-    checkValidity(input, false, apply, apply);
+      input.value = '2012-02-28';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '1000-01-01';
+      checkValidity(input, false, apply, apply);
 
-    input.min = '2012-02-29';
-    checkValidity(input, true, apply, apply);
+      input.value = '20120-01-01';
+      checkValidity(input, true, apply, apply);
+
+      input.min = '0050-01-01';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '2012-02-28';
-    checkValidity(input, false, apply, apply);
+      input.value = '0049-01-01';
+      checkValidity(input, false, apply, apply);
+
+      input.min = '';
+      checkValidity(input, true, apply, false);
 
-    input.value = '1000-01-01';
-    checkValidity(input, false, apply, apply);
+      input.min = 'foo';
+      checkValidity(input, true, apply, false);
+      break;
+    case 'number':
+      input.min = '0';
+      input.value = '1';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '20120-01-01';
-    checkValidity(input, true, apply, apply);
+      input.value = '0';
+      checkValidity(input, true, apply, apply);
+
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
 
-    input.min = '0050-01-01';
-    checkValidity(input, true, apply, apply);
+      input.value = '-1';
+      checkValidity(input, false, apply, apply);
+
+      input.min = '-1';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '0049-01-01';
-    checkValidity(input, false, apply, apply);
-  } else {
-    input.value = '1';
-    checkValidity(input, true, apply, apply);
+      input.value = '-42';
+      checkValidity(input, false, apply, apply);
+
+      input.min = '';
+      checkValidity(input, true, apply, false);
+
+      input.min = 'foo';
+      checkValidity(input, true, apply, false);
 
-    input.value = '0';
-    checkValidity(input, true, apply, apply);
-
-    input.value = 'foo';
-    checkValidity(input, true, apply, apply);
+      // Check that we correctly convert input.min to a double in
+      // validationMessage.
+      input.min = "4.333333333333333333333333333333333331";
+      input.value = "2";
+      is(input.validationMessage,
+         "Please select a value that is higher than 4.33333333333333.",
+         "validation message");
+      break;
+    case 'time':
+      input.min = '20:20';
+      input.value = '20:20:01';
+      checkValidity(input, true, apply, apply);
 
-    input.value = '-1';
-    checkValidity(input, false, apply, apply);
+      input.value = '20:20:00';
+      checkValidity(input, true, apply, apply);
+
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '10:00';
+      checkValidity(input, false, apply, apply);
 
-    input.min = '-1';
-    checkValidity(input, true, apply, apply);
+      input.min = '20:20:00.001';
+      input.value = '20:20';
+      checkValidity(input, false, apply, apply);
 
-    input.value = '-42';
-    checkValidity(input, false, apply, apply);
-  }
+      input.value = '00:00';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '23:59';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '20:20:01';
+      checkValidity(input, true, apply, apply);
 
-  input.min = '';
-  checkValidity(input, true, apply, false);
+      input.value = '20:20:00.01';
+      checkValidity(input, true, apply, apply);
 
-  input.min = 'foo';
-  checkValidity(input, true, apply, false);
+      input.value = '20:20:00.1';
+      checkValidity(input, true, apply, apply);
+
+      input.min = '00:00:00';
+      input.value = '01:00';
+      checkValidity(input, true, apply, apply);
 
-  // Check that we correctly convert input.min to a double in validationMessage.
-  if (input.type == 'number') {
-    input.min = "4.333333333333333333333333333333333331";
-    input.value = "2";
-    is(input.validationMessage,
-       "Please select a value that is higher than 4.33333333333333.",
-       "validation message");
+      input.value = '00:00:00.000';
+      checkValidity(input, true, apply, apply);
+
+      input.min = '';
+      checkValidity(input, true, apply, false);
+
+      input.min = 'foo';
+      checkValidity(input, true, apply, false);
+      break;
+    default:
+      ok(false, 'write tests for ' + input.type);
   }
 
   // Cleaning up,
   input.removeAttribute('min');
   input.value = '';
 }
 
 SimpleTest.finish();
--- a/content/html/content/test/test_bug598643.html
+++ b/content/html/content/test/test_bug598643.html
@@ -44,20 +44,20 @@ function testFileControl(aElement)
   ok(!aElement.validity.tooLong,
      "the file control shouldn't suffer from being too long");
 }
 
 var types = [
   // These types can be too long.
   [ "text", "email", "password", "url", "search", "tel" ],
   // These types can't be too long.
-  [ "radio", "checkbox", "submit", "button", "reset", "image", "hidden",  ],
+  [ "radio", "checkbox", "submit", "button", "reset", "image", "hidden",
+    'number', 'date', 'time' ],
   // These types can't be too long but are not implemented yet.
-  [ "number", "range", "color", "datetime", "date", "month", "week", "time",
-    "datetime-local" ],
+  [ "range", "color", "datetime", "month", "week", 'datetime-local' ]
 ];
 
 var input = document.createElement("input");
 input.maxLength = 1;
 input.value = "foo";
 
 // Too long types.
 for (type of types[0]) {
@@ -83,19 +83,17 @@ for (type of types[1]) {
   ok(input.validity.valid, "the element should be valid [type=" + type + "]");
   ok(!input.validity.tooLong,
      "the element shouldn't suffer from being too long [type=" + type + "]");
 }
 
 // Not too long types but TODO.
 for (type of types[2]) {
   input.type = type
-  ok(input.validity.valid, "the element should be valid [type=" + type + "]");
-  ok(!input.validity.tooLong,
-     "the element shouldn't suffer from being too long [type=" + type + "]");
+  todo_is(input.type, type, type + " should not be implemented");
 }
 
 testFileControl(input);
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/media/AudioChannelFormat.cpp
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "AudioChannelFormat.h"
+
+#include <algorithm>
+
+namespace mozilla {
+
+enum {
+  SURROUND_L,
+  SURROUND_R,
+  SURROUND_C,
+  SURROUND_LFE,
+  SURROUND_SL,
+  SURROUND_SR
+};
+
+static const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6;
+
+uint32_t
+GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2)
+{
+  if (aChannels1 == 3 && aChannels2 == 4) {
+    // quad layout has no center channel, but input has a center channel as well
+    // as L and R, so we actually need a 5-channel layout here.
+    return 5;
+  }
+  return std::max(aChannels1, aChannels2);
+}
+
+void
+AudioChannelsUpMix(nsTArray<const void*>* aChannelArray,
+                   uint32_t aOutputChannelCount,
+                   const void* aZeroChannel)
+{
+  uint32_t inputChannelCount = aChannelArray->Length();
+  uint32_t outputChannelCount =
+    GetAudioChannelsSuperset(aOutputChannelCount, inputChannelCount);
+  NS_ASSERTION(outputChannelCount > inputChannelCount,
+               "No up-mix needed");
+  NS_ASSERTION(inputChannelCount > 0, "Bad number of channels");
+  NS_ASSERTION(outputChannelCount > 0, "Bad number of channels");
+
+  aChannelArray->SetLength(outputChannelCount);
+
+  if (inputChannelCount < CUSTOM_CHANNEL_LAYOUTS) {
+    const void* surroundChannels[CUSTOM_CHANNEL_LAYOUTS] =
+      { aZeroChannel, aZeroChannel, aZeroChannel,
+        aZeroChannel, aZeroChannel, aZeroChannel
+      };
+    // First just map everything up to 5.1
+    switch (inputChannelCount) {
+    case 1:
+      surroundChannels[SURROUND_C] = aChannelArray->ElementAt(0);
+      break;
+    case 2:
+      surroundChannels[SURROUND_L] = aChannelArray->ElementAt(0);
+      surroundChannels[SURROUND_R] = aChannelArray->ElementAt(1);
+      break;
+    case 3:
+      surroundChannels[SURROUND_L] = aChannelArray->ElementAt(0);
+      surroundChannels[SURROUND_R] = aChannelArray->ElementAt(1);
+      surroundChannels[SURROUND_C] = aChannelArray->ElementAt(2);
+      break;
+    case 4:
+      surroundChannels[SURROUND_L] = aChannelArray->ElementAt(0);
+      surroundChannels[SURROUND_R] = aChannelArray->ElementAt(1);
+      surroundChannels[SURROUND_SL] = aChannelArray->ElementAt(2);
+      surroundChannels[SURROUND_SR] = aChannelArray->ElementAt(3);
+      break;
+    case 5:
+      surroundChannels[SURROUND_L] = aChannelArray->ElementAt(0);
+      surroundChannels[SURROUND_R] = aChannelArray->ElementAt(1);
+      surroundChannels[SURROUND_C] = aChannelArray->ElementAt(2);
+      surroundChannels[SURROUND_SL] = aChannelArray->ElementAt(3);
+      surroundChannels[SURROUND_SR] = aChannelArray->ElementAt(4);
+      break;
+    }
+
+    if (outputChannelCount < CUSTOM_CHANNEL_LAYOUTS) {
+      // Map back to aOutputChannelCount
+      switch (outputChannelCount) {
+      case 2:
+        // Upmix from mono, so use the center channel.
+        aChannelArray->ElementAt(0) = surroundChannels[SURROUND_C];
+        aChannelArray->ElementAt(1) = surroundChannels[SURROUND_C];
+        break;
+      case 3:
+        aChannelArray->ElementAt(0) = surroundChannels[SURROUND_L];
+        aChannelArray->ElementAt(1) = surroundChannels[SURROUND_R];
+        aChannelArray->ElementAt(2) = surroundChannels[SURROUND_C];
+        break;
+      case 4:
+        // We avoided this case up above.
+        NS_ASSERTION(inputChannelCount != 3,
+                     "3->4 upmix not supported directly");
+        if (inputChannelCount == 1) {
+          // Output has no center channel, so map the mono to
+          // L+R channels per Web Audio
+          aChannelArray->ElementAt(0) = surroundChannels[SURROUND_C];
+          aChannelArray->ElementAt(1) = surroundChannels[SURROUND_C];
+        } else {
+          aChannelArray->ElementAt(0) = surroundChannels[SURROUND_L];
+          aChannelArray->ElementAt(1) = surroundChannels[SURROUND_R];
+        }
+        aChannelArray->ElementAt(2) = surroundChannels[SURROUND_SL];
+        aChannelArray->ElementAt(3) = surroundChannels[SURROUND_SR];
+        break;
+      case 5:
+        aChannelArray->ElementAt(0) = surroundChannels[SURROUND_L];
+        aChannelArray->ElementAt(1) = surroundChannels[SURROUND_R];
+        aChannelArray->ElementAt(2) = surroundChannels[SURROUND_C];
+        aChannelArray->ElementAt(3) = surroundChannels[SURROUND_SL];
+        aChannelArray->ElementAt(4) = surroundChannels[SURROUND_SR];
+      }
+      return;
+    }
+
+    memcpy(aChannelArray->Elements(), surroundChannels, sizeof(surroundChannels));
+    inputChannelCount = CUSTOM_CHANNEL_LAYOUTS;
+  }
+
+  for (uint32_t i = inputChannelCount; i < outputChannelCount; ++i) {
+    aChannelArray->ElementAt(i) = aZeroChannel;
+  }
+}
+
+/**
+ * DownMixMatrix represents a conversion matrix efficiently by exploiting the
+ * fact that each input channel contributes to at most one output channel,
+ * except possibly for the C input channel in layouts that have one. Also,
+ * every input channel is multiplied by the same coefficient for every output
+ * channel it contributes to.
+ */
+struct DownMixMatrix {
+  // Every input channel c is copied to output channel mInputDestination[c]
+  // after multiplying by mInputCoefficient[c].
+  uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS];
+  // If not IGNORE, then the C channel is copied to this output channel after
+  // multiplying by its coefficient.
+  uint8_t mCExtraDestination;
+  float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS];
+};
+
+static const int IGNORE = CUSTOM_CHANNEL_LAYOUTS;
+static const float IGNORE_F = 0.0f;
+
+static const DownMixMatrix
+gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
+{
+  // Downmixes to mono
+  { { 0, 0 }, IGNORE, { 0.5f, 0.5f } },
+  { { 0, 0, 0 }, IGNORE, { 0.3333f, 0.3333f, 0.3333f } },
+  { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } },
+  { { 0, 0, 0, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, 0.5f, 0.5f } },
+  { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, IGNORE_F, 0.5f, 0.5f } },
+  // Downmixes to stereo
+  { { 0, 1, 0 }, 1, { 1.0f, 1.0f, 0.7071f } },
+  { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } },
+  { { 0, 1, 0, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, 0.7071f, 0.7071f } },
+  { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 0.7071f, 0.7071f } },
+  // Downmixes to 3-channel
+  { { 0, 1, 0, 1 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } },
+  { { 0, 1, 2, 0, 1 }, IGNORE, { 0.5f, 0.5f, 1.0f, 0.5f, 0.5f } },
+  { { 0, 1, 2, IGNORE, 0, 1 }, IGNORE, { 0.5f, 0.5f, 1.0f, IGNORE_F, 0.5f, 0.5f } },
+  // Downmixes to quad
+  { { 0, 1, 0, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, 1.0f, 1.0f } },
+  { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 1.0f, 1.0f } },
+  // Downmixes to 5-channel
+  { { 0, 1, 2, IGNORE, 3, 4 }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, 1.0f, 1.0f } }
+};
+
+static const int gDownMixMatrixIndexByOutputChannels[CUSTOM_CHANNEL_LAYOUTS - 1] =
+  { 0, 5, 9, 12, 14 };
+
+void
+AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray,
+                     float** aOutputChannels,
+                     uint32_t aOutputChannelCount,
+                     uint32_t aDuration)
+{
+  uint32_t inputChannelCount = aChannelArray.Length();
+  const void* const* inputChannels = aChannelArray.Elements();
+  NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do");
+
+  if (aOutputChannelCount >= 6) {
+    // Just drop the unknown channels.
+    for (uint32_t o = 0; o < aOutputChannelCount; ++o) {
+      memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(float));
+    }
+    return;
+  }
+
+  // Ignore unknown channels, they're just dropped.
+  inputChannelCount = std::min<uint32_t>(6, inputChannelCount);
+
+  const DownMixMatrix& m = gDownMixMatrices[
+    gDownMixMatrixIndexByOutputChannels[aOutputChannelCount - 1] +
+    inputChannelCount - aOutputChannelCount - 1];
+
+  // This is slow, but general. We can define custom code for special
+  // cases later.
+  for (uint32_t s = 0; s < aDuration; ++s) {
+    // Reserve an extra junk channel at the end for the cases where we
+    // want an input channel to contribute to nothing
+    float outputChannels[CUSTOM_CHANNEL_LAYOUTS];
+    memset(outputChannels, 0, sizeof(float)*(CUSTOM_CHANNEL_LAYOUTS - 1));
+    for (uint32_t c = 0; c < inputChannelCount; ++c) {
+      outputChannels[m.mInputDestination[c]] +=
+        m.mInputCoefficient[c]*(static_cast<const float*>(inputChannels[c]))[s];
+    }
+    // Utilize the fact that in every layout, C is the third channel.
+    if (m.mCExtraDestination != IGNORE) {
+      outputChannels[m.mCExtraDestination] +=
+        m.mInputCoefficient[SURROUND_C]*(static_cast<const float*>(inputChannels[SURROUND_C]))[s];
+    }
+
+    for (uint32_t c = 0; c < aOutputChannelCount; ++c) {
+      aOutputChannels[c][s] = outputChannels[c];
+    }
+  }
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/content/media/AudioChannelFormat.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 MOZILLA_AUDIOCHANNELFORMAT_H_
+#define MOZILLA_AUDIOCHANNELFORMAT_H_
+
+#include "nsTArray.h"
+
+namespace mozilla {
+
+/*
+ * This file provides utilities for upmixing and downmixing channels.
+ *
+ * The channel layouts, upmixing and downmixing are consistent with the
+ * Web Audio spec.
+ *
+ * Channel layouts for up to 6 channels:
+ *   mono   { M }
+ *   stereo { L, R }
+ *          { L, R, C }
+ *   quad   { L, R, SL, SR }
+ *          { L, R, C, SL, SR }
+ *   5.1    { L, R, C, LFE, SL, SR }
+ *
+ * Only 1, 2, 4 and 6 are currently defined in Web Audio.
+ */
+
+/**
+ * Return a channel count whose channel layout includes all the channels from
+ * aChannels1 and aChannels2.
+ */
+uint32_t
+GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2);
+
+/**
+ * Given an array of input channel data, and an output channel count,
+ * replaces the array with an array of upmixed channels.
+ * This shuffles the array and may set some channel buffers to aZeroChannel.
+ * Don't call this with input count >= output count.
+ * This may return *more* channels than requested. In that case, downmixing
+ * is required to to get to aOutputChannelCount. (This is how we handle
+ * odd cases like 3 -> 4 upmixing.)
+ * If aChannelArray.Length() was the input to one of a series of
+ * GetAudioChannelsSuperset calls resulting in aOutputChannelCount,
+ * no downmixing will be required.
+ */
+void
+AudioChannelsUpMix(nsTArray<const void*>* aChannelArray,
+                   uint32_t aOutputChannelCount,
+                   const void* aZeroChannel);
+
+/**
+ * Given an array of input channels (which must be float format!),
+ * downmix to aOutputChannelCount, and copy the results to the
+ * channel buffers in aOutputChannels.
+ * Don't call this with input count <= output count.
+ */
+void
+AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray,
+                     float** aOutputChannels,
+                     uint32_t aOutputChannelCount,
+                     uint32_t aDuration);
+
+// A version of AudioChannelsDownMix that downmixes int16_ts may be required.
+
+} // namespace mozilla
+
+#endif /* MOZILLA_AUDIOCHANNELFORMAT_H_ */
--- a/content/media/AudioSampleFormat.h
+++ b/content/media/AudioSampleFormat.h
@@ -27,16 +27,20 @@ enum AudioSampleFormat
   // The format used for output by AudioStream.
 #ifdef MOZ_SAMPLE_TYPE_S16
   AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_S16
 #else
   AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_FLOAT32
 #endif
 };
 
+enum {
+  MAX_AUDIO_SAMPLE_SIZE = sizeof(float)
+};
+
 template <AudioSampleFormat Format> class AudioSampleTraits;
 
 template <> class AudioSampleTraits<AUDIO_FORMAT_FLOAT32> {
 public:
   typedef float Type;
 };
 template <> class AudioSampleTraits<AUDIO_FORMAT_S16> {
 public:
@@ -148,22 +152,19 @@ ScaleAudioSamples(short* aBuffer, int aC
     aBuffer[i] = short((int32_t(aBuffer[i]) * volume) >> 16);
   }
 }
 
 inline const void*
 AddAudioSampleOffset(const void* aBase, AudioSampleFormat aFormat,
                      int32_t aOffset)
 {
-  switch (aFormat) {
-  case AUDIO_FORMAT_FLOAT32:
-    return static_cast<const float*>(aBase) + aOffset;
-  case AUDIO_FORMAT_S16:
-    return static_cast<const int16_t*>(aBase) + aOffset;
-  default:
-    NS_ERROR("Unknown format");
-    return nullptr;
-  }
+  MOZ_STATIC_ASSERT(AUDIO_FORMAT_S16 == 0, "Bad constant");
+  MOZ_STATIC_ASSERT(AUDIO_FORMAT_FLOAT32 == 1, "Bad constant");
+  NS_ASSERTION(aFormat == AUDIO_FORMAT_S16 || aFormat == AUDIO_FORMAT_FLOAT32,
+               "Unknown format");
+
+  return static_cast<const uint8_t*>(aBase) + (aFormat + 1)*2*aOffset;
 }
 
 } // namespace mozilla
 
 #endif /* MOZILLA_AUDIOSAMPLEFORMAT_H_ */
--- a/content/media/AudioSegment.cpp
+++ b/content/media/AudioSegment.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "AudioSegment.h"
 
 #include "AudioStream.h"
+#include "AudioChannelFormat.h"
 
 namespace mozilla {
 
 template <class SrcT, class DestT>
 static void
 InterleaveAndConvertBuffer(const SrcT** aSourceChannels,
                            int32_t aLength, float aVolume,
                            int32_t aChannels,
@@ -82,37 +83,94 @@ InterleaveAndConvertBuffer(const void** 
 void
 AudioSegment::ApplyVolume(float aVolume)
 {
   for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
     ci->mVolume *= aVolume;
   }
 }
 
-static const int STATIC_AUDIO_SAMPLES = 10000;
+static const int AUDIO_PROCESSING_FRAMES = 640; /* > 10ms of 48KHz audio */
+static const int GUESS_AUDIO_CHANNELS = 2;
+static const uint8_t gZeroChannel[MAX_AUDIO_SAMPLE_SIZE*AUDIO_PROCESSING_FRAMES] = {0};
 
 void
 AudioSegment::WriteTo(AudioStream* aOutput)
 {
-  NS_ASSERTION(mChannels == aOutput->GetChannels(), "Wrong number of channels");
-  nsAutoTArray<AudioDataValue,STATIC_AUDIO_SAMPLES> buf;
+  uint32_t outputChannels = aOutput->GetChannels();
+  nsAutoTArray<AudioDataValue,AUDIO_PROCESSING_FRAMES*GUESS_AUDIO_CHANNELS> buf;
+  nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> channelData;
+  nsAutoTArray<float,AUDIO_PROCESSING_FRAMES*GUESS_AUDIO_CHANNELS> downmixConversionBuffer;
+  nsAutoTArray<float,AUDIO_PROCESSING_FRAMES*GUESS_AUDIO_CHANNELS> downmixOutputBuffer;
+
   for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
     AudioChunk& c = *ci;
-    if (uint64_t(mChannels)*c.mDuration > INT32_MAX) {
-      NS_ERROR("Buffer overflow");
-      return;
+    TrackTicks offset = 0;
+    while (offset < c.mDuration) {
+      TrackTicks durationTicks =
+        std::min<TrackTicks>(c.mDuration - offset, AUDIO_PROCESSING_FRAMES);
+      if (uint64_t(outputChannels)*durationTicks > INT32_MAX || offset > INT32_MAX) {
+        NS_ERROR("Buffer overflow");
+        return;
+      }
+      uint32_t duration = uint32_t(durationTicks);
+      buf.SetLength(outputChannels*duration);
+      if (c.mBuffer) {
+        channelData.SetLength(c.mChannelData.Length());
+        for (uint32_t i = 0; i < channelData.Length(); ++i) {
+          channelData[i] =
+            AddAudioSampleOffset(c.mChannelData[i], c.mBufferFormat, int32_t(offset));
+        }
+
+        if (channelData.Length() < outputChannels) {
+          // Up-mix. Note that this might actually make channelData have more
+          // than outputChannels temporarily.
+          AudioChannelsUpMix(&channelData, outputChannels, gZeroChannel);
+        }
+
+        if (channelData.Length() > outputChannels) {
+          // Down-mix.
+          if (c.mBufferFormat != AUDIO_FORMAT_FLOAT32) {
+            NS_ASSERTION(c.mBufferFormat == AUDIO_FORMAT_S16, "unknown format");
+            downmixConversionBuffer.SetLength(duration*channelData.Length());
+            for (uint32_t i = 0; i < channelData.Length(); ++i) {
+              float* conversionBuf = downmixConversionBuffer.Elements() + (i*duration);
+              const int16_t* sourceBuf = static_cast<const int16_t*>(channelData[i]);
+              for (uint32_t j = 0; j < duration; ++j) {
+                conversionBuf[j] = AudioSampleToFloat(sourceBuf[j]);
+              }
+              channelData[i] = conversionBuf;
+            }
+          }
+
+          downmixOutputBuffer.SetLength(duration*outputChannels);
+          nsAutoTArray<float*,GUESS_AUDIO_CHANNELS> outputChannelBuffers;
+          nsAutoTArray<const void*,GUESS_AUDIO_CHANNELS> outputChannelData;
+          outputChannelBuffers.SetLength(outputChannels);
+          outputChannelData.SetLength(outputChannels);
+          for (uint32_t i = 0; i < outputChannels; ++i) {
+            outputChannelData[i] = outputChannelBuffers[i] =
+                downmixOutputBuffer.Elements() + duration*i;
+          }
+          AudioChannelsDownMix(channelData, outputChannelBuffers.Elements(),
+                               outputChannels, duration);
+          InterleaveAndConvertBuffer(outputChannelData.Elements(), AUDIO_FORMAT_FLOAT32,
+                                     duration, c.mVolume,
+                                     outputChannels,
+                                     buf.Elements());
+        } else {
+          InterleaveAndConvertBuffer(channelData.Elements(), c.mBufferFormat,
+                                     duration, c.mVolume,
+                                     outputChannels,
+                                     buf.Elements());
+        }
+      } else {
+        // Assumes that a bit pattern of zeroes == 0.0f
+        memset(buf.Elements(), 0, buf.Length()*sizeof(AudioDataValue));
+      }
+      aOutput->Write(buf.Elements(), int32_t(duration));
+      offset += duration;
     }
-    buf.SetLength(int32_t(mChannels*c.mDuration));
-    if (c.mBuffer) {
-      InterleaveAndConvertBuffer(c.mChannelData.Elements(), c.mBufferFormat,
-                                 int32_t(c.mDuration), c.mVolume,
-                                 aOutput->GetChannels(),
-                                 buf.Elements());
-    } else {
-      // Assumes that a bit pattern of zeroes == 0.0f
-      memset(buf.Elements(), 0, buf.Length()*sizeof(AudioDataValue));
-    }
-    aOutput->Write(buf.Elements(), int32_t(c.mDuration));
   }
   aOutput->Start();
 }
 
 }
--- a/content/media/AudioSegment.h
+++ b/content/media/AudioSegment.h
@@ -82,81 +82,54 @@ struct AudioChunk {
 /**
  * A list of audio samples consisting of a sequence of slices of SharedBuffers.
  * The audio rate is determined by the track, not stored in this class.
  */
 class AudioSegment : public MediaSegmentBase<AudioSegment, AudioChunk> {
 public:
   typedef mozilla::AudioSampleFormat SampleFormat;
 
-  AudioSegment() : MediaSegmentBase<AudioSegment, AudioChunk>(AUDIO), mChannels(0) {}
+  AudioSegment() : MediaSegmentBase<AudioSegment, AudioChunk>(AUDIO) {}
 
-  bool IsInitialized()
-  {
-    return mChannels > 0;
-  }
-  void Init(int32_t aChannels)
-  {
-    NS_ASSERTION(aChannels > 0, "Bad number of channels");
-    NS_ASSERTION(!IsInitialized(), "Already initialized");
-    mChannels = aChannels;
-  }
-  int32_t GetChannels()
-  {
-    NS_ASSERTION(IsInitialized(), "Not initialized");
-    return mChannels;
-  }
   void AppendFrames(already_AddRefed<ThreadSharedObject> aBuffer,
                     const nsTArray<const float*>& aChannelData,
                     int32_t aDuration)
   {
-    NS_ASSERTION(mChannels > 0, "Not initialized");
-    NS_ASSERTION(!aBuffer.get() || aChannelData.Length() == uint32_t(mChannels),
-                 "Wrong number of channels");
     AudioChunk* chunk = AppendChunk(aDuration);
     chunk->mBuffer = aBuffer;
     for (uint32_t channel = 0; channel < aChannelData.Length(); ++channel) {
       chunk->mChannelData.AppendElement(aChannelData[channel]);
     }
     chunk->mVolume = 1.0f;
     chunk->mBufferFormat = AUDIO_FORMAT_FLOAT32;
   }
   void AppendFrames(already_AddRefed<ThreadSharedObject> aBuffer,
                     const nsTArray<const int16_t*>& aChannelData,
                     int32_t aDuration)
   {
-    NS_ASSERTION(mChannels > 0, "Not initialized");
-    NS_ASSERTION(!aBuffer.get() || aChannelData.Length() == uint32_t(mChannels),
-                 "Wrong number of channels");
     AudioChunk* chunk = AppendChunk(aDuration);
     chunk->mBuffer = aBuffer;
     for (uint32_t channel = 0; channel < aChannelData.Length(); ++channel) {
       chunk->mChannelData.AppendElement(aChannelData[channel]);
     }
     chunk->mVolume = 1.0f;
     chunk->mBufferFormat = AUDIO_FORMAT_S16;
   }
+  // Consumes aChunk, and returns a pointer to the persistent copy of aChunk
+  // in the segment.
+  AudioChunk* AppendAndConsumeChunk(AudioChunk* aChunk)
+  {
+    AudioChunk* chunk = AppendChunk(aChunk->mDuration);
+    chunk->mBuffer = aChunk->mBuffer.forget();
+    chunk->mChannelData.SwapElements(aChunk->mChannelData);
+    chunk->mVolume = aChunk->mVolume;
+    chunk->mBufferFormat = aChunk->mBufferFormat;
+    return chunk;
+  }
   void ApplyVolume(float aVolume);
-  /**
-   * aOutput must have a matching number of channels, but we will automatically
-   * convert sample formats.
-   */
   void WriteTo(AudioStream* aOutput);
 
-  // Segment-generic methods not in MediaSegmentBase
-  void InitFrom(const AudioSegment& aOther)
-  {
-    NS_ASSERTION(mChannels == 0, "Channels already set");
-    mChannels = aOther.mChannels;
-  }
-  void CheckCompatible(const AudioSegment& aOther) const
-  {
-    NS_ASSERTION(aOther.mChannels == mChannels, "Non-matching channels");
-  }
   static Type StaticType() { return AUDIO; }
-
-protected:
-  int32_t mChannels;
 };
 
 }
 
 #endif /* MOZILLA_AUDIOSEGMENT_H_ */
--- a/content/media/Makefile.in
+++ b/content/media/Makefile.in
@@ -13,16 +13,17 @@ MODULE = content
 LIBRARY_NAME = gkconmedia_s
 LIBXUL_LIBRARY = 1
 ifndef _MSC_VER
 FAIL_ON_WARNINGS := 1
 endif # !_MSC_VER
 
 EXPORTS = \
   AbstractMediaDecoder.h \
+  AudioChannelFormat.h \
   AudioSampleFormat.h \
   AudioSegment.h \
   BufferMediaResource.h \
   DecoderTraits.h \
   FileBlockCache.h \
   MediaDecoderOwner.h \
   MediaResource.h \
   MediaSegment.h \
@@ -39,16 +40,17 @@ EXPORTS = \
   VideoFrameContainer.h \
   VideoUtils.h \
   VideoSegment.h \
   VorbisUtils.h \
   MediaMetadataManager.h \
   $(NULL)
 
 CPPSRCS = \
+  AudioChannelFormat.cpp \
   AudioSegment.cpp \
   DecoderTraits.cpp \
   FileBlockCache.cpp \
   MediaResource.cpp \
   MediaStreamGraph.cpp \
   AudioAvailableEventManager.cpp \
   MediaDecoder.cpp \
   MediaDecoderStateMachine.cpp \
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -512,32 +512,28 @@ void MediaDecoderStateMachine::SendStrea
 
   if (aAudio->mTime <= aStream->mLastAudioPacketTime) {
     // ignore packet that we've already processed
     return;
   }
   aStream->mLastAudioPacketTime = aAudio->mTime;
   aStream->mLastAudioPacketEndTime = aAudio->GetEnd();
 
-  NS_ASSERTION(aOutput->GetChannels() == int32_t(aAudio->mChannels),
-               "Wrong number of channels");
-
   // This logic has to mimic AudioLoop closely to make sure we write
   // the exact same silences
   CheckedInt64 audioWrittenOffset = UsecsToFrames(mInfo.mAudioRate,
       aStream->mInitialTime + mStartTime) + aStream->mAudioFramesWritten;
   CheckedInt64 frameOffset = UsecsToFrames(mInfo.mAudioRate, aAudio->mTime);
   if (!audioWrittenOffset.isValid() || !frameOffset.isValid())
     return;
   if (audioWrittenOffset.value() < frameOffset.value()) {
     // Write silence to catch up
     LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of silence to MediaStream",
                        mDecoder.get(), int32_t(frameOffset.value() - audioWrittenOffset.value())));
     AudioSegment silence;
-    silence.InitFrom(*aOutput);
     silence.InsertNullDataAtStart(frameOffset.value() - audioWrittenOffset.value());
     aStream->mAudioFramesWritten += silence.GetDuration();
     aOutput->AppendFrom(&silence);
   }
 
   int64_t offset;
   if (aStream->mAudioFramesWritten == 0) {
     NS_ASSERTION(frameOffset.value() <= audioWrittenOffset.value(),
@@ -599,33 +595,31 @@ void MediaDecoderStateMachine::SendStrea
 
   int64_t minLastAudioPacketTime = INT64_MAX;
   SourceMediaStream* mediaStream = stream->mStream;
   StreamTime endPosition = 0;
 
   if (!stream->mStreamInitialized) {
     if (mInfo.mHasAudio) {
       AudioSegment* audio = new AudioSegment();
-      audio->Init(mInfo.mAudioChannels);
       mediaStream->AddTrack(TRACK_AUDIO, mInfo.mAudioRate, 0, audio);
     }
     if (mInfo.mHasVideo) {
       VideoSegment* video = new VideoSegment();
       mediaStream->AddTrack(TRACK_VIDEO, RATE_VIDEO, 0, video);
     }
     stream->mStreamInitialized = true;
   }
 
   if (mInfo.mHasAudio) {
     nsAutoTArray<AudioData*,10> audio;
     // It's OK to hold references to the AudioData because while audio
     // is captured, only the decoder thread pops from the queue (see below).
     mReader->AudioQueue().GetElementsAfter(stream->mLastAudioPacketTime, &audio);
     AudioSegment output;
-    output.Init(mInfo.mAudioChannels);
     for (uint32_t i = 0; i < audio.Length(); ++i) {
       SendStreamAudio(audio[i], stream, &output);
     }
     if (output.GetDuration() > 0) {
       mediaStream->AppendToTrack(TRACK_AUDIO, &output);
     }
     if (mReader->AudioQueue().IsFinished() && !stream->mHaveSentFinishAudio) {
       mediaStream->EndTrack(TRACK_AUDIO);
--- a/content/media/MediaSegment.h
+++ b/content/media/MediaSegment.h
@@ -114,19 +114,17 @@ protected:
 /**
  * C is the implementation class subclassed from MediaSegmentBase.
  * C must contain a Chunk class.
  */
 template <class C, class Chunk> class MediaSegmentBase : public MediaSegment {
 public:
   virtual MediaSegment* CreateEmptyClone() const
   {
-    C* s = new C();
-    s->InitFrom(*static_cast<const C*>(this));
-    return s;
+    return new C();
   }
   virtual void AppendFrom(MediaSegment* aSource)
   {
     NS_ASSERTION(aSource->GetType() == C::StaticType(), "Wrong type");
     AppendFromInternal(static_cast<C*>(aSource));
   }
   void AppendFrom(C* aSource)
   {
@@ -137,21 +135,16 @@ public:
   {
     NS_ASSERTION(aSource.GetType() == C::StaticType(), "Wrong type");
     AppendSliceInternal(static_cast<const C&>(aSource), aStart, aEnd);
   }
   void AppendSlice(const C& aOther, TrackTicks aStart, TrackTicks aEnd)
   {
     AppendSliceInternal(aOther, aStart, aEnd);
   }
-  void InitToSlice(const C& aOther, TrackTicks aStart, TrackTicks aEnd)
-  {
-    static_cast<C*>(this)->InitFrom(aOther);
-    AppendSliceInternal(aOther, aStart, aEnd);
-  }
   /**
    * Replace the first aDuration ticks with null media data, because the data
    * will not be required again.
    */
   virtual void ForgetUpTo(TrackTicks aDuration)
   {
     if (mChunks.IsEmpty() || aDuration <= 0) {
       return;
@@ -210,32 +203,30 @@ public:
 protected:
   MediaSegmentBase(Type aType) : MediaSegment(aType) {}
 
   /**
    * Appends the contents of aSource to this segment, clearing aSource.
    */
   void AppendFromInternal(MediaSegmentBase<C, Chunk>* aSource)
   {
-    static_cast<C*>(this)->CheckCompatible(*static_cast<C*>(aSource));
     MOZ_ASSERT(aSource->mDuration >= 0);
     mDuration += aSource->mDuration;
     aSource->mDuration = 0;
     if (!mChunks.IsEmpty() && !aSource->mChunks.IsEmpty() &&
         mChunks[mChunks.Length() - 1].CanCombineWithFollowing(aSource->mChunks[0])) {
       mChunks[mChunks.Length() - 1].mDuration += aSource->mChunks[0].mDuration;
       aSource->mChunks.RemoveElementAt(0);
     }
     mChunks.MoveElementsFrom(aSource->mChunks);
   }
 
   void AppendSliceInternal(const MediaSegmentBase<C, Chunk>& aSource,
                            TrackTicks aStart, TrackTicks aEnd)
   {
-    static_cast<C*>(this)->CheckCompatible(static_cast<const C&>(aSource));
     NS_ASSERTION(aStart <= aEnd, "Endpoints inverted");
     NS_ASSERTION(aStart >= 0 && aEnd <= aSource.mDuration,
                  "Slice out of range");
     mDuration += aEnd - aStart;
     TrackTicks offset = 0;
     for (uint32_t i = 0; i < aSource.mChunks.Length() && offset < aEnd; ++i) {
       const Chunk& c = aSource.mChunks[i];
       TrackTicks start = std::max(aStart, offset);
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -1153,24 +1153,24 @@ MediaStreamGraphImpl::CreateOrDestroyAud
           // The stream wants to play audio, but nothing will play for the forseeable
           // future, so don't create the stream.
           continue;
         }
 
         // XXX allocating a AudioStream could be slow so we're going to have to do
         // something here ... preallocation, async allocation, multiplexing onto a single
         // stream ...
-        AudioSegment* audio = tracks->Get<AudioSegment>();
         MediaStream::AudioOutputStream* audioOutputStream =
           aStream->mAudioOutputStreams.AppendElement();
         audioOutputStream->mAudioPlaybackStartTime = aAudioOutputStartTime;
         audioOutputStream->mBlockedAudioTime = 0;
         audioOutputStream->mStream = AudioStream::AllocateStream();
-        audioOutputStream->mStream->Init(audio->GetChannels(),
-                                         tracks->GetRate(), AUDIO_CHANNEL_NORMAL);
+        // XXX for now, allocate stereo output. But we need to fix this to
+        // match the system's ideal channel configuration.
+        audioOutputStream->mStream->Init(2, tracks->GetRate(), AUDIO_CHANNEL_NORMAL);
         audioOutputStream->mTrackID = tracks->GetID();
       }
     }
   }
 
   for (int32_t i = audioOutputStreamsFound.Length() - 1; i >= 0; --i) {
     if (!audioOutputStreamsFound[i]) {
       aStream->mAudioOutputStreams[i].mStream->Shutdown();
@@ -1206,17 +1206,16 @@ MediaStreamGraphImpl::PlayAudio(MediaStr
     // some amount of blocked time after the current time.
     GraphTime t = aFrom;
     while (t < aTo) {
       GraphTime end;
       bool blocked = aStream->mBlocked.GetAt(t, &end);
       end = std::min(end, aTo);
 
       AudioSegment output;
-      output.InitFrom(*audio);
       if (blocked) {
         // Track total blocked time in aStream->mBlockedAudioTime so that
         // the amount of silent samples we've inserted for blocking never gets
         // more than one sample away from the ideal amount.
         TrackTicks startTicks =
             TimeToTicksRoundDown(track->GetRate(), audioOutput.mBlockedAudioTime);
         audioOutput.mBlockedAudioTime += end - t;
         TrackTicks endTicks =
--- a/content/media/VideoSegment.h
+++ b/content/media/VideoSegment.h
@@ -99,20 +99,14 @@ public:
     }
     if (aStart) {
       *aStart = mDuration - c->mDuration;
     }
     return &c->mFrame;
   }
 
   // Segment-generic methods not in MediaSegmentBase
-  void InitFrom(const VideoSegment& aOther)
-  {
-  }
-  void CheckCompatible(const VideoSegment& aOther) const
-  {
-  }
   static Type StaticType() { return VIDEO; }
 };
 
 }
 
 #endif /* MOZILLA_VIDEOSEGMENT_H_ */
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -338,19 +338,25 @@ MOCHITEST_FILES += \
 		test_can_play_type_no_webm.html \
 		$(NULL)
 endif
 
 ifdef MOZ_DASH
 MOCHITEST_FILES += \
     test_can_play_type_dash.html \
     dash/dash-manifest.mpd \
+    dash/dash-manifest-sjs.mpd \
+    test_dash_detect_stream_switch.html \
+    dash_detect_stream_switch.sjs \
     dash/dash-webm-video-320x180.webm \
     dash/dash-webm-video-428x240.webm \
     dash/dash-webm-audio-128k.webm \
+    dash/dash-manifest-garbled.mpd \
+    dash/dash-manifest-garbled-webm.mpd \
+    dash/garbled.webm \
     $(NULL)
 else
 MOCHITEST_FILES += \
     test_can_play_type_no_dash.html \
     $(NULL)
 endif
 
 ifdef MOZ_WAVE
new file mode 100644
--- /dev/null
+++ b/content/media/test/dash/dash-manifest-garbled-webm.mpd
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns="urn:mpeg:DASH:schema:MPD:2011"
+  xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+  type="static"
+  mediaPresentationDuration="PT3.958S"
+  minBufferTime="PT1S"
+  profiles="urn:webm:dash:profile:webm-on-demand:2012">
+  <BaseURL>./</BaseURL>
+  <Period id="0" start="PT0S" duration="PT3.958S" >
+    <AdaptationSet id="0" mimeType="video/webm" codecs="vp8" lang="eng" subsegmentAlignment="true" subsegmentStartsWithSAP="1" bitstreamSwitching="true">
+      <Representation id="0" bandwidth="54207" width="320" height="180">
+        <BaseURL>garbled.webm</BaseURL>
+        <SegmentBase indexRange="35090-35123">
+          <Initialization range="0-228" />
+        </SegmentBase>
+      </Representation>
+      <Representation id="1" bandwidth="78006" width="428" height="240">
+        <BaseURL>dash-webm-video-428x240.webm</BaseURL>
+        <SegmentBase indexRange="50173-50206">
+          <Initialization range="0-228" />
+        </SegmentBase>
+      </Representation>
+    </AdaptationSet>
+    <AdaptationSet id="1" mimeType="audio/webm" codecs="vorbis" lang="eng" audioSamplingRate="48000" subsegmentStartsWithSAP="1">
+      <Representation id="2" bandwidth="57264">
+        <BaseURL>dash-webm-audio-128k.webm</BaseURL>
+        <SegmentBase indexRange="41927-41946">
+          <Initialization range="0-4521" />
+        </SegmentBase>
+      </Representation>
+    </AdaptationSet>
+  </Period>
+</MPD>
new file mode 100644
--- /dev/null
+++ b/content/media/test/dash/dash-manifest-garbled.mpd
@@ -0,0 +1,1 @@
+PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxNUEQgbWVkaWFQcmVzZW50YXRpb25EdXJhdGlvbj0iUFQxOS41MVMiIG1pbkJ1ZmZlclRpbWU9IlBUMVMiIHByb2ZpbGVzPSJ1cm46d2VibTpkYXNoOnByb2ZpbGU6d2VibS1vbi1kZW1hbmQ6MjAxMiIgdHlwZT0ic3RhdGljIiB4bWxucz0idXJuOm1wZWc6REFTSDpzY2hlbWE6TVBEOjIwMTEiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhzaTpzY2hlbWFMb2NhdGlvbj0idXJuOm1wZWc6REFTSDpzY2hlbWE6TVBEOjIwMTEiPjxCYXNlVVJMPmh0dHA6Ly93d3cuZ29vZ2xlLmNvbTwvQmFzZVVSTD48UGVyaW9kIGR1cmF0aW9uPSJQVDE5LjUxUyIgaWQ9IjAiIHN0YXJ0PSJQVDBTIj48QWRhcHRhdGlvblNldCBhdWRpb1NhbXBsaW5nUmF0ZT0iNDgwMDAiIGNvZGVjcz0idm9yYmlzIiBpZD0iMSIgbGFuZz0iZW5nIiBtaW1lVHlwZT0iYXVkaW8vd2VibSIgc3Vic2VnbWVudFN0YXJ0c1dpdGhTQVA9IjEiPjxSZXByZXNlbnRhdGlvbiBiYW5kd2lkdGg9IjIwMTA5IiBpZD0iMiI+PEJhc2VVUkwvPjxTZWdtZW50QmFzZSBpbmRleFJhbmdlPSIzMTk3ODAtMzIwNjEyIj48SW5pdGlhbGl6YXRpb24gcmFuZ2U9IjAtMjA4NzAiLz48L1NlZ21lbnRCYXNlPjwvUmVwcmVzZW50YXRpb24+PC9BZGFwdGF0aW9uU2V0PjwvUGVyaW9kPjwvTVBEPg
new file mode 100644
--- /dev/null
+++ b/content/media/test/dash/dash-manifest-sjs.mpd
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xmlns="urn:mpeg:DASH:schema:MPD:2011"
+  xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+  type="static"
+  mediaPresentationDuration="PT3.958S"
+  minBufferTime="PT1S"
+  profiles="urn:webm:dash:profile:webm-on-demand:2012">
+  <BaseURL>./dash_detect_stream_switch.sjs?name=</BaseURL>
+  <Period id="0" start="PT0S" duration="PT3.958S" >
+    <AdaptationSet id="0" mimeType="video/webm" codecs="vp8" lang="eng" subsegmentAlignment="true" subsegmentStartsWithSAP="1" bitstreamSwitching="true">
+      <Representation id="0" bandwidth="54207" width="320" height="180">
+        <BaseURL>dash-webm-video-320x180.webm</BaseURL>
+        <SegmentBase indexRange="35090-35123">
+          <Initialization range="0-228" />
+        </SegmentBase>
+      </Representation>
+      <Representation id="1" bandwidth="78006" width="428" height="240">
+        <BaseURL>dash-webm-video-428x240.webm</BaseURL>
+        <SegmentBase indexRange="50173-50206">
+          <Initialization range="0-228" />
+        </SegmentBase>
+      </Representation>
+    </AdaptationSet>
+    <AdaptationSet id="1" mimeType="audio/webm" codecs="vorbis" lang="eng" audioSamplingRate="48000" subsegmentStartsWithSAP="1">
+      <Representation id="2" bandwidth="57264">
+        <BaseURL>dash-webm-audio-128k.webm</BaseURL>
+        <SegmentBase indexRange="41927-41946">
+          <Initialization range="0-4521" />
+        </SegmentBase>
+      </Representation>
+    </AdaptationSet>
+  </Period>
+</MPD>
new file mode 100644
--- /dev/null
+++ b/content/media/test/dash/garbled.webm
@@ -0,0 +1,1 @@
+PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxNUEQgbWVkaWFQcmVzZW50YXRpb25EdXJhdGlvbj0iUFQxOS41MVMiIG1pbkJ1ZmZlclRpbWU9IlBUMVMiIHByb2ZpbGVzPSJ1cm46d2VibTpkYXNoOnByb2ZpbGU6d2VibS1vbi1kZW1hbmQ6MjAxMiIgdHlwZT0ic3RhdGljIiB4bWxucz0idXJuOm1wZWc6REFTSDpzY2hlbWE6TVBEOjIwMTEiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhzaTpzY2hlbWFMb2NhdGlvbj0idXJuOm1wZWc6REFTSDpzY2hlbWE6TVBEOjIwMTEiPjxCYXNlVVJMPmh0dHA6Ly93d3cuZ29vZ2xlLmNvbTwvQmFzZVVSTD48UGVyaW9kIGR1cmF0aW9uPSJQVDE5LjUxUyIgaWQ9IjAiIHN0YXJ0PSJQVDBTIj48QWRhcHRhdGlvblNldCBhdWRpb1NhbXBsaW5nUmF0ZT0iNDgwMDAiIGNvZGVjcz0idm9yYmlzIiBpZD0iMSIgbGFuZz0iZW5nIiBtaW1lVHlwZT0iYXVkaW8vd2VibSIgc3Vic2VnbWVudFN0YXJ0c1dpdGhTQVA9IjEiPjxSZXByZXNlbnRhdGlvbiBiYW5kd2lkdGg9IjIwMTA5IiBpZD0iMiI+PEJhc2VVUkwvPjxTZWdtZW50QmFzZSBpbmRleFJhbmdlPSIzMTk3ODAtMzIwNjEyIj48SW5pdGlhbGl6YXRpb24gcmFuZ2U9IjAtMjA4NzAiLz48L1NlZ21lbnRCYXNlPjwvUmVwcmVzZW50YXRpb24+PC9BZGFwdGF0aW9uU2V0PjwvUGVyaW9kPjwvTVBEPg
new file mode 100644
--- /dev/null
+++ b/content/media/test/dash_detect_stream_switch.sjs
@@ -0,0 +1,114 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+/* dash_detect_stream_switch.sjs
+ *
+ * Parses requests for DASH manifests and ensures stream switching takes place
+ * by verifying the subsegments downloaded and the streams they belong to.
+ * If unexpected subsegments (byte ranges) are requested, the script will
+ * will respond with a 404.
+ */
+
+var DEBUG = false;
+
+function parseQuery(request, key) {
+  var params = request.queryString.split('&');
+  if (DEBUG) {
+    dump("DASH-SJS: request params = \"" + params + "\"\n");
+  }
+  for (var j = 0; j < params.length; ++j) {
+    var p = params[j];
+	if (p == key)
+	  return true;
+    if (p.indexOf(key + "=") === 0)
+	  return p.substring(key.length + 1);
+	if (p.indexOf("=") < 0 && key === "")
+	  return p;
+  }
+  return false;
+}
+
+function handleRequest(request, response)
+{
+  try {
+    var name = parseQuery(request, "name");
+    var range = request.hasHeader("Range") ? request.getHeader("Range")
+                                           : undefined;
+    
+    // Should not get request for 1st subsegment from 2nd stream, nor 2nd
+    // subsegment from 1st stream.
+    if (name == "dash-webm-video-320x180.webm" && range == "bytes=25514-32767" ||
+        name == "dash-webm-video-428x240.webm" && range == "bytes=228-35852") 
+    {
+      throw "Should not request " + name + " with byte-range " + range;
+    } else {
+      var rangeSplit = range.split("=");
+      if (rangeSplit.length != 2) {
+        throw "DASH-SJS: ERROR: invalid number of tokens (" + rangeSplit.length +
+              ") delimited by \'=\' in \'Range\' header.";
+      }
+      var offsets = rangeSplit[1].split("-");
+      if (offsets.length != 2) {
+        throw "DASH-SJS: ERROR: invalid number of tokens (" + offsets.length +
+              ") delimited by \'-\' in \'Range\' header.";
+      }
+      var startOffset = parseInt(offsets[0]);
+      var endOffset = parseInt(offsets[1]);
+      var file = Components.classes["@mozilla.org/file/directory_service;1"].
+                            getService(Components.interfaces.nsIProperties).
+                            get("CurWorkD", Components.interfaces.nsILocalFile);
+      var fis  = Components.classes['@mozilla.org/network/file-input-stream;1'].
+                            createInstance(Components.interfaces.nsIFileInputStream);
+      var bis  = Components.classes["@mozilla.org/binaryinputstream;1"].
+                            createInstance(Components.interfaces.nsIBinaryInputStream);
+
+      var paths = "tests/content/media/test/" + name;
+      var split = paths.split("/");
+      for (var i = 0; i < split.length; ++i) {
+        file.append(split[i]);
+      }
+
+      fis.init(file, -1, -1, false);
+      // Exception: start offset should be within file bounds.
+      if (startOffset > file.fileSize) {
+        throw "Starting offset [" + startOffset + "] is after end of file [" +
+              file.fileSize + "].";
+      }
+      // End offset may be too large in the MPD. Real world HTTP servers just
+      // return what data they can; do the same here - reduce the end offset.
+      if (endOffset >= file.fileSize) {
+        if (DEBUG) {
+          dump("DASH-SJS: reducing endOffset [" + endOffset + "] to fileSize [" +
+               (file.fileSize-1) + "]\n");
+        }
+        endOffset = file.fileSize-1;
+      }
+      fis.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, startOffset);
+      bis.setInputStream(fis);
+      
+      var byteLengthToRead = endOffset + 1 - startOffset;
+      var totalBytesExpected = byteLengthToRead + startOffset;
+      if (DEBUG) {
+        dump("DASH-SJS: byteLengthToRead = " + byteLengthToRead +
+             " byteLengthToRead+startOffset = " + totalBytesExpected +
+             " fileSize = " + file.fileSize + "\n");
+      }
+
+      var bytes = bis.readBytes(byteLengthToRead);
+      response.setStatusLine(request.httpVersion, 206, "Partial Content");
+      response.setHeader("Content-Length", ""+bytes.length, false);
+      response.setHeader("Content-Type", "application/dash+xml", false);
+      var contentRange = "bytes " + startOffset + "-" + endOffset + "/" +
+                         file.fileSize;
+      response.setHeader("Content-Range", contentRange, false);
+      response.write(bytes, bytes.length);
+      bis.close();
+    }
+  } catch (e) {
+    dump ("DASH-SJS-ERROR: " + e + "\n");
+    response.setStatusLine(request.httpVersion, 404, "Not found");
+  }
+}
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -190,16 +190,23 @@ var gInvalidTests = [
   { name:"invalid-m2c0.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-m2c1.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-cmap-short.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-cmap-s0c0.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-cmap-s0c2.opus", type:"audio/ogg; codecs=opus"},
   { name:"invalid-cmap-s1c2.opus", type:"audio/ogg; codecs=opus"},
 ];
 
+// Files to test for stream switching. Note: media files referenced in DASH MPD
+// files should be accessed via dash_detect_stream_switch.sjs.
+var gStreamSwitchTests = [
+  { name:"dash-manifest-sjs.mpd", type:"application/dash+xml",
+    width:320, height:180, duration:3.966 }
+];
+
 // Converts a path/filename to a file:// URI which we can load from disk.
 // Optionally checks whether the file actually exists on disk at the location
 // we've specified.
 function fileUriToSrc(path, mustExist) {
   // android mochitest doesn't support file://
   if (navigator.appVersion.indexOf("Android") != -1)
     return path;
 
@@ -345,16 +352,18 @@ var g404Tests = [
 // an error and emptied event, and no loadedmetadata or ended event.
 var gDecodeErrorTests = [
   // Valid files with unsupported codecs
   { name:"r11025_msadpcm_c1.wav", type:"audio/x-wav" },
   { name:"dirac.ogg", type:"video/ogg" },
   // Invalid files
   { name:"bogus.wav", type:"audio/x-wav" },
   { name:"bogus.ogv", type:"video/ogg" },
+  { name:"dash-manifest-garbled.mpd", type:"application/dash+xml" },
+  { name:"dash-manifest-garbled-webm.mpd", type:"application/dash+xml" },
 
   { name:"bogus.duh", type:"bogus/duh" }
 ];
 
 // These are files that are used for media fragments tests
 var gFragmentTests = [
   { name:"big.wav", type:"audio/x-wav", duration:9.278981, size:102444 }
 ];
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_dash_detect_stream_switch.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=792935
+-->
+<head>
+  <title>Test for Bug 792935 - DASH Stream Switching</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=792935">Mozilla Bug 792935</a>
+  
+</div>
+<pre id="test">
+<script type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function createTestArray() {
+  var tests = [];
+  var tmpVid = document.createElement("video");
+
+  for (var testNum=0; testNum<gStreamSwitchTests.length; testNum++) {
+    var test = gStreamSwitchTests[testNum];
+    if (!tmpVid.canPlayType(test.type)) {
+      continue;
+    }
+    tests.push(test);
+  }
+  return tests;
+}
+
+function ended(evt) {
+  var v = evt.target;
+  if (v.parentNode) {
+    v.parentNode.removeChild(v);
+  }
+  ok(true, "Fully played DASH video implies correct byte ranges downloaded.");
+  dump("STREAM-SWITCH-TEST: Finished " + v._name + "\n");
+  manager.finished(v.token);
+}
+
+function error(evt) {
+  var v = evt.target;
+  ok(false, "Error suggests wrong byte range requested for " + v._name);
+}
+
+function startTest(test, token) {
+  var v = document.createElement('video');
+  manager.started(token);
+  v.type = test.type;
+  v.src = test.name;
+  v._name = test.name + " stream switch test";
+  v.token = token;
+  v.autoplay = true;
+
+  v.addEventListener("error", error, false);
+  v.addEventListener("ended", ended, false);
+
+  dump("STREAM-SWITCH-TEST: Started " + name + "\n");
+  document.body.appendChild(v);
+}
+
+var testArray = createTestArray();
+if (testArray && testArray.length > 0) {
+  manager.runTests(testArray, startTest);
+} else {
+  var v = document.createElement('video');
+  var canPlay = v.canPlayType("application/dash+xml");
+  // If the test array is empty even though DASH is enabled, the test should
+  // fail, i.e. canPlay should be false when testArray is empty.
+  todo(canPlay, "No types supported - DASH " +
+                (canPlay ? "enabled" : "disabled"));
+}  
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/media/webrtc/MediaEngineDefault.cpp
+++ b/content/media/webrtc/MediaEngineDefault.cpp
@@ -12,17 +12,16 @@
 #include "ImageTypes.h"
 #include "prmem.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #include "nsISupportsUtils.h"
 #endif
 
-#define CHANNELS 1
 #define VIDEO_RATE USECS_PER_S
 #define AUDIO_RATE 16000
 
 namespace mozilla {
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(MediaEngineDefaultVideoSource, nsITimerCallback)
 /**
  * Default video source.
@@ -331,17 +330,16 @@ MediaEngineDefaultAudioSource::Start(Sou
   if (!mTimer) {
     return NS_ERROR_FAILURE;
   }
 
   mSource = aStream;
 
   // AddTrack will take ownership of segment
   AudioSegment* segment = new AudioSegment();
-  segment->Init(CHANNELS);
   mSource->AddTrack(aID, AUDIO_RATE, 0, segment);
 
   // We aren't going to add any more tracks
   mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX);
 
   // Remember TrackID so we can finish later
   mTrackID = aID;
 
@@ -377,17 +375,16 @@ MediaEngineDefaultAudioSource::Snapshot(
 {
    return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 MediaEngineDefaultAudioSource::Notify(nsITimer* aTimer)
 {
   AudioSegment segment;
-  segment.Init(CHANNELS);
   segment.InsertNullDataAtStart(AUDIO_RATE/100); // 10ms of fake data
 
   mSource->AppendToTrack(mTrackID, &segment);
 
   return NS_OK;
 }
 
 void
--- a/content/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -144,17 +144,16 @@ MediaEngineWebRTCAudioSource::Start(Sour
   }
 
   {
     ReentrantMonitorAutoEnter enter(mMonitor);
     mSources.AppendElement(aStream);
   }
 
   AudioSegment* segment = new AudioSegment();
-  segment->Init(CHANNELS);
   aStream->AddTrack(aID, SAMPLE_FREQUENCY, 0, segment);
   aStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
   LOG(("Initial audio"));
   mTrackID = aID;
 
   if (mState == kStarted) {
     return NS_OK;
   }
@@ -358,17 +357,16 @@ MediaEngineWebRTCAudioSource::Process(co
   uint32_t len = mSources.Length();
   for (uint32_t i = 0; i < len; i++) {
     nsRefPtr<SharedBuffer> buffer = SharedBuffer::Create(length * sizeof(sample));
 
     sample* dest = static_cast<sample*>(buffer->Data());
     memcpy(dest, audio10ms, length * sizeof(sample));
 
     AudioSegment segment;
-    segment.Init(CHANNELS);
     nsAutoTArray<const sample*,1> channels;
     channels.AppendElement(dest);
     segment.AppendFrames(buffer.forget(), channels, length);
 
     SourceMediaStream *source = mSources[i];
     if (source) {
       // This is safe from any thread, and is safe if the track is Finished
       // or Destroyed
--- a/content/smil/nsSMILAnimationController.cpp
+++ b/content/smil/nsSMILAnimationController.cpp
@@ -9,16 +9,17 @@
 #include "nsCSSProps.h"
 #include "nsITimer.h"
 #include "mozilla/dom/Element.h"
 #include "nsIDocument.h"
 #include "nsISMILAnimationElement.h"
 #include "nsIDOMSVGAnimationElement.h"
 #include "nsSMILTimedElement.h"
 #include <algorithm>
+#include "mozilla/AutoRestore.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 // nsSMILAnimationController implementation
 
 //----------------------------------------------------------------------
--- a/content/svg/content/src/DOMSVGAnimatedLengthList.cpp
+++ b/content/svg/content/src/DOMSVGAnimatedLengthList.cpp
@@ -5,16 +5,17 @@
 
 #include "DOMSVGAnimatedLengthList.h"
 #include "DOMSVGLengthList.h"
 #include "SVGAnimatedLengthList.h"
 #include "nsSVGElement.h"
 #include "nsCOMPtr.h"
 #include "nsSVGAttrTearoffTable.h"
 #include "mozilla/dom/SVGAnimatedLengthListBinding.h"
+#include "nsContentUtils.h"
 
 // See the architecture comment in this file's header.
 
 namespace mozilla {
 
 static nsSVGAttrTearoffTable<SVGAnimatedLengthList, DOMSVGAnimatedLengthList>
   sSVGAnimatedLengthListTearoffTable;
 
--- a/content/svg/content/src/DOMSVGAnimatedNumberList.cpp
+++ b/content/svg/content/src/DOMSVGAnimatedNumberList.cpp
@@ -5,16 +5,17 @@
 
 #include "DOMSVGAnimatedNumberList.h"
 #include "DOMSVGNumberList.h"
 #include "SVGAnimatedNumberList.h"
 #include "nsSVGElement.h"
 #include "nsCOMPtr.h"
 #include "nsSVGAttrTearoffTable.h"
 #include "mozilla/dom/SVGAnimatedNumberListBinding.h"
+#include "nsContentUtils.h"
 
 // See the architecture comment in this file's header.
 
 namespace mozilla {
 
 static nsSVGAttrTearoffTable<SVGAnimatedNumberList, DOMSVGAnimatedNumberList>
   sSVGAnimatedNumberListTearoffTable;
 
--- a/content/svg/content/src/DOMSVGAnimatedTransformList.cpp
+++ b/content/svg/content/src/DOMSVGAnimatedTransformList.cpp
@@ -3,16 +3,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/. */
 
 #include "DOMSVGAnimatedTransformList.h"
 #include "DOMSVGTransformList.h"
 #include "SVGAnimatedTransformList.h"
 #include "nsSVGAttrTearoffTable.h"
 #include "mozilla/dom/SVGAnimatedTransformListBinding.h"
+#include "nsContentUtils.h"
 
 namespace mozilla {
 
 static
   nsSVGAttrTearoffTable<SVGAnimatedTransformList,DOMSVGAnimatedTransformList>
   sSVGAnimatedTransformListTearoffTable;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGAnimatedTransformList, mElement)
--- a/content/svg/content/src/Makefile.in
+++ b/content/svg/content/src/Makefile.in
@@ -87,17 +87,16 @@ CPPSRCS		= \
 		SVGGradientElement.cpp \
 		SVGGraphicsElement.cpp \
 		SVGImageElement.cpp \
 		SVGIntegerPairSMILType.cpp \
 		SVGLength.cpp \
 		SVGLengthList.cpp \
 		SVGLengthListSMILType.cpp \
 		SVGLineElement.cpp \
-		SVGLocatableElement.cpp \
 		SVGMarkerElement.cpp \
 		SVGMaskElement.cpp \
 		SVGMatrix.cpp \
 		SVGMetadataElement.cpp \
 		SVGMotionSMILType.cpp \
 		SVGMotionSMILAttr.cpp \
 		SVGMotionSMILAnimationFunction.cpp \
 		SVGMotionSMILPathUtils.cpp \
@@ -171,17 +170,16 @@ EXPORTS_mozilla/dom = \
 	SVGDescElement.h \
 	SVGEllipseElement.h \
 	SVGForeignObjectElement.h \
 	SVGGElement.h \
 	SVGGradientElement.h \
 	SVGGraphicsElement.h \
 	SVGImageElement.h \
 	SVGLineElement.h \
-	SVGLocatableElement.h \
 	SVGMarkerElement.h \
 	SVGMaskElement.h \
 	SVGMatrix.h \
 	SVGMetadataElement.h \
 	SVGMPathElement.h \
 	SVGPathElement.h \
 	SVGPatternElement.h \
 	SVGPolygonElement.h \
--- a/content/svg/content/src/SVGAngle.cpp
+++ b/content/svg/content/src/SVGAngle.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "SVGAngle.h"
 #include "nsSVGAngle.h"
 #include "mozilla/dom/SVGAngleBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAngle, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGAngle)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGAngle)
--- a/content/svg/content/src/SVGAnimatedAngle.cpp
+++ b/content/svg/content/src/SVGAnimatedAngle.cpp
@@ -2,16 +2,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/. */
 
 #include "SVGAnimatedAngle.h"
 #include "SVGAngle.h"
 #include "nsSVGAngle.h"
 #include "mozilla/dom/SVGAnimatedAngleBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedAngle, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGAnimatedAngle)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGAnimatedAngle)
--- a/content/svg/content/src/SVGAnimatedBoolean.cpp
+++ b/content/svg/content/src/SVGAnimatedBoolean.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "SVGAnimatedBoolean.h"
 #include "nsSVGBoolean.h"
 #include "mozilla/dom/SVGAnimatedBooleanBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedBoolean, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGAnimatedBoolean)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGAnimatedBoolean)
--- a/content/svg/content/src/SVGAnimatedLength.cpp
+++ b/content/svg/content/src/SVGAnimatedLength.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "mozilla/dom/SVGAnimatedLength.h"
 #include "mozilla/dom/SVGAnimatedLengthBinding.h"
+#include "nsContentUtils.h"
 
 DOMCI_DATA(SVGAnimatedLength, mozilla::dom::SVGAnimatedLength)
 
 namespace mozilla {
 namespace dom {
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedLength, mSVGElement)
 
--- a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
+++ b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
@@ -7,16 +7,17 @@
 
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsSMILValue.h"
 #include "nsSVGAttrTearoffTable.h"
 #include "SMILEnumType.h"
 #include "nsAttrValueInlines.h"
 #include "mozilla/dom/SVGAnimatedPreserveAspectRatioBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 ////////////////////////////////////////////////////////////////////////
 // SVGAnimatedPreserveAspectRatio class
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGAnimatedPreserveAspectRatio, mSVGElement)
 
--- a/content/svg/content/src/SVGContentUtils.cpp
+++ b/content/svg/content/src/SVGContentUtils.cpp
@@ -13,16 +13,17 @@
 #include "nsComputedDOMStyle.h"
 #include "nsFontMetrics.h"
 #include "nsIFrame.h"
 #include "nsIScriptError.h"
 #include "nsLayoutUtils.h"
 #include "SVGAnimationElement.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 SVGSVGElement*
 SVGContentUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
 {
   nsIContent *element = nullptr;
--- a/content/svg/content/src/SVGFragmentIdentifier.cpp
+++ b/content/svg/content/src/SVGFragmentIdentifier.cpp
@@ -3,16 +3,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/. */
 
 #include "SVGFragmentIdentifier.h"
 #include "nsIDOMSVGDocument.h"
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/SVGViewElement.h"
 #include "SVGAnimatedTransformList.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 
 static bool
 IsMatchingParameter(const nsAString &aString, const nsAString &aParameterName)
 {
   // The first two tests ensure aString.Length() > aParameterName.Length()
   // so it's then safe to do the third test
--- a/content/svg/content/src/SVGGraphicsElement.cpp
+++ b/content/svg/content/src/SVGGraphicsElement.cpp
@@ -1,15 +1,14 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "mozilla/dom/SVGGraphicsElement.h"
-#include "mozilla/dom/SVGGraphicsElementBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ADDREF_INHERITED(SVGGraphicsElement, SVGGraphicsElementBase)
--- a/content/svg/content/src/SVGImageElement.cpp
+++ b/content/svg/content/src/SVGImageElement.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/dom/SVGAnimatedLength.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "imgIContainer.h"
 #include "imgINotificationObserver.h"
 #include "gfxContext.h"
 #include "mozilla/dom/SVGImageElementBinding.h"
+#include "nsContentUtils.h"
 
 DOMCI_NODE_DATA(SVGImageElement, mozilla::dom::SVGImageElement)
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Image)
 
 namespace mozilla {
 namespace dom {
 
deleted file mode 100644
--- a/content/svg/content/src/SVGLocatableElement.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/dom/SVGLocatableElement.h"
-#include "nsIFrame.h"
-#include "nsISVGChildFrame.h"
-#include "nsSVGRect.h"
-#include "nsSVGUtils.h"
-#include "SVGContentUtils.h"
-#include "mozilla/dom/SVGMatrix.h"
-#include "mozilla/dom/SVGSVGElement.h"
-
-namespace mozilla {
-namespace dom {
-
-//----------------------------------------------------------------------
-// nsISupports methods
-
-NS_IMPL_ADDREF_INHERITED(SVGLocatableElement, nsSVGElement)
-NS_IMPL_RELEASE_INHERITED(SVGLocatableElement, nsSVGElement)
-
-NS_INTERFACE_MAP_BEGIN(SVGLocatableElement)
-  NS_INTERFACE_MAP_ENTRY(mozilla::dom::SVGLocatableElement)
-NS_INTERFACE_MAP_END_INHERITING(nsSVGElement)
-
-
-//----------------------------------------------------------------------
-
-nsSVGElement*
-SVGLocatableElement::GetNearestViewportElement()
-{
-  return SVGContentUtils::GetNearestViewportElement(this);
-}
-
-nsSVGElement*
-SVGLocatableElement::GetFarthestViewportElement()
-{
-  return SVGContentUtils::GetOuterSVGElement(this);
-}
-
-already_AddRefed<nsIDOMSVGRect>
-SVGLocatableElement::GetBBox(ErrorResult& rv)
-{
-  nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
-
-  if (!frame || (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
-    rv.Throw(NS_ERROR_FAILURE);
-    return nullptr;
-  }
-
-  nsISVGChildFrame* svgframe = do_QueryFrame(frame);
-  if (!svgframe) {
-    rv.Throw(NS_ERROR_NOT_IMPLEMENTED); // XXX: outer svg
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIDOMSVGRect> rect;
-  rv = NS_NewSVGRect(getter_AddRefs(rect), nsSVGUtils::GetBBox(frame));
-  return rect.forget();
-}
-
-already_AddRefed<SVGMatrix>
-SVGLocatableElement::GetCTM()
-{
-  nsIDocument* currentDoc = GetCurrentDoc();
-  if (currentDoc) {
-    // Flush all pending notifications so that our frames are up to date
-    currentDoc->FlushPendingNotifications(Flush_Layout);
-  }
-  gfxMatrix m = SVGContentUtils::GetCTM(this, false);
-  nsCOMPtr<SVGMatrix> mat = m.IsSingular() ? nullptr : new SVGMatrix(m);
-  return mat.forget();
-}
-
-already_AddRefed<SVGMatrix>
-SVGLocatableElement::GetScreenCTM()
-{
-  nsIDocument* currentDoc = GetCurrentDoc();
-  if (currentDoc) {
-    // Flush all pending notifications so that our frames are up to date
-    currentDoc->FlushPendingNotifications(Flush_Layout);
-  }
-  gfxMatrix m = SVGContentUtils::GetCTM(this, true);
-  nsCOMPtr<SVGMatrix> mat = m.IsSingular() ? nullptr : new SVGMatrix(m);
-  return mat.forget();
-}
-
-already_AddRefed<SVGMatrix>
-SVGLocatableElement::GetTransformToElement(SVGLocatableElement& aElement,
-                                           ErrorResult& rv)
-{
-  // the easiest way to do this (if likely to increase rounding error):
-  nsCOMPtr<SVGMatrix> ourScreenCTM = GetScreenCTM();
-  nsCOMPtr<SVGMatrix> targetScreenCTM = aElement.GetScreenCTM();
-  if (!ourScreenCTM || !targetScreenCTM) {
-    rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return nullptr;
-  }
-  nsCOMPtr<SVGMatrix> tmp = targetScreenCTM->Inverse(rv);
-  if (rv.Failed()) return nullptr;
-
-  nsCOMPtr<SVGMatrix> mat = tmp->Multiply(*ourScreenCTM).get();
-  return mat.forget();
-}
-
-} // namespace dom
-} // namespace mozilla
-
deleted file mode 100644
--- a/content/svg/content/src/SVGLocatableElement.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 SVGLocatableElement_h
-#define SVGLocatableElement_h
-
-#include "nsSVGElement.h"
-
-#define MOZILLA_SVGLOCATABLEELEMENT_IID \
-  { 0xe20176ba, 0xc48d, 0x4704, \
-    {0x89, 0xec, 0xe6, 0x69, 0x6c, 0xb7, 0xb8, 0xb3} }
-
-class nsIDOMSVGRect;
-
-namespace mozilla {
-
-namespace dom {
-class SVGMatrix;
-
-class SVGLocatableElement : public nsSVGElement
-{
-public:
-  SVGLocatableElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-    : nsSVGElement(aNodeInfo) {}
-  virtual ~SVGLocatableElement() {}
-
-  NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_SVGLOCATABLEELEMENT_IID)
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // WebIDL
-  nsSVGElement* GetNearestViewportElement();
-  nsSVGElement* GetFarthestViewportElement();
-  already_AddRefed<nsIDOMSVGRect> GetBBox(ErrorResult& rv);
-  already_AddRefed<SVGMatrix> GetCTM();
-  already_AddRefed<SVGMatrix> GetScreenCTM();
-  already_AddRefed<SVGMatrix> GetTransformToElement(SVGLocatableElement& aElement,
-                                                    ErrorResult& rv);
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(SVGLocatableElement,
-                              MOZILLA_SVGLOCATABLEELEMENT_IID)
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // SVGLocatableElement_h
-
--- a/content/svg/content/src/SVGPreserveAspectRatio.cpp
+++ b/content/svg/content/src/SVGPreserveAspectRatio.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "SVGPreserveAspectRatio.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "mozilla/dom/SVGPreserveAspectRatioBinding.h"
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace dom;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGPreserveAspectRatio, mSVGElement)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGPreserveAspectRatio)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPreserveAspectRatio)
--- a/content/svg/content/src/SVGTSpanElement.cpp
+++ b/content/svg/content/src/SVGTSpanElement.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "mozilla/dom/SVGTSpanElement.h"
 #include "mozilla/dom/SVGTSpanElementBinding.h"
+#include "nsContentUtils.h"
 
 DOMCI_NODE_DATA(SVGTSpanElement, mozilla::dom::SVGTSpanElement)
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(TSpan)
 
 namespace mozilla {
 namespace dom {
 
--- a/content/svg/content/src/SVGTransformableElement.cpp
+++ b/content/svg/content/src/SVGTransformableElement.cpp
@@ -1,32 +1,32 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "mozilla/dom/SVGTransformableElement.h"
+#include "mozilla/dom/SVGMatrix.h"
+#include "mozilla/dom/SVGSVGElement.h"
 #include "DOMSVGAnimatedTransformList.h"
+#include "nsContentUtils.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsIFrame.h"
+#include "nsISVGChildFrame.h"
+#include "nsSVGRect.h"
 #include "nsSVGUtils.h"
-#include "nsContentUtils.h"
+#include "SVGContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
-NS_IMPL_ADDREF_INHERITED(SVGTransformableElement, SVGLocatableElement)
-NS_IMPL_RELEASE_INHERITED(SVGTransformableElement, SVGLocatableElement)
-
-NS_INTERFACE_MAP_BEGIN(SVGTransformableElement)
-  NS_INTERFACE_MAP_ENTRY(mozilla::dom::SVGTransformableElement)
-NS_INTERFACE_MAP_END_INHERITING(SVGLocatableElement)
+NS_IMPL_ISUPPORTS_INHERITED0(SVGTransformableElement, nsSVGElement)
 
 already_AddRefed<DOMSVGAnimatedTransformList>
 SVGTransformableElement::Transform()
 {
   // We're creating a DOM wrapper, so we must tell GetAnimatedTransformList
   // to allocate the SVGAnimatedTransformList if it hasn't already done so:
   return DOMSVGAnimatedTransformList::GetDOMWrapper(
            GetAnimatedTransformList(DO_ALLOCATE), this).get();
@@ -41,25 +41,25 @@ SVGTransformableElement::IsAttributeMapp
 {
   static const MappedAttributeEntry* const map[] = {
     sColorMap,
     sFillStrokeMap,
     sGraphicsMap
   };
 
   return FindAttributeDependence(name, map) ||
-    SVGLocatableElement::IsAttributeMapped(name);
+    nsSVGElement::IsAttributeMapped(name);
 }
 
 nsChangeHint
 SVGTransformableElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                                 int32_t aModType) const
 {
   nsChangeHint retval =
-    SVGLocatableElement::GetAttributeChangeHint(aAttribute, aModType);
+    nsSVGElement::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::transform ||
       aAttribute == nsGkAtoms::mozAnimateMotionDummyAttr) {
     // We add nsChangeHint_UpdateOverflow so that nsFrame::UpdateOverflow()
     // will be called on us and our ancestors.
     nsIFrame* frame =
       const_cast<SVGTransformableElement*>(this)->GetPrimaryFrame();
     if (!frame || (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
       return retval; // no change
@@ -143,11 +143,88 @@ SVGAnimatedTransformList*
 SVGTransformableElement::GetAnimatedTransformList(uint32_t aFlags)
 {
   if (!mTransforms && (aFlags & DO_ALLOCATE)) {
     mTransforms = new SVGAnimatedTransformList();
   }
   return mTransforms;
 }
 
+nsSVGElement*
+SVGTransformableElement::GetNearestViewportElement()
+{
+  return SVGContentUtils::GetNearestViewportElement(this);
+}
+
+nsSVGElement*
+SVGTransformableElement::GetFarthestViewportElement()
+{
+  return SVGContentUtils::GetOuterSVGElement(this);
+}
+
+already_AddRefed<nsIDOMSVGRect>
+SVGTransformableElement::GetBBox(ErrorResult& rv)
+{
+  nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
+
+  if (!frame || (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
+    rv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsISVGChildFrame* svgframe = do_QueryFrame(frame);
+  if (!svgframe) {
+    rv.Throw(NS_ERROR_NOT_IMPLEMENTED); // XXX: outer svg
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIDOMSVGRect> rect;
+  rv = NS_NewSVGRect(getter_AddRefs(rect), nsSVGUtils::GetBBox(frame));
+  return rect.forget();
+}
+
+already_AddRefed<SVGMatrix>
+SVGTransformableElement::GetCTM()
+{
+  nsIDocument* currentDoc = GetCurrentDoc();
+  if (currentDoc) {
+    // Flush all pending notifications so that our frames are up to date
+    currentDoc->FlushPendingNotifications(Flush_Layout);
+  }
+  gfxMatrix m = SVGContentUtils::GetCTM(this, false);
+  nsCOMPtr<SVGMatrix> mat = m.IsSingular() ? nullptr : new SVGMatrix(m);
+  return mat.forget();
+}
+
+already_AddRefed<SVGMatrix>
+SVGTransformableElement::GetScreenCTM()
+{
+  nsIDocument* currentDoc = GetCurrentDoc();
+  if (currentDoc) {
+    // Flush all pending notifications so that our frames are up to date
+    currentDoc->FlushPendingNotifications(Flush_Layout);
+  }
+  gfxMatrix m = SVGContentUtils::GetCTM(this, true);
+  nsCOMPtr<SVGMatrix> mat = m.IsSingular() ? nullptr : new SVGMatrix(m);
+  return mat.forget();
+}
+
+already_AddRefed<SVGMatrix>
+SVGTransformableElement::GetTransformToElement(SVGGraphicsElement& aElement,
+                                               ErrorResult& rv)
+{
+  // the easiest way to do this (if likely to increase rounding error):
+  nsCOMPtr<SVGMatrix> ourScreenCTM = GetScreenCTM();
+  nsCOMPtr<SVGMatrix> targetScreenCTM = aElement.GetScreenCTM();
+  if (!ourScreenCTM || !targetScreenCTM) {
+    rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+  nsCOMPtr<SVGMatrix> tmp = targetScreenCTM->Inverse(rv);
+  if (rv.Failed()) return nullptr;
+
+  nsCOMPtr<SVGMatrix> mat = tmp->Multiply(*ourScreenCTM).get();
+  return mat.forget();
+}
+
 } // namespace dom
 } // namespace mozilla
 
--- a/content/svg/content/src/SVGTransformableElement.h
+++ b/content/svg/content/src/SVGTransformableElement.h
@@ -1,40 +1,48 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 SVGTransformableElement_h
 #define SVGTransformableElement_h
 
-#include "mozilla/dom/SVGLocatableElement.h"
+#include "nsSVGElement.h"
 #include "gfxMatrix.h"
 #include "SVGAnimatedTransformList.h"
 
-#define MOZILLA_SVGTRANSFORMABLEELEMENT_IID \
-  { 0x77888cba, 0x0b43, 0x4654, \
-    {0x96, 0x3c, 0xf5, 0x50, 0xfc, 0xb5, 0x5e, 0x32}}
+class nsIDOMSVGRect;
 
 namespace mozilla {
 class DOMSVGAnimatedTransformList;
 
 namespace dom {
-class SVGTransformableElement : public SVGLocatableElement
+
+class SVGGraphicsElement;
+class SVGMatrix;
+
+class SVGTransformableElement : public nsSVGElement
 {
 public:
   SVGTransformableElement(already_AddRefed<nsINodeInfo> aNodeInfo)
-    : SVGLocatableElement(aNodeInfo) {}
+    : nsSVGElement(aNodeInfo) {}
   virtual ~SVGTransformableElement() {}
 
-  NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_SVGTRANSFORMABLEELEMENT_IID)
   NS_DECL_ISUPPORTS_INHERITED
 
   // WebIDL
   already_AddRefed<DOMSVGAnimatedTransformList> Transform();
+  nsSVGElement* GetNearestViewportElement();
+  nsSVGElement* GetFarthestViewportElement();
+  already_AddRefed<nsIDOMSVGRect> GetBBox(ErrorResult& rv);
+  already_AddRefed<SVGMatrix> GetCTM();
+  already_AddRefed<SVGMatrix> GetScreenCTM();
+  already_AddRefed<SVGMatrix> GetTransformToElement(SVGGraphicsElement& aElement,
+                                                    ErrorResult& rv);
 
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
   nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                       int32_t aModType) const;
 
 
@@ -56,16 +64,13 @@ protected:
   // nsSVGElement overrides
 
   nsAutoPtr<SVGAnimatedTransformList> mTransforms;
 
   // XXX maybe move this to property table, to save space on un-animated elems?
   nsAutoPtr<gfxMatrix> mAnimateMotionTransform;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(SVGTransformableElement,
-                              MOZILLA_SVGTRANSFORMABLEELEMENT_IID)
-
 } // namespace dom
 } // namespace mozilla
 
 #endif // SVGTransformableElement_h
 
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -32,16 +32,17 @@
 #include "nsNetUtil.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsSVGFilterElement.h"
 #include "nsSVGString.h"
 #include "nsSVGEffects.h"
 #include "gfxUtils.h"
 #include "SVGContentUtils.h"
 #include <algorithm>
+#include "nsContentUtils.h"
 
 #if defined(XP_WIN) 
 // Prevent Windows redefining LoadImage
 #undef LoadImage
 #endif
 
 #define NUM_ENTRIES_IN_4x5_MATRIX 20
 
--- a/content/xbl/src/nsXBLProtoImplMember.h
+++ b/content/xbl/src/nsXBLProtoImplMember.h
@@ -6,17 +6,17 @@
 #ifndef nsXBLProtoImplMember_h__
 #define nsXBLProtoImplMember_h__
 
 #include "nsIAtom.h"
 #include "nsString.h"
 #include "jsapi.h"
 #include "nsString.h"
 #include "nsIServiceManager.h"
-#include "nsContentUtils.h"
+#include "nsContentUtils.h" // For NS_CONTENT_DELETE_LIST_MEMBER.
 #include "nsCycleCollectionParticipant.h"
 
 class nsIContent;
 class nsIScriptContext;
 
 struct nsXBLTextWithLineNumber
 {
   PRUnichar* mText;
--- a/content/xbl/src/nsXBLResourceLoader.cpp
+++ b/content/xbl/src/nsXBLResourceLoader.cpp
@@ -34,16 +34,37 @@ NS_IMPL_CYCLE_COLLECTION_1(nsXBLResource
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXBLResourceLoader)
   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXBLResourceLoader)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXBLResourceLoader)
 
+struct nsXBLResource
+{
+  nsXBLResource* mNext;
+  nsIAtom* mType;
+  nsString mSrc;
+
+  nsXBLResource(nsIAtom* aType, const nsAString& aSrc)
+  {
+    MOZ_COUNT_CTOR(nsXBLResource);
+    mNext = nullptr;
+    mType = aType;
+    mSrc = aSrc;
+  }
+
+  ~nsXBLResource()
+  {
+    MOZ_COUNT_DTOR(nsXBLResource);
+    NS_CONTENT_DELETE_LIST_MEMBER(nsXBLResource, this, mNext);
+  }
+};
+
 nsXBLResourceLoader::nsXBLResourceLoader(nsXBLPrototypeBinding* aBinding,
                                          nsXBLPrototypeResources* aResources)
 :mBinding(aBinding),
  mResources(aResources),
  mResourceList(nullptr),
  mLastResource(nullptr),
  mLoadingResources(false),
  mInLoadResourcesFunc(false),
--- a/content/xbl/src/nsXBLResourceLoader.h
+++ b/content/xbl/src/nsXBLResourceLoader.h
@@ -1,47 +1,29 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "nsCOMPtr.h"
 #include "nsICSSLoaderObserver.h"
 #include "nsCOMArray.h"
-#include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsIContent;
 class nsIAtom;
 class nsIScriptContext;
 class nsSupportsHashtable;
 class nsXBLPrototypeResources;
 class nsXBLPrototypeBinding;
+struct nsXBLResource;
 
 // *********************************************************************/
 // The XBLResourceLoader class
 
-struct nsXBLResource {
-  nsXBLResource* mNext;
-  nsIAtom* mType;
-  nsString mSrc;
-
-  nsXBLResource(nsIAtom* aType, const nsAString& aSrc) {
-    MOZ_COUNT_CTOR(nsXBLResource);
-    mNext = nullptr;
-    mType = aType;
-    mSrc = aSrc;
-  }
-
-  ~nsXBLResource() { 
-    MOZ_COUNT_DTOR(nsXBLResource);  
-    NS_CONTENT_DELETE_LIST_MEMBER(nsXBLResource, this, mNext);
-  }
-};
-
 class nsXBLResourceLoader : public nsICSSLoaderObserver
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsXBLResourceLoader)
 
   // nsICSSLoaderObserver
   NS_IMETHOD StyleSheetLoaded(nsCSSStyleSheet* aSheet, bool aWasAlternate,
--- a/content/xslt/src/base/txStringUtils.h
+++ b/content/xslt/src/base/txStringUtils.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef txStringUtils_h__
 #define txStringUtils_h__
 
 #include "nsAString.h"
 #include "nsIAtom.h"
 #include "nsUnicharUtils.h"
-#include "nsContentUtils.h"
+#include "nsContentUtils.h" // For ASCIIToLower().
 
 typedef nsCaseInsensitiveStringComparator txCaseInsensitiveStringComparator;
 
 /**
  * Check equality between a string and an atom containing ASCII.
  */
 inline bool
 TX_StringEqualsAtom(const nsASingleFragmentString& aString, nsIAtom* aAtom)
--- a/content/xslt/src/xml/txXMLUtils.cpp
+++ b/content/xslt/src/xml/txXMLUtils.cpp
@@ -9,16 +9,17 @@
 
 #include "txXMLUtils.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsGkAtoms.h"
 #include "txStringUtils.h"
 #include "txNamespaceMap.h"
 #include "txXPathTreeWalker.h"
+#include "nsContentUtils.h"
 
 nsresult
 txExpandedName::init(const nsAString& aQName, txNamespaceMap* aResolver,
                      bool aUseDefault)
 {
     const nsAFlatString& qName = PromiseFlatString(aQName);
     const PRUnichar* colon;
     bool valid = XMLUtils::isValidQName(qName, &colon);
@@ -191,16 +192,23 @@ void XMLUtils::normalizePIValue(nsAStrin
         }
         piValue.Append(ch);
         prevCh = ch;
         ++conversionLoop;
     }
 }
 
 //static
+bool XMLUtils::isValidQName(const nsAFlatString& aQName,
+                            const PRUnichar** aColon)
+{
+  return NS_SUCCEEDED(nsContentUtils::CheckQName(aQName, true, aColon));
+}
+
+//static
 bool XMLUtils::getXMLSpacePreserve(const txXPathNode& aNode)
 {
     nsAutoString value;
     txXPathTreeWalker walker(aNode);
     do {
         if (walker.getAttr(nsGkAtoms::space, kNameSpaceID_XML, value)) {
             if (TX_StringEqualsAtom(value, nsGkAtoms::preserve)) {
                 return true;
--- a/content/xslt/src/xml/txXMLUtils.h
+++ b/content/xslt/src/xml/txXMLUtils.h
@@ -10,17 +10,16 @@
 #ifndef MITRE_XMLUTILS_H
 #define MITRE_XMLUTILS_H
 
 #include "txCore.h"
 #include "nsCOMPtr.h"
 #include "nsDependentSubstring.h"
 #include "nsIAtom.h"
 #include "txXPathNode.h"
-#include "nsContentUtils.h"
 
 #define kExpatSeparatorChar 0xFFFF
 
 extern "C" int MOZ_XMLIsLetter(const char* ptr);
 extern "C" int MOZ_XMLIsNCNameChar(const char* ptr);
 
 class nsIAtom;
 class txNamespaceMap;
@@ -109,20 +108,17 @@ public:
      * Normalizes the value of a XML processingInstruction
     **/
     static void normalizePIValue(nsAString& attValue);
 
     /**
      * Returns true if the given string is a valid XML QName
      */
     static bool isValidQName(const nsAFlatString& aQName,
-                               const PRUnichar** aColon)
-    {
-        return NS_SUCCEEDED(nsContentUtils::CheckQName(aQName, true, aColon));
-    }
+                             const PRUnichar** aColon);
 
     /**
      * Returns true if the given character represents an Alpha letter
      */
     static bool isLetter(PRUnichar aChar)
     {
         return !!MOZ_XMLIsLetter(reinterpret_cast<const char*>(&aChar));
     }   
--- a/content/xslt/src/xpath/txXPathNode.h
+++ b/content/xslt/src/xpath/txXPathNode.h
@@ -6,17 +6,17 @@
 #ifndef txXPathNode_h__
 #define txXPathNode_h__
 
 #include "nsAutoPtr.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMNode.h"
 #include "nsINameSpaceManager.h"
-#include "nsContentUtils.h"
+#include "nsContentUtils.h" // For NameSpaceManager().
 
 typedef nsIDOMNode txXPathNodeType;
 
 class txXPathNode
 {
 public:
     bool operator==(const txXPathNode& aNode) const;
     bool operator!=(const txXPathNode& aNode) const
--- a/content/xul/document/src/nsXULContentSink.cpp
+++ b/content/xul/document/src/nsXULContentSink.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 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/. */
 
 /*
  * An implementation for a Gecko-style content sink that knows how
  * to build a content model (the "prototype" document) from XUL.
  *
@@ -868,54 +869,34 @@ XULContentSinkImpl::OpenScript(const PRU
           if (nsContentUtils::IsJavascriptMIMEType(mimeType)) {
               langID = nsIProgrammingLanguage::JAVASCRIPT;
               version = JSVERSION_LATEST;
           } else {
               langID = nsIProgrammingLanguage::UNKNOWN;
           }
 
           if (langID != nsIProgrammingLanguage::UNKNOWN) {
-            // Get the version string, and ensure the language supports it.
-            nsAutoString versionName;
-            rv = parser.GetParameter("version", versionName);
+              // Get the version string, and ensure the language supports it.
+              nsAutoString versionName;
+              rv = parser.GetParameter("version", versionName);
 
-            if (NS_SUCCEEDED(rv)) {
-              version = nsContentUtils::ParseJavascriptVersion(versionName);
-            } else if (rv != NS_ERROR_INVALID_ARG) {
-              return rv;
-            }
-          }
-          // Some js specifics yet to be abstracted.
-          if (langID == nsIProgrammingLanguage::JAVASCRIPT) {
-              // By default scripts in XUL documents have E4X turned on. This
-              // is still OK if version is JSVERSION_UNKNOWN (-1),
-              version = js::VersionSetMoarXML(JSVersion(version), true);
-
-              nsAutoString value;
-              rv = parser.GetParameter("e4x", value);
-              if (NS_FAILED(rv)) {
-                  if (rv != NS_ERROR_INVALID_ARG)
-                      return rv;
-              } else {
-                  if (value.Length() == 1 && value[0] == '0')
-                    version = js::VersionSetMoarXML(JSVersion(version), false);
+              if (NS_SUCCEEDED(rv)) {
+                  version = nsContentUtils::ParseJavascriptVersion(versionName);
+              } else if (rv != NS_ERROR_INVALID_ARG) {
+                  return rv;
               }
           }
       }
       else if (key.EqualsLiteral("language")) {
           // Language is deprecated, and the impl in nsScriptLoader ignores the
           // various version strings anyway.  So we make no attempt to support
           // languages other than JS for language=
           nsAutoString lang(aAttributes[1]);
           if (nsContentUtils::IsJavaScriptLanguage(lang, &version)) {
               langID = nsIProgrammingLanguage::JAVASCRIPT;
-
-              // Even when JS version < 1.6 is specified, E4X is
-              // turned on in XUL.
-              version = js::VersionSetMoarXML(JSVersion(version), true);
           }
       }
       aAttributes += 2;
   }
 
   // Not all script languages have a "sandbox" concept.  At time of
   // writing, Python is the only other language, and it does not.
   // For such languages, neither any inline script nor remote script are
--- a/dom/apps/src/AppsService.js
+++ b/dom/apps/src/AppsService.js
@@ -63,13 +63,18 @@ AppsService.prototype = {
     return DOMApplicationRegistry.getCoreAppsBasePath();
   },
 
   getWebAppsBasePath: function getWebAppsBasePath() {
     debug("getWebAppsBasePath()");
     return DOMApplicationRegistry.getWebAppsBasePath();
   },
 
+  getAppInfo: function getAppInfo(aAppId) {
+    debug("getAppInfo()");
+    return DOMApplicationRegistry.getAppInfo(aAppId);
+  },
+
   classID : APPS_SERVICE_CID,
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService])
 }
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AppsService])
--- a/dom/apps/src/AppsServiceChild.jsm
+++ b/dom/apps/src/AppsServiceChild.jsm
@@ -106,12 +106,21 @@ this.DOMApplicationRegistry = {
   getCoreAppsBasePath: function getCoreAppsBasePath() {
     debug("getCoreAppsBasePath() not yet supported on child!");
     return null;
   },
 
   getWebAppsBasePath: function getWebAppsBasePath() {
     debug("getWebAppsBasePath() not yet supported on child!");
     return null;
-  }
+  },
+
+  getAppInfo: function getAppInfo(aAppId) {
+    if (!this.webapps[aAppId]) {
+      debug("No webapp for " + aAppId);
+      return null;
+    }
+    return { "basePath":  this.webapps[aAppId].basePath + "/",
+             "isCoreApp": !this.webapps[aAppId].removable };
+  },
 }
 
 DOMApplicationRegistry.init();
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -70,17 +70,17 @@ this.DOMApplicationRegistry = {
   children: [ ],
   allAppsLaunchable: false,
 
   init: function() {
     this.messages = ["Webapps:Install", "Webapps:Uninstall",
                      "Webapps:GetSelf", "Webapps:CheckInstalled",
                      "Webapps:GetInstalled", "Webapps:GetNotInstalled",
                      "Webapps:Launch", "Webapps:GetAll",
-                     "Webapps:InstallPackage", "Webapps:GetAppInfo",
+                     "Webapps:InstallPackage",
                      "Webapps:GetList", "Webapps:RegisterForMessages",
                      "Webapps:UnregisterForMessages",
                      "Webapps:CancelDownload", "Webapps:CheckForUpdate",
                      "Webapps:Download", "Webapps:ApplyDownload",
                      "child-process-shutdown"];
 
     this.frameMessages = ["Webapps:ClearBrowserData"];
 
@@ -793,24 +793,16 @@ this.DOMApplicationRegistry = {
         this.getNotInstalled(msg, mm);
         break;
       case "Webapps:GetAll":
         this.getAll(msg, mm);
         break;
       case "Webapps:InstallPackage":
         this.doInstallPackage(msg, mm);
         break;
-      case "Webapps:GetAppInfo":
-        if (!this.webapps[msg.id]) {
-          debug("No webapp for " + msg.id);
-          return null;
-        }
-        return { "basePath":  this.webapps[msg.id].basePath + "/",
-                 "isCoreApp": !this.webapps[msg.id].removable };
-        break;
       case "Webapps:RegisterForMessages":
         this.addMessageListener(msg, mm);
         break;
       case "Webapps:UnregisterForMessages":
         this.removeMessageListener(msg, mm);
         break;
       case "child-process-shutdown":
         this.removeMessageListener(["Webapps:Internal:AllMessages"], mm);
@@ -831,16 +823,25 @@ this.DOMApplicationRegistry = {
         this.applyDownload(msg.manifestURL);
         break;
       case "Activities:Register:OK":
         this.notifyAppsRegistryReady();
         break;
     }
   },
 
+  getAppInfo: function getAppInfo(aAppId) {
+    if (!this.webapps[aAppId]) {
+      debug("No webapp for " + aAppId);
+      return null;
+    }
+    return { "basePath":  this.webapps[aAppId].basePath + "/",
+             "isCoreApp": !this.webapps[aAppId].removable };
+  },
+
   // Some messages can be listened by several content processes:
   // Webapps:AddApp
   // Webapps:RemoveApp
   // Webapps:Install:Return:OK
   // Webapps:Uninstall:Return:OK
   // Webapps:Uninstall:Broadcast:Return:OK
   // Webapps:OfflineCache
   // Webapps:checkForUpdate:Return:OK
@@ -2231,23 +2232,27 @@ this.DOMApplicationRegistry = {
                 }
                 app.appStatus = AppsUtils.getAppManifestStatus(manifest);
 
                 // Save the new Etag for the package.
                 if (aIsUpdate) {
                   if (!app.staged) {
                     app.staged = { };
                   }
-                  app.staged.packageEtag =
-                    requestChannel.getResponseHeader("Etag");
+                  try {
+                    app.staged.packageEtag =
+                      requestChannel.getResponseHeader("Etag");
+                  } catch(e) { }
                   app.staged.packageHash = aHash;
                   app.staged.appStatus =
                     AppsUtils.getAppManifestStatus(manifest);
                 } else {
-                  app.packageEtag = requestChannel.getResponseHeader("Etag");
+                  try {
+                    app.packageEtag = requestChannel.getResponseHeader("Etag");
+                  } catch(e) { }
                   app.packageHash = aHash;
                   app.appStatus = AppsUtils.getAppManifestStatus(manifest);
                 }
 
                 if (aOnSuccess) {
                   aOnSuccess(id, manifest);
                 }
               } catch (e) {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1901,27 +1901,18 @@ WindowStateHolder::~WindowStateHolder()
 
 NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder)
 
 nsresult
 nsGlobalWindow::CreateOuterObject(nsGlobalWindow* aNewInner)
 {
   JSContext* cx = mContext->GetNativeContext();
 
-  bool isChrome = IsChromeWindow();
-  if (isChrome) {
-    // Always enable E4X for XUL and other chrome content -- there is no
-    // need to preserve the <!-- script hiding hack from JS-in-HTML daze
-    // (introduced in 1995 for graceful script degradation in Netscape 1,
-    // Mosaic, and other pre-JS browsers).
-    JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_MOAR_XML);
-  }
-
   JSObject* outer = NewOuterWindowProxy(cx, aNewInner->FastGetGlobalJSObject(),
-                                        isChrome);
+                                        IsChromeWindow());
   if (!outer) {
     return NS_ERROR_FAILURE;
   }
 
   js::SetProxyExtra(outer, 0, js::PrivateValue(ToSupports(this)));
 
   return SetOuterObject(cx, outer);
 }
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -998,32 +998,28 @@ nsJSContext::JSOptionChangedCallback(con
   bool useMethodJIT = Preferences::GetBool(chromeWindow || !contentWindow ?
                                                js_methodjit_chrome_str :
                                                js_methodjit_content_str);
   bool usePCCounts = Preferences::GetBool(chromeWindow || !contentWindow ?
                                             js_pccounts_chrome_str :
                                             js_pccounts_content_str);
   bool useMethodJITAlways = Preferences::GetBool(js_methodjit_always_str);
   bool useTypeInference = !chromeWindow && contentWindow && Preferences::GetBool(js_typeinfer_str);
-  bool useXML = Preferences::GetBool(chromeWindow || !contentWindow ?
-                                     "javascript.options.xml.chrome" :
-                                     "javascript.options.xml.content");
   bool useHardening = Preferences::GetBool(js_jit_hardening_str);
   bool useIon = Preferences::GetBool(js_ion_content_str);
   bool parallelIonCompilation = Preferences::GetBool(js_ion_parallel_compilation_str);
   nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
   if (xr) {
     bool safeMode = false;
     xr->GetInSafeMode(&safeMode);
     if (safeMode) {
       useMethodJIT = false;
       usePCCounts = false;
       useTypeInference = false;
       useMethodJITAlways = true;
-      useXML = false;
       useHardening = false;
       useIon = false;
     }
   }
 
   if (useMethodJIT)
     newDefaultJSOptions |= JSOPTION_METHODJIT;
   else
@@ -1044,39 +1040,33 @@ nsJSContext::JSOptionChangedCallback(con
   else
     newDefaultJSOptions &= ~JSOPTION_TYPE_INFERENCE;
 
   if (useIon)
     newDefaultJSOptions |= JSOPTION_ION;
   else
     newDefaultJSOptions &= ~JSOPTION_ION;
 
-  if (useXML)
-    newDefaultJSOptions |= JSOPTION_ALLOW_XML;
-  else
-    newDefaultJSOptions &= ~JSOPTION_ALLOW_XML;
-
 #ifdef DEBUG
   // In debug builds, warnings are enabled in chrome context if
   // javascript.options.strict.debug is true
   bool strictDebug = Preferences::GetBool(js_strict_debug_option_str);
   if (strictDebug && (newDefaultJSOptions & JSOPTION_STRICT) == 0) {
     if (chromeWindow || !contentWindow)
       newDefaultJSOptions |= JSOPTION_STRICT;
   }
 #endif
 
   bool werror = Preferences::GetBool(js_werror_option_str);
   if (werror)
     newDefaultJSOptions |= JSOPTION_WERROR;
   else
     newDefaultJSOptions &= ~JSOPTION_WERROR;
 
-  ::JS_SetOptions(context->mContext,
-                  newDefaultJSOptions & (JSRUNOPTION_MASK | JSOPTION_ALLOW_XML));
+  ::JS_SetOptions(context->mContext, newDefaultJSOptions & JSRUNOPTION_MASK);
 
   ::JS_SetParallelCompilationEnabled(context->mContext, parallelIonCompilation);
 
   // Save the new defaults for the next page load (InitContext).
   context->mDefaultJSOptions = newDefaultJSOptions;
 
   JSRuntime *rt = JS_GetRuntime(context->mContext);
   JS_SetJitHardening(rt, useHardening);
@@ -1102,17 +1092,17 @@ nsJSContext::nsJSContext(JSRuntime *aRun
   mPrev = &sContextList;
   if (sContextList) {
     sContextList->mPrev = &mNext;
   }
   sContextList = this;
 
   ++sContextCount;
 
-  mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS | JSOPTION_ALLOW_XML;
+  mDefaultJSOptions = JSOPTION_PRIVATE_IS_NSISUPPORTS;
 
   mContext = ::JS_NewContext(aRuntime, gStackSize);
   if (mContext) {
     ::JS_SetContextPrivate(mContext, static_cast<nsIScriptContext *>(this));
 
     // Preserve any flags the context callback might have set.
     mDefaultJSOptions |= ::JS_GetOptions(mContext);
 
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -647,31 +647,27 @@ DOMInterfaces = {
     'nativeType': 'nsSVGElement',
     'hasXPConnectImpls': True,
     'hasInstanceInterface': 'nsIDOMSVGElement',
     'resultNotAddRefed': ['ownerSVGElement', 'viewportElement', 'style']
 },
 
 'SVGGraphicsElement': {
     'concrete': False,
+    'resultNotAddRefed': ['nearestViewportElement', 'farthestViewportElement']
 },
 
 'SVGGradientElement': {
     'concrete': False,
 },
 
 'SVGImageElement': {
     'hasInstanceInterface': 'nsIDOMSVGImageElement',
 },
 
-'SVGLocatableElement': {
-    'concrete': False,
-    'resultNotAddRefed': ['nearestViewportElement', 'farthestViewportElement']
-},
-
 'SVGLengthList': {
     'nativeType': 'mozilla::DOMSVGLengthList',
     'headerFile': 'DOMSVGLengthList.h',
     'resultNotAddRefed': [ 'getItem' ]
 },
 
 'SVGLinearGradientElement': {
     'headerFile': 'mozilla/dom/SVGGradientElement.h',
@@ -823,20 +819,16 @@ DOMInterfaces = {
 },
 
 'SVGTransform': {
     'nativeType': 'mozilla::DOMSVGTransform',
     'headerFile': 'DOMSVGTransform.h',
     'resultNotAddRefed': [ 'matrix' ]
 },
 
-'SVGTransformableElement': {
-    'concrete': False
-},
-
 'SVGTransformList': {
     'nativeType': 'mozilla::DOMSVGTransformList',
     'headerFile': 'DOMSVGTransformList.h',
     'resultNotAddRefed': [ 'getItem' ]
 },
 
 'SVGSVGElement': {
     'resultNotAddRefed': [ 'getElementById' ]
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -662,17 +662,17 @@ BluetoothHfpManager::HandleShutdown()
   gInShutdown = true;
   CloseSocket();
   gBluetoothHfpManager = nullptr;
   return NS_OK;
 }
 
 // Virtual function of class SocketConsumer
 void
-BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
+BluetoothHfpManager::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoCString msg((const char*)aMessage->mData.get(), aMessage->mSize);
   msg.StripWhitespace();
 
   nsTArray<nsCString> atCommandValues;
 
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -47,17 +47,17 @@ enum BluetoothCmeError {
   NETWORK_TIMEOUT = 31,
   NETWORK_NOT_ALLOWED = 32
 };
 
 class BluetoothHfpManager : public mozilla::ipc::UnixSocketConsumer
 {
 public:
   static BluetoothHfpManager* Get();
-  virtual void ReceiveSocketData(mozilla::ipc::UnixSocketRawData* aMessage)
+  virtual void ReceiveSocketData(nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage)
     MOZ_OVERRIDE;
 
   bool Connect(const nsAString& aDeviceObjectPath,
                const bool aIsHandsfree,
                BluetoothReplyRunnable* aRunnable);
   void Disconnect();
   bool Listen();
 
--- a/dom/bluetooth/BluetoothOppManager.cpp
+++ b/dom/bluetooth/BluetoothOppManager.cpp
@@ -889,17 +889,17 @@ BluetoothOppManager::ClientDataHandler(U
     }
   } else {
     NS_WARNING("Unhandled ObexRequestCode");
   }
 }
 
 // Virtual function of class SocketConsumer
 void
-BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
+BluetoothOppManager::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
 {
   if (mLastCommand) {
     ClientDataHandler(aMessage);
     return;
   }
 
   ServerDataHandler(aMessage);
 }
--- a/dom/bluetooth/BluetoothOppManager.h
+++ b/dom/bluetooth/BluetoothOppManager.h
@@ -28,17 +28,17 @@ public:
    * function add_reserved_service_records() in
    * external/bluetooth/bluez/src/adapter.c for more information.
    */
   static const int DEFAULT_OPP_CHANNEL = 10;
   static const int MAX_PACKET_LENGTH = 0xFFFE;
 
   ~BluetoothOppManager();
   static BluetoothOppManager* Get();
-  void ReceiveSocketData(mozilla::ipc::UnixSocketRawData* aMessage)
+  void ReceiveSocketData(nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage)
     MOZ_OVERRIDE;
   void ClientDataHandler(mozilla::ipc::UnixSocketRawData* aMessage);
   void ServerDataHandler(mozilla::ipc::UnixSocketRawData* aMessage);
 
   /*
    * If a application wnats to send a file, first, it needs to
    * call Connect() to create a valid RFCOMM connection. After
    * that, call SendFile()/StopSendingFile() to control file-sharing
--- a/dom/bluetooth/BluetoothScoManager.cpp
+++ b/dom/bluetooth/BluetoothScoManager.cpp
@@ -166,17 +166,17 @@ BluetoothScoManager::Get()
   }
 
   gBluetoothScoManager = manager;
   return gBluetoothScoManager;
 }
 
 // Virtual function of class SocketConsumer
 void
-BluetoothScoManager::ReceiveSocketData(mozilla::ipc::UnixSocketRawData* aMessage)
+BluetoothScoManager::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage)
 {
   // SCO socket do nothing here
   MOZ_NOT_REACHED("This should never be called!");
 }
 
 nsresult
 BluetoothScoManager::HandleShutdown()
 {
--- a/dom/bluetooth/BluetoothScoManager.h
+++ b/dom/bluetooth/BluetoothScoManager.h
@@ -17,17 +17,17 @@ class BluetoothReplyRunnable;
 class BluetoothScoManagerObserver;
 
 class BluetoothScoManager : public mozilla::ipc::UnixSocketConsumer
 {
 public:
   ~BluetoothScoManager();
 
   static BluetoothScoManager* Get();
-  void ReceiveSocketData(mozilla::ipc::UnixSocketRawData* aMessage)
+  void ReceiveSocketData(nsAutoPtr<mozilla::ipc::UnixSocketRawData>& aMessage)
     MOZ_OVERRIDE;
 
   bool Connect(const nsAString& aDeviceObjectPath);
   void Disconnect();
   bool Listen();
 
 private:
   friend class BluetoothScoManagerObserver;
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -981,16 +981,33 @@ GetPropertyIndex(Properties* prop, const
     if (!strncmp(propertyName, prop[i].name, strlen(propertyName))) {
       return i;
     }
   }
   return -1;
 }
 
 bool
+HasAudioService(uint32_t aCodValue)
+{
+  return ((aCodValue & 0x200000) == 0x200000);
+}
+
+bool
+ContainsIcon(const InfallibleTArray<BluetoothNamedValue>& aProperties)
+{
+  for (uint8_t i = 0; i < aProperties.Length(); i++) {
+    if (aProperties[i].name().EqualsLiteral("Icon")) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool
 GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
             int aPropertyTypeLen, int* aPropIndex,
             InfallibleTArray<BluetoothNamedValue>& aProperties)
 {
   DBusMessageIter prop_val, array_val_iter;
   char* property = NULL;
   uint32_t array_type;
   int i, type;
@@ -1370,16 +1387,36 @@ EventFilter(DBusConnection* aConn, DBusM
           .AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Address"),
                                              addrstr));
 
         // We also need to create a path for the device, to make sure we know
         // where to access it later.
         v.get_ArrayOfBluetoothNamedValue()
           .AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Path"),
                                              path));
+        const InfallibleTArray<BluetoothNamedValue>& properties =
+          v.get_ArrayOfBluetoothNamedValue();
+        if (!ContainsIcon(properties)) {
+          for (uint8_t i = 0; i < properties.Length(); i++) {
+            // It is possible that property Icon missed due to CoD of major
+            // class is TOY but service class is "Audio", we need to assign
+            // Icon as audio-card. This is for PTS test TC_AG_COD_BV_02_I.
+            // As HFP specification defined that
+            // service class is "Audio" can be considered as HFP AG.
+            if (properties[i].name().EqualsLiteral("Class")) {
+              if (HasAudioService(properties[i].value().get_uint32_t())) {
+                v.get_ArrayOfBluetoothNamedValue()
+                  .AppendElement(
+                    BluetoothNamedValue(NS_LITERAL_STRING("Icon"),
+                                        NS_LITERAL_STRING("audio-card")));
+              }
+              break;
+            }
+          }
+        }
       }
     } else {
       errorStr.AssignLiteral("DBus device found message structure not as expected!");
     }
   } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceDisappeared")) {
     const char* str;
     if (!dbus_message_get_args(aMsg, &err,
                                DBUS_TYPE_STRING, &str,
--- a/dom/interfaces/apps/nsIAppsService.idl
+++ b/dom/interfaces/apps/nsIAppsService.idl
@@ -11,17 +11,17 @@ interface mozIApplication;
 #define APPS_SERVICE_CID { 0x05072afa, 0x92fe, 0x45bf, { 0xae, 0x22, 0x39, 0xb6, 0x9c, 0x11, 0x70, 0x58 } }
 #define APPS_SERVICE_CONTRACTID "@mozilla.org/AppsService;1"
 %}
 
 /*
  * This service allows accessing some DOMApplicationRegistry methods from
  * non-javascript code.
  */
-[scriptable, uuid(e65f9397-e191-4273-aa5f-f13c185ce63b)]
+[scriptable, uuid(4ac27836-4d79-4d35-b105-d6fb7f4f8e41)]
 interface nsIAppsService : nsISupports
 {
   mozIDOMApplication getAppByManifestURL(in DOMString manifestURL);
 
   /**
    * Returns the |localId| of the app associated with the |manifestURL| passed
    * in parameter.
    * Returns nsIScriptSecurityManager::NO_APP_ID if |manifestURL| isn't a valid
@@ -55,9 +55,11 @@ interface nsIAppsService : nsISupports
    * Returns the basepath for core apps
    */
   DOMString getCoreAppsBasePath();
 
   /**
    * Returns the basepath for regular packaged apps
    */
   DOMString getWebAppsBasePath();
+
+  jsval getAppInfo(in DOMString appId);
 };
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -214,17 +214,18 @@ private:
 
   // When this timer expires, we set mResetPriorityTimer to null and run
   // ResetPriorityNow().
   nsCOMPtr<nsITimer> mResetPriorityTimer;
 
   nsWeakPtr mMemoryMinimizerRunnable;
 };
 
-NS_IMPL_ISUPPORTS2(ProcessPriorityManager, nsIObserver, nsIDOMEventListener)
+NS_IMPL_ISUPPORTS3(ProcessPriorityManager, nsIObserver,
+                   nsIDOMEventListener, nsITimerCallback)
 
 ProcessPriorityManager::ProcessPriorityManager()
   : mProcessPriority(ProcessPriority(-1))
 {
   // When our parent process forked us, it set our priority either to
   // FOREGROUND (if our parent launched this process to meet an immediate need)
   // or one of the BACKGROUND priorities (if our parent launched this process
   // to meet a future need).
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -547,29 +547,32 @@ PeerConnection.prototype = {
       type: desc.type
     });
   },
 
   updateIce: function(config, constraints, restart) {
     return Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
 
-  addIceCandidate: function(cand) {
+  addIceCandidate: function(cand, onSuccess, onError) {
     if (!cand) {
       throw new Error ("NULL candidate passed to addIceCandidate!");
     }
 
     if (!cand.candidate || !cand.sdpMLineIndex) {
       throw new Error ("Invalid candidate passed to addIceCandidate!");
     }
 
+    this._onAddIceCandidateSuccess = onSuccess;
+    this._onAddIceCandidateError = onError;
+
     this._queueOrRun({
       func: this._pc.addIceCandidate,
       args: [cand.candidate, cand.sdpMid || "", cand.sdpMLineIndex],
-      wait: false
+      wait: true
     });
   },
 
   addStream: function(stream, constraints) {
     // TODO: Implement constraints.
     this._queueOrRun({
       func: this._pc.addStream,
       args: [stream],
@@ -753,16 +756,32 @@ PeerConnectionObserver.prototype = {
   onSetRemoteDescriptionError: function(code) {
     this._dompc._pendingType = null;
     if (this._dompc._onSetRemoteDescriptionFailure) {
       this._dompc._onSetRemoteDescriptionFailure.onCallback(code);
     }
     this._dompc._executeNext();
   },
 
+  onAddIceCandidateSuccess: function(code) {
+    this._dompc._pendingType = null;
+    if (this._dompc._onAddIceCandidateSuccess) {
+      this._dompc._onAddIceCandidateSuccess.onCallback(code);
+    }
+    this._dompc._executeNext();
+  },
+
+  onAddIceCandidateError: function(code) {
+    this._dompc._pendingType = null;
+    if (this._dompc._onAddIceCandidateError) {
+      this._dompc._onAddIceCandidateError.onCallback(code);
+    }
+    this._dompc._executeNext();
+  },
+
   onStateChange: function(state) {
     if (state != Ci.IPeerConnectionObserver.kIceState) {
       return;
     }
 
     let self = this;
     let iceCb = function() {};
     let iceGatherCb = function() {};
--- a/dom/media/bridge/IPeerConnection.idl
+++ b/dom/media/bridge/IPeerConnection.idl
@@ -37,16 +37,18 @@ interface IPeerConnectionObserver : nsIS
   void onCreateOfferSuccess(in string offer);
   void onCreateOfferError(in unsigned long code);
   void onCreateAnswerSuccess(in string answer);
   void onCreateAnswerError(in unsigned long code);
   void onSetLocalDescriptionSuccess(in unsigned long code);
   void onSetRemoteDescriptionSuccess(in unsigned long code);
   void onSetLocalDescriptionError(in unsigned long code);
   void onSetRemoteDescriptionError(in unsigned long code);
+  void onAddIceCandidateSuccess(in unsigned long code);
+  void onAddIceCandidateError(in unsigned long code);
 
   /* Data channel callbacks */
   void notifyDataChannel(in nsIDOMDataChannel channel);
   void notifyConnection();
   void notifyClosedConnection();
 
   /* Notification of one of several types of state changed */
   void onStateChange(in unsigned long state);
--- a/dom/media/nsIDOMRTCPeerConnection.idl
+++ b/dom/media/nsIDOMRTCPeerConnection.idl
@@ -54,17 +54,19 @@ interface nsIDOMRTCPeerConnection : nsIS
   void setRemoteDescription(in nsIDOMRTCSessionDescription desc,
     [optional] in RTCPeerConnectionCallback successCallback,
     [optional] in RTCPeerConnectionCallback failureCallback);
 
   void updateIce([optional] in jsval configuration,
     [optional] in jsval constraints,
     [optional] in bool restart);
 
-  void addIceCandidate(in nsIDOMRTCIceCandidate candidate);
+  void addIceCandidate(in nsIDOMRTCIceCandidate candidate,
+    [optional] in RTCPeerConnectionCallback successCallback,
+    [optional] in RTCPeerConnectionCallback failureCallback);
 
   void addStream(in nsIDOMMediaStream stream,
     [optional] in jsval constraints);
 
   void removeStream(in nsIDOMMediaStream stream);
   void close();
 
   /* Readonly attributes */
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/crashtests/834100.html
@@ -0,0 +1,24 @@
+<html class="reftest-wait">
+  <head>
+    <script language="javascript">
+
+function start() {
+  remotePC = new mozRTCPeerConnection();
+  var cand = new mozRTCIceCandidate(
+                {candidate: "1 1 UDP 1 127.0.0.1 34567 type host",
+                 sdpMid: "helloworld",
+                 sdbMid: "helloworld", // Mis-spelt attribute for bug 833948 compatibility.
+                 sdpMLineIndex: 1
+                });
+  remotePC.addIceCandidate(cand);
+  remotePC.addIceCandidate(cand, function(sdp){}, finish);
+}
+
+function finish(arg) {
+  document.documentElement.removeAttribute("class");
+}
+    </script>
+  </head>
+  <body onload="start()">
+  </body>
+</html>
--- a/dom/media/tests/crashtests/crashtests.list
+++ b/dom/media/tests/crashtests/crashtests.list
@@ -3,9 +3,10 @@ default-preferences pref(media.peerconne
 load 780790.html
 load 791270.html
 load 791278.html
 load 791330.html
 load 799419.html
 load 801227.html
 load 802982.html
 load 812785.html
+load 834100.html
 load 822197.html
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1,9 +1,9 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 var PeerConnection = {
   pc1_offer : null,
   pc2_answer : null,
 
@@ -13,44 +13,50 @@ var PeerConnection = {
    * @param {object) aPCLocal Local client
    * @param {object} aPCRemote Remote client
    * @param {function} aSuccessCallback Method to call when the connection has been established
    */
   handShake: function PC_handShake(aPCLocal, aPCRemote, aSuccessCallback) {
 
     function onCreateOfferSuccess(aOffer) {
       pc1_offer = aOffer;
+      info("Calling setLocalDescription on local peer connection");
       aPCLocal.setLocalDescription(aOffer, onSetLocalDescriptionSuccess1,
                                    unexpectedCallbackAndFinish);
     }
 
     function onSetLocalDescriptionSuccess1() {
+      info("Calling setRemoteDescription on remote peer connection");
       aPCRemote.setRemoteDescription(pc1_offer, onSetRemoteDescriptionSuccess1,
                                      unexpectedCallbackAndFinish);
     }
 
     function onSetRemoteDescriptionSuccess1() {
+      info("Calling createAnswer on remote peer connection");
       aPCRemote.createAnswer(onCreateAnswerSuccess, unexpectedCallbackAndFinish);
     }
 
     function onCreateAnswerSuccess(aAnswer) {
       pc2_answer = aAnswer;
+      info("Calling setLocalDescription on remote peer connection");
       aPCRemote.setLocalDescription(aAnswer, onSetLocalDescriptionSuccess2,
                                     unexpectedCallbackAndFinish);
     }
 
     function onSetLocalDescriptionSuccess2() {
+      info("Calling setRemoteDescription on local peer connection");
       aPCLocal.setRemoteDescription(pc2_answer, onSetRemoteDescriptionSuccess2,
                                     unexpectedCallbackAndFinish);
     }
 
     function onSetRemoteDescriptionSuccess2() {
       aSuccessCallback();
     }
 
+    info("Calling createOffer on local peer connection");
     aPCLocal.createOffer(onCreateOfferSuccess, unexpectedCallbackAndFinish);
   },
 
   /**
    * Finds the given media stream in the list of available streams.
    *
    * This function is necessary because localStreams and remoteStreams don't have
    * an indexOf method.
--- a/dom/media/tests/mochitest/test_peerConnection_basicAudio.html
+++ b/dom/media/tests/mochitest/test_peerConnection_basicAudio.html
@@ -1,9 +1,9 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=796892
 -->
 <head>
   <meta charset="utf-8">
   <title>Basic audio-only peer connection</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
@@ -37,61 +37,68 @@ https://bugzilla.mozilla.org/show_bug.cg
     audioLocal = document.getElementById("audioLocal");
     audioPCLocal = document.getElementById("audioPCLocal");
     audioPCRemote = document.getElementById("audioPCRemote");
 
     pcLocal = new mozRTCPeerConnection();
     pcRemote = new mozRTCPeerConnection();
 
     pcLocal.onaddstream = function (aObj) {
+      info("Local Peer Connection onaddstream has been called");
       test_data.pcLocal.push(aObj.stream);
 
       audioPCRemote.mozSrcObject = aObj.stream;
       audioPCRemote.play();
     };
 
     pcRemote.onaddstream = function (aObj) {
+      info("Remote Peer Connection onaddstream has been called");
       test_data.pcRemote.push(aObj.stream);
 
       audioPCLocal.mozSrcObject = aObj.stream;
       audioPCLocal.play();
     };
 
     navigator.mozGetUserMedia({audio: true, fake: true}, function onSuccess(aLocalInputStream) {
+      info("Calling addStream on local peer connection");
       pcLocal.addStream(aLocalInputStream);
 
       navigator.mozGetUserMedia({audio: true, fake: true}, function onSuccess(aRemoteInputStream) {
+        info("Calling addStream on remote peer connection");
         pcRemote.addStream(aRemoteInputStream);
 
         audioLocal.mozSrcObject = aLocalInputStream;
         audioLocal.play();
 
         PeerConnection.handShake(pcLocal, pcRemote, function () {
+          info("Finished peer connection handshake");
           is(pcLocal.localStreams.length, 1,
              "A single local stream has been attached to the local peer");
           is(pcRemote.localStreams.length, 1,
              "A single local stream has been attached to the remote peer");
 
           // TODO: check that the streams are of the expected types.
-	  // Bug 834837.
+          // Bug 834837.
 
           ok(PeerConnection.findStream(pcLocal.remoteStreams, test_data.pcLocal[0]) !== -1,
              "Remote audio stream for local peer is accessible");
           ok(PeerConnection.findStream(pcRemote.remoteStreams, test_data.pcRemote[0]) !== -1,
              "Remote audio stream for remote peer is accessible");
 
           info("For now simply disconnect. We will add checks for media in a follow-up bug");
           disconnect();
         });
       }, unexpectedCallbackAndFinish);
     }, unexpectedCallbackAndFinish);
   }, true);
 
   function disconnect() {
+    info("Calling close on the local peer connection");
     pcLocal.close();
+    info("Calling close on the remote peer connection");
     pcRemote.close();
 
     info("We can't run any checks and clean-up code due to a crash (see bug 820072)");
 
     SimpleTest.finish();
   }
 </script>
 </pre>
--- a/dom/media/tests/mochitest/test_peerConnection_basicAudioVideo.html
+++ b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideo.html
@@ -1,9 +1,9 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=796890
 -->
 <head>
   <meta charset="utf-8">
   <title>Basic video-only peer connection</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
@@ -47,80 +47,90 @@ https://bugzilla.mozilla.org/show_bug.cg
     videoLocal = document.getElementById("videoLocal");
     videoPCLocal = document.getElementById("videoPCLocal");
     videoPCRemote = document.getElementById("videoPCRemote");
 
     pcLocal = new mozRTCPeerConnection();
     pcRemote = new mozRTCPeerConnection();
 
     pcLocal.onaddstream = function (aObj) {
+      info("Local Peer Connection onaddstream has been called");
       test_data.pcLocal.push(aObj.stream);
 
       videoPCRemote.mozSrcObject = aObj.stream;
       videoPCRemote.play();
     };
 
     pcRemote.onaddstream = function (aObj) {
+      info("Remote Peer Connection onaddstream has been called");
       test_data.pcRemote.push(aObj.stream);
 
       videoPCLocal.mozSrcObject = aObj.stream;
       videoPCLocal.play();
     };
 
     navigator.mozGetUserMedia({audio: true, fake: true},
                               function onSuccess(aLocalAudioInputStream) {
+      info("Calling addStream on local peer connection with audio stream");
       pcLocal.addStream(aLocalAudioInputStream);
 
       audioLocal.mozSrcObject = aLocalAudioInputStream;
       audioLocal.play();
 
       navigator.mozGetUserMedia({video: true, fake: true},
                                 function onSuccess(aLocalVideoInputStream) {
+        info("Calling addStream on local peer connection with video stream");
         pcLocal.addStream(aLocalVideoInputStream);
 
         videoLocal.mozSrcObject = aLocalVideoInputStream;
         videoLocal.play();
 
         navigator.mozGetUserMedia({audio: true, fake: true},
                                   function onSuccess(aRemoteAudioInputStream) {
+          info("Calling addStream on remote peer connection with audio stream");
           pcRemote.addStream(aRemoteAudioInputStream);
 
           navigator.mozGetUserMedia({video: true, fake: true},
                                     function onSuccess(aRemoteVideoInputStream) {
+            info("Calling addStream on remote peer connection with video stream");
             pcRemote.addStream(aRemoteVideoInputStream);
 
             PeerConnection.handShake(pcLocal, pcRemote, function () {
+              info("Finished peer connection handshake");
               is(pcLocal.localStreams.length, 2,
                  "Two local streams have been attached to the local peer");
               is(pcRemote.localStreams.length, 2,
                  "Two local local streams have been attached to the remote peer");
 
               is(test_data.pcLocal.length, 1,
                  "A remote stream has been attached to the local peer");
               is(test_data.pcRemote.length, 1,
                  "A remote stream has been attached to the remote peer");
 
-	      // TODO: check that the streams are of the expected types.
-	      // Bug 834837.
+              // TODO: check that the streams are of the expected types.
+              // Bug 834837.
+
               ok(PeerConnection.findStream(pcLocal.remoteStreams, test_data.pcLocal[0]) !== -1,
                  "Remote stream for local peer is accessible");
               ok(PeerConnection.findStream(pcRemote.remoteStreams, test_data.pcRemote[0]) !== -1,
                  "Remote stream for remote peer is accessible");
 
               info("For now simply disconnect. We will add checks for media in a follow-up bug");
               disconnect();
             });
           }, unexpectedCallbackAndFinish);
         }, unexpectedCallbackAndFinish);
       }, unexpectedCallbackAndFinish);
     }, unexpectedCallbackAndFinish);
   }, true);
 
   function disconnect() {
+    info("Calling close on the local peer connection");
     pcLocal.close();
+    info("Calling close on the remote peer connection");
     pcRemote.close();
 
     info("We can't run any checks and clean-up code due to a crash (see bug 820072)");
 
     SimpleTest.finish();
   }
 </script>
 </pre>
--- a/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoCombined.html
+++ b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoCombined.html
@@ -1,9 +1,9 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=796890
 -->
 <head>
   <meta charset="utf-8">
   <title>Basic video-only peer connection</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
@@ -41,68 +41,75 @@ https://bugzilla.mozilla.org/show_bug.cg
     videoLocal = document.getElementById("videoLocal");
     videoPCLocal = document.getElementById("videoPCLocal");
     videoPCRemote = document.getElementById("videoPCRemote");
 
     pcLocal = new mozRTCPeerConnection();
     pcRemote = new mozRTCPeerConnection();
 
     pcLocal.onaddstream = function (aObj) {
+      info("Local Peer Connection onaddstream has been called");
       test_data.pcLocal.push(aObj.stream);
 
       videoPCRemote.mozSrcObject = aObj.stream;
       videoPCRemote.play();
     };
 
     pcRemote.onaddstream = function (aObj) {
+      info("Remote Peer Connection onaddstream has been called");
       test_data.pcRemote.push(aObj.stream);
 
       videoPCLocal.mozSrcObject = aObj.stream;
       videoPCLocal.play();
     };
 
     navigator.mozGetUserMedia({audio: true, video: true, fake: true},
                               function onSuccess(aLocalInputStream) {
+      info("Calling addStream on local peer connection");
       pcLocal.addStream(aLocalInputStream);
 
       navigator.mozGetUserMedia({audio: true, video: true, fake: true},
                                 function onSuccess(aRemoteInputStream) {
+        info("Calling addStream on remote peer connection");
         pcRemote.addStream(aRemoteInputStream);
 
         videoLocal.mozSrcObject = aLocalInputStream;
         videoLocal.play();
 
         PeerConnection.handShake(pcLocal, pcRemote, function () {
+          info("Finished peer connection handshake");
           is(pcLocal.localStreams.length, 1,
              "A single local stream has been attached to the local peer");
           is(pcRemote.localStreams.length, 1,
              "A single local stream has been attached to the remote peer");
 
           is(test_data.pcLocal.length, 1,
              "A remote stream has been attached to the local peer");
           is(test_data.pcRemote.length, 1,
              "A remote stream has been attached to the remote peer");
 
-	  // TODO: check that the streams are of the expected types.
-	  // Bug 834837.
+          // TODO: check that the streams are of the expected types.
+          // Bug 834837.
 
           ok(PeerConnection.findStream(pcLocal.remoteStreams, test_data.pcLocal[0]) !== -1,
              "Remote stream for local peer is accessible");
           ok(PeerConnection.findStream(pcRemote.remoteStreams, test_data.pcRemote[0]) !== -1,
              "Remote stream for remote peer is accessible");
 
           info("For now simply disconnect. We will add checks for media in a follow-up bug");
-	  disconnect();
+          disconnect();
         });
       }, unexpectedCallbackAndFinish);
     }, unexpectedCallbackAndFinish);
   }, true);
 
   function disconnect() {
+    info("Calling close on the local peer connection");
     pcLocal.close();
+    info("Calling close on the remote peer connection");
     pcRemote.close();
 
     info("We can't run any checks and clean-up code due to a crash (see bug 820072)");
 
     SimpleTest.finish();
   }
 </script>
 </pre>
--- a/dom/media/tests/mochitest/test_peerConnection_basicVideo.html
+++ b/dom/media/tests/mochitest/test_peerConnection_basicVideo.html
@@ -1,9 +1,9 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=796888
 -->
 <head>
   <meta charset="utf-8">
   <title>Basic video-only peer connection</title>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
@@ -37,61 +37,68 @@ https://bugzilla.mozilla.org/show_bug.cg
     videoLocal = document.getElementById("videoLocal");
     videoPCLocal = document.getElementById("videoPCLocal");
     videoPCRemote = document.getElementById("videoPCRemote");
 
     pcLocal = new mozRTCPeerConnection();
     pcRemote = new mozRTCPeerConnection();
 
     pcLocal.onaddstream = function (aObj) {
+      info("Local Peer Connection onaddstream has been called");
       test_data.pcLocal.push(aObj.stream);
 
       videoPCRemote.mozSrcObject = aObj.stream;
       videoPCRemote.play();
     };
 
     pcRemote.onaddstream = function (aObj) {
+      info("Remote Peer Connection onaddstream has been called");
       test_data.pcRemote.push(aObj.stream);
 
       videoPCLocal.mozSrcObject = aObj.stream;
       videoPCLocal.play();
     };
 
     navigator.mozGetUserMedia({video: true, fake: true}, function onSuccess(aLocalInputStream) {
+      info("Calling addStream on local peer connection");
       pcLocal.addStream(aLocalInputStream);
 
       navigator.mozGetUserMedia({video: true, fake: true}, function onSuccess(aRemoteInputStream) {
+        info("Calling addStream on remote peer connection");
         pcRemote.addStream(aRemoteInputStream);
 
         videoLocal.mozSrcObject = aLocalInputStream;
         videoLocal.play();
 
         PeerConnection.handShake(pcLocal, pcRemote, function () {
+          info("Finished peer connection handshake");
           is(pcLocal.localStreams.length, 1,
              "A single local stream has been attached to the local peer");
           is(pcRemote.localStreams.length, 1,
              "A single local stream has been attached to the remote peer");
 
           // TODO: check that the streams are of the expected types.
-	  // Bug 834837.
+          // Bug 834837.
 
           ok(PeerConnection.findStream(pcLocal.remoteStreams, test_data.pcLocal[0]) !== -1,
              "Remote video stream for local peer is accessible");
           ok(PeerConnection.findStream(pcRemote.remoteStreams, test_data.pcRemote[0]) !== -1,
              "Remote video stream for remote peer is accessible");
 
           info("For now simply disconnect. We will add checks for media in a follow-up bug");
           disconnect();
         });
       }, unexpectedCallbackAndFinish);
     }, unexpectedCallbackAndFinish);
   }, true);
 
   function disconnect() {
+    info("Calling close on the local peer connection");
     pcLocal.close();
+    info("Calling close on the remote peer connection");
     pcRemote.close();
 
     info("We can't run any checks and clean-up code due to a crash (see bug 820072)");
 
     SimpleTest.finish();
   }
 </script>
 </pre>
--- a/dom/network/interfaces/nsIDOMMobileConnection.idl
+++ b/dom/network/interfaces/nsIDOMMobileConnection.idl
@@ -24,17 +24,17 @@ interface nsIDOMMozMobileConnection : ns
   const long ICC_SERVICE_CLASS_DATA_ASYNC = (1 << 5);
   const long ICC_SERVICE_CLASS_PACKET = (1 << 6);
   const long ICC_SERVICE_CLASS_PAD = (1 << 7);
   const long ICC_SERVICE_CLASS_MAX = (1 << 7);
 
   /**
    * Indicates the state of the device's ICC card.
    *
-   * Possible values: null, 'absent', 'pinRequired', 'pukRequired',
+   * Possible values: null, 'unknown', 'absent', 'pinRequired', 'pukRequired',
    * 'networkLocked', 'ready'.
    */
   readonly attribute DOMString cardState;
 
   /**
    * Information stored in the device's ICC card.
    */
   readonly attribute nsIDOMMozMobileICCInfo iccInfo;
--- a/dom/src/json/nsJSON.cpp
+++ b/dom/src/json/nsJSON.cpp
@@ -234,19 +234,19 @@ nsJSON::EncodeInternal(JSContext* cx, co
       return NS_ERROR_INVALID_ARG;
   }
   // GetMethod may have thrown
   else if (JS_IsExceptionPending(cx))
     // passing NS_OK will throw the pending exception
     return NS_OK;
 
   // Backward compatibility:
-  // function/xml shall not pass, just "plain" objects and arrays
+  // function shall not pass, just "plain" objects and arrays
   JSType type = JS_TypeOfValue(cx, val);
-  if (type == JSTYPE_FUNCTION || type == JSTYPE_XML)
+  if (type == JSTYPE_FUNCTION)
     return NS_ERROR_INVALID_ARG;
 
   // We're good now; try to stringify
   if (!JS_Stringify(cx, &val, NULL, JSVAL_NULL, WriteCallback, writer))
     return NS_ERROR_FAILURE;
 
   return NS_OK;
 }
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -314,17 +314,17 @@ CellBroadcastEtwsInfo.prototype = {
 
   warningType: null,
   emergencyUserAlert: null,
   popup: null
 };
 
 function RILContentHelper() {
   this.rilContext = {
-    cardState:            RIL.GECKO_CARDSTATE_UNAVAILABLE,
+    cardState:            RIL.GECKO_CARDSTATE_UNKNOWN,
     iccInfo:              new MobileICCInfo(),
     voiceConnectionInfo:  new MobileConnectionInfo(),
     dataConnectionInfo:   new MobileConnectionInfo()
   };
   this.voicemailInfo = new VoicemailInfo();
 
   this.initRequests();
   this.initMessageListener(RIL_IPC_MSG_NAMES);
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -209,17 +209,17 @@ function RadioInterfaceLayer() {
 
   debug("Starting RIL Worker");
   this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
   this.worker.onerror = this.onerror.bind(this);
   this.worker.onmessage = this.onmessage.bind(this);
 
   this.rilContext = {
     radioState:     RIL.GECKO_RADIOSTATE_UNAVAILABLE,
-    cardState:      RIL.GECKO_CARDSTATE_UNAVAILABLE,
+    cardState:      RIL.GECKO_CARDSTATE_UNKNOWN,
     icc:            null,
 
     // These objects implement the nsIDOMMozMobileConnectionInfo interface,
     // although the actual implementation lives in the content process. So are
     // the child attributes `network` and `cell`, which implement
     // nsIDOMMozMobileNetworkInfo and nsIDOMMozMobileCellInfo respectively.
     voice:          {connected: false,
                      emergencyCallsOnly: false,
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -59,29 +59,46 @@ NS_DEFINE_CID(kNetworkManagerCID, NS_NET
 SystemWorkerManager *gInstance = nullptr;
 
 class ConnectWorkerToRIL : public WorkerTask
 {
 public:
   virtual bool RunTask(JSContext *aCx);
 };
 
+class SendRilSocketDataTask : public nsRunnable
+{
+public:
+  SendRilSocketDataTask(UnixSocketRawData *aRawData)
+    : mRawData(aRawData)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    SystemWorkerManager::SendRilRawData(mRawData);
+    return NS_OK;
+  }
+
+private:
+  UnixSocketRawData *mRawData;
+};
+
 JSBool
 PostToRIL(JSContext *cx, unsigned argc, jsval *vp)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
 
   if (argc != 1) {
     JS_ReportError(cx, "Expecting a single argument with the RIL message");
     return false;
   }
 
   jsval v = JS_ARGV(cx, vp)[0];
 
-  nsAutoPtr<RilRawData> rm(new RilRawData());
   JSAutoByteString abs;
   void *data;
   size_t size;
   if (JSVAL_IS_STRING(v)) {
     JSString *str = JSVAL_TO_STRING(v);
     if (!abs.encode(cx, str)) {
       return false;
     }
@@ -106,87 +123,37 @@ PostToRIL(JSContext *cx, unsigned argc, 
     size = JS_GetTypedArrayByteLength(obj);
     data = JS_GetArrayBufferViewData(obj);
   } else {
     JS_ReportError(cx,
                    "Incorrect argument. Expecting a string or a typed array");
     return false;
   }
 
-  if (size > RilRawData::MAX_DATA_SIZE) {
-    JS_ReportError(cx, "Passed-in data is too large");
-    return false;
-  }
+  UnixSocketRawData* raw = new UnixSocketRawData(size);
+  memcpy(raw->mData, data, raw->mSize);
 
-  rm->mSize = size;
-  memcpy(rm->mData, data, size);
-
-  RilRawData *tosend = rm.forget();
-  JS_ALWAYS_TRUE(SendRilRawData(&tosend));
+  nsRefPtr<SendRilSocketDataTask> task = new SendRilSocketDataTask(raw);
+  NS_DispatchToMainThread(task);
   return true;
 }
 
 bool
 ConnectWorkerToRIL::RunTask(JSContext *aCx)
 {
   // Set up the postRILMessage on the function for worker -> RIL thread
   // communication.
   NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
   NS_ASSERTION(!JS_IsRunning(aCx), "Are we being called somehow?");
   JSObject *workerGlobal = JS_GetGlobalObject(aCx);
 
   return !!JS_DefineFunction(aCx, workerGlobal, "postRILMessage", PostToRIL, 1,
                              0);
 }
 
-class RILReceiver : public RilConsumer
-{
-  class DispatchRILEvent : public WorkerTask
-  {
-  public:
-    DispatchRILEvent(RilRawData *aMessage)
-      : mMessage(aMessage)
-    { }
-
-    virtual bool RunTask(JSContext *aCx);
-
-  private:
-    nsAutoPtr<RilRawData> mMessage;
-  };
-
-public:
-  RILReceiver(WorkerCrossThreadDispatcher *aDispatcher)
-    : mDispatcher(aDispatcher)
-  { }
-
-  virtual void MessageReceived(RilRawData *aMessage) {
-    nsRefPtr<DispatchRILEvent> dre(new DispatchRILEvent(aMessage));
-    mDispatcher->PostTask(dre);
-  }
-
-private:
-  nsRefPtr<WorkerCrossThreadDispatcher> mDispatcher;
-};
-
-bool
-RILReceiver::DispatchRILEvent::RunTask(JSContext *aCx)
-{
-  JSObject *obj = JS_GetGlobalObject(aCx);
-
-  JSObject *array = JS_NewUint8Array(aCx, mMessage->mSize);
-  if (!array) {
-    return false;
-  }
-
-  memcpy(JS_GetArrayBufferViewData(array), mMessage->mData, mMessage->mSize);
-  jsval argv[] = { OBJECT_TO_JSVAL(array) };
-  return JS_CallFunctionName(aCx, obj, "onRILMessage", NS_ARRAY_LENGTH(argv),
-                             argv, argv);
-}
-
 #ifdef MOZ_WIDGET_GONK
 
 JSBool
 DoNetdCommand(JSContext *cx, unsigned argc, jsval *vp)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Expecting to be on the worker thread");
 
   if (argc != 1) {
@@ -401,17 +368,20 @@ SystemWorkerManager::Shutdown()
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   mShutdown = true;
 
 #ifdef MOZ_WIDGET_GONK
   ShutdownAutoMounter();
 #endif
 
-  StopRil();
+  if (mRilConsumer) {
+    mRilConsumer->Shutdown();
+    mRilConsumer = nullptr;
+  }
 
 #ifdef MOZ_WIDGET_GONK
   StopNetd();
   mNetdWorker = nullptr;
 #endif
 
   nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker));
   if (wifi) {
@@ -450,16 +420,27 @@ SystemWorkerManager::FactoryCreate()
 
 // static
 nsIInterfaceRequestor*
 SystemWorkerManager::GetInterfaceRequestor()
 {
   return gInstance;
 }
 
+bool
+SystemWorkerManager::SendRilRawData(UnixSocketRawData* aRaw)
+{
+  if (!gInstance->mRilConsumer) {
+    // Probably shuting down.
+    delete aRaw;
+    return true;
+  }
+  return gInstance->mRilConsumer->SendSocketData(aRaw);
+}
+
 NS_IMETHODIMP
 SystemWorkerManager::GetInterface(const nsIID &aIID, void **aResult)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (aIID.Equals(NS_GET_IID(nsIWifi))) {
     return CallQueryInterface(mWifiWorker,
                               reinterpret_cast<nsIWifi**>(aResult));
@@ -492,18 +473,17 @@ SystemWorkerManager::RegisterRilWorker(c
   }
 
   nsRefPtr<ConnectWorkerToRIL> connection = new ConnectWorkerToRIL();
   if (!wctd->PostTask(connection)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   // Now that we're set up, connect ourselves to the RIL thread.
-  mozilla::RefPtr<RILReceiver> receiver = new RILReceiver(wctd);
-  StartRil(receiver);
+  mRilConsumer = new RilConsumer(wctd);
   return NS_OK;
 }
 
 #ifdef MOZ_WIDGET_GONK
 nsresult
 SystemWorkerManager::InitNetd(JSContext *cx)
 {
   nsCOMPtr<nsIWorkerHolder> worker = do_GetService(kNetworkManagerCID);
--- a/dom/system/gonk/SystemWorkerManager.h
+++ b/dom/system/gonk/SystemWorkerManager.h
@@ -26,16 +26,22 @@
 #include "nsDebug.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
 class nsIWorkerHolder;
 
 namespace mozilla {
+
+namespace ipc {
+  class RilConsumer;
+  class UnixSocketRawData;
+}
+
 namespace dom {
 namespace gonk {
 
 class SystemWorkerManager : public nsIObserver,
                             public nsIInterfaceRequestor,
                             public nsISystemWorkerManager
 {
 public:
@@ -48,30 +54,34 @@ public:
   void Shutdown();
 
   static already_AddRefed<SystemWorkerManager>
   FactoryCreate();
 
   static nsIInterfaceRequestor*
   GetInterfaceRequestor();
 
+  static bool SendRilRawData(ipc::UnixSocketRawData* aRaw);
+
 private:
   SystemWorkerManager();
   ~SystemWorkerManager();
 
 #ifdef MOZ_WIDGET_GONK
   nsresult InitNetd(JSContext *cx);
 #endif
   nsresult InitWifi(JSContext *cx);
 
 #ifdef MOZ_WIDGET_GONK
   nsCOMPtr<nsIWorkerHolder> mNetdWorker;
 #endif
   nsCOMPtr<nsIWorkerHolder> mWifiWorker;
 
+  nsRefPtr<ipc::RilConsumer> mRilConsumer;
+
   bool mShutdown;
 };
 
 }
 }
 }
 
 #endif // mozilla_dom_system_b2g_systemworkermanager_h__
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -2199,17 +2199,17 @@ this.CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242
 this.CALL_FAIL_IMEI_NOT_ACCEPTED = 243;
 this.CALL_FAIL_ERROR_UNSPECIFIED = 0xffff;
 
 // Other Gecko-specific constants
 this.GECKO_RADIOSTATE_UNAVAILABLE   = null;
 this.GECKO_RADIOSTATE_OFF           = "off";
 this.GECKO_RADIOSTATE_READY         = "ready";
 
-this.GECKO_CARDSTATE_UNAVAILABLE    = null;
+this.GECKO_CARDSTATE_UNKNOWN        = "unknown";
 this.GECKO_CARDSTATE_ABSENT         = "absent";
 this.GECKO_CARDSTATE_PIN_REQUIRED   = "pinRequired";
 this.GECKO_CARDSTATE_PUK_REQUIRED   = "pukRequired";
 this.GECKO_CARDSTATE_NETWORK_LOCKED = "networkLocked";
 this.GECKO_CARDSTATE_NOT_READY      = null;
 this.GECKO_CARDSTATE_READY          = "ready";
 
 this.GECKO_NETWORK_SELECTION_UNKNOWN   = null;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -2830,16 +2830,18 @@ let RIL = {
         break;
       case CARD_APPSTATE_SUBSCRIPTION_PERSO:
         newCardState = GECKO_CARDSTATE_NETWORK_LOCKED;
         break;
       case CARD_APPSTATE_READY:
         newCardState = GECKO_CARDSTATE_READY;
         break;
       case CARD_APPSTATE_UNKNOWN:
+        newCardState = GECKO_CARDSTATE_UNKNOWN;
+        break;
       case CARD_APPSTATE_DETECTED:
       default:
         newCardState = GECKO_CARDSTATE_NOT_READY;
     }
 
     if (this.cardState == newCardState) {
       return;
     }
--- a/dom/webidl/SVGGraphicsElement.webidl
+++ b/dom/webidl/SVGGraphicsElement.webidl
@@ -5,12 +5,25 @@
  *
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-interface SVGGraphicsElement : SVGTransformableElement {
+interface SVGGraphicsElement : SVGElement {
+  readonly attribute SVGAnimatedTransformList transform;
+
+  readonly attribute SVGElement? nearestViewportElement;
+  readonly attribute SVGElement? farthestViewportElement;
+
+  [Throws]
+  SVGRect getBBox();
+  // Not implemented
+  // SVGRect getStrokeBBox();
+  SVGMatrix? getCTM();
+  SVGMatrix? getScreenCTM();
+  [Throws]
+  SVGMatrix getTransformToElement(SVGGraphicsElement element);
 };
 
 SVGGraphicsElement implements SVGTests;
deleted file mode 100644
--- a/dom/webidl/SVGLocatableElement.webidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/.
- *
- * The origin of this IDL file is
- * http://www.w3.org/TR/SVG2/
- *
- * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
- * liability, trademark and document use rules apply.
- */
-
-interface SVGRect;
-
-interface SVGLocatableElement : SVGElement {
-
-  readonly attribute SVGElement? nearestViewportElement;
-  readonly attribute SVGElement? farthestViewportElement;
-
-  [Throws]
-  SVGRect getBBox();
-  // Not implemented
-  // SVGRect getStrokeBBox();
-  SVGMatrix? getCTM();
-  SVGMatrix? getScreenCTM();
-  [Throws]
-  SVGMatrix getTransformToElement(SVGLocatableElement element);
-};
-
deleted file mode 100644
--- a/dom/webidl/SVGTransformableElement.webidl
+++ /dev/null
@@ -1,16 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/.
- *
- * The origin of this IDL file is
- * http://www.w3.org/TR/SVG2/
- *
- * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
- * liability, trademark and document use rules apply.
- */
-
-interface SVGTransformableElement : SVGLocatableElement {
-  readonly attribute SVGAnimatedTransformList transform;
-};
-
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -127,17 +127,16 @@ webidl_files = \
   SVGForeignObjectElement.webidl \
   SVGGElement.webidl \
   SVGGradientElement.webidl \
   SVGGraphicsElement.webidl \
   SVGImageElement.webidl \
   SVGLengthList.webidl \
   SVGLinearGradientElement.webidl \
   SVGLineElement.webidl \
-  SVGLocatableElement.webidl \
   SVGMarkerElement.webidl \
   SVGMaskElement.webidl \
   SVGMatrix.webidl \
   SVGMetadataElement.webidl \
   SVGMPathElement.webidl \
   SVGNumberList.webidl \
   SVGPathElement.webidl \
   SVGPathSeg.webidl \
@@ -159,17 +158,16 @@ webidl_files = \
   SVGSymbolElement.webidl \
   SVGTests.webidl \
   SVGTextContentElement.webidl \
   SVGTextElement.webidl \
   SVGTextPathElement.webidl \
   SVGTextPositioningElement.webidl \
   SVGTitleElement.webidl \
   SVGTransform.webidl \
-  SVGTransformableElement.webidl \
   SVGTransformList.webidl \
   SVGTSpanElement.webidl \
   SVGUnitTypes.webidl \
   SVGUseElement.webidl \
   SVGURIReference.webidl \
   SVGViewElement.webidl \
   SVGZoomAndPan.webidl \
   Text.webidl \
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -146,17 +146,16 @@ MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(gStrin
                   "gStringChars should have the right length.");
 
 enum {
   PREF_strict = 0,
   PREF_werror,
   PREF_methodjit,
   PREF_methodjit_always,
   PREF_typeinference,
-  PREF_allow_xml,
   PREF_jit_hardening,
   PREF_mem_max,
   PREF_ion,
   PREF_mem_gc_allocation_threshold_mb,
 
 #ifdef JS_GC_ZEAL
   PREF_gczeal,
 #endif
@@ -167,17 +166,16 @@ enum {
 #define JS_OPTIONS_DOT_STR "javascript.options."
 
 const char* gPrefsToWatch[] = {
   JS_OPTIONS_DOT_STR "strict",
   JS_OPTIONS_DOT_STR "werror",
   JS_OPTIONS_DOT_STR "methodjit.content",
   JS_OPTIONS_DOT_STR "methodjit_always",
   JS_OPTIONS_DOT_STR "typeinference",
-  JS_OPTIONS_DOT_STR "allow_xml",
   JS_OPTIONS_DOT_STR "jit_hardening",
   JS_OPTIONS_DOT_STR "mem.max",
   JS_OPTIONS_DOT_STR "ion.content",
   "dom.workers.mem.gc_allocation_threshold_mb"
 
 #ifdef JS_GC_ZEAL
   , PREF_WORKERS_GCZEAL
 #endif
@@ -225,19 +223,16 @@ PrefCallback(const char* aPrefName, void
       newOptions |= JSOPTION_METHODJIT_ALWAYS;
     }
     if (Preferences::GetBool(gPrefsToWatch[PREF_typeinference])) {
       newOptions |= JSOPTION_TYPE_INFERENCE;
     }
     if (Preferences::GetBool(gPrefsToWatch[PREF_ion])) {
       newOptions |= JSOPTION_ION;
     }
-    if (Preferences::GetBool(gPrefsToWatch[PREF_allow_xml])) {
-      newOptions |= JSOPTION_ALLOW_XML;
-    }
 
     RuntimeService::SetDefaultJSContextOptions(newOptions);
     rts->UpdateAllWorkerJSContextOptions();
   }
 #ifdef JS_GC_ZEAL
   else if (!strcmp(aPrefName, gPrefsToWatch[PREF_gczeal])) {
     int32_t gczeal = Preferences::GetInt(gPrefsToWatch[PREF_gczeal]);
     RuntimeService::SetDefaultGCZeal(uint8_t(clamped(gczeal, 0, 3)));
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -9,17 +9,16 @@
 
 #include "GeckoContentController.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/TimeStamp.h"
 #include "InputData.h"
 #include "Axis.h"
-#include "nsContentUtils.h"
 #include "TaskThrottler.h"
 
 #include "base/message_loop.h"
 
 namespace mozilla {
 namespace layers {
 
 class CompositorParent;
--- a/gfx/layers/ipc/Axis.cpp
+++ b/gfx/layers/ipc/Axis.cpp
@@ -2,16 +2,17 @@
 /* vim: set sw=4 ts=8 et 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/. */
 
 #include "Axis.h"
 #include "AsyncPanZoomController.h"
 #include "mozilla/Preferences.h"
+#include "nsThreadUtils.h"
 #include <algorithm>
 
 namespace mozilla {
 namespace layers {
 
 static const float EPSILON = 0.0001f;
 
 /**
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -97,17 +97,17 @@ Decoder::Finish(RasterImage::eShutdownIn
     // Log data errors to the error console
     nsCOMPtr<nsIConsoleService> consoleService =
       do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     nsCOMPtr<nsIScriptError> errorObject =
       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
 
     if (consoleService && errorObject && !HasDecoderError()) {
       nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated: ") +
-                       NS_ConvertASCIItoUTF16(mImage.GetURIString()));
+                       NS_ConvertUTF8toUTF16(mImage.GetURIString()));
 
       if (NS_SUCCEEDED(errorObject->InitWithWindowID(
                          msg,
                          NS_ConvertUTF8toUTF16(mImage.GetURIString()),
                          EmptyString(), 0, 0, nsIScriptError::errorFlag,
                          "Image", mImage.InnerWindowID()
                        ))) {
         consoleService->LogMessage(errorObject);
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -2806,17 +2806,17 @@ RasterImage::RequestDecodeCore(RequestDe
   // If we've read all the data we have, we're done
   if (mBytesDecoded == mSourceData.Length())
     return NS_OK;
 
   // If we can do decoding now, do so.  Small images will decode completely,
   // large images will decode a bit and post themselves to the event loop
   // to finish decoding.
   if (!mDecoded && !mInDecoder && mHasSourceData && aDecodeType == SOMEWHAT_SYNCHRONOUS) {
-    SAMPLE_LABEL_PRINTF("RasterImage", "DecodeABitOf", "%s", GetURIString());
+    SAMPLE_LABEL_PRINTF("RasterImage", "DecodeABitOf", "%s", GetURIString().get());
     DecodeWorker::Singleton()->DecodeABitOf(this);
     return NS_OK;
   }
 
   // If we get this far, dispatch the worker. We do this instead of starting
   // any immediate decoding to guarantee that all our decode notifications are
   // dispatched asynchronously, and to ensure we stay responsive.
   DecodeWorker::Singleton()->RequestDecode(this);
@@ -2825,17 +2825,17 @@ RasterImage::RequestDecodeCore(RequestDe
 }
 
 // Synchronously decodes as much data as possible
 nsresult
 RasterImage::SyncDecode()
 {
   nsresult rv;
 
-  SAMPLE_LABEL_PRINTF("RasterImage", "SyncDecode", "%s", GetURIString());;
+  SAMPLE_LABEL_PRINTF("RasterImage", "SyncDecode", "%s", GetURIString().get());;
 
   // If we're decoded already, no worries
   if (mDecoded)
     return NS_OK;
 
   // If we're not storing source data, there isn't much to do here
   if (!StoringSourceData())
     return NS_OK;
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -285,17 +285,23 @@ public:
     kDisposeClearAll         = -1, // Clear the whole image, revealing
                                    // what was there before the gif displayed
     kDisposeNotSpecified,   // Leave frame, let new frame draw on top
     kDisposeKeep,           // Leave frame, let new frame draw on top
     kDisposeClear,          // Clear the frame's area, revealing bg
     kDisposeRestorePrevious // Restore the previous (composited) frame
   };
 
-  const char* GetURIString() { return mURIString.get();}
+  nsCString GetURIString() {
+    nsCString spec;
+    if (GetURI()) {
+      GetURI()->GetSpec(spec);
+    }
+    return spec;
+  }
 
   // Called from module startup. Sets up RasterImage to be used.
   static void Initialize();
 
   enum ScaleStatus
   {
     SCALE_INVALID,
     SCALE_PENDING,
@@ -642,17 +648,16 @@ private: // data
 
   // Discard members
   uint32_t                   mLockCount;
   DiscardTracker::Node       mDiscardTrackerNode;
 
   // Source data members
   FallibleTArray<char>       mSourceData;
   nsCString                  mSourceDataMimeType;
-  nsCString                  mURIString;
 
   friend class DiscardTracker;
 
   // Decoder and friends
   nsRefPtr<Decoder>              mDecoder;
   DecodeRequest                  mDecodeRequest;
   uint32_t                       mBytesDecoded;
 
--- a/ipc/chromium/src/chrome/common/ipc_message_utils.h
+++ b/ipc/chromium/src/chrome/common/ipc_message_utils.h
@@ -61,18 +61,59 @@ class MessageIterator {
   }
  private:
   const Message& msg_;
   mutable void* iter_;
 };
 
 //-----------------------------------------------------------------------------
 // ParamTraits specializations, etc.
+//
+// The full set of types ParamTraits is specialized upon contains *possibly*
+// repeated types: unsigned long may be uint32_t or size_t, unsigned long long
+// may be uint64_t or size_t, nsresult may be uint32_t, and so on.  You can't
+// have ParamTraits<unsigned int> *and* ParamTraits<uint32_t> if unsigned int
+// is uint32_t -- that's multiple definitions, and you can only have one.
+//
+// You could use #ifs and macro conditions to avoid duplicates, but they'd be
+// hairy: heavily dependent upon OS and compiler author choices, forced to
+// address all conflicts by hand.  Happily there's a better way.  The basic
+// idea looks like this, where T -> U represents T inheriting from U:
+//
+// class ParamTraits<P>
+// |
+// --> class ParamTraits1<P>
+//     |
+//     --> class ParamTraits2<P>
+//         |
+//         --> class ParamTraitsN<P> // or however many levels
+//
+// The default specialization of ParamTraits{M}<P> is an empty class that
+// inherits from ParamTraits{M + 1}<P> (or nothing in the base case).
+//
+// Now partition the set of parameter types into sets without duplicates.
+// Assign each set of types to a level M.  Then specialize ParamTraitsM for
+// each of those types.  A reference to ParamTraits<P> will consist of some
+// number of empty classes inheriting in sequence, ending in a non-empty
+// ParamTraits{N}<P>.  It's okay for the parameter types to be duplicative:
+// either name of a type will resolve to the same ParamTraits{N}<P>.
+//
+// The nice thing is that because templates are instantiated lazily, if we
+// indeed have uint32_t == unsigned int, say, with the former in level N and
+// the latter in M > N, ParamTraitsM<unsigned int> won't be created (as long as
+// nobody uses ParamTraitsM<unsigned int>, but why would you), and no duplicate
+// code will be compiled or extra symbols generated.  It's as efficient at
+// runtime as manually figuring out and avoiding conflicts by #ifs.
+//
+// The scheme we follow below names the various classes according to the types
+// in them, and the number of ParamTraits levels is larger, but otherwise it's
+// exactly the above idea.
+//
 
-template <class P> struct ParamTraits {};
+template <class P> struct ParamTraits;
 
 template <class P>
 static inline void WriteParam(Message* m, const P& p) {
   ParamTraits<P>::Write(m, p);
 }
 
 template <class P>
 static inline bool WARN_UNUSED_RESULT ReadParam(const Message* m, void** iter,
@@ -80,119 +121,102 @@ static inline bool WARN_UNUSED_RESULT Re
   return ParamTraits<P>::Read(m, iter, p);
 }
 
 template <class P>
 static inline void LogParam(const P& p, std::wstring* l) {
   ParamTraits<P>::Log(p, l);
 }
 
+// Fundamental types.
+
+template <class P>
+struct ParamTraitsFundamental {};
+
 template <>
-struct ParamTraits<bool> {
+struct ParamTraitsFundamental<bool> {
   typedef bool param_type;
   static void Write(Message* m, const param_type& p) {
     m->WriteBool(p);
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
     return m->ReadBool(iter, r);
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(p ? L"true" : L"false");
   }
 };
 
 template <>
-struct ParamTraits<int16_t> {
-  typedef int16_t param_type;
-  static void Write(Message* m, const param_type& p) {
-    m->WriteInt(p);
-  }
-  static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadInt16(iter, r);
-  }
-  static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"%hd", p));
-  }
-};
-
-template <>
-struct ParamTraits<uint16_t> {
-  typedef uint16_t param_type;
-  static void Write(Message* m, const param_type& p) {
-    m->WriteInt(p);
-  }
-  static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadUInt16(iter, r);
-  }
-  static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"%hu", p));
-  }
-};
-
-template <>
-struct ParamTraits<int> {
+struct ParamTraitsFundamental<int> {
   typedef int param_type;
   static void Write(Message* m, const param_type& p) {
     m->WriteInt(p);
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
     return m->ReadInt(iter, r);
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(StringPrintf(L"%d", p));
   }
 };
 
 template <>
-struct ParamTraits<long> {
+struct ParamTraitsFundamental<long> {
   typedef long param_type;
   static void Write(Message* m, const param_type& p) {
     m->WriteLong(p);
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
     return m->ReadLong(iter, r);
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(StringPrintf(L"%l", p));
   }
 };
 
 template <>
-struct ParamTraits<unsigned long> {
+struct ParamTraitsFundamental<unsigned long> {
   typedef unsigned long param_type;
   static void Write(Message* m, const param_type& p) {
     m->WriteULong(p);
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
     return m->ReadULong(iter, r);
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(StringPrintf(L"%ul", p));
   }
 };
 
 template <>
-struct ParamTraits<nsresult> {
-  typedef nsresult param_type;
+struct ParamTraitsFundamental<long long> {
+  typedef long long param_type;
   static void Write(Message* m, const param_type& p) {
-    m->WriteUInt32(static_cast<uint32_t>(p));
-  }
+    m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type));
+ }
   static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadUInt32(iter, reinterpret_cast<uint32_t*>(r));
+    const char *data;
+    int data_size = 0;
+    bool result = m->ReadData(iter, &data, &data_size);
+    if (result && data_size == sizeof(param_type)) {
+      memcpy(r, data, sizeof(param_type));
+    } else {
+      result = false;
+      NOTREACHED();
+    }
+    return result;
   }
   static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"%u", static_cast<uint32_t>(p)));
+    l->append(StringPrintf(L"%ll", p));
   }
 };
 
-#if (defined(OS_OPENBSD) && defined(ARCH_CPU_64_BITS))
-// On OpenBSD, uint64_t is unsigned long long
-// see https://bugzilla.mozilla.org/show_bug.cgi?id=648735#c27
 template <>
-struct ParamTraits<unsigned long long> {
+struct ParamTraitsFundamental<unsigned long long> {
   typedef unsigned long long param_type;
   static void Write(Message* m, const param_type& p) {
     m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type));
  }
   static bool Read(const Message* m, void** iter, param_type* r) {
     const char *data;
     int data_size = 0;
     bool result = m->ReadData(iter, &data, &data_size);
@@ -205,125 +229,17 @@ struct ParamTraits<unsigned long long> {
     return result;
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(StringPrintf(L"%ull", p));
   }
 };
 
 template <>
-struct ParamTraits<long long> {
-  typedef long long param_type;
-  static void Write(Message* m, const param_type& p) {
-    m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type));
- }
-  static bool Read(const Message* m, void** iter, param_type* r) {
-    const char *data;
-    int data_size = 0;
-    bool result = m->ReadData(iter, &data, &data_size);
-    if (result && data_size == sizeof(param_type)) {
-      memcpy(r, data, sizeof(param_type));
-    } else {
-      result = false;
-      NOTREACHED();
-    }
-    return result;
-  }
-  static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"%ll", p));
-  }
-};
-#endif
-
-#if !(defined(OS_MACOSX) || defined(OS_OPENBSD) || defined(OS_WIN) || ((defined(OS_BSD) || defined(OS_LINUX)) && defined(ARCH_CPU_64_BITS)) || defined(ARCH_CPU_S390))
-// There size_t is a synonym for |unsigned long| ...
-template <>
-struct ParamTraits<size_t> {
-  typedef size_t param_type;
-  static void Write(Message* m, const param_type& p) {
-    m->WriteSize(p);
-  }
-  static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadSize(iter, r);
-  }
-  static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"%u", p));
-  }
-};
-
-#elif !defined(OS_MACOSX)
-// ... so we need to define traits for |unsigned int|.
-// XXX duplicating OS_MACOSX version below so as not to conflict
-template <>
-struct ParamTraits<uint32_t> {
-  typedef uint32_t param_type;
-  static void Write(Message* m, const param_type& p) {
-    m->WriteUInt32(p);
-  }
-  static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadUInt32(iter, r);
-  }
-  static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"%u", p));
-  }
-};
-
-#endif // if !(defined(OS_LINUX) && defined(ARCH_CPU_64_BITS))
-
-#if defined(OS_MACOSX)
-// On Linux size_t & uint32_t can be the same type.
-// TODO(playmobil): Fix compilation if this is not the case.
-template <>
-struct ParamTraits<uint32_t> {
-  typedef uint32_t param_type;
-  static void Write(Message* m, const param_type& p) {
-    m->WriteUInt32(p);
-  }
-  static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadUInt32(iter, r);
-  }
-  static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"%u", p));
-  }
-};
-#endif  // defined(OS_MACOSX)
-
-#if !((defined(OS_BSD) || defined(OS_LINUX)) && defined(ARCH_CPU_64_BITS))
-// int64_t is |long int| on 64-bit systems, uint64_t is |unsigned long|
-template <>
-struct ParamTraits<int64_t> {
-  typedef int64_t param_type;
-  static void Write(Message* m, const param_type& p) {
-    m->WriteInt64(p);
-  }
-  static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadInt64(iter, r);
-  }
-  static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"%" PRId64L, p));
-  }
-};
-
-template <>
-struct ParamTraits<uint64_t> {
-  typedef uint64_t param_type;
-  static void Write(Message* m, const param_type& p) {
-    m->WriteInt64(static_cast<int64_t>(p));
-  }
-  static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadInt64(iter, reinterpret_cast<int64_t*>(r));
-  }
-  static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"%" PRIu64L, p));
-  }
-};
-#endif // if !(defined(OS_LINUX) && defined(ARCH_CPU_64_BITS))
-
-template <>
-struct ParamTraits<double> {
+struct ParamTraitsFundamental<double> {
   typedef double param_type;
   static void Write(Message* m, const param_type& p) {
     m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type));
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
     const char *data;
     int data_size = 0;
     bool result = m->ReadData(iter, &data, &data_size);
@@ -336,97 +252,145 @@ struct ParamTraits<double> {
 
     return result;
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(StringPrintf(L"e", p));
   }
 };
 
+// Fixed-size <stdint.h> types.
+
+template <class P>
+struct ParamTraitsFixed : ParamTraitsFundamental<P> {};
+
 template <>
-struct ParamTraits<base::Time> {
-  typedef base::Time param_type;
+struct ParamTraitsFixed<int16_t> {
+  typedef int16_t param_type;
   static void Write(Message* m, const param_type& p) {
-    ParamTraits<int64_t>::Write(m, p.ToInternalValue());
+    m->WriteInt(p);
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
-    int64_t value;
-    if (!ParamTraits<int64_t>::Read(m, iter, &value))
-      return false;
-    *r = base::Time::FromInternalValue(value);
-    return true;
+    return m->ReadInt16(iter, r);
   }
   static void Log(const param_type& p, std::wstring* l) {
-    ParamTraits<int64_t>::Log(p.ToInternalValue(), l);
+    l->append(StringPrintf(L"%hd", p));
   }
 };
 
-#if defined(OS_WIN)
 template <>
-struct ParamTraits<LOGFONT> {
-  typedef LOGFONT param_type;
+struct ParamTraitsFixed<uint16_t> {
+  typedef uint16_t param_type;
   static void Write(Message* m, const param_type& p) {
-    m->WriteData(reinterpret_cast<const char*>(&p), sizeof(LOGFONT));
+    m->WriteInt(p);
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
-    const char *data;
-    int data_size = 0;
-    bool result = m->ReadData(iter, &data, &data_size);
-    if (result && data_size == sizeof(LOGFONT)) {
-      memcpy(r, data, sizeof(LOGFONT));
-    } else {
-      result = false;
-      NOTREACHED();
-    }
-
-    return result;
+    return m->ReadUInt16(iter, r);
   }
   static void Log(const param_type& p, std::wstring* l) {
-    l->append(StringPrintf(L"<LOGFONT>"));
+    l->append(StringPrintf(L"%hu", p));
+  }
+};
+
+template <>
+struct ParamTraitsFixed<uint32_t> {
+  typedef uint32_t param_type;
+  static void Write(Message* m, const param_type& p) {
+    m->WriteUInt32(p);
+  }
+  static bool Read(const Message* m, void** iter, param_type* r) {
+    return m->ReadUInt32(iter, r);
+  }
+  static void Log(const param_type& p, std::wstring* l) {
+    l->append(StringPrintf(L"%u", p));
   }
 };
 
 template <>
-struct ParamTraits<MSG> {
-  typedef MSG param_type;
+struct ParamTraitsFixed<int64_t> {
+  typedef int64_t param_type;
   static void Write(Message* m, const param_type& p) {
-    m->WriteData(reinterpret_cast<const char*>(&p), sizeof(MSG));
+    m->WriteInt64(p);
+  }
+  static bool Read(const Message* m, void** iter, param_type* r) {
+    return m->ReadInt64(iter, r);
+  }
+  static void Log(const param_type& p, std::wstring* l) {
+    l->append(StringPrintf(L"%" PRId64L, p));
+  }
+};
+
+template <>
+struct ParamTraitsFixed<uint64_t> {
+  typedef uint64_t param_type;
+  static void Write(Message* m, const param_type& p) {
+    m->WriteInt64(static_cast<int64_t>(p));
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
-    const char *data;
-    int data_size = 0;
-    bool result = m->ReadData(iter, &data, &data_size);
-    if (result && data_size == sizeof(MSG)) {
-      memcpy(r, data, sizeof(MSG));
-    } else {
-      result = false;
-      NOTREACHED();
-    }
-
-    return result;
+    return m->ReadInt64(iter, reinterpret_cast<int64_t*>(r));
+  }
+  static void Log(const param_type& p, std::wstring* l) {
+    l->append(StringPrintf(L"%" PRIu64L, p));
   }
 };
-#endif  // defined(OS_WIN)
+
+// Other standard C types.
+
+template <class P>
+struct ParamTraitsLibC : ParamTraitsFixed<P> {};
 
 template <>
-struct ParamTraits<std::string> {
+struct ParamTraitsLibC<size_t> {
+  typedef size_t param_type;
+  static void Write(Message* m, const param_type& p) {
+    m->WriteSize(p);
+  }
+  static bool Read(const Message* m, void** iter, param_type* r) {
+    return m->ReadSize(iter, r);
+  }
+  static void Log(const param_type& p, std::wstring* l) {
+    l->append(StringPrintf(L"%u", p));
+  }
+};
+
+// std::* types.
+
+template <class P>
+struct ParamTraitsStd : ParamTraitsLibC<P> {};
+
+template <>
+struct ParamTraitsStd<std::string> {
   typedef std::string param_type;
   static void Write(Message* m, const param_type& p) {
     m->WriteString(p);
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
     return m->ReadString(iter, r);
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(UTF8ToWide(p));
   }
 };
 
 template <>
-struct ParamTraits<std::vector<unsigned char> > {
+struct ParamTraitsStd<std::wstring> {
+  typedef std::wstring param_type;
+  static void Write(Message* m, const param_type& p) {
+    m->WriteWString(p);
+  }
+  static bool Read(const Message* m, void** iter, param_type* r) {
+    return m->ReadWString(iter, r);
+  }
+  static void Log(const param_type& p, std::wstring* l) {
+    l->append(p);
+  }
+};
+
+template <>
+struct ParamTraitsStd<std::vector<unsigned char> > {
   typedef std::vector<unsigned char> param_type;
   static void Write(Message* m, const param_type& p) {
     if (p.size() == 0) {
       m->WriteData(NULL, 0);
     } else {
       m->WriteData(reinterpret_cast<const char*>(&p.front()),
                    static_cast<int>(p.size()));
     }
@@ -443,17 +407,17 @@ struct ParamTraits<std::vector<unsigned 
   }
   static void Log(const param_type& p, std::wstring* l) {
     for (size_t i = 0; i < p.size(); ++i)
       l->push_back(p[i]);
   }
 };
 
 template <>
-struct ParamTraits<std::vector<char> > {
+struct ParamTraitsStd<std::vector<char> > {
   typedef std::vector<char> param_type;
   static void Write(Message* m, const param_type& p) {
     if (p.size() == 0) {
       m->WriteData(NULL, 0);
     } else {
       m->WriteData(&p.front(), static_cast<int>(p.size()));
     }
   }
@@ -469,17 +433,17 @@ struct ParamTraits<std::vector<char> > {
   }
   static void Log(const param_type& p, std::wstring* l) {
     for (size_t i = 0; i < p.size(); ++i)
       l->push_back(p[i]);
   }
 };
 
 template <class P>
-struct ParamTraits<std::vector<P> > {
+struct ParamTraitsStd<std::vector<P> > {
   typedef std::vector<P> param_type;
   static void Write(Message* m, const param_type& p) {
     WriteParam(m, static_cast<int>(p.size()));
     for (size_t i = 0; i < p.size(); i++)
       WriteParam(m, p[i]);
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
     int size;
@@ -508,17 +472,17 @@ struct ParamTraits<std::vector<P> > {
         l->append(L" ");
 
       LogParam((p[i]), l);
     }
   }
 };
 
 template <class K, class V>
-struct ParamTraits<std::map<K, V> > {
+struct ParamTraitsStd<std::map<K, V> > {
   typedef std::map<K, V> param_type;
   static void Write(Message* m, const param_type& p) {
     WriteParam(m, static_cast<int>(p.size()));
     typename param_type::const_iterator iter;
     for (iter = p.begin(); iter != p.end(); ++iter) {
       WriteParam(m, iter->first);
       WriteParam(m, iter->second);
     }
@@ -537,110 +501,126 @@ struct ParamTraits<std::map<K, V> > {
     }
     return true;
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(L"<std::map>");
   }
 };
 
+// Windows-specific types.
 
+template <class P>
+struct ParamTraitsWindows : ParamTraitsStd<P> {};
+
+#if defined(OS_WIN)
 template <>
-struct ParamTraits<std::wstring> {
-  typedef std::wstring param_type;
+struct ParamTraitsWindows<LOGFONT> {
+  typedef LOGFONT param_type;
   static void Write(Message* m, const param_type& p) {
-    m->WriteWString(p);
+    m->WriteData(reinterpret_cast<const char*>(&p), sizeof(LOGFONT));
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadWString(iter, r);
+    const char *data;
+    int data_size = 0;
+    bool result = m->ReadData(iter, &data, &data_size);
+    if (result && data_size == sizeof(LOGFONT)) {
+      memcpy(r, data, sizeof(LOGFONT));
+    } else {
+      result = false;
+      NOTREACHED();
+    }
+
+    return result;
   }
   static void Log(const param_type& p, std::wstring* l) {
-    l->append(p);
+    l->append(StringPrintf(L"<LOGFONT>"));
   }
 };
 
-// If WCHAR_T_IS_UTF16 is defined, then string16 is a std::wstring so we don't
-// need this trait.
-#if !defined(WCHAR_T_IS_UTF16)
 template <>
-struct ParamTraits<string16> {
-  typedef string16 param_type;
+struct ParamTraitsWindows<MSG> {
+  typedef MSG param_type;
   static void Write(Message* m, const param_type& p) {
-    m->WriteString16(p);
+    m->WriteData(reinterpret_cast<const char*>(&p), sizeof(MSG));
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
-    return m->ReadString16(iter, r);
-  }
-  static void Log(const param_type& p, std::wstring* l) {
-    l->append(UTF16ToWide(p));
+    const char *data;
+    int data_size = 0;
+    bool result = m->ReadData(iter, &data, &data_size);
+    if (result && data_size == sizeof(MSG)) {
+      memcpy(r, data, sizeof(MSG));
+    } else {
+      result = false;
+      NOTREACHED();
+    }
+
+    return result;
   }
 };
-#endif
 
-// and, a few more useful types...
-#if defined(OS_WIN)
 template <>
-struct ParamTraits<HANDLE> {
+struct ParamTraitsWindows<HANDLE> {
   typedef HANDLE param_type;
   static void Write(Message* m, const param_type& p) {
     m->WriteIntPtr(reinterpret_cast<intptr_t>(p));
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
     DCHECK_EQ(sizeof(param_type), sizeof(intptr_t));
     return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r));
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(StringPrintf(L"0x%X", p));
   }
 };
 
 template <>
-struct ParamTraits<HCURSOR> {
+struct ParamTraitsWindows<HCURSOR> {
   typedef HCURSOR param_type;
   static void Write(Message* m, const param_type& p) {
     m->WriteIntPtr(reinterpret_cast<intptr_t>(p));
   }
   static bool Read(const Message* m, void** iter, param_type* r) {
     DCHECK_EQ(sizeof(param_type), sizeof(intptr_t));
     return m->ReadIntPtr(iter, reinterpret_cast<intptr_t*>(r));
   }
   static void Log(const param_type& p, std::wstring* l) {
     l->append(StringPrintf(L"0x%X", p));
   }
 };
 
 template <>
-struct ParamTraits<HWND> {