author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Wed, 10 Jun 2015 15:25:21 +0200 | |
changeset 248140 | 1bd6254c5f41d21145696dc6c7496a45d73fab6a |
parent 248139 | 846253a39b05f5449f8750d92dcbdb7a480388d4 (current diff) |
parent 247936 | e101c589c242cc1b414442acfb72d79d55b9ceac (diff) |
child 248141 | 4776477b6357eaab96ad3c63556d86b97e674fbe |
push id | 60888 |
push user | kwierso@gmail.com |
push date | Thu, 11 Jun 2015 01:38:38 +0000 |
treeherder | mozilla-inbound@39e638ed06bf [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 41.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
browser/app/profile/firefox.js | file | annotate | diff | comparison | revisions | |
browser/base/content/tabbrowser.xml | file | annotate | diff | comparison | revisions | |
dom/canvas/WebGLBindableName.h | file | annotate | diff | comparison | revisions | |
mobile/android/chrome/content/browser.js | file | annotate | diff | comparison | revisions | |
security/manager/ssl/tests/unit/test_cert_trust/ca.der | file | annotate | diff | comparison | revisions | |
security/manager/ssl/tests/unit/test_cert_trust/ee.der | file | annotate | diff | comparison | revisions | |
security/manager/ssl/tests/unit/test_cert_trust/generate.py | file | annotate | diff | comparison | revisions | |
security/manager/ssl/tests/unit/test_cert_trust/int.der | file | annotate | diff | comparison | revisions |
--- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -450,17 +450,18 @@ DocAccessible::Shutdown() // array as they are shutdown. int32_t childDocCount = mChildDocuments.Length(); for (int32_t idx = childDocCount - 1; idx >= 0; idx--) mChildDocuments[idx]->Shutdown(); mChildDocuments.Clear(); // XXX thinking about ordering? - if (IPCAccessibilityActive()) { + if (mIPCDoc) { + MOZ_ASSERT(IPCAccessibilityActive()); mIPCDoc->Shutdown(); MOZ_ASSERT(!mIPCDoc); } if (mVirtualCursor) { mVirtualCursor->RemoveObserver(this); mVirtualCursor = nullptr; }
--- a/aclocal.m4 +++ b/aclocal.m4 @@ -28,16 +28,17 @@ builtin(include, build/autoconf/arch.m4) builtin(include, build/autoconf/android.m4)dnl builtin(include, build/autoconf/zlib.m4)dnl builtin(include, build/autoconf/linux.m4)dnl builtin(include, build/autoconf/python-virtualenv.m4)dnl builtin(include, build/autoconf/winsdk.m4)dnl builtin(include, build/autoconf/icu.m4)dnl builtin(include, build/autoconf/ffi.m4)dnl builtin(include, build/autoconf/clang-plugin.m4)dnl +builtin(include, build/autoconf/alloc.m4)dnl MOZ_PROG_CHECKMSYS() # Read the user's .mozconfig script. We can't do this in # configure.in: autoconf puts the argument parsing code above anything # expanded from configure.in, and we need to get the configure options # from .mozconfig in place before that argument parsing code. MOZ_READ_MOZCONFIG(.)
--- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="70b7fcbf7ff0ef38d04f82d68a56f2bb44ec694a"/>
--- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="70b7fcbf7ff0ef38d04f82d68a56f2bb44ec694a"/>
--- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -14,17 +14,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9d0e5057ee5404a31ec1bf76131cb11336a7c3b6"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -12,17 +12,17 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="70b7fcbf7ff0ef38d04f82d68a56f2bb44ec694a"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="70b7fcbf7ff0ef38d04f82d68a56f2bb44ec694a"/>
--- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="70b7fcbf7ff0ef38d04f82d68a56f2bb44ec694a"/>
--- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -14,17 +14,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9d0e5057ee5404a31ec1bf76131cb11336a7c3b6"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="70b7fcbf7ff0ef38d04f82d68a56f2bb44ec694a"/>
--- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "9844b7c9d4429a041cff7201f1a63d0264e155ff", + "git_revision": "e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "8edfc1021ec1ceb0a7f7fb0b23e96b44a0fe8254", + "revision": "c33bf7766d1b19c407c3bbab943403ddee172915", "repo_path": "integration/gaia-central" }
--- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -12,17 +12,17 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="70b7fcbf7ff0ef38d04f82d68a56f2bb44ec694a"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="9844b7c9d4429a041cff7201f1a63d0264e155ff"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="e3eaf72ccd1bfe6d60d37efde6d3b92c1dbc5ff9"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="70b7fcbf7ff0ef38d04f82d68a56f2bb44ec694a"/>
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -970,16 +970,17 @@ pref("gecko.handlerService.schemes.ircs. // By default, we don't want protocol/content handlers to be registered from a different host, see bug 402287 pref("gecko.handlerService.allowRegisterFromDifferentHost", false); #ifdef MOZ_SAFE_BROWSING pref("browser.safebrowsing.enabled", true); pref("browser.safebrowsing.malware.enabled", true); pref("browser.safebrowsing.downloads.enabled", true); pref("browser.safebrowsing.downloads.remote.enabled", true); +pref("browser.safebrowsing.downloads.remote.timeout_ms", 10000); pref("browser.safebrowsing.debug", false); pref("browser.safebrowsing.updateURL", "https://safebrowsing.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2&key=%GOOGLE_API_KEY%"); pref("browser.safebrowsing.gethashURL", "https://safebrowsing.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2"); pref("browser.safebrowsing.reportURL", "https://safebrowsing.google.com/safebrowsing/report?"); pref("browser.safebrowsing.reportGenericURL", "http://%LOCALE%.phish-generic.mozilla.com/?hl=%LOCALE%"); pref("browser.safebrowsing.reportErrorURL", "http://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%"); pref("browser.safebrowsing.reportPhishURL", "http://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%");
--- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -687,17 +687,17 @@ this.mTabBrowser.mIsBusy = true; } } else if (aStateFlags & nsIWebProgressListener.STATE_STOP && aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) { if (this.mTab.hasAttribute("busy")) { this.mTab.removeAttribute("busy"); - this.mTabBrowser._tabAttrModified(this.mTab); + this.mTabBrowser._tabAttrModified(this.mTab, ["busy"]); if (!this.mTab.selected) this.mTab.setAttribute("unread", "true"); } this.mTab.removeAttribute("progress"); if (aWebProgress.isTopLevel) { if (!Components.isSuccessCode(aStatus) && !isTabEmpty(this.mTab)) { @@ -887,17 +887,17 @@ if (sizedIconUrl) { sizedIconUrl = this.PlacesUtils.getImageURLForResolution(window, sizedIconUrl); } if (sizedIconUrl != aTab.getAttribute("image")) { if (sizedIconUrl) aTab.setAttribute("image", sizedIconUrl); else aTab.removeAttribute("image"); - this._tabAttrModified(aTab); + this._tabAttrModified(aTab, ["image"]); } this._callProgressListeners(browser, "onLinkIconAvailable", [browser.mIconURL]); ]]> </body> </method> <method name="getIcon"> @@ -1162,18 +1162,18 @@ bubbles: true, cancelable: false, detail: { previousTab: oldTab } }); this.mCurrentTab.dispatchEvent(event); - this._tabAttrModified(oldTab); - this._tabAttrModified(this.mCurrentTab); + this._tabAttrModified(oldTab, ["selected"]); + this._tabAttrModified(this.mCurrentTab, ["selected"]); if (oldBrowser != newBrowser && oldBrowser.docShell && oldBrowser.docShell.contentViewer.inPermitUnload) { // Since the user is switching away from a tab that has // a beforeunload prompt active, we remove the prompt. // This prevents confusing user flows like the following: // 1. User attempts to close Firefox @@ -1295,35 +1295,39 @@ } fm.setFocus(newBrowser, focusFlags); ]]></body> </method> <method name="_tabAttrModified"> <parameter name="aTab"/> + <parameter name="aChanged"/> <body><![CDATA[ if (aTab.closing) return; - // This event should be dispatched when any of these attributes change: - // label, crop, busy, image, selected - var event = document.createEvent("Events"); - event.initEvent("TabAttrModified", true, false); + let event = new CustomEvent("TabAttrModified", { + bubbles: true, + cancelable: false, + detail: { + changed: aChanged, + } + }); aTab.dispatchEvent(event); ]]></body> </method> <method name="setTabTitleLoading"> <parameter name="aTab"/> <body> <![CDATA[ aTab.label = this.mStringBundle.getString("tabs.connecting"); aTab.crop = "end"; - this._tabAttrModified(aTab); + this._tabAttrModified(aTab, ["label", "crop"]); ]]> </body> </method> <method name="setTabTitle"> <parameter name="aTab"/> <body> <![CDATA[ @@ -1358,17 +1362,17 @@ } if (aTab.label == title && aTab.crop == crop) return false; aTab.label = title; aTab.crop = crop; - this._tabAttrModified(aTab); + this._tabAttrModified(aTab, ["label", "crop"]); if (aTab.selected) this.updateTitlebar(); return true; ]]> </body> </method> @@ -2456,17 +2460,17 @@ } else { // Workarounds for bug 458697 // Icon might have been set on DOMLinkAdded, don't override that. if (!ourBrowser.mIconURL && otherBrowser.mIconURL) this.setIcon(aOurTab, otherBrowser.mIconURL); var isBusy = aOtherTab.hasAttribute("busy"); if (isBusy) { aOurTab.setAttribute("busy", "true"); - this._tabAttrModified(aOurTab); + this._tabAttrModified(aOurTab, ["busy"]); if (aOurTab.selected) this.mIsBusy = true; } this._swapBrowserDocShells(aOurTab, otherBrowser); } // Handle findbar data (if any)
new file mode 100644 --- /dev/null +++ b/build/autoconf/alloc.m4 @@ -0,0 +1,53 @@ +dnl This Source Code Form is subject to the terms of the Mozilla Public +dnl License, v. 2.0. If a copy of the MPL was not distributed with this +dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. + +dnl Check for the existence of various allocation headers/functions +AC_DEFUN([MOZ_CHECK_ALLOCATOR],[ + +MALLOC_HEADERS="malloc.h malloc_np.h malloc/malloc.h sys/malloc.h" +MALLOC_H= + +for file in $MALLOC_HEADERS; do + MOZ_CHECK_HEADER($file, [MALLOC_H=$file]) + if test "$MALLOC_H" != ""; then + AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>) + break + fi +done + +MOZ_CHECK_HEADERS(alloca.h) + +AC_CHECK_FUNCS(strndup posix_memalign memalign) + +AC_CHECK_FUNCS(malloc_usable_size) +MALLOC_USABLE_SIZE_CONST_PTR=const +MOZ_CHECK_HEADERS([malloc.h], [ + AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument]) + AC_TRY_COMPILE([#include <malloc.h> + #include <stddef.h> + size_t malloc_usable_size(const void *ptr);], + [return malloc_usable_size(0);], + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no]) + MALLOC_USABLE_SIZE_CONST_PTR=) +]) +AC_DEFINE_UNQUOTED([MALLOC_USABLE_SIZE_CONST_PTR],[$MALLOC_USABLE_SIZE_CONST_PTR]) + + +dnl In newer bionic headers, valloc is built but not defined, +dnl so we check more carefully here. +AC_MSG_CHECKING([for valloc in malloc.h]) +AC_EGREP_HEADER(valloc, malloc.h, + AC_DEFINE(HAVE_VALLOC) + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no])) + +AC_MSG_CHECKING([for valloc in unistd.h]) +AC_EGREP_HEADER(valloc, unistd.h, + AC_DEFINE(HAVE_VALLOC) + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no])) + + +])
--- a/build/mach_bootstrap.py +++ b/build/mach_bootstrap.py @@ -42,16 +42,17 @@ SEARCH_PATHS = [ 'build/pymake', 'config', 'dom/bindings', 'dom/bindings/parser', 'layout/tools/reftest', 'other-licenses/ply', 'xpcom/idl-parser', 'testing', + 'testing/tools/autotry', 'testing/taskcluster', 'testing/xpcshell', 'testing/web-platform', 'testing/web-platform/harness', 'testing/marionette/client', 'testing/marionette/client/marionette/runner/mixins/browsermob-proxy-py', 'testing/marionette/transport', 'testing/marionette/driver',
--- a/configure.in +++ b/configure.in @@ -3394,62 +3394,16 @@ if test -n "$MOZ_LINKER" -a "$OS_TARGET" dnl we need to use LDFLAGS because nspr doesn't inherit DSO_LDOPTS. dnl Using LDFLAGS in nspr is safe, since we only really build dnl libraries there. DSO_LDOPTS="$DSO_LDOPTS -nostartfiles" NSPR_LDFLAGS="$NSPR_LDFLAGS -nostartfiles" fi fi -dnl Check for the existence of various allocation headers/functions - -MALLOC_HEADERS="malloc.h malloc_np.h malloc/malloc.h sys/malloc.h" -MALLOC_H= - -for file in $MALLOC_HEADERS; do - MOZ_CHECK_HEADER($file, [MALLOC_H=$file]) - if test "$MALLOC_H" != ""; then - AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>) - break - fi -done - -MOZ_CHECK_HEADERS(alloca.h) - -AC_CHECK_FUNCS(strndup posix_memalign memalign) - -AC_CHECK_FUNCS(malloc_usable_size) -MALLOC_USABLE_SIZE_CONST_PTR=const -MOZ_CHECK_HEADERS([malloc.h], [ - AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument]) - AC_TRY_COMPILE([#include <malloc.h> - #include <stddef.h> - size_t malloc_usable_size(const void *ptr);], - [return malloc_usable_size(0);], - AC_MSG_RESULT([yes]), - AC_MSG_RESULT([no]) - MALLOC_USABLE_SIZE_CONST_PTR=) -]) -AC_DEFINE_UNQUOTED([MALLOC_USABLE_SIZE_CONST_PTR],[$MALLOC_USABLE_SIZE_CONST_PTR]) - - -dnl In newer bionic headers, valloc is built but not defined, -dnl so we check more carefully here. -AC_MSG_CHECKING([for valloc in malloc.h]) -AC_EGREP_HEADER(valloc, malloc.h, - AC_DEFINE(HAVE_VALLOC) - AC_MSG_RESULT([yes]), - AC_MSG_RESULT([no])) - -AC_MSG_CHECKING([for valloc in unistd.h]) -AC_EGREP_HEADER(valloc, unistd.h, - AC_DEFINE(HAVE_VALLOC) - AC_MSG_RESULT([yes]), - AC_MSG_RESULT([no])) - dnl See if compiler supports some gcc-style attributes AC_CACHE_CHECK(for __attribute__((always_inline)), ac_cv_attribute_always_inline, [AC_TRY_COMPILE([inline void f(void) __attribute__((always_inline));], [], ac_cv_attribute_always_inline=yes, ac_cv_attribute_always_inline=no)]) @@ -3474,16 +3428,18 @@ AC_CACHE_CHECK(for LC_MESSAGES, ac_cv_i18n_lc_messages=no)]) if test "$ac_cv_i18n_lc_messages" = yes; then AC_DEFINE(HAVE_I18N_LC_MESSAGES) fi AC_HAVE_FUNCS(localeconv) fi # ! SKIP_COMPILER_CHECKS +MOZ_CHECK_ALLOCATOR + TARGET_XPCOM_ABI= if test -n "${CPU_ARCH}" -a -n "${TARGET_COMPILER_ABI}"; then TARGET_XPCOM_ABI="${CPU_ARCH}-${TARGET_COMPILER_ABI}" AC_DEFINE_UNQUOTED(TARGET_XPCOM_ABI, ["${TARGET_XPCOM_ABI}"]) fi dnl We can't run TRY_COMPILE tests on Windows, so hard-code some dnl features that Windows actually does support.
--- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -11191,22 +11191,18 @@ ExitFullscreenInDocTree(nsIDocument* aMa // Move the top-level window out of fullscreen mode. SetWindowFullScreen(root, false); } /* static */ void nsDocument::ExitFullscreen(nsIDocument* aDoc) { - // Unlock the pointer, if it's locked. - nsCOMPtr<Element> pointerLockedElement = - do_QueryReferent(EventStateManager::sPointerLockedElement); - if (pointerLockedElement) { - UnlockPointer(); - } + // Unlock the pointer + UnlockPointer(); if (aDoc) { ExitFullscreenInDocTree(aDoc); return; } // Clear fullscreen stacks in all fullscreen roots' descendant documents. FullscreenRoots::ForEach(&ExitFullscreenInDocTree); @@ -11253,39 +11249,33 @@ nsDocument::RestorePreviousFullScreenSta NS_ASSERTION(!IsFullScreenDoc() || !FullscreenRoots::IsEmpty(), "Should have at least 1 fullscreen root when fullscreen!"); if (!IsFullScreenDoc() || !GetWindow() || FullscreenRoots::IsEmpty()) { return; } // If fullscreen mode is updated the pointer should be unlocked - nsCOMPtr<Element> pointerLockedElement = - do_QueryReferent(EventStateManager::sPointerLockedElement); - if (pointerLockedElement) { - UnlockPointer(); - } + UnlockPointer(); nsCOMPtr<nsIDocument> fullScreenDoc = GetFullscreenLeaf(this); // Clear full-screen stacks in all descendant in process documents, bottom up. nsIDocument* doc = fullScreenDoc; while (doc != this) { NS_ASSERTION(doc->IsFullScreenDoc(), "Should be full-screen doc"); static_cast<nsDocument*>(doc)->CleanupFullscreenState(); - UnlockPointer(); DispatchFullScreenChange(doc); doc = doc->GetParentDocument(); } // Roll-back full-screen state to previous full-screen element. NS_ASSERTION(doc == this, "Must have reached this doc."); while (doc != nullptr) { static_cast<nsDocument*>(doc)->FullScreenStackPop(); - UnlockPointer(); DispatchFullScreenChange(doc); if (static_cast<nsDocument*>(doc)->mFullScreenStack.IsEmpty()) { // Full-screen stack in document is empty. Go back up to the parent // document. We'll pop the containing element off its stack, and use // its next full-screen element as the full-screen element. static_cast<nsDocument*>(doc)->CleanupFullscreenState(); doc = doc->GetParentDocument(); } else { @@ -11661,29 +11651,20 @@ nsDocument::RequestFullScreen(Element* a // order, but we traverse the doctree in a leaf-to-root order, so we save // references to the documents we must dispatch to so that we get the order // as specified. nsAutoTArray<nsIDocument*, 8> changed; // Remember the root document, so that if a full-screen document is hidden // we can reset full-screen state in the remaining visible full-screen documents. nsIDocument* fullScreenRootDoc = nsContentUtils::GetRootDocument(this); - if (fullScreenRootDoc->IsFullScreenDoc()) { - // A document is already in fullscreen, unlock the mouse pointer - // before setting a new document to fullscreen - UnlockPointer(); - } // If a document is already in fullscreen, then unlock the mouse pointer // before setting a new document to fullscreen - nsCOMPtr<Element> pointerLockedElement = - do_QueryReferent(EventStateManager::sPointerLockedElement); - if (pointerLockedElement) { - UnlockPointer(); - } + UnlockPointer(); // Process options -- in this case, just HMD if (aOptions.mVRHMDDevice) { nsRefPtr<gfx::VRHMDInfo> hmdRef = aOptions.mVRHMDDevice; aElement->SetProperty(nsGkAtoms::vr_state, hmdRef.forget().take(), ReleaseHMDInfoRef, true); }
--- a/dom/bluetooth/bluedroid/BluetoothSocket.cpp +++ b/dom/bluetooth/bluedroid/BluetoothSocket.cpp @@ -1,27 +1,23 @@ /* -*- Mode: C++; 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/. */ #include "BluetoothSocket.h" - #include <fcntl.h> #include <sys/socket.h> - -#include "base/message_loop.h" #include "BluetoothSocketObserver.h" #include "BluetoothInterface.h" #include "BluetoothUtils.h" #include "mozilla/ipc/UnixSocketWatcher.h" #include "mozilla/FileUtils.h" #include "mozilla/RefPtr.h" -#include "nsThreadUtils.h" #include "nsXULAppAPI.h" using namespace mozilla::ipc; USING_BLUETOOTH_NAMESPACE static const size_t MAX_READ_SIZE = 1 << 16; static BluetoothSocketInterface* sBluetoothSocketInterface; @@ -69,21 +65,21 @@ public: */ enum ConnectionStatus { SOCKET_IS_DISCONNECTED = 0, SOCKET_IS_LISTENING, SOCKET_IS_CONNECTING, SOCKET_IS_CONNECTED }; - DroidSocketImpl(nsIThread* aConsumerThread, + DroidSocketImpl(MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, BluetoothSocket* aConsumer) : ipc::UnixFdWatcher(aIOLoop) - , DataSocketIO(aConsumerThread) + , DataSocketIO(aConsumerLoop) , mConsumer(aConsumer) , mShuttingDownOnIOThread(false) , mConnectionStatus(SOCKET_IS_DISCONNECTED) { } ~DroidSocketImpl() { MOZ_ASSERT(IsConsumerThread()); @@ -168,17 +164,17 @@ public: MOZ_ASSERT(!IsConsumerThread()); MOZ_ASSERT(!mShuttingDownOnIOThread); Close(); // will also remove fd from I/O loop mShuttingDownOnIOThread = true; } private: - class ReceiveRunnable; + class ReceiveTask; /** * libevent triggered functions that reads data from socket when available and * guarenteed non-blocking. Only to be called on IO thread. * * @param aFd [in] File descriptor to read from */ virtual void OnFileCanReadWithoutBlocking(int aFd); @@ -314,19 +310,18 @@ DroidSocketImpl::Accept(int aFd) if (!(flags & O_NONBLOCK)) { int res = TEMP_FAILURE_RETRY(fcntl(aFd, F_SETFL, flags | O_NONBLOCK)); NS_ENSURE_TRUE_VOID(!res); } SetFd(aFd); mConnectionStatus = SOCKET_IS_CONNECTED; - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS)); AddWatchers(READ_WATCHER, true); if (HasPendingData()) { AddWatchers(WRITE_WATCHER, false); } } void @@ -421,35 +416,33 @@ public: mImpl->mConsumer->NotifyDisconnect(); } } private: DroidSocketImpl* mImpl; }; -class AcceptRunnable final : public SocketIORunnable<DroidSocketImpl> +class InvokeAcceptTask final : public SocketTask<DroidSocketImpl> { public: - AcceptRunnable(DroidSocketImpl* aImpl, int aFd) - : SocketIORunnable<DroidSocketImpl>(aImpl) - , mFd(aFd) + InvokeAcceptTask(DroidSocketImpl* aImpl, int aFd) + : SocketTask<DroidSocketImpl>(aImpl) + , mFd(aFd) { } - NS_IMETHOD Run() override + void Run() override { MOZ_ASSERT(GetIO()->IsConsumerThread()); MOZ_ASSERT(sBluetoothSocketInterface); BluetoothSocketResultHandler* res = new AcceptResultHandler(GetIO()); GetIO()->mConsumer->SetCurrentResultHandler(res); sBluetoothSocketInterface->Accept(mFd, res); - - return NS_OK; } private: int mFd; }; void DroidSocketImpl::OnSocketCanAcceptWithoutBlocking(int aFd) @@ -457,18 +450,17 @@ DroidSocketImpl::OnSocketCanAcceptWithou MOZ_ASSERT(!IsConsumerThread()); MOZ_ASSERT(!mShuttingDownOnIOThread); /* When a listening socket is ready for receiving data, * we can call |Accept| on it. */ RemoveWatchers(READ_WATCHER); - GetConsumerThread()->Dispatch(new AcceptRunnable(this, aFd), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask(FROM_HERE, new InvokeAcceptTask(this, aFd)); } void DroidSocketImpl::OnFileCanWriteWithoutBlocking(int aFd) { if (mConnectionStatus == SOCKET_IS_CONNECTED) { OnSocketCanSendWithoutBlocking(aFd); } else if (mConnectionStatus == SOCKET_IS_CONNECTING) { @@ -502,19 +494,18 @@ DroidSocketImpl::OnSocketCanConnectWitho MOZ_ASSERT(!mShuttingDownOnIOThread); /* We follow Posix behaviour here: Connect operations are * complete once we can write to the connecting socket. */ mConnectionStatus = SOCKET_IS_CONNECTED; - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS)); AddWatchers(READ_WATCHER, true); if (HasPendingData()) { AddWatchers(WRITE_WATCHER, false); } } // |DataSocketIO| @@ -532,54 +523,51 @@ DroidSocketImpl::QueryReceiveBuffer( return NS_OK; } /** * |ReceiveRunnable| transfers data received on the I/O thread * to an instance of |BluetoothSocket| on the consumer thread. */ -class DroidSocketImpl::ReceiveRunnable final - : public SocketIORunnable<DroidSocketImpl> +class DroidSocketImpl::ReceiveTask final : public SocketTask<DroidSocketImpl> { public: - ReceiveRunnable(DroidSocketImpl* aIO, UnixSocketBuffer* aBuffer) - : SocketIORunnable<DroidSocketImpl>(aIO) + ReceiveTask(DroidSocketImpl* aIO, UnixSocketBuffer* aBuffer) + : SocketTask<DroidSocketImpl>(aIO) , mBuffer(aBuffer) { } - NS_IMETHOD Run() override + void Run() override { - DroidSocketImpl* io = SocketIORunnable<DroidSocketImpl>::GetIO(); + DroidSocketImpl* io = SocketTask<DroidSocketImpl>::GetIO(); MOZ_ASSERT(io->IsConsumerThread()); if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) { // Since we've already explicitly closed and the close // happened before this, this isn't really an error. - return NS_OK; + return; } BluetoothSocket* bluetoothSocket = io->GetBluetoothSocket(); MOZ_ASSERT(bluetoothSocket); bluetoothSocket->ReceiveSocketData(mBuffer); - - return NS_OK; } private: nsAutoPtr<UnixSocketBuffer> mBuffer; }; void DroidSocketImpl::ConsumeBuffer() { - GetConsumerThread()->Dispatch(new ReceiveRunnable(this, mBuffer.forget()), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask(FROM_HERE, + new ReceiveTask(this, mBuffer.forget())); } void DroidSocketImpl::DiscardBuffer() { // Nothing to do. } @@ -646,24 +634,24 @@ private: }; nsresult BluetoothSocket::Connect(const nsAString& aDeviceAddress, const BluetoothUuid& aServiceUuid, BluetoothSocketType aType, int aChannel, bool aAuth, bool aEncrypt, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop) { MOZ_ASSERT(!mImpl); SetConnectionStatus(SOCKET_CONNECTING); - mImpl = new DroidSocketImpl(aConsumerThread, aIOLoop, this); + mImpl = new DroidSocketImpl(aConsumerLoop, aIOLoop, this); BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl); SetCurrentResultHandler(res); sBluetoothSocketInterface->Connect( aDeviceAddress, aType, aServiceUuid.mUuid, aChannel, aEncrypt, aAuth, res); @@ -673,24 +661,18 @@ BluetoothSocket::Connect(const nsAString nsresult BluetoothSocket::Connect(const nsAString& aDeviceAddress, const BluetoothUuid& aServiceUuid, BluetoothSocketType aType, int aChannel, bool aAuth, bool aEncrypt) { - nsIThread* consumerThread = nullptr; - nsresult rv = NS_GetCurrentThread(&consumerThread); - if (NS_FAILED(rv)) { - return rv; - } - return Connect(aDeviceAddress, aServiceUuid, aType, aChannel, aAuth, - aEncrypt, consumerThread, XRE_GetIOMessageLoop()); + aEncrypt, MessageLoop::current(), XRE_GetIOMessageLoop()); } class ListenResultHandler final : public BluetoothSocketResultHandler { public: ListenResultHandler(DroidSocketImpl* aImpl) : mImpl(aImpl) { @@ -716,24 +698,24 @@ private: }; nsresult BluetoothSocket::Listen(const nsAString& aServiceName, const BluetoothUuid& aServiceUuid, BluetoothSocketType aType, int aChannel, bool aAuth, bool aEncrypt, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop) { MOZ_ASSERT(!mImpl); SetConnectionStatus(SOCKET_LISTENING); - mImpl = new DroidSocketImpl(aConsumerThread, aIOLoop, this); + mImpl = new DroidSocketImpl(aConsumerLoop, aIOLoop, this); BluetoothSocketResultHandler* res = new ListenResultHandler(mImpl); SetCurrentResultHandler(res); sBluetoothSocketInterface->Listen( aType, aServiceName, aServiceUuid.mUuid, aChannel, aEncrypt, aAuth, res); @@ -743,24 +725,18 @@ BluetoothSocket::Listen(const nsAString& nsresult BluetoothSocket::Listen(const nsAString& aServiceName, const BluetoothUuid& aServiceUuid, BluetoothSocketType aType, int aChannel, bool aAuth, bool aEncrypt) { - nsIThread* consumerThread = nullptr; - nsresult rv = NS_GetCurrentThread(&consumerThread); - if (NS_FAILED(rv)) { - return rv; - } - return Listen(aServiceName, aServiceUuid, aType, aChannel, aAuth, aEncrypt, - consumerThread, XRE_GetIOMessageLoop()); + MessageLoop::current(), XRE_GetIOMessageLoop()); } void BluetoothSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer) { MOZ_ASSERT(mObserver); mObserver->ReceiveSocketData(this, aBuffer);
--- a/dom/bluetooth/bluedroid/BluetoothSocket.h +++ b/dom/bluetooth/bluedroid/BluetoothSocket.h @@ -6,17 +6,16 @@ #ifndef mozilla_dom_bluetooth_BluetoothSocket_h #define mozilla_dom_bluetooth_BluetoothSocket_h #include "BluetoothCommon.h" #include "mozilla/ipc/DataSocket.h" class MessageLoop; -class nsIThread; BEGIN_BLUETOOTH_NAMESPACE class BluetoothSocketObserver; class BluetoothSocketResultHandler; class DroidSocketImpl; class BluetoothSocket final : public mozilla::ipc::DataSocket @@ -24,31 +23,31 @@ class BluetoothSocket final : public moz public: BluetoothSocket(BluetoothSocketObserver* aObserver); nsresult Connect(const nsAString& aDeviceAddress, const BluetoothUuid& aServiceUuid, BluetoothSocketType aType, int aChannel, bool aAuth, bool aEncrypt, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop); nsresult Connect(const nsAString& aDeviceAddress, const BluetoothUuid& aServiceUuid, BluetoothSocketType aType, int aChannel, bool aAuth, bool aEncrypt); nsresult Listen(const nsAString& aServiceName, const BluetoothUuid& aServiceUuid, BluetoothSocketType aType, int aChannel, bool aAuth, bool aEncrypt, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop); nsresult Listen(const nsAString& aServiceName, const BluetoothUuid& aServiceUuid, BluetoothSocketType aType, int aChannel, bool aAuth, bool aEncrypt);
--- a/dom/bluetooth/bluez/BluetoothSocket.cpp +++ b/dom/bluetooth/bluez/BluetoothSocket.cpp @@ -3,19 +3,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "BluetoothSocket.h" #include <fcntl.h> #include "BluetoothSocketObserver.h" #include "BluetoothUnixSocketConnector.h" -#include "mozilla/unused.h" -#include "nsTArray.h" -#include "nsThreadUtils.h" +#include "mozilla/RefPtr.h" #include "nsXULAppAPI.h" using namespace mozilla::ipc; BEGIN_BLUETOOTH_NAMESPACE static const size_t MAX_READ_SIZE = 1 << 16; @@ -23,17 +21,17 @@ static const size_t MAX_READ_SIZE = 1 << // BluetoothSocketIO // class BluetoothSocket::BluetoothSocketIO final : public UnixSocketWatcher , public DataSocketIO { public: - BluetoothSocketIO(nsIThread* aConsumerThread, + BluetoothSocketIO(MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, BluetoothSocket* aConsumer, UnixSocketConnector* aConnector); ~BluetoothSocketIO(); void GetSocketAddr(nsAString& aAddrStr) const; BluetoothSocket* GetBluetoothSocket(); @@ -85,17 +83,17 @@ public: bool IsShutdownOnConsumerThread() const override; bool IsShutdownOnIOThread() const override; void ShutdownOnConsumerThread() override; void ShutdownOnIOThread() override; private: - class ReceiveRunnable; + class ReceiveTask; void FireSocketError(); /** * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated * directly from consumer thread. All non-consumer-thread accesses should * happen with mIO as container. */ @@ -129,22 +127,22 @@ private: /** * I/O buffer for received data */ nsAutoPtr<UnixSocketRawData> mBuffer; }; BluetoothSocket::BluetoothSocketIO::BluetoothSocketIO( - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, BluetoothSocket* aConsumer, UnixSocketConnector* aConnector) : UnixSocketWatcher(aIOLoop) - , DataSocketIO(aConsumerThread) + , DataSocketIO(aConsumerLoop) , mConsumer(aConsumer) , mConnector(aConnector) , mShuttingDownOnIOThread(false) , mAddressLength(0) , mDelayedConnectTask(nullptr) { MOZ_ASSERT(mConsumer); MOZ_ASSERT(mConnector); @@ -276,19 +274,18 @@ BluetoothSocket::BluetoothSocketIO::Send } void BluetoothSocket::BluetoothSocketIO::OnConnected() { MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS)); AddWatchers(READ_WATCHER, true); if (HasPendingData()) { AddWatchers(WRITE_WATCHER, false); } } void @@ -326,19 +323,18 @@ BluetoothSocket::BluetoothSocketIO::OnSo if (NS_WARN_IF(NS_FAILED(rv))) { FireSocketError(); return; } Close(); SetSocket(fd, SOCKET_IS_CONNECTED); - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS)); AddWatchers(READ_WATCHER, true); if (HasPendingData()) { AddWatchers(WRITE_WATCHER, false); } } void @@ -377,20 +373,18 @@ void BluetoothSocket::BluetoothSocketIO::FireSocketError() { MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); // Clean up watchers, statuses, fds Close(); // Tell the consumer thread we've errored - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR), - NS_DISPATCH_NORMAL); - + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_ERROR)); } // |DataSocketIO| nsresult BluetoothSocket::BluetoothSocketIO::QueryReceiveBuffer( UnixSocketIOBuffer** aBuffer) { @@ -400,57 +394,55 @@ BluetoothSocket::BluetoothSocketIO::Quer mBuffer = new UnixSocketRawData(MAX_READ_SIZE); } *aBuffer = mBuffer.get(); return NS_OK; } /** - * |ReceiveRunnable| transfers data received on the I/O thread + * |ReceiveTask| transfers data received on the I/O thread * to an instance of |BluetoothSocket| on the consumer thread. */ -class BluetoothSocket::BluetoothSocketIO::ReceiveRunnable final - : public SocketIORunnable<BluetoothSocketIO> +class BluetoothSocket::BluetoothSocketIO::ReceiveTask final + : public SocketTask<BluetoothSocketIO> { public: - ReceiveRunnable(BluetoothSocketIO* aIO, UnixSocketBuffer* aBuffer) - : SocketIORunnable<BluetoothSocketIO>(aIO) + ReceiveTask(BluetoothSocketIO* aIO, UnixSocketBuffer* aBuffer) + : SocketTask<BluetoothSocketIO>(aIO) , mBuffer(aBuffer) { } - NS_IMETHOD Run() override + void Run() override { - BluetoothSocketIO* io = SocketIORunnable<BluetoothSocketIO>::GetIO(); + BluetoothSocketIO* io = SocketTask<BluetoothSocketIO>::GetIO(); MOZ_ASSERT(io->IsConsumerThread()); if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) { // Since we've already explicitly closed and the close // happened before this, this isn't really an error. - return NS_OK; + return; } BluetoothSocket* bluetoothSocket = io->GetBluetoothSocket(); MOZ_ASSERT(bluetoothSocket); bluetoothSocket->ReceiveSocketData(mBuffer); - - return NS_OK; } private: nsAutoPtr<UnixSocketBuffer> mBuffer; }; void BluetoothSocket::BluetoothSocketIO::ConsumeBuffer() { - GetConsumerThread()->Dispatch(new ReceiveRunnable(this, mBuffer.forget()), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask(FROM_HERE, + new ReceiveTask(this, mBuffer.forget())); } void BluetoothSocket::BluetoothSocketIO::DiscardBuffer() { // Nothing to do. } @@ -645,24 +637,24 @@ BluetoothSocket::SendSocketData(const ns SendSocketData(new UnixSocketRawData(aStr.BeginReading(), aStr.Length())); return true; } nsresult BluetoothSocket::Connect(BluetoothUnixSocketConnector* aConnector, int aDelayMs, - nsIThread* aConsumerThread, MessageLoop* aIOLoop) + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop) { MOZ_ASSERT(aConnector); - MOZ_ASSERT(aConsumerThread); + MOZ_ASSERT(aConsumerLoop); MOZ_ASSERT(aIOLoop); MOZ_ASSERT(!mIO); - mIO = new BluetoothSocketIO(aConsumerThread, aIOLoop, this, aConnector); + mIO = new BluetoothSocketIO(aConsumerLoop, aIOLoop, this, aConnector); SetConnectionStatus(SOCKET_CONNECTING); if (aDelayMs > 0) { DelayedConnectTask* connectTask = new DelayedConnectTask(mIO); mIO->SetDelayedConnectTask(connectTask); MessageLoop::current()->PostDelayedTask(FROM_HERE, connectTask, aDelayMs); } else { aIOLoop->PostTask(FROM_HERE, new ConnectTask(mIO)); @@ -670,52 +662,41 @@ BluetoothSocket::Connect(BluetoothUnixSo return NS_OK; } nsresult BluetoothSocket::Connect(BluetoothUnixSocketConnector* aConnector, int aDelayMs) { - nsIThread* consumerThread = nullptr; - nsresult rv = NS_GetCurrentThread(&consumerThread); - if (NS_FAILED(rv)) { - return rv; - } - - return Connect(aConnector, aDelayMs, consumerThread, XRE_GetIOMessageLoop()); + return Connect(aConnector, aDelayMs, MessageLoop::current(), + XRE_GetIOMessageLoop()); } nsresult BluetoothSocket::Listen(BluetoothUnixSocketConnector* aConnector, - nsIThread* aConsumerThread, MessageLoop* aIOLoop) + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop) { MOZ_ASSERT(aConnector); - MOZ_ASSERT(aConsumerThread); + MOZ_ASSERT(aConsumerLoop); MOZ_ASSERT(aIOLoop); MOZ_ASSERT(!mIO); - mIO = new BluetoothSocketIO(aConsumerThread, aIOLoop, this, aConnector); + mIO = new BluetoothSocketIO(aConsumerLoop, aIOLoop, this, aConnector); SetConnectionStatus(SOCKET_LISTENING); aIOLoop->PostTask(FROM_HERE, new ListenTask(mIO)); return NS_OK; } nsresult BluetoothSocket::Listen(BluetoothUnixSocketConnector* aConnector) { - nsIThread* consumerThread = nullptr; - nsresult rv = NS_GetCurrentThread(&consumerThread); - if (NS_FAILED(rv)) { - return rv; - } - - return Listen(aConnector, consumerThread, XRE_GetIOMessageLoop()); + return Listen(aConnector, MessageLoop::current(), XRE_GetIOMessageLoop()); } void BluetoothSocket::GetAddress(nsAString& aAddrStr) { aAddrStr.Truncate(); if (!mIO || GetConnectionStatus() != SOCKET_CONNECTED) { NS_WARNING("No socket currently open!");
--- a/dom/bluetooth/bluez/BluetoothSocket.h +++ b/dom/bluetooth/bluez/BluetoothSocket.h @@ -3,23 +3,20 @@ /* 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_bluetooth_BluetoothSocket_h #define mozilla_dom_bluetooth_BluetoothSocket_h #include "BluetoothCommon.h" -#include <stdlib.h> #include "mozilla/ipc/DataSocket.h" #include "mozilla/ipc/UnixSocketWatcher.h" -#include "mozilla/RefPtr.h" #include "nsAutoPtr.h" #include "nsString.h" -#include "nsThreadUtils.h" class MessageLoop; BEGIN_BLUETOOTH_NAMESPACE class BluetoothSocketObserver; class BluetoothUnixSocketConnector; @@ -61,22 +58,22 @@ public: bool SendSocketData(const nsACString& aMessage); /** * Starts a task on the socket that will try to connect to a socket in a * non-blocking manner. * * @param aConnector Connector object for socket type specific functions * @param aDelayMs Time delay in milli-seconds. - * @param aConsumerThread The socket's consumer thread. + * @param aConsumerLoop The socket's consumer thread. * @param aIOLoop The socket's I/O thread. * @return NS_OK on success, or an XPCOM error code otherwise. */ nsresult Connect(BluetoothUnixSocketConnector* aConnector, int aDelayMs, - nsIThread* aConsumerThread, MessageLoop* aIOLoop); + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop); /** * Starts a task on the socket that will try to connect to a socket in a * non-blocking manner. * * @param aConnector Connector object for socket type specific functions * @param aDelayMs Time delay in milli-seconds. * @return NS_OK on success, or an XPCOM error code otherwise. @@ -84,22 +81,22 @@ public: nsresult Connect(BluetoothUnixSocketConnector* aConnector, int aDelayMs = 0); /** * Starts a task on the socket that will try to accept a new connection in a * non-blocking manner. * * @param aConnector Connector object for socket type specific functions - * @param aConsumerThread The socket's consumer thread. + * @param aConsumerLoop The socket's consumer thread. * @param aIOLoop The socket's I/O thread. * @return NS_OK on success, or an XPCOM error code otherwise. */ nsresult Listen(BluetoothUnixSocketConnector* aConnector, - nsIThread* aConsumerThread, MessageLoop* aIOLoop); + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop); /** * Starts a task on the socket that will try to accept a new connection in a * non-blocking manner. * * @param aConnector Connector object for socket type specific functions * @return NS_OK on success, or an XPCOM error code otherwise. */
--- a/dom/canvas/WebGL1Context.h +++ b/dom/canvas/WebGL1Context.h @@ -28,17 +28,16 @@ public: // nsWrapperCache virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; private: virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) override; virtual bool ValidateBufferTarget(GLenum target, const char* info) override; virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override; - virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) override; virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override; virtual bool ValidateQueryTarget(GLenum target, const char* info) override; virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override; }; } // namespace mozilla #endif // WEBGL_1_CONTEXT_H_
--- a/dom/canvas/WebGL1ContextBuffers.cpp +++ b/dom/canvas/WebGL1ContextBuffers.cpp @@ -30,32 +30,16 @@ WebGL1Context::ValidateBufferTarget(GLen bool WebGL1Context::ValidateBufferIndexedTarget(GLenum target, const char* info) { ErrorInvalidEnumInfo(info, target); return false; } -/** Buffer and Target validation for BindBuffer */ -bool -WebGL1Context::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, - const char* info) -{ - if (!buffer) - return true; - - if (buffer->HasEverBeenBound() && target != buffer->Target()) { - ErrorInvalidOperation("%s: buffer already bound to a different target", info); - return false; - } - - return true; -} - bool WebGL1Context::ValidateBufferUsageEnum(GLenum usage, const char* info) { switch (usage) { case LOCAL_GL_STREAM_DRAW: case LOCAL_GL_STATIC_DRAW: case LOCAL_GL_DYNAMIC_DRAW: return true;
--- a/dom/canvas/WebGL2Context.h +++ b/dom/canvas/WebGL2Context.h @@ -360,20 +360,21 @@ private: void UpdateBoundQuery(GLenum target, WebGLQuery* query); bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info); bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, const char* info); + // CreateVertexArrayImpl is assumed to be infallible. + virtual WebGLVertexArray* CreateVertexArrayImpl() override; virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) override; virtual bool ValidateBufferTarget(GLenum target, const char* info) override; virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override; - virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) override; virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override; virtual bool ValidateQueryTarget(GLenum target, const char* info) override; virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override; }; } // namespace mozilla #endif
--- a/dom/canvas/WebGL2ContextBuffers.cpp +++ b/dom/canvas/WebGL2ContextBuffers.cpp @@ -41,46 +41,16 @@ WebGL2Context::ValidateBufferIndexedTarg default: ErrorInvalidEnumInfo(info, target); return false; } } bool -WebGL2Context::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, - const char* info) -{ - if (!buffer) - return true; - - switch (target) { - case LOCAL_GL_COPY_READ_BUFFER: - case LOCAL_GL_COPY_WRITE_BUFFER: - return true; - - case LOCAL_GL_ELEMENT_ARRAY_BUFFER: - return !buffer->HasEverBeenBound() || - buffer->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER; - - case LOCAL_GL_ARRAY_BUFFER: - case LOCAL_GL_PIXEL_PACK_BUFFER: - case LOCAL_GL_PIXEL_UNPACK_BUFFER: - case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: - case LOCAL_GL_UNIFORM_BUFFER: - return !buffer->HasEverBeenBound() || - buffer->Target() != LOCAL_GL_ELEMENT_ARRAY_BUFFER; - } - - ErrorInvalidOperation("%s: buffer already bound to a incompatible target %s", - info, EnumName(buffer->Target().get())); - return false; -} - -bool WebGL2Context::ValidateBufferUsageEnum(GLenum usage, const char* info) { switch (usage) { case LOCAL_GL_DYNAMIC_COPY: case LOCAL_GL_DYNAMIC_DRAW: case LOCAL_GL_DYNAMIC_READ: case LOCAL_GL_STATIC_COPY: case LOCAL_GL_STATIC_DRAW: @@ -118,17 +88,17 @@ WebGL2Context::CopyBufferSubData(GLenum const WebGLRefPtr<WebGLBuffer>& writeBufferSlot = GetBufferSlotByTarget(writeTarget); if (!readBufferSlot || !writeBufferSlot) return; const WebGLBuffer* readBuffer = readBufferSlot.get(); if (!readBuffer) return ErrorInvalidOperation("copyBufferSubData: No buffer bound to readTarget"); - const WebGLBuffer* writeBuffer = writeBufferSlot.get(); + WebGLBuffer* writeBuffer = writeBufferSlot.get(); if (!writeBuffer) return ErrorInvalidOperation("copyBufferSubData: No buffer bound to writeTarget"); if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(), "copyBufferSubData")) { return; } @@ -140,51 +110,70 @@ WebGL2Context::CopyBufferSubData(GLenum } if (readTarget == writeTarget && !ValidateDataRanges(readOffset, writeOffset, size, "copyBufferSubData")) { return; } + WebGLBuffer::Kind readType = readBuffer->Content(); + WebGLBuffer::Kind writeType = writeBuffer->Content(); + + if (readType != WebGLBuffer::Kind::Undefined && + writeType != WebGLBuffer::Kind::Undefined && + writeType != readType) + { + ErrorInvalidOperation("copyBufferSubData: Can't copy %s data to %s data", + (readType == WebGLBuffer::Kind::OtherData) ? "other" : "element", + (writeType == WebGLBuffer::Kind::OtherData) ? "other" : "element"); + return; + } + WebGLContextUnchecked::CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); + + if (writeType == WebGLBuffer::Kind::Undefined) { + writeBuffer->BindTo( + (readType == WebGLBuffer::Kind::OtherData) ? LOCAL_GL_ARRAY_BUFFER + : LOCAL_GL_ELEMENT_ARRAY_BUFFER); + } } void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset, const dom::Nullable<dom::ArrayBuffer>& maybeData) { if (IsContextLost()) return; - + // For the WebGLBuffer bound to the passed target, read // returnedData.byteLength bytes from the buffer starting at byte // offset offset and write them to returnedData. // If zero is bound to target, an INVALID_OPERATION error is // generated. if (!ValidateBufferTarget(target, "getBufferSubData")) return; // If offset is less than zero, an INVALID_VALUE error is // generated. if (offset < 0) - return ErrorInvalidValue("getBufferSubData: negative offset"); + return ErrorInvalidValue("getBufferSubData: negative offset"); // If returnedData is null then an INVALID_VALUE error is // generated. if (maybeData.IsNull()) return ErrorInvalidValue("getBufferSubData: returnedData is null"); WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target); WebGLBuffer* boundBuffer = bufferSlot.get(); if (!boundBuffer) return ErrorInvalidOperation("getBufferSubData: no buffer bound"); - + // If offset + returnedData.byteLength would extend beyond the end // of the buffer an INVALID_VALUE error is generated. const dom::ArrayBuffer& data = maybeData.Value(); data.ComputeLengthAndData(); CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.Length(); if (!neededByteLength.isValid()) { ErrorInvalidValue("getBufferSubData: Integer overflow computing the needed"
--- a/dom/canvas/WebGL2ContextSamplers.cpp +++ b/dom/canvas/WebGL2ContextSamplers.cpp @@ -49,17 +49,18 @@ WebGL2Context::IsSampler(WebGLSampler* s return false; if (!ValidateObjectAllowDeleted("isSampler", sampler)) return false; if (sampler->IsDeleted()) return false; - return !sampler->HasEverBeenBound(); + MakeContextCurrent(); + return gl->fIsSampler(sampler->mGLName); } void WebGL2Context::BindSampler(GLuint unit, WebGLSampler* sampler) { if (IsContextLost()) return;
--- a/dom/canvas/WebGL2ContextTransformFeedback.cpp +++ b/dom/canvas/WebGL2ContextTransformFeedback.cpp @@ -55,17 +55,17 @@ WebGL2Context::IsTransformFeedback(WebGL if (!ValidateObjectAllowDeleted("isTransformFeedback", tf)) return false; if (tf->IsDeleted()) return false; MakeContextCurrent(); - return gl->fIsTransformFeedback(tf->GLName()); + return gl->fIsTransformFeedback(tf->mGLName); } void WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf) { if (IsContextLost()) return; @@ -79,21 +79,18 @@ WebGL2Context::BindTransformFeedback(GLe if (currentTF && currentTF->mIsActive && !currentTF->mIsPaused) { return ErrorInvalidOperation("bindTransformFeedback: Currently bound transform " "feedback is active and not paused"); } if (tf && tf->IsDeleted()) return ErrorInvalidOperation("bindTransformFeedback: Attempt to bind deleted id"); - if (tf) - tf->BindTo(LOCAL_GL_TRANSFORM_FEEDBACK); - MakeContextCurrent(); - gl->fBindTransformFeedback(target, tf ? tf->GLName() : 0); + gl->fBindTransformFeedback(target, tf ? tf->mGLName : 0); if (tf) mBoundTransformFeedback = tf; else mBoundTransformFeedback = mDefaultTransformFeedback; } void WebGL2Context::BeginTransformFeedback(GLenum primitiveMode)
--- a/dom/canvas/WebGL2ContextVAOs.cpp +++ b/dom/canvas/WebGL2ContextVAOs.cpp @@ -1,20 +1,21 @@ /* -*- Mode: C++; tab-width: 4; 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 "WebGL2Context.h" #include "GLContext.h" +#include "WebGLVertexArrayObject.h" -using namespace mozilla; -using namespace mozilla::dom; +namespace mozilla { // ------------------------------------------------------------------------- // Vertex Array Object -// TODO(djg): Implemented in WebGLContext -/* - already_AddRefed<WebGLVertexArrayObject> CreateVertexArray(); - void DeleteVertexArray(WebGLVertexArrayObject* vertexArray); - bool IsVertexArray(WebGLVertexArrayObject* vertexArray); - void BindVertexArray(WebGLVertexArrayObject* vertexArray); -*/ + +WebGLVertexArray* +WebGL2Context::CreateVertexArrayImpl() +{ + return dom::WebGLVertexArrayObject::Create(this); +} + +} // namespace mozilla
deleted file mode 100644 --- a/dom/canvas/WebGLBindableName.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; 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/. */ - -#ifndef WEBGLBINDABLENAME_H_ -#define WEBGLBINDABLENAME_H_ - -#include "WebGLTypes.h" - -#include "GLDefs.h" -#include "mozilla/TypeTraits.h" -#include "mozilla/Assertions.h" - -namespace mozilla { - -/** Represents a binding to a GL binding point - */ -template<typename T> -class WebGLBindable -{ -public: - WebGLBindable() : mTarget(LOCAL_GL_NONE) { } - bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; } - - void BindTo(T target) { - MOZ_ASSERT(target != LOCAL_GL_NONE, "Can't bind to GL_NONE."); - MOZ_ASSERT(!HasEverBeenBound() || mTarget == target, "Rebinding is illegal."); - - bool targetChanged = (target != mTarget); - mTarget = target; - if (targetChanged) - OnTargetChanged(); - } - - T Target() const { - MOZ_ASSERT(HasEverBeenBound()); - return mTarget; - } - -protected: - //! Called after mTarget has been changed by BindTo(target). - virtual void OnTargetChanged() {} - - T mTarget; -}; - - -/** Represents a GL name that can be bound to a target. - */ -template<typename T> -class WebGLBindableName - : public WebGLBindable<T> -{ -public: - - explicit WebGLBindableName(GLuint aName) - : WebGLBindable<T>() - , mGLName(aName) - { } - GLuint GLName() const { return mGLName; } - -protected: - const GLuint mGLName; -}; - - -} // namespace mozilla - -#endif // !WEBGLBINDABLENAME_H_
--- a/dom/canvas/WebGLBuffer.cpp +++ b/dom/canvas/WebGLBuffer.cpp @@ -8,60 +8,82 @@ #include "GLContext.h" #include "mozilla/dom/WebGLRenderingContextBinding.h" #include "WebGLContext.h" #include "WebGLElementArrayCache.h" namespace mozilla { WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf) - : WebGLBindableName<BufferBinding>(buf) - , WebGLContextBoundObject(webgl) + : WebGLContextBoundObject(webgl) + , mGLName(buf) + , mContent(Kind::Undefined) , mByteLength(0) { mContext->mBuffers.insertBack(this); } WebGLBuffer::~WebGLBuffer() { DeleteOnce(); } void +WebGLBuffer::BindTo(GLenum target) +{ + switch (target) { + case LOCAL_GL_ELEMENT_ARRAY_BUFFER: + mContent = Kind::ElementArray; + if (!mCache) + mCache = new WebGLElementArrayCache; + break; + + case LOCAL_GL_ARRAY_BUFFER: + case LOCAL_GL_PIXEL_PACK_BUFFER: + case LOCAL_GL_PIXEL_UNPACK_BUFFER: + case LOCAL_GL_UNIFORM_BUFFER: + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: + mContent = Kind::OtherData; + break; + + case LOCAL_GL_COPY_READ_BUFFER: + case LOCAL_GL_COPY_WRITE_BUFFER: + /* Do nothing. Doesn't set the type of the buffer contents. */ + break; + + default: + MOZ_CRASH(); + } +} + +void WebGLBuffer::Delete() { mContext->MakeContextCurrent(); mContext->gl->fDeleteBuffers(1, &mGLName); mByteLength = 0; mCache = nullptr; LinkedListElement<WebGLBuffer>::remove(); // remove from mContext->mBuffers } -void -WebGLBuffer::OnTargetChanged() -{ - if (!mCache && mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER) - mCache = new WebGLElementArrayCache; -} - bool WebGLBuffer::ElementArrayCacheBufferData(const void* ptr, size_t bufferSizeInBytes) { - if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER) + if (mContent == Kind::ElementArray) return mCache->BufferData(ptr, bufferSizeInBytes); return true; } void WebGLBuffer::ElementArrayCacheBufferSubData(size_t pos, const void* ptr, size_t updateSizeInBytes) { - if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER) + if (mContent == Kind::ElementArray) mCache->BufferSubData(pos, ptr, updateSizeInBytes); } size_t WebGLBuffer::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { size_t sizeOfCache = mCache ? mCache->SizeOfIncludingThis(mallocSizeOf) : 0;
--- a/dom/canvas/WebGLBuffer.h +++ b/dom/canvas/WebGLBuffer.h @@ -5,35 +5,43 @@ #ifndef WEBGL_BUFFER_H_ #define WEBGL_BUFFER_H_ #include "GLDefs.h" #include "mozilla/LinkedList.h" #include "mozilla/MemoryReporting.h" #include "nsWrapperCache.h" -#include "WebGLBindableName.h" #include "WebGLObjectModel.h" #include "WebGLStrongTypes.h" #include "WebGLTypes.h" namespace mozilla { class WebGLElementArrayCache; class WebGLBuffer final : public nsWrapperCache - , public WebGLBindableName<BufferBinding> , public WebGLRefCountedObject<WebGLBuffer> , public LinkedListElement<WebGLBuffer> , public WebGLContextBoundObject { public: + + enum class Kind { + Undefined, + ElementArray, + OtherData + }; + explicit WebGLBuffer(WebGLContext* webgl, GLuint buf); + void BindTo(GLenum target); + Kind Content() const { return mContent; } + void Delete(); size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; WebGLsizeiptr ByteLength() const { return mByteLength; } void SetByteLength(WebGLsizeiptr byteLength) { mByteLength = byteLength; } bool ElementArrayCacheBufferData(const void* ptr, size_t bufferSizeInBytes); @@ -47,23 +55,24 @@ public: bool IsElementArrayUsedWithMultipleTypes() const; WebGLContext* GetParentObject() const { return Context(); } virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; + const GLenum mGLName; + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer) protected: ~WebGLBuffer(); - virtual void OnTargetChanged() override; - + Kind mContent; WebGLsizeiptr mByteLength; nsAutoPtr<WebGLElementArrayCache> mCache; }; } // namespace mozilla #endif // WEBGL_BUFFER_H_
--- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1875,17 +1875,17 @@ WebGLContext::TexImageFromVideoElement(c srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr); } const gl::OriginPos destOrigin = mPixelStoreFlipY ? gl::OriginPos::BottomLeft : gl::OriginPos::TopLeft; bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), - tex->GLName(), + tex->mGLName, texImageTarget.get(), destOrigin); if (ok) { TexInternalFormat effectiveInternalFormat = EffectiveInternalFormatFromInternalFormatAndType(internalFormat, type); MOZ_ASSERT(effectiveInternalFormat != LOCAL_GL_NONE); tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width,
--- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -934,16 +934,18 @@ protected: nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundUniformBuffers; nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundTransformFeedbackBuffers; WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTarget(GLenum target); WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTargetIndexed(GLenum target, GLuint index); + GLenum GetCurrentBinding(WebGLBuffer* buffer) const; + // ----------------------------------------------------------------------------- // Queries (WebGL2ContextQueries.cpp) protected: WebGLRefPtr<WebGLQuery>& GetQuerySlotByTarget(GLenum target); WebGLRefPtr<WebGLQuery> mActiveOcclusionQuery; WebGLRefPtr<WebGLQuery> mActiveTransformFeedbackQuery; @@ -1385,20 +1387,22 @@ private: // Like ValidateObject, but only for cases when `object` is known to not be // null already. template<class ObjectType> bool ValidateObjectAssumeNonNull(const char* info, ObjectType* object); private: // ------------------------------------------------------------------------- // Context customization points + virtual WebGLVertexArray* CreateVertexArrayImpl(); + virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) = 0; virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0; virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0; - virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) = 0; + virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info); virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) = 0; virtual bool ValidateQueryTarget(GLenum usage, const char* info) = 0; virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) = 0; protected: int32_t MaxTextureSizeForTarget(TexTarget target) const { return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize : mGLMaxCubeMapTextureSize;
--- a/dom/canvas/WebGLContextBuffers.cpp +++ b/dom/canvas/WebGLContextBuffers.cpp @@ -15,34 +15,17 @@ void WebGLContext::UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer) { WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target); bufferSlot = buffer; if (!buffer) return; - /* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1 - * - * In the WebGL 2 API, buffers have their WebGL buffer type - * initially set to undefined. Calling bindBuffer, bindBufferRange - * or bindBufferBase with the target argument set to any buffer - * binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will - * then set the WebGL buffer type of the buffer being bound - * according to the table above. - * - * Any call to one of these functions which attempts to bind a - * WebGLBuffer that has the element array WebGL buffer type to a - * binding point that falls under other data, or bind a - * WebGLBuffer which has the other data WebGL buffer type to - * ELEMENT_ARRAY_BUFFER will generate an INVALID_OPERATION error, - * and the state of the binding point will remain untouched. - */ - if (target != LOCAL_GL_COPY_READ_BUFFER && target != LOCAL_GL_COPY_WRITE_BUFFER) - buffer->BindTo(target); + buffer->BindTo(target); } void WebGLContext::UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer) { UpdateBoundBuffer(target, buffer); WebGLRefPtr<WebGLBuffer>& bufferIndexSlot = @@ -405,22 +388,60 @@ WebGLContext::DeleteBuffer(WebGLBuffer* return; if (!ValidateObjectAllowDeletedOrNull("deleteBuffer", buffer)) return; if (!buffer || buffer->IsDeleted()) return; - if (mBoundArrayBuffer == buffer) - BindBuffer(LOCAL_GL_ARRAY_BUFFER, static_cast<WebGLBuffer*>(nullptr)); + // TODO: Extract this into a helper function? + if (mBoundArrayBuffer == buffer) { + WebGLContextUnchecked::BindBuffer(LOCAL_GL_ARRAY_BUFFER, nullptr); + mBoundArrayBuffer = nullptr; + } if (mBoundVertexArray->mElementArrayBuffer == buffer) { - BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, - static_cast<WebGLBuffer*>(nullptr)); + WebGLContextUnchecked::BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nullptr); + mBoundVertexArray->mElementArrayBuffer = nullptr; + } + + // WebGL binding points + if (IsWebGL2()) { + if (mBoundCopyReadBuffer == buffer) + mBoundCopyReadBuffer = nullptr; + + if (mBoundCopyWriteBuffer == buffer) + mBoundCopyWriteBuffer = nullptr; + + if (mBoundPixelPackBuffer == buffer) + mBoundPixelPackBuffer = nullptr; + + if (mBoundPixelUnpackBuffer == buffer) + mBoundPixelUnpackBuffer = nullptr; + + if (mBoundTransformFeedbackBuffer == buffer) + mBoundTransformFeedbackBuffer = nullptr; + + if (mBoundUniformBuffer == buffer) + mBoundUniformBuffer = nullptr; + + const size_t xfBufferCount = mBoundTransformFeedbackBuffers.Length(); + for (size_t n = 0; n < xfBufferCount; n++) { + if (mBoundTransformFeedbackBuffers[n] == buffer) { + mBoundTransformFeedbackBuffers[n] = nullptr; + } + } + + const size_t uniformBufferCount = mBoundUniformBuffers.Length(); + for (size_t n = 0; n < uniformBufferCount; n++) { + if (mBoundUniformBuffers[n] == buffer) { + mBoundUniformBuffers[n] = nullptr; + } + } } for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) { if (mBoundVertexArray->HasAttrib(i) && mBoundVertexArray->mAttribs[i].buf == buffer) { mBoundVertexArray->mAttribs[i].buf = nullptr; } @@ -430,19 +451,99 @@ WebGLContext::DeleteBuffer(WebGLBuffer* } bool WebGLContext::IsBuffer(WebGLBuffer* buffer) { if (IsContextLost()) return false; - return ValidateObjectAllowDeleted("isBuffer", buffer) && - !buffer->IsDeleted() && - buffer->HasEverBeenBound(); + if (!ValidateObjectAllowDeleted("isBuffer", buffer)) + return false; + + if (buffer->IsDeleted()) + return false; + + MakeContextCurrent(); + return gl->fIsBuffer(buffer->mGLName); +} + +bool +WebGLContext::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, + const char* info) +{ + if (!buffer) + return true; + + /* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1 + * + * In the WebGL 2 API, buffers have their WebGL buffer type + * initially set to undefined. Calling bindBuffer, bindBufferRange + * or bindBufferBase with the target argument set to any buffer + * binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will + * then set the WebGL buffer type of the buffer being bound + * according to the table above. + * + * Any call to one of these functions which attempts to bind a + * WebGLBuffer that has the element array WebGL buffer type to a + * binding point that falls under other data, or bind a + * WebGLBuffer which has the other data WebGL buffer type to + * ELEMENT_ARRAY_BUFFER will generate an INVALID_OPERATION error, + * and the state of the binding point will remain untouched. + */ + + GLenum boundTo = GetCurrentBinding(buffer); + if (boundTo != LOCAL_GL_NONE) { + if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && + boundTo != LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) + { + ErrorInvalidOperation("Can't bind buffer to TRANSFORM_FEEDBACK_BUFFER as the " + "buffer is already bound to another bind point."); + return false; + } + else if (target != LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && + boundTo == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) + { + ErrorInvalidOperation("Can't bind buffer to bind point as it is currently " + "bound to TRANSFORM_FEEDBACK_BUFFER."); + return false; + } + } + + WebGLBuffer::Kind content = buffer->Content(); + if (content == WebGLBuffer::Kind::Undefined) + return true; + + switch (target) { + case LOCAL_GL_COPY_READ_BUFFER: + case LOCAL_GL_COPY_WRITE_BUFFER: + return true; + + case LOCAL_GL_ELEMENT_ARRAY_BUFFER: + if (content == WebGLBuffer::Kind::ElementArray) + return true; + break; + + case LOCAL_GL_ARRAY_BUFFER: + case LOCAL_GL_PIXEL_PACK_BUFFER: + case LOCAL_GL_PIXEL_UNPACK_BUFFER: + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: + case LOCAL_GL_UNIFORM_BUFFER: + if (content == WebGLBuffer::Kind::OtherData) + return true; + break; + + default: + MOZ_CRASH(); + } + + ErrorInvalidOperation("%s: buffer already contains %s data.", info, + content == WebGLBuffer::Kind::OtherData ? "other" : "element"); + + return false; } bool WebGLContext::ValidateBufferUsageEnum(GLenum target, const char* info) { switch (target) { case LOCAL_GL_STREAM_DRAW: case LOCAL_GL_STATIC_DRAW: @@ -506,16 +607,47 @@ WebGLContext::GetBufferSlotByTargetIndex return mBoundUniformBuffers[index]; default: MOZ_CRASH("Should not get here."); } } GLenum +WebGLContext::GetCurrentBinding(WebGLBuffer* buffer) const +{ + if (mBoundArrayBuffer == buffer) + return LOCAL_GL_ARRAY_BUFFER; + + if (mBoundCopyReadBuffer == buffer) + return LOCAL_GL_COPY_READ_BUFFER; + + if (mBoundCopyWriteBuffer == buffer) + return LOCAL_GL_COPY_WRITE_BUFFER; + + if (mBoundPixelPackBuffer == buffer) + return LOCAL_GL_PIXEL_PACK_BUFFER; + + if (mBoundPixelUnpackBuffer == buffer) + return LOCAL_GL_PIXEL_UNPACK_BUFFER; + + if (mBoundTransformFeedbackBuffer == buffer || + mBoundTransformFeedbackBuffers.Contains(buffer)) { + return LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER; + } + + if (mBoundUniformBuffer == buffer || + mBoundUniformBuffers.Contains(buffer)) { + return LOCAL_GL_UNIFORM_BUFFER; + } + + return LOCAL_GL_NONE; +} + +GLenum WebGLContext::CheckedBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { #ifdef XP_MACOSX // bug 790879 if (gl->WorkAroundDriverBugs() && int64_t(size) > INT32_MAX) // cast avoids a potential always-true warning on 32bit {
--- a/dom/canvas/WebGLContextDraw.cpp +++ b/dom/canvas/WebGLContextDraw.cpp @@ -595,17 +595,17 @@ WebGLContext::DoFakeVertexAttrib0(GLuint array[4 * i + 3] = mVertexAttrib0Vector[3]; } gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array.get(), LOCAL_GL_DYNAMIC_DRAW); } else { gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nullptr, LOCAL_GL_DYNAMIC_DRAW); } GLenum error = GetAndFlushUnderlyingGLErrors(); - gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0); + gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0); // note that we do this error checking and early return AFTER having restored the buffer binding above if (error) { ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation " "with %d vertices. Try reducing the number of vertices.", vertexCount); return false; } } @@ -621,17 +621,17 @@ WebGLContext::UndoFakeVertexAttrib0() { WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need(); if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default)) return; if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) { const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0]; - gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName()); + gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->mGLName); if (attrib0.integer) { gl->fVertexAttribIPointer(0, attrib0.size, attrib0.type, attrib0.stride, reinterpret_cast<const GLvoid*>(attrib0.byteOffset)); } else { gl->fVertexAttribPointer(0, @@ -640,17 +640,17 @@ WebGLContext::UndoFakeVertexAttrib0() attrib0.normalized, attrib0.stride, reinterpret_cast<const GLvoid*>(attrib0.byteOffset)); } } else { gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); } - gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0); + gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0); } WebGLContextFakeBlackStatus WebGLContext::ResolvedFakeBlackStatus() { // handle this case first, it's the generic case if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded)) return mFakeBlackStatus; @@ -732,21 +732,21 @@ WebGLContext::UnbindFakeBlackTextures() { // this is the generic case: try to return early if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded)) return; for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) { if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) { gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i); - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName()); + gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->mGLName); } if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) { gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i); - gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName()); + gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->mGLName); } } gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture); } WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext* gl, TexTarget target, GLenum format) : mGL(gl)
--- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -154,19 +154,21 @@ WebGLContext::BindFramebuffer(GLenum tar if (wfb && wfb->IsDeleted()) return; MakeContextCurrent(); if (!wfb) { gl->fBindFramebuffer(target, 0); } else { - wfb->BindTo(target); - GLuint framebuffername = wfb->GLName(); + GLuint framebuffername = wfb->mGLName; gl->fBindFramebuffer(target, framebuffername); +#ifdef ANDROID + wfb->mIsFB = true; +#endif } switch (target) { case LOCAL_GL_FRAMEBUFFER: mBoundDrawFramebuffer = wfb; mBoundReadFramebuffer = wfb; break; case LOCAL_GL_DRAW_FRAMEBUFFER: @@ -191,25 +193,25 @@ WebGLContext::BindRenderbuffer(GLenum ta if (!ValidateObjectAllowDeletedOrNull("bindRenderbuffer", wrb)) return; // silently ignore a deleted buffer if (wrb && wrb->IsDeleted()) return; - if (wrb) - wrb->BindTo(target); - MakeContextCurrent(); // Sometimes we emulate renderbuffers (depth-stencil emu), so there's not // always a 1-1 mapping from `wrb` to GL name. Just have `wrb` handle it. if (wrb) { wrb->BindRenderbuffer(); +#ifdef ANDROID + wrb->mIsRB = true; +#endif } else { gl->fBindRenderbuffer(target, 0); } mBoundRenderbuffer = wrb; } void @@ -732,17 +734,17 @@ WebGLContext::DeleteTexture(WebGLTexture GLuint activeTexture = mActiveTexture; for (int32_t i = 0; i < mGLMaxTextureUnits; i++) { if ((mBound2DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_2D) || (mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP) || (mBound3DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_3D)) { ActiveTexture(LOCAL_GL_TEXTURE0 + i); - BindTexture(tex->Target().get(), nullptr); + BindTexture(tex->Target(), nullptr); } } ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture); tex->RequestDelete(); } void @@ -1686,19 +1688,32 @@ WebGLContext::Hint(GLenum target, GLenum } bool WebGLContext::IsFramebuffer(WebGLFramebuffer* fb) { if (IsContextLost()) return false; - return ValidateObjectAllowDeleted("isFramebuffer", fb) && - !fb->IsDeleted() && - fb->HasEverBeenBound(); + if (!ValidateObjectAllowDeleted("isFramebuffer", fb)) + return false; + + if (fb->IsDeleted()) + return false; + +#ifdef ANDROID + if (gl->WorkAroundDriverBugs() && + gl->Renderer() == GLRenderer::AndroidEmulator) + { + return fb->mIsFB; + } +#endif + + MakeContextCurrent(); + return gl->fIsFramebuffer(fb->mGLName); } bool WebGLContext::IsProgram(WebGLProgram* prog) { if (IsContextLost()) return false; @@ -1706,19 +1721,32 @@ WebGLContext::IsProgram(WebGLProgram* pr } bool WebGLContext::IsRenderbuffer(WebGLRenderbuffer* rb) { if (IsContextLost()) return false; - return ValidateObjectAllowDeleted("isRenderBuffer", rb) && - !rb->IsDeleted() && - rb->HasEverBeenBound(); + if (!ValidateObjectAllowDeleted("isRenderBuffer", rb)) + return false; + + if (rb->IsDeleted()) + return false; + +#ifdef ANDROID + if (gl->WorkAroundDriverBugs() && + gl->Renderer() == GLRenderer::AndroidEmulator) + { + return rb->mIsRB; + } +#endif + + MakeContextCurrent(); + return gl->fIsRenderbuffer(rb->PrimaryGLName()); } bool WebGLContext::IsShader(WebGLShader* shader) { if (IsContextLost()) return false;
--- a/dom/canvas/WebGLContextReporter.cpp +++ b/dom/canvas/WebGLContextReporter.cpp @@ -121,18 +121,17 @@ WebGLMemoryTracker::GetBufferCacheMemory { const ContextsArrayType& contexts = Contexts(); int64_t result = 0; for(size_t i = 0; i < contexts.Length(); ++i) { for (const WebGLBuffer* buffer = contexts[i]->mBuffers.getFirst(); buffer; buffer = buffer->getNext()) { - if (buffer->HasEverBeenBound() && - buffer->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER) { + if (buffer->Content() == WebGLBuffer::Kind::ElementArray) { result += buffer->SizeOfIncludingThis(WebGLBufferMallocSizeOf); } } } return result; } MOZ_DEFINE_MALLOC_SIZE_OF(WebGLShaderMallocSizeOf)
--- a/dom/canvas/WebGLContextState.cpp +++ b/dom/canvas/WebGLContextState.cpp @@ -189,31 +189,48 @@ WebGLContext::GetParameter(JSContext* cx gl->fGetBooleanv(pname, &disjoint); } return JS::BooleanValue(bool(disjoint)); } } if (IsWebGL2()) { switch (pname) { - case LOCAL_GL_MAX_SAMPLES: - case LOCAL_GL_MAX_UNIFORM_BLOCK_SIZE: - case LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS: { - GLint val; - gl->fGetIntegerv(pname, &val); - return JS::NumberValue(uint32_t(val)); - } + case LOCAL_GL_MAX_SAMPLES: + case LOCAL_GL_MAX_UNIFORM_BLOCK_SIZE: + case LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS: { + GLint val; + gl->fGetIntegerv(pname, &val); + return JS::NumberValue(uint32_t(val)); + } + + case LOCAL_GL_TEXTURE_BINDING_3D: + return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv); + + // DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING. + case LOCAL_GL_READ_FRAMEBUFFER_BINDING: + return WebGLObjectAsJSValue(cx, mBoundReadFramebuffer.get(), rv); - case LOCAL_GL_TEXTURE_BINDING_3D: { - return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv); - } + case LOCAL_GL_PIXEL_PACK_BUFFER_BINDING: + return WebGLObjectAsJSValue(cx, mBoundPixelPackBuffer.get(), rv); + + case LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING: + return WebGLObjectAsJSValue(cx, mBoundPixelUnpackBuffer.get(), rv); + + case LOCAL_GL_UNIFORM_BUFFER_BINDING: + return WebGLObjectAsJSValue(cx, mBoundUniformBuffer.get(), rv); - // DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING. - case LOCAL_GL_READ_FRAMEBUFFER_BINDING: - return WebGLObjectAsJSValue(cx, mBoundReadFramebuffer.get(), rv); + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv); + + case LOCAL_GL_COPY_READ_BUFFER_BINDING: + return WebGLObjectAsJSValue(cx, mBoundCopyReadBuffer.get(), rv); + + case LOCAL_GL_COPY_WRITE_BUFFER_BINDING: + return WebGLObjectAsJSValue(cx, mBoundCopyWriteBuffer.get(), rv); } } switch (pname) { // // String params // case LOCAL_GL_VENDOR: @@ -528,23 +545,16 @@ WebGLContext::GetParameter(JSContext* cx } return arr; } case LOCAL_GL_ARRAY_BUFFER_BINDING: { return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv); } - case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: { - if (!IsWebGL2()) { - break; - } - return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv); - } - case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING: { return WebGLObjectAsJSValue(cx, mBoundVertexArray->mElementArrayBuffer.get(), rv); } case LOCAL_GL_RENDERBUFFER_BINDING: { return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv); }
--- a/dom/canvas/WebGLContextUnchecked.cpp +++ b/dom/canvas/WebGLContextUnchecked.cpp @@ -19,31 +19,42 @@ WebGLContextUnchecked::WebGLContextUnche // ----------------------------------------------------------------------------- // Buffer Objects void WebGLContextUnchecked::BindBuffer(GLenum target, WebGLBuffer* buffer) { gl->MakeCurrent(); - gl->fBindBuffer(target, buffer ? buffer->GLName() : 0); + gl->fBindBuffer(target, buffer ? buffer->mGLName : 0); } void WebGLContextUnchecked::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer) { gl->MakeCurrent(); - gl->fBindBufferBase(target, index, buffer ? buffer->GLName() : 0); + gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0); } void WebGLContextUnchecked::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size) { gl->MakeCurrent(); - gl->fBindBufferRange(target, index, buffer ? buffer->GLName() : 0, offset, size); + +#ifdef XP_MACOSX + if (buffer && buffer->Content() == WebGLBuffer::Kind::Undefined && + gl->WorkAroundDriverBugs()) + { + // BindBufferRange will fail if the buffer's contents is undefined. + // Bind so driver initializes the buffer. + gl->fBindBuffer(target, buffer->mGLName); + } +#endif + + gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset, size); } void WebGLContextUnchecked::CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { gl->MakeCurrent(); gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); } @@ -51,79 +62,77 @@ WebGLContextUnchecked::CopyBufferSubData // ----------------------------------------------------------------------------- // Sampler Objects void WebGLContextUnchecked::BindSampler(GLuint unit, WebGLSampler* sampler) { gl->MakeCurrent(); - gl->fBindSampler(unit, sampler ? sampler->GLName() : 0); - if (sampler) - sampler->BindTo(LOCAL_GL_SAMPLER_BINDING); + gl->fBindSampler(unit, sampler ? sampler->mGLName : 0); } GLint WebGLContextUnchecked::GetSamplerParameteriv(WebGLSampler* sampler, GLenum pname) { MOZ_ASSERT(sampler, "Did you validate?"); GLint param = 0; gl->MakeCurrent(); - gl->fGetSamplerParameteriv(sampler->GLName(), pname, ¶m); + gl->fGetSamplerParameteriv(sampler->mGLName, pname, ¶m); return param; } GLfloat WebGLContextUnchecked::GetSamplerParameterfv(WebGLSampler* sampler, GLenum pname) { MOZ_ASSERT(sampler, "Did you validate?"); GLfloat param = 0.0f; gl->MakeCurrent(); - gl->fGetSamplerParameterfv(sampler->GLName(), pname, ¶m); + gl->fGetSamplerParameterfv(sampler->mGLName, pname, ¶m); return param; } void WebGLContextUnchecked::SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param) { MOZ_ASSERT(sampler, "Did you validate?"); gl->MakeCurrent(); - gl->fSamplerParameteri(sampler->GLName(), pname, param); + gl->fSamplerParameteri(sampler->mGLName, pname, param); } void WebGLContextUnchecked::SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const GLint* param) { MOZ_ASSERT(sampler, "Did you validate?"); gl->MakeCurrent(); - gl->fSamplerParameteriv(sampler->GLName(), pname, param); + gl->fSamplerParameteriv(sampler->mGLName, pname, param); } void WebGLContextUnchecked::SamplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat param) { MOZ_ASSERT(sampler, "Did you validate?"); gl->MakeCurrent(); - gl->fSamplerParameterf(sampler->GLName(), pname, param); + gl->fSamplerParameterf(sampler->mGLName, pname, param); } void WebGLContextUnchecked::SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const GLfloat* param) { MOZ_ASSERT(sampler, "Did you validate?"); gl->MakeCurrent(); - gl->fSamplerParameterfv(sampler->GLName(), pname, param); + gl->fSamplerParameterfv(sampler->mGLName, pname, param); } } // namespace mozilla
--- a/dom/canvas/WebGLContextUtils.cpp +++ b/dom/canvas/WebGLContextUtils.cpp @@ -1093,51 +1093,51 @@ WebGLContext::AssertCachedBindings() if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) { GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0; AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound); } // Bound object state if (IsWebGL2()) { - GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->GLName() + GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, bound); - bound = mBoundReadFramebuffer ? mBoundReadFramebuffer->GLName() : 0; + bound = mBoundReadFramebuffer ? mBoundReadFramebuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_READ_FRAMEBUFFER_BINDING, bound); } else { MOZ_ASSERT(mBoundDrawFramebuffer == mBoundReadFramebuffer); - GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->GLName() + GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound); } GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound); // Textures GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0; AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture); WebGLTexture* curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_2D); - bound = curTex ? curTex->GLName() : 0; + bound = curTex ? curTex->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_2D, bound); curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_CUBE_MAP); - bound = curTex ? curTex->GLName() : 0; + bound = curTex ? curTex->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, bound); // Buffers - bound = mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0; + bound = mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_ARRAY_BUFFER_BINDING, bound); MOZ_ASSERT(mBoundVertexArray); WebGLBuffer* curBuff = mBoundVertexArray->mElementArrayBuffer; - bound = curBuff ? curBuff->GLName() : 0; + bound = curBuff ? curBuff->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING, bound); MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors()); #endif } void WebGLContext::AssertCachedState()
--- a/dom/canvas/WebGLContextValidate.cpp +++ b/dom/canvas/WebGLContextValidate.cpp @@ -261,18 +261,20 @@ WebGLContext::ValidateDataOffsetSize(Web */ bool WebGLContext::ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info) { MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid()); MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid()); bool separate = (readOffset + size < writeOffset || writeOffset + size < readOffset); - if (!separate) - ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and [writeOffset, writeOffset + size) overlap"); + if (!separate) { + ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and [writeOffset, " + "writeOffset + size) overlap", info); + } return separate; } bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char* info) { switch (target) {
--- a/dom/canvas/WebGLContextVertexArray.cpp +++ b/dom/canvas/WebGLContextVertexArray.cpp @@ -46,24 +46,30 @@ WebGLContext::BindVertexArray(WebGLVerte } already_AddRefed<WebGLVertexArray> WebGLContext::CreateVertexArray() { if (IsContextLost()) return nullptr; - nsRefPtr<WebGLVertexArray> globj = WebGLVertexArray::Create(this); + nsRefPtr<WebGLVertexArray> globj = CreateVertexArrayImpl(); MakeContextCurrent(); globj->GenVertexArray(); return globj.forget(); } +WebGLVertexArray* +WebGLContext::CreateVertexArrayImpl() +{ + return WebGLVertexArray::Create(this); +} + void WebGLContext::DeleteVertexArray(WebGLVertexArray* array) { if (IsContextLost()) return; if (array == nullptr) return; @@ -81,14 +87,19 @@ bool WebGLContext::IsVertexArray(WebGLVertexArray* array) { if (IsContextLost()) return false; if (!array) return false; - return ValidateObjectAllowDeleted("isVertexArray", array) && - !array->IsDeleted() && - array->HasEverBeenBound(); + if (!ValidateObjectAllowDeleted("isVertexArray", array)) + return false; + + if (array->IsDeleted()) + return false; + + MakeContextCurrent(); + return array->IsVertexArray(); } } // namespace mozilla
--- a/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp +++ b/dom/canvas/WebGLExtensionDisjointTimerQuery.cpp @@ -88,18 +88,18 @@ WebGLExtensionDisjointTimerQuery::BeginQ if (mActiveQuery) { mContext->ErrorInvalidOperation("beginQueryEXT: A query is already" " active."); return; } mContext->MakeContextCurrent(); gl::GLContext* gl = mContext->GL(); - gl->fBeginQuery(target, query->GLName()); - query->BindTo(LOCAL_GL_TIME_ELAPSED_EXT); + gl->fBeginQuery(target, query->mGLName); + query->mTarget = LOCAL_GL_TIME_ELAPSED_EXT; mActiveQuery = query; } void WebGLExtensionDisjointTimerQuery::EndQueryEXT(GLenum target) { if (mIsLost) return; @@ -132,18 +132,18 @@ WebGLExtensionDisjointTimerQuery::QueryC if (target != LOCAL_GL_TIMESTAMP_EXT) { mContext->ErrorInvalidEnumInfo("queryCounterEXT: requires" " TIMESTAMP_EXT.", target); return; } mContext->MakeContextCurrent(); - mContext->GL()->fQueryCounter(query->GLName(), target); - query->BindTo(LOCAL_GL_TIMESTAMP_EXT); + mContext->GL()->fQueryCounter(query->mGLName, target); + query->mTarget = LOCAL_GL_TIMESTAMP_EXT; } void WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target, GLenum pname, JS::MutableHandle<JS::Value> retval) { if (mIsLost) @@ -205,25 +205,25 @@ WebGLExtensionDisjointTimerQuery::GetQue mContext->MakeContextCurrent(); // XXX: Note that the query result *may change* within the same task! // This does not follow the specification, which states that all calls // checking query results must return the same value until the event loop // is empty. switch (pname) { case LOCAL_GL_QUERY_RESULT_EXT: { GLuint64 result = 0; - mContext->GL()->fGetQueryObjectui64v(query->GLName(), + mContext->GL()->fGetQueryObjectui64v(query->mGLName, LOCAL_GL_QUERY_RESULT_EXT, &result); retval.set(JS::NumberValue(result)); break; } case LOCAL_GL_QUERY_RESULT_AVAILABLE_EXT: { GLuint avail = 0; - mContext->GL()->fGetQueryObjectuiv(query->GLName(), + mContext->GL()->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT_AVAILABLE_EXT, &avail); retval.set(JS::BooleanValue(bool(avail))); break; } default: mContext->ErrorInvalidEnumInfo("getQueryObjectEXT: Invalid query" " property.", pname);
--- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -373,17 +373,17 @@ WebGLFramebuffer::AttachPoint::FinalizeA } MOZ_ASSERT(HasImage()); if (Texture()) { MOZ_ASSERT(gl == Texture()->Context()->GL()); const GLenum imageTarget = ImageTarget().get(); const GLint mipLevel = MipLevel(); - const GLuint glName = Texture()->GLName(); + const GLuint glName = Texture()->mGLName; if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, imageTarget, glName, mipLevel); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, imageTarget, glName, mipLevel); } else { gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(), @@ -399,24 +399,28 @@ WebGLFramebuffer::AttachPoint::FinalizeA MOZ_CRASH(); } //////////////////////////////////////////////////////////////////////////////// // WebGLFramebuffer WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo) - : WebGLBindableName<FBTarget>(fbo) - , WebGLContextBoundObject(webgl) + : WebGLContextBoundObject(webgl) + , mGLName(fbo) , mStatus(0) , mReadBufferMode(LOCAL_GL_COLOR_ATTACHMENT0) , mColorAttachment0(this, LOCAL_GL_COLOR_ATTACHMENT0) , mDepthAttachment(this, LOCAL_GL_DEPTH_ATTACHMENT) , mStencilAttachment(this, LOCAL_GL_STENCIL_ATTACHMENT) , mDepthStencilAttachment(this, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) +#ifdef ANDROID + , mIsFB(false) +#endif + { mContext->mFramebuffers.insertBack(this); } void WebGLFramebuffer::Delete() { mColorAttachment0.Clear(); @@ -427,16 +431,20 @@ WebGLFramebuffer::Delete() const size_t moreColorAttachmentCount = mMoreColorAttachments.Length(); for (size_t i = 0; i < moreColorAttachmentCount; i++) { mMoreColorAttachments[i].Clear(); } mContext->MakeContextCurrent(); mContext->gl->fDeleteFramebuffers(1, &mGLName); LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers); + +#ifdef ANDROID + mIsFB = false; +#endif } void WebGLFramebuffer::FramebufferRenderbuffer(FBAttachment attachPointEnum, RBTarget rbtarget, WebGLRenderbuffer* rb) { MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
--- a/dom/canvas/WebGLFramebuffer.h +++ b/dom/canvas/WebGLFramebuffer.h @@ -3,37 +3,37 @@ * 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 WEBGL_FRAMEBUFFER_H_ #define WEBGL_FRAMEBUFFER_H_ #include "mozilla/LinkedList.h" #include "nsWrapperCache.h" -#include "WebGLBindableName.h" #include "WebGLObjectModel.h" #include "WebGLStrongTypes.h" namespace mozilla { class WebGLRenderbuffer; class WebGLTexture; namespace gl { class GLContext; } class WebGLFramebuffer final : public nsWrapperCache - , public WebGLBindableName<FBTarget> , public WebGLRefCountedObject<WebGLFramebuffer> , public LinkedListElement<WebGLFramebuffer> , public WebGLContextBoundObject , public SupportsWeakPtr<WebGLFramebuffer> { + friend class WebGLContext; + public: MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLFramebuffer) class AttachPoint { public: WebGLFramebuffer* const mFB; private: @@ -48,17 +48,16 @@ public: ~AttachPoint(); void Unlink() { mRenderbufferPtr = nullptr; mTexturePtr = nullptr; } bool IsDefined() const; - bool IsDeleteRequested() const; TexInternalFormat EffectiveInternalFormat() const; bool HasAlpha() const; bool IsReadableFloat() const; void Clear() { @@ -94,28 +93,39 @@ public: bool HasImage() const; bool IsComplete() const; void FinalizeAttachment(gl::GLContext* gl, FBAttachment attachmentLoc) const; }; + const GLuint mGLName; + private: mutable GLenum mStatus; GLenum mReadBufferMode; // No need to chase pointers for the oft-used color0. AttachPoint mColorAttachment0; AttachPoint mDepthAttachment; AttachPoint mStencilAttachment; AttachPoint mDepthStencilAttachment; nsTArray<AttachPoint> mMoreColorAttachments; +#ifdef ANDROID + // Bug 1140459: Some drivers (including our test slaves!) don't + // give reasonable answers for IsRenderbuffer, maybe others. + // This shows up on Android 2.3 emulator. + // + // So we track the `is a Framebuffer` state ourselves. + bool mIsFB; +#endif + public: WebGLFramebuffer(WebGLContext* webgl, GLuint fbo); private: ~WebGLFramebuffer() { DeleteOnce(); }
--- a/dom/canvas/WebGLRenderbuffer.cpp +++ b/dom/canvas/WebGLRenderbuffer.cpp @@ -42,24 +42,26 @@ NeedsDepthStencilEmu(gl::GLContext* gl, JSObject* WebGLRenderbuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) { return dom::WebGLRenderbufferBinding::Wrap(cx, this, aGivenProto); } WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl) - : WebGLBindable<RBTarget>() - , WebGLContextBoundObject(webgl) + : WebGLContextBoundObject(webgl) , mPrimaryRB(0) , mSecondaryRB(0) , mInternalFormat(0) , mInternalFormatForGL(0) , mImageDataStatus(WebGLImageDataStatus::NoImageData) , mSamples(1) +#ifdef ANDROID + , mIsRB(false) +#endif { mContext->MakeContextCurrent(); mContext->gl->fGenRenderbuffers(1, &mPrimaryRB); if (!SupportsDepthStencil(mContext->gl)) mContext->gl->fGenRenderbuffers(1, &mSecondaryRB); mContext->mRenderbuffers.insertBack(this); @@ -70,16 +72,19 @@ WebGLRenderbuffer::Delete() { mContext->MakeContextCurrent(); mContext->gl->fDeleteRenderbuffers(1, &mPrimaryRB); if (mSecondaryRB) mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB); LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers); +#ifdef ANDROID + mIsRB = false; +#endif } int64_t WebGLRenderbuffer::MemoryUsage() const { int64_t pixels = int64_t(Width()) * int64_t(Height()); GLenum primaryFormat = InternalFormatForGL();
--- a/dom/canvas/WebGLRenderbuffer.h +++ b/dom/canvas/WebGLRenderbuffer.h @@ -3,25 +3,23 @@ * 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 WEBGL_RENDERBUFFER_H_ #define WEBGL_RENDERBUFFER_H_ #include "mozilla/LinkedList.h" #include "nsWrapperCache.h" -#include "WebGLBindableName.h" #include "WebGLFramebufferAttachable.h" #include "WebGLObjectModel.h" namespace mozilla { class WebGLRenderbuffer final : public nsWrapperCache - , public WebGLBindable<RBTarget> , public WebGLRefCountedObject<WebGLRenderbuffer> , public LinkedListElement<WebGLRenderbuffer> , public WebGLRectangleObject , public WebGLContextBoundObject , public WebGLFramebufferAttachable { public: explicit WebGLRenderbuffer(WebGLContext* webgl); @@ -36,16 +34,18 @@ public: MOZ_ASSERT(x != WebGLImageDataStatus::NoImageData || mImageDataStatus == WebGLImageDataStatus::NoImageData); mImageDataStatus = x; } GLsizei Samples() const { return mSamples; } void SetSamples(GLsizei samples) { mSamples = samples; } + GLuint PrimaryGLName() const { return mPrimaryRB; } + GLenum InternalFormat() const { return mInternalFormat; } void SetInternalFormat(GLenum internalFormat) { mInternalFormat = internalFormat; } GLenum InternalFormatForGL() const { return mInternalFormatForGL; } void SetInternalFormatForGL(GLenum internalFormatForGL) { mInternalFormatForGL = internalFormatForGL; @@ -75,15 +75,24 @@ protected: } GLuint mPrimaryRB; GLuint mSecondaryRB; GLenum mInternalFormat; GLenum mInternalFormatForGL; WebGLImageDataStatus mImageDataStatus; GLsizei mSamples; +#ifdef ANDROID + // Bug 1140459: Some drivers (including our test slaves!) don't + // give reasonable answers for IsRenderbuffer, maybe others. + // This shows up on Android 2.3 emulator. + // + // So we track the `is a Renderbuffer` state ourselves. + bool mIsRB; +#endif + friend class WebGLContext; friend class WebGLFramebuffer; }; } // namespace mozilla #endif // WEBGL_RENDERBUFFER_H_
--- a/dom/canvas/WebGLSampler.cpp +++ b/dom/canvas/WebGLSampler.cpp @@ -7,18 +7,18 @@ #include "GLContext.h" #include "mozilla/dom/WebGL2RenderingContextBinding.h" #include "WebGLContext.h" namespace mozilla { WebGLSampler::WebGLSampler(WebGLContext* webgl, GLuint sampler) - : WebGLBindableName<GLenum>(sampler), - WebGLContextBoundObject(webgl) + : WebGLContextBoundObject(webgl) + , mGLName(sampler) { mContext->mSamplers.insertBack(this); } WebGLSampler::~WebGLSampler() { DeleteOnce(); }
--- a/dom/canvas/WebGLSampler.h +++ b/dom/canvas/WebGLSampler.h @@ -3,33 +3,33 @@ * 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 WEBGL_SAMPLER_H_ #define WEBGL_SAMPLER_H_ #include "mozilla/LinkedList.h" #include "nsWrapperCache.h" -#include "WebGLBindableName.h" #include "WebGLObjectModel.h" namespace mozilla { class WebGLSampler final : public nsWrapperCache - , public WebGLBindableName<GLenum> , public WebGLRefCountedObject<WebGLSampler> , public LinkedListElement<WebGLSampler> , public WebGLContextBoundObject { friend class WebGLContext2; public: explicit WebGLSampler(WebGLContext* webgl, GLuint sampler); + const GLuint mGLName; + void Delete(); WebGLContext* GetParentObject() const; virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; private: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSampler)
--- a/dom/canvas/WebGLShader.cpp +++ b/dom/canvas/WebGLShader.cpp @@ -87,16 +87,21 @@ TranslateWithoutValidation(const nsACStr glesslVersion = 100; } std::string reversionedSource = source; reversionedSource.erase(versionStrStart, versionStrLen); switch (glesslVersion) { case 100: + if (!versionStrLen) { + /* According to ARB_ES2_compatibility extension glsl + * should accept #version 100 for ES 2 shaders. */ + reversionedSource.insert(versionStrStart, "#version 100\n"); + } break; case 300: reversionedSource.insert(versionStrStart, "#version 330\n"); break; default: MOZ_CRASH("Bad `glesslVersion`."); }
--- a/dom/canvas/WebGLTexture.cpp +++ b/dom/canvas/WebGLTexture.cpp @@ -19,18 +19,19 @@ namespace mozilla { JSObject* WebGLTexture::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) { return dom::WebGLTextureBinding::Wrap(cx, this, aGivenProto); } WebGLTexture::WebGLTexture(WebGLContext* webgl, GLuint tex) - : WebGLBindableName<TexTarget>(tex) - , WebGLContextBoundObject(webgl) + : WebGLContextBoundObject(webgl) + , mGLName(tex) + , mTarget(LOCAL_GL_NONE) , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR) , mMagFilter(LOCAL_GL_LINEAR) , mWrapS(LOCAL_GL_REPEAT) , mWrapT(LOCAL_GL_REPEAT) , mFacesCount(0) , mMaxLevelWithCustomImages(0) , mHaveGeneratedMipmap(false) , mImmutable(false) @@ -137,29 +138,27 @@ void WebGLTexture::Bind(TexTarget texTarget) { // This function should only be called by bindTexture(). It assumes that the // GL context is already current. bool firstTimeThisTextureIsBound = !HasEverBeenBound(); if (firstTimeThisTextureIsBound) { - BindTo(texTarget); + mTarget = texTarget.get(); } else if (texTarget != Target()) { mContext->ErrorInvalidOperation("bindTexture: This texture has already" " been bound to a different target."); // Very important to return here before modifying texture state! This // was the place when I lost a whole day figuring very strange "invalid // write" crashes. return; } - GLuint name = GLName(); - - mContext->gl->fBindTexture(texTarget.get(), name); + mContext->gl->fBindTexture(texTarget.get(), mGLName); if (firstTimeThisTextureIsBound) { mFacesCount = (texTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? 6 : 1; EnsureMaxLevelWithCustomImagesAtLeast(0); SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); // Thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R // is not present in GLES 2, but is present in GL and it seems as if for @@ -224,17 +223,17 @@ WebGLTexture::SetCustomMipmap() EnsureMaxLevelWithCustomImagesAtLeast(maxLevel); for (size_t level = EffectiveBaseMipmapLevel() + 1; level <= EffectiveMaxMipmapLevel(); ++level) { imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1); imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1); imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1); - for(size_t face = 0; face < mFacesCount; ++face) { + for (size_t face = 0; face < mFacesCount; ++face) { ImageInfoAtFace(face, level) = imageInfo; } } } mHaveGeneratedMipmap = false; } bool @@ -271,18 +270,18 @@ WebGLTexture::IsCubeComplete() const bool WebGLTexture::IsMipmapCubeComplete() const { // In particular, this checks that this is a cube map: if (!IsCubeComplete()) return false; for (int i = 0; i < 6; i++) { - const TexImageTarget face = TexImageTargetForTargetAndFace(LOCAL_GL_TEXTURE_CUBE_MAP, - i); + const TexImageTarget face = + TexImageTargetForTargetAndFace(LOCAL_GL_TEXTURE_CUBE_MAP, i); if (!DoesMipmapHaveAllLevelsConsistentlyDefined(face)) return false; } return true; } bool WebGLTexture::IsMipmapRangeValid() const @@ -621,28 +620,28 @@ WebGLTexture::EnsureNoUninitializedImage const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level); if (!imageInfo.HasUninitializedImageData()) return; mContext->MakeContextCurrent(); // Try to clear with glClear. if (imageTarget == LOCAL_GL_TEXTURE_2D) { - bool cleared = ClearWithTempFB(mContext, GLName(), imageTarget, level, + bool cleared = ClearWithTempFB(mContext, mGLName, imageTarget, level, imageInfo.mEffectiveInternalFormat, imageInfo.mHeight, imageInfo.mWidth); if (cleared) { SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData); return; } } // That didn't work. Try uploading zeros then. - gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget.get()); + gl::ScopedBindTexture autoBindTex(mContext->gl, mGLName, mTarget); size_t bitspertexel = GetBitsPerTexel(imageInfo.mEffectiveInternalFormat); MOZ_ASSERT((bitspertexel % 8) == 0); // That would only happen for // compressed images, which cannot use // deferred initialization. size_t bytespertexel = bitspertexel / 8; CheckedUint32 checked_byteLength = WebGLContext::GetImageSize(
--- a/dom/canvas/WebGLTexture.h +++ b/dom/canvas/WebGLTexture.h @@ -7,17 +7,16 @@ #define WEBGL_TEXTURE_H_ #include <algorithm> #include "mozilla/Assertions.h" #include "mozilla/CheckedInt.h" #include "mozilla/LinkedList.h" #include "nsAlgorithm.h" #include "nsWrapperCache.h" -#include "WebGLBindableName.h" #include "WebGLFramebufferAttachable.h" #include "WebGLObjectModel.h" #include "WebGLStrongTypes.h" namespace mozilla { // Zero is not an integer power of two. inline bool @@ -26,27 +25,29 @@ IsPOTAssumingNonnegative(GLsizei x) MOZ_ASSERT(x >= 0); return x && (x & (x-1)) == 0; } // NOTE: When this class is switched to new DOM bindings, update the (then-slow) // WrapObject calls in GetParameter and GetFramebufferAttachmentParameter. class WebGLTexture final : public nsWrapperCache - , public WebGLBindableName<TexTarget> , public WebGLRefCountedObject<WebGLTexture> , public LinkedListElement<WebGLTexture> , public WebGLContextBoundObject , public WebGLFramebufferAttachable { public: explicit WebGLTexture(WebGLContext* webgl, GLuint tex); void Delete(); + bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; } + GLenum Target() const { return mTarget; } + WebGLContext* GetParentObject() const { return Context(); } virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture) @@ -58,16 +59,22 @@ protected: friend class WebGLContext; friend class WebGLFramebuffer; // We store information about the various images that are part of this // texture. (cubemap faces, mipmap levels) public: + const GLuint mGLName; + +protected: + GLenum mTarget; + +public: class ImageInfo : public WebGLRectangleObject { public: ImageInfo() : mEffectiveInternalFormat(LOCAL_GL_NONE) , mDepth(0) , mImageDataStatus(WebGLImageDataStatus::NoImageData)
--- a/dom/canvas/WebGLTimerQuery.cpp +++ b/dom/canvas/WebGLTimerQuery.cpp @@ -15,35 +15,48 @@ namespace mozilla { JSObject* WebGLTimerQuery::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) { return dom::WebGLTimerQueryEXTBinding::Wrap(cx, this, aGivenProto); } WebGLTimerQuery::WebGLTimerQuery(WebGLContext* webgl, GLuint aName) - : WebGLBindableName<QueryBinding>(aName) - , WebGLContextBoundObject(webgl) + : WebGLContextBoundObject(webgl) + , mGLName(aName) + , mTarget(LOCAL_GL_NONE) { } +WebGLTimerQuery::~WebGLTimerQuery() +{ + DeleteOnce(); +} + WebGLTimerQuery* WebGLTimerQuery::Create(WebGLContext* webgl) { GLuint name = 0; webgl->MakeContextCurrent(); webgl->gl->fGenQueries(1, &name); return new WebGLTimerQuery(webgl, name); } void WebGLTimerQuery::Delete() { mContext->MakeContextCurrent(); mContext->gl->fDeleteQueries(1, &mGLName); } +WebGLContext* +WebGLTimerQuery::GetParentObject() const +{ + return Context(); +} + + NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTimerQuery) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTimerQuery, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTimerQuery, Release) } // namespace mozilla
--- a/dom/canvas/WebGLTimerQuery.h +++ b/dom/canvas/WebGLTimerQuery.h @@ -9,41 +9,41 @@ #include "nsWrapperCache.h" #include "WebGLObjectModel.h" namespace mozilla { class WebGLTimerQuery final : public nsWrapperCache - , public WebGLBindableName<QueryBinding> , public WebGLRefCountedObject<WebGLTimerQuery> , public WebGLContextBoundObject { public: static WebGLTimerQuery* Create(WebGLContext* webgl); - // WebGLRefCountedObject void Delete(); - // nsWrapperCache - WebGLContext* GetParentObject() const { - return Context(); - } + bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; } + GLenum Target() const { return mTarget; } + + WebGLContext* GetParentObject() const; // NS virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; + const GLenum mGLName; + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTimerQuery) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTimerQuery) private: explicit WebGLTimerQuery(WebGLContext* webgl, GLuint aName); - ~WebGLTimerQuery() { - DeleteOnce(); - } + ~WebGLTimerQuery(); + + GLenum mTarget; friend class WebGLExtensionDisjointTimerQuery; }; } // namespace mozilla #endif // WEBGL_TIMER_QUERY_H_
--- a/dom/canvas/WebGLTransformFeedback.cpp +++ b/dom/canvas/WebGLTransformFeedback.cpp @@ -8,18 +8,18 @@ #include "GLContext.h" #include "mozilla/dom/WebGL2RenderingContextBinding.h" #include "WebGL2Context.h" namespace mozilla { WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf) - : WebGLBindableName<GLenum>(tf) - , WebGLContextBoundObject(webgl) + : WebGLContextBoundObject(webgl) + , mGLName(tf) , mMode(LOCAL_GL_NONE) , mIsActive(false) , mIsPaused(false) { mContext->mTransformFeedbacks.insertBack(this); } WebGLTransformFeedback::~WebGLTransformFeedback()
--- a/dom/canvas/WebGLTransformFeedback.h +++ b/dom/canvas/WebGLTransformFeedback.h @@ -3,43 +3,44 @@ * 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 WEBGL_TRANSFORM_FEEDBACK_H_ #define WEBGL_TRANSFORM_FEEDBACK_H_ #include "mozilla/LinkedList.h" #include "nsWrapperCache.h" -#include "WebGLBindableName.h" #include "WebGLObjectModel.h" namespace mozilla { class WebGLTransformFeedback final : public nsWrapperCache - , public WebGLBindableName<GLenum> , public WebGLRefCountedObject<WebGLTransformFeedback> , public LinkedListElement<WebGLTransformFeedback> , public WebGLContextBoundObject { friend class WebGLContext; friend class WebGL2Context; public: explicit WebGLTransformFeedback(WebGLContext* webgl, GLuint tf); void Delete(); WebGLContext* GetParentObject() const; virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; + const GLuint mGLName; + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTransformFeedback) private: ~WebGLTransformFeedback(); + GLenum mMode; bool mIsActive; bool mIsPaused; }; } // namespace mozilla #endif // WEBGL_TRANSFORM_FEEDBACK_H_
--- a/dom/canvas/WebGLVertexArray.cpp +++ b/dom/canvas/WebGLVertexArray.cpp @@ -16,18 +16,17 @@ namespace mozilla { JSObject* WebGLVertexArray::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) { return dom::WebGLVertexArrayObjectOESBinding::Wrap(cx, this, aGivenProto); } WebGLVertexArray::WebGLVertexArray(WebGLContext* webgl) - : WebGLBindable<VAOBinding>() - , WebGLContextBoundObject(webgl) + : WebGLContextBoundObject(webgl) , mGLName(0) { mContext->mVertexArrays.insertBack(this); } WebGLVertexArray* WebGLVertexArray::Create(WebGLContext* webgl) { @@ -45,16 +44,22 @@ WebGLVertexArray::Delete() { DeleteImpl(); LinkedListElement<WebGLVertexArray>::removeFrom(mContext->mVertexArrays); mElementArrayBuffer = nullptr; mAttribs.Clear(); } +bool +WebGLVertexArray::IsVertexArray() +{ + return IsVertexArrayImpl(); +} + void WebGLVertexArray::EnsureAttrib(GLuint index) { MOZ_ASSERT(index < GLuint(mContext->mGLMaxVertexAttribs)); if (index >= mAttribs.Length()) { mAttribs.SetLength(index + 1); }
--- a/dom/canvas/WebGLVertexArray.h +++ b/dom/canvas/WebGLVertexArray.h @@ -3,57 +3,51 @@ * 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 WEBGL_VERTEX_ARRAY_H_ #define WEBGL_VERTEX_ARRAY_H_ #include "mozilla/LinkedList.h" #include "nsWrapperCache.h" -#include "WebGLBindableName.h" #include "WebGLBuffer.h" #include "WebGLObjectModel.h" #include "WebGLStrongTypes.h" #include "WebGLVertexAttribData.h" namespace mozilla { class WebGLVertexArrayFake; class WebGLVertexArray : public nsWrapperCache - , public WebGLBindable<VAOBinding> , public WebGLRefCountedObject<WebGLVertexArray> , public LinkedListElement<WebGLVertexArray> , public WebGLContextBoundObject { public: static WebGLVertexArray* Create(WebGLContext* webgl); void BindVertexArray() { // Bind to dummy value to signal that this vertex array has ever been // bound. - BindTo(LOCAL_GL_VERTEX_ARRAY_BINDING); BindVertexArrayImpl(); }; - virtual void GenVertexArray() = 0; - virtual void BindVertexArrayImpl() = 0; - virtual void DeleteImpl() = 0; - void EnsureAttrib(GLuint index); bool HasAttrib(GLuint index) const { return index < mAttribs.Length(); } bool IsAttribArrayEnabled(GLuint index) const { return HasAttrib(index) && mAttribs[index].enabled; } // Implement parent classes: void Delete(); + bool IsVertexArray(); WebGLContext* GetParentObject() const { return Context(); } virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArray) @@ -63,16 +57,21 @@ public: protected: explicit WebGLVertexArray(WebGLContext* webgl); virtual ~WebGLVertexArray() { MOZ_ASSERT(IsDeleted()); } + virtual void GenVertexArray() = 0; + virtual void BindVertexArrayImpl() = 0; + virtual void DeleteImpl() = 0; + virtual bool IsVertexArrayImpl() = 0; + GLuint mGLName; nsTArray<WebGLVertexAttribData> mAttribs; WebGLRefPtr<WebGLBuffer> mElementArrayBuffer; friend class WebGLContext; friend class WebGLVertexArrayFake; friend class WebGL2Context; };
--- a/dom/canvas/WebGLVertexArrayFake.cpp +++ b/dom/canvas/WebGLVertexArrayFake.cpp @@ -5,16 +5,21 @@ #include "WebGLVertexArrayFake.h" #include "GLContext.h" #include "WebGLContext.h" namespace mozilla { +WebGLVertexArrayFake::WebGLVertexArrayFake(WebGLContext* webgl) + : WebGLVertexArray(webgl) + , mIsVAO(false) +{ } + void WebGLVertexArrayFake::BindVertexArrayImpl() { // Go through and re-bind all buffers and setup all // vertex attribute pointers gl::GLContext* gl = mContext->gl; WebGLRefPtr<WebGLVertexArray> prevVertexArray = mContext->mBoundVertexArray; @@ -47,11 +52,24 @@ WebGLVertexArrayFake::BindVertexArrayImp for (size_t i = mAttribs.Length(); i < len; ++i) { const WebGLVertexAttribData& vd = prevVertexArray->mAttribs[i]; if (vd.enabled) gl->fDisableVertexAttribArray(i); } mContext->BindBuffer(LOCAL_GL_ARRAY_BUFFER, prevBuffer); + mIsVAO = true; +} + +void +WebGLVertexArrayFake::DeleteImpl() +{ + mIsVAO = false; +} + +bool +WebGLVertexArrayFake::IsVertexArrayImpl() +{ + return mIsVAO; } } // namespace mozilla
--- a/dom/canvas/WebGLVertexArrayFake.h +++ b/dom/canvas/WebGLVertexArrayFake.h @@ -8,28 +8,29 @@ #include "WebGLVertexArray.h" namespace mozilla { class WebGLVertexArrayFake final : public WebGLVertexArray { -public: + friend class WebGLVertexArray; + +protected: virtual void BindVertexArrayImpl() override; - virtual void DeleteImpl() override {}; + virtual void DeleteImpl() override; virtual void GenVertexArray() override {}; + virtual bool IsVertexArrayImpl() override; private: - explicit WebGLVertexArrayFake(WebGLContext* webgl) - : WebGLVertexArray(webgl) - { } + explicit WebGLVertexArrayFake(WebGLContext* webgl); ~WebGLVertexArrayFake() { DeleteOnce(); } - friend class WebGLVertexArray; + bool mIsVAO; }; } // namespace mozilla #endif // WEBGL_VERTEX_ARRAY_FAKE_H_
--- a/dom/canvas/WebGLVertexArrayGL.cpp +++ b/dom/canvas/WebGLVertexArrayGL.cpp @@ -5,32 +5,68 @@ #include "WebGLVertexArrayGL.h" #include "GLContext.h" #include "WebGLContext.h" namespace mozilla { +WebGLVertexArrayGL::WebGLVertexArrayGL(WebGLContext* webgl) + : WebGLVertexArray(webgl) +#if defined(XP_LINUX) + , mIsVAO(false) +#endif +{ } + +WebGLVertexArrayGL::~WebGLVertexArrayGL() +{ + DeleteOnce(); +} + void WebGLVertexArrayGL::DeleteImpl() { mElementArrayBuffer = nullptr; mContext->MakeContextCurrent(); mContext->gl->fDeleteVertexArrays(1, &mGLName); + +#if defined(XP_LINUX) + mIsVAO = false; +#endif } void WebGLVertexArrayGL::BindVertexArrayImpl() { mContext->mBoundVertexArray = this; + mContext->gl->fBindVertexArray(mGLName); - mContext->gl->fBindVertexArray(mGLName); +#if defined(XP_LINUX) + mIsVAO = true; +#endif } void WebGLVertexArrayGL::GenVertexArray() { mContext->gl->fGenVertexArrays(1, &mGLName); } +bool +WebGLVertexArrayGL::IsVertexArrayImpl() +{ +#if defined(XP_LINUX) + gl::GLContext* gl = mContext->gl; + if (gl->WorkAroundDriverBugs() && + gl->Vendor() == gl::GLVendor::VMware && + gl->Renderer() == gl::GLRenderer::GalliumLlvmpipe) + { + return mIsVAO; + } +#endif + + mContext->MakeContextCurrent(); + return mContext->gl->fIsVertexArray(mGLName) != 0; +} + } // namespace mozilla
--- a/dom/canvas/WebGLVertexArrayGL.h +++ b/dom/canvas/WebGLVertexArrayGL.h @@ -5,31 +5,35 @@ #ifndef WEBGL_VERTEX_ARRAY_GL_H_ #define WEBGL_VERTEX_ARRAY_GL_H_ #include "WebGLVertexArray.h" namespace mozilla { -class WebGLVertexArrayGL final +class WebGLVertexArrayGL : public WebGLVertexArray { + friend class WebGLVertexArray; + public: virtual void DeleteImpl() override; virtual void BindVertexArrayImpl() override; virtual void GenVertexArray() override; + virtual bool IsVertexArrayImpl() override; -private: - explicit WebGLVertexArrayGL(WebGLContext* webgl) - : WebGLVertexArray(webgl) - { } +protected: + explicit WebGLVertexArrayGL(WebGLContext* webgl); + ~WebGLVertexArrayGL(); - ~WebGLVertexArrayGL() { - DeleteOnce(); - } - - friend class WebGLVertexArray; +#if defined(XP_LINUX) + // Bug 1140459: Some drivers (including our test slaves!) don't + // give reasonable answers for IsRenderbuffer, maybe others. + // + // So we track the `is a VAO` state ourselves. + bool mIsVAO; +#endif }; } // namespace mozilla #endif // WEBGL_VERTEX_ARRAY_GL_H_
copy from dom/canvas/WebGLVertexArrayGL.h copy to dom/canvas/WebGLVertexArrayObject.cpp --- a/dom/canvas/WebGLVertexArrayGL.h +++ b/dom/canvas/WebGLVertexArrayObject.cpp @@ -1,35 +1,35 @@ -/* -*- 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: 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/. */ -#ifndef WEBGL_VERTEX_ARRAY_GL_H_ -#define WEBGL_VERTEX_ARRAY_GL_H_ +#include "WebGLVertexArrayObject.h" -#include "WebGLVertexArray.h" +#include "mozilla/dom/WebGL2RenderingContextBinding.h" namespace mozilla { +namespace dom { -class WebGLVertexArrayGL final - : public WebGLVertexArray +WebGLVertexArray* +WebGLVertexArrayObject::Create(WebGLContext* webgl) { -public: - virtual void DeleteImpl() override; - virtual void BindVertexArrayImpl() override; - virtual void GenVertexArray() override; + // WebGL 2: This is core in GL ES 3. If support is missing something + // is very wrong. + bool vaoSupport = webgl->GL()->IsSupported(gl::GLFeature::vertex_array_object); + MOZ_RELEASE_ASSERT(vaoSupport, "Vertex Array Objects aren't supported."); + if (vaoSupport) + return new WebGLVertexArrayObject(webgl); -private: - explicit WebGLVertexArrayGL(WebGLContext* webgl) - : WebGLVertexArray(webgl) - { } + return nullptr; +} - ~WebGLVertexArrayGL() { - DeleteOnce(); - } +JSObject* +WebGLVertexArrayObject::WrapObject(JSContext* cx, + JS::Handle<JSObject*> givenProto) +{ + return dom::WebGLVertexArrayObjectBinding::Wrap(cx, this, givenProto); +} - friend class WebGLVertexArray; -}; - +} // namespace dom } // namespace mozilla - -#endif // WEBGL_VERTEX_ARRAY_GL_H_
copy from dom/canvas/WebGLVertexArrayGL.h copy to dom/canvas/WebGLVertexArrayObject.h --- a/dom/canvas/WebGLVertexArrayGL.h +++ b/dom/canvas/WebGLVertexArrayObject.h @@ -1,35 +1,42 @@ -/* -*- 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: 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/. */ +#ifndef mozilla_dom_WebGLVertexArrayObject_h +#define mozilla_dom_WebGLVertexArrayObject_h -#ifndef WEBGL_VERTEX_ARRAY_GL_H_ -#define WEBGL_VERTEX_ARRAY_GL_H_ - -#include "WebGLVertexArray.h" +#include "WebGLVertexArrayGL.h" namespace mozilla { +namespace dom { -class WebGLVertexArrayGL final - : public WebGLVertexArray +/** + * This class implements the DOM bindings for WebGL 2 VAO. + * + * This exists to so the object returned from gl.createVertexArray() + * is an instance of WebGLVertexArrayObject (to match the WebGL 2 + * spec.) + */ +class WebGLVertexArrayObject final + : public WebGLVertexArrayGL { public: - virtual void DeleteImpl() override; - virtual void BindVertexArrayImpl() override; - virtual void GenVertexArray() override; + static WebGLVertexArray* Create(WebGLContext* webgl); + + virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override; private: - explicit WebGLVertexArrayGL(WebGLContext* webgl) - : WebGLVertexArray(webgl) - { } + explicit WebGLVertexArrayObject(WebGLContext* webgl) + : WebGLVertexArrayGL(webgl) + { } - ~WebGLVertexArrayGL() { - DeleteOnce(); - } - - friend class WebGLVertexArray; + ~WebGLVertexArrayObject() { + DeleteOnce(); + } }; +} // namespace dom } // namespace mozilla -#endif // WEBGL_VERTEX_ARRAY_GL_H_ +#endif // !mozilla_dom_WebGLVertexArrayObject_h
--- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -26,16 +26,17 @@ EXPORTS.mozilla.ipc += [ EXPORTS.mozilla.dom += [ 'CanvasGradient.h', 'CanvasPath.h', 'CanvasPattern.h', 'CanvasRenderingContext2D.h', 'CanvasUtils.h', 'ImageData.h', 'TextMetrics.h', + 'WebGLVertexArrayObject.h', ] # http://support.microsoft.com/kb/143208 DEFINES['NOMINMAX'] = True # Canvas 2D and common sources UNIFIED_SOURCES += [ 'CanvasImageCache.cpp', @@ -123,16 +124,17 @@ UNIFIED_SOURCES += [ 'WebGLTexture.cpp', 'WebGLTimerQuery.cpp', 'WebGLTransformFeedback.cpp', 'WebGLUniformLocation.cpp', 'WebGLValidateStrings.cpp', 'WebGLVertexArray.cpp', 'WebGLVertexArrayFake.cpp', 'WebGLVertexArrayGL.cpp', + 'WebGLVertexArrayObject.cpp', ] LOCAL_INCLUDES += [ '/js/xpconnect/wrappers', ] FAIL_ON_WARNINGS = True include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -543,24 +543,26 @@ FetchDriver::ContinueHttpFetchAfterNetwo workers::AssertIsOnMainThread(); MOZ_ASSERT(mResponse); MOZ_ASSERT(!mResponse->IsError()); return SucceedWithResponse(); } already_AddRefed<InternalResponse> -FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse) +FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse, nsIURI* aFinalURI) { MOZ_ASSERT(aResponse); - if (!aResponse->FinalURL()) { - nsAutoCString reqURL; + nsAutoCString reqURL; + if (aFinalURI) { + aFinalURI->GetSpec(reqURL); + } else { mRequest->GetURL(reqURL); - aResponse->SetUrl(reqURL); } + aResponse->SetUrl(reqURL); // FIXME(nsm): Handle mixed content check, step 7 of fetch. nsRefPtr<InternalResponse> filteredResponse; switch (mRequest->GetResponseTainting()) { case InternalRequest::RESPONSETAINT_BASIC: filteredResponse = aResponse->BasicResponse(); break; @@ -579,17 +581,17 @@ FetchDriver::BeginAndGetFilteredResponse mObserver->OnResponseAvailable(filteredResponse); mResponseAvailableCalled = true; return filteredResponse.forget(); } void FetchDriver::BeginResponse(InternalResponse* aResponse) { - nsRefPtr<InternalResponse> r = BeginAndGetFilteredResponse(aResponse); + nsRefPtr<InternalResponse> r = BeginAndGetFilteredResponse(aResponse, nullptr); // Release the ref. } nsresult FetchDriver::SucceedWithResponse() { workers::AssertIsOnMainThread(); if (mObserver) { @@ -711,19 +713,27 @@ FetchDriver::OnStartRequest(nsIRequest* // Cancel request. return rv; } response->SetBody(pipeInputStream); nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); response->InitChannelInfo(channel); + nsCOMPtr<nsIURI> channelURI; + rv = channel->GetURI(getter_AddRefs(channelURI)); + if (NS_WARN_IF(NS_FAILED(rv))) { + FailWithNetworkError(); + // Cancel request. + return rv; + } + // Resolves fetch() promise which may trigger code running in a worker. Make // sure the Response is fully initialized before calling this. - mResponse = BeginAndGetFilteredResponse(response); + mResponse = BeginAndGetFilteredResponse(response, channelURI); nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { FailWithNetworkError(); // Cancel request. return rv; }
--- a/dom/fetch/FetchDriver.h +++ b/dom/fetch/FetchDriver.h @@ -83,18 +83,19 @@ private: ~FetchDriver(); nsresult Fetch(bool aCORSFlag); nsresult ContinueFetch(bool aCORSFlag); nsresult BasicFetch(); nsresult HttpFetch(bool aCORSFlag = false, bool aCORSPreflightFlag = false, bool aAuthenticationFlag = false); nsresult ContinueHttpFetchAfterNetworkFetch(); // Returns the filtered response sent to the observer. + // Callers who don't have access to a channel can pass null for aFinalURI. already_AddRefed<InternalResponse> - BeginAndGetFilteredResponse(InternalResponse* aResponse); + BeginAndGetFilteredResponse(InternalResponse* aResponse, nsIURI* aFinalURI); // Utility since not all cases need to do any post processing of the filtered // response. void BeginResponse(InternalResponse* aResponse); nsresult FailWithNetworkError(); nsresult SucceedWithResponse(); nsresult DoesNotRequirePreflight(nsIChannel* aChannel); };
--- a/dom/fetch/InternalResponse.cpp +++ b/dom/fetch/InternalResponse.cpp @@ -9,17 +9,16 @@ #include "mozilla/dom/InternalHeaders.h" #include "nsStreamUtils.h" namespace mozilla { namespace dom { InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText) : mType(ResponseType::Default) - , mFinalURL(false) , mStatus(aStatus) , mStatusText(aStatusText) , mHeaders(new InternalHeaders(HeadersGuardEnum::Response)) { } already_AddRefed<InternalResponse> InternalResponse::Clone()
--- a/dom/fetch/InternalResponse.h +++ b/dom/fetch/InternalResponse.h @@ -43,17 +43,16 @@ public: already_AddRefed<InternalResponse> OpaqueResponse() { MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueResponse a already wrapped response"); nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString()); response->mType = ResponseType::Opaque; response->mTerminationReason = mTerminationReason; response->mURL = mURL; - response->mFinalURL = mFinalURL; response->mChannelInfo = mChannelInfo; response->mWrappedResponse = this; return response.forget(); } already_AddRefed<InternalResponse> BasicResponse(); @@ -85,28 +84,16 @@ public: } void SetUrl(const nsACString& aURL) { mURL.Assign(aURL); } - bool - FinalURL() const - { - return mFinalURL; - } - - void - SetFinalURL(bool aFinalURL) - { - mFinalURL = aFinalURL; - } - uint16_t GetStatus() const { return mStatus; } const nsCString& GetStatusText() const @@ -192,25 +179,23 @@ private: // InternalResponse, except headers, body and wrapped response (if any) which // are left uninitialized. Used for cloning and filtering. already_AddRefed<InternalResponse> CreateIncompleteCopy() { nsRefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText); copy->mType = mType; copy->mTerminationReason = mTerminationReason; copy->mURL = mURL; - copy->mFinalURL = mFinalURL; copy->mChannelInfo = mChannelInfo; return copy.forget(); } ResponseType mType; nsCString mTerminationReason; nsCString mURL; - bool mFinalURL; const uint16_t mStatus; const nsCString mStatusText; nsRefPtr<InternalHeaders> mHeaders; nsCOMPtr<nsIInputStream> mBody; ChannelInfo mChannelInfo; // For filtered responses. // Cache, and SW interception should always serialize/access the underlying
--- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -853,17 +853,18 @@ ReadCompressedIndexDataValuesFromBlob( return NS_ERROR_FILE_CORRUPTED; } nsCString keyBuffer(reinterpret_cast<const char*>(blobDataIter), uint32_t(keyBufferLength)); blobDataIter += keyBufferLength; if (NS_WARN_IF(!aIndexValues.InsertElementSorted( - IndexDataValue(indexId, unique, Key(keyBuffer))))) { + IndexDataValue(indexId, unique, Key(keyBuffer)), + fallible))) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_OUT_OF_MEMORY; } } MOZ_ASSERT(blobDataIter == blobDataEnd); return NS_OK; @@ -2729,17 +2730,18 @@ InsertIndexDataValuesFunction::OnFunctio // Update the array with the new addition. if (NS_WARN_IF(!indexValues.SetCapacity(indexValues.Length() + 1, fallible))) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_OUT_OF_MEMORY; } MOZ_ALWAYS_TRUE( - indexValues.InsertElementSorted(IndexDataValue(indexId, !!unique, value))); + indexValues.InsertElementSorted(IndexDataValue(indexId, !!unique, value), + fallible)); // Compress the array. UniqueFreePtr<uint8_t> indexValuesBlob; uint32_t indexValuesBlobLength; rv = MakeCompressedIndexDataValues(indexValues, indexValuesBlob, &indexValuesBlobLength); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -17851,17 +17853,18 @@ DatabaseOperationBase::IndexDataValuesFr const IndexUpdateInfo& updateInfo = aUpdateInfos[idxIndex]; const int64_t& indexId = updateInfo.indexId(); const Key& key = updateInfo.value(); bool unique; MOZ_ALWAYS_TRUE(aUniqueIndexTable.Get(indexId, &unique)); MOZ_ALWAYS_TRUE( - aIndexValues.InsertElementSorted(IndexDataValue(indexId, unique, key))); + aIndexValues.InsertElementSorted(IndexDataValue(indexId, unique, key), + fallible)); } return NS_OK; } // static nsresult DatabaseOperationBase::InsertIndexTableRows( @@ -22286,17 +22289,18 @@ UpdateIndexDataValuesFunction::OnFunctio // First construct the full list to update the index_data_values row. for (uint32_t index = 0; index < updateInfoCount; index++) { const IndexUpdateInfo& info = updateInfos[index]; MOZ_ALWAYS_TRUE( indexValues.InsertElementSorted(IndexDataValue(metadata.id(), metadata.unique(), - info.value()))); + info.value()), + fallible)); } UniqueFreePtr<uint8_t> indexValuesBlob; uint32_t indexValuesBlobLength; rv = MakeCompressedIndexDataValues(indexValues, indexValuesBlob, &indexValuesBlobLength); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -22322,17 +22326,18 @@ UpdateIndexDataValuesFunction::OnFunctio MOZ_ASSERT(indexValues.Capacity() >= updateInfoCount); for (uint32_t index = 0; index < updateInfoCount; index++) { const IndexUpdateInfo& info = updateInfos[index]; MOZ_ALWAYS_TRUE( indexValues.InsertElementSorted(IndexDataValue(metadata.id(), metadata.unique(), - info.value()))); + info.value()), + fallible)); } } rv = InsertIndexTableRows(mConnection, objectStoreId, key, indexValues); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
--- a/dom/media/AbstractThread.cpp +++ b/dom/media/AbstractThread.cpp @@ -128,9 +128,21 @@ AbstractThread::InitStatics() ClearOnShutdown(&sMainThread); if (!sCurrentThreadTLS.init()) { MOZ_CRASH(); } sCurrentThreadTLS.set(sMainThread); } +void +AbstractThread::DispatchStateChange(already_AddRefed<nsIRunnable> aRunnable) +{ + GetCurrent()->TailDispatcher().AddStateChangeTask(this, Move(aRunnable)); +} + +/* static */ void +AbstractThread::DispatchDirectTask(already_AddRefed<nsIRunnable> aRunnable) +{ + GetCurrent()->TailDispatcher().AddDirectTask(Move(aRunnable)); +} + } // namespace mozilla
--- a/dom/media/AbstractThread.h +++ b/dom/media/AbstractThread.h @@ -74,16 +74,20 @@ public: virtual nsIThread* AsXPCOMThread() { MOZ_CRASH("Not an XPCOM thread!"); } // Convenience method for getting an AbstractThread for the main thread. static AbstractThread* MainThread(); // Must be called exactly once during startup. static void InitStatics(); + void DispatchStateChange(already_AddRefed<nsIRunnable> aRunnable); + + static void DispatchDirectTask(already_AddRefed<nsIRunnable> aRunnable); + protected: virtual ~AbstractThread() {} static ThreadLocal<AbstractThread*> sCurrentThreadTLS; // True if we want to require that every task dispatched from tasks running in // this queue go through our queue's tail dispatcher. const bool mSupportsTailDispatch; };
--- a/dom/media/AudioSink.cpp +++ b/dom/media/AudioSink.cpp @@ -160,28 +160,20 @@ void AudioSink::SetPreservesPitch(bool aPreservesPitch) { AssertCurrentThreadInMonitor(); mPreservesPitch = aPreservesPitch; mSetPreservesPitch = true; } void -AudioSink::StartPlayback() +AudioSink::SetPlaying(bool aPlaying) { AssertCurrentThreadInMonitor(); - mPlaying = true; - GetReentrantMonitor().NotifyAll(); -} - -void -AudioSink::StopPlayback() -{ - AssertCurrentThreadInMonitor(); - mPlaying = false; + mPlaying = aPlaying; GetReentrantMonitor().NotifyAll(); } void AudioSink::AudioLoop() { AssertOnAudioThread(); SINK_LOG("AudioLoop started");
--- a/dom/media/AudioSink.h +++ b/dom/media/AudioSink.h @@ -37,18 +37,17 @@ public: // Shut down the AudioSink's resources. The decoder monitor must not be // held during this call, as it may block processing thread event queues. void Shutdown(); void SetVolume(double aVolume); void SetPlaybackRate(double aPlaybackRate); void SetPreservesPitch(bool aPreservesPitch); - void StartPlayback(); - void StopPlayback(); + void SetPlaying(bool aPlaying); private: ~AudioSink() {} // The main loop for the audio thread. Sent to the thread as // an nsRunnableMethod. This continually does blocking writes to // to audio stream to play audio data. void AudioLoop();
--- a/dom/media/DecodedStream.cpp +++ b/dom/media/DecodedStream.cpp @@ -64,33 +64,45 @@ public: private: Mutex mMutex; // Members below are protected by mMutex. nsRefPtr<MediaStream> mStream; int64_t mLastOutputTime; // microseconds bool mStreamFinishedOnMainThread; }; +static void +UpdateStreamBlocking(MediaStream* aStream, bool aBlocking) +{ + int32_t delta = aBlocking ? 1 : -1; + if (NS_IsMainThread()) { + aStream->ChangeExplicitBlockerCount(delta); + } else { + nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArg<int32_t>( + aStream, &MediaStream::ChangeExplicitBlockerCount, delta); + AbstractThread::MainThread()->Dispatch(r.forget()); + } +} + DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream) : mAudioFramesWritten(0) , mNextVideoTime(-1) , mNextAudioTime(-1) , mStreamInitialized(false) , mHaveSentFinish(false) , mHaveSentFinishAudio(false) , mHaveSentFinishVideo(false) , mStream(aStream) - , mHaveBlockedForPlayState(false) - , mHaveBlockedForStateMachineNotPlaying(false) + , mPlaying(false) , mEOSVideoCompensation(false) { mListener = new DecodedStreamGraphListener(mStream); mStream->AddListener(mListener); - // Block the stream until the initialization is done. - mStream->ChangeExplicitBlockerCount(1); + // Block the stream as mPlaying is initially false. + UpdateStreamBlocking(mStream, true); } DecodedStreamData::~DecodedStreamData() { mListener->Forget(); mStream->Destroy(); } @@ -101,16 +113,25 @@ DecodedStreamData::IsFinished() const } int64_t DecodedStreamData::GetPosition() const { return mListener->GetLastOutputTime(); } +void +DecodedStreamData::SetPlaying(bool aPlaying) +{ + if (mPlaying != aPlaying) { + mPlaying = aPlaying; + UpdateStreamBlocking(mStream, !mPlaying); + } +} + class OutputStreamListener : public MediaStreamListener { typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent; public: OutputStreamListener(DecodedStream* aDecodedStream, MediaStream* aStream) : mDecodedStream(aDecodedStream), mStream(aStream) {} void NotifyEvent(MediaStreamGraph* aGraph, MediaStreamGraphEvent event) override { @@ -285,9 +306,17 @@ DecodedStream::Connect(ProcessedMediaStr os->Init(this, aStream); Connect(os); if (aFinishWhenEnded) { // Ensure that aStream finishes the moment mDecodedStream does. aStream->SetAutofinish(true); } } +void +DecodedStream::SetPlaying(bool aPlaying) +{ + GetReentrantMonitor().AssertCurrentThreadIn(); + MOZ_ASSERT(mData); + mData->SetPlaying(aPlaying); +} + } // namespace mozilla
--- a/dom/media/DecodedStream.h +++ b/dom/media/DecodedStream.h @@ -36,16 +36,17 @@ class Image; * not connected to streams created by captureStreamUntilEnded. */ class DecodedStreamData { public: explicit DecodedStreamData(SourceMediaStream* aStream); ~DecodedStreamData(); bool IsFinished() const; int64_t GetPosition() const; + void SetPlaying(bool aPlaying); /* The following group of fields are protected by the decoder's monitor * and can be read or written on any thread. */ // Count of audio frames written to the stream int64_t mAudioFramesWritten; // mNextVideoTime is the end timestamp for the last packet sent to the stream. // Therefore video packets starting at or after this time need to be copied @@ -61,22 +62,17 @@ public: bool mStreamInitialized; bool mHaveSentFinish; bool mHaveSentFinishAudio; bool mHaveSentFinishVideo; // The decoder is responsible for calling Destroy() on this stream. const nsRefPtr<SourceMediaStream> mStream; nsRefPtr<DecodedStreamGraphListener> mListener; - // True when we've explicitly blocked this stream because we're - // not in PLAY_STATE_PLAYING. Used on the main thread only. - bool mHaveBlockedForPlayState; - // We also have an explicit blocker on the stream when - // mDecoderStateMachine is non-null and MediaDecoderStateMachine is false. - bool mHaveBlockedForStateMachineNotPlaying; + bool mPlaying; // True if we need to send a compensation video frame to ensure the // StreamTime going forward. bool mEOSVideoCompensation; }; class OutputStreamData { public: ~OutputStreamData(); @@ -91,16 +87,17 @@ class DecodedStream { public: explicit DecodedStream(ReentrantMonitor& aMonitor); DecodedStreamData* GetData() const; void DestroyData(); void RecreateData(MediaStreamGraph* aGraph); nsTArray<OutputStreamData>& OutputStreams(); ReentrantMonitor& GetReentrantMonitor() const; void Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded); + void SetPlaying(bool aPlaying); private: void Connect(OutputStreamData* aStream); UniquePtr<DecodedStreamData> mData; // Data about MediaStreams that are being fed by the decoder. nsTArray<OutputStreamData> mOutputStreams; ReentrantMonitor& mMonitor;
--- a/dom/media/MediaData.cpp +++ b/dom/media/MediaData.cpp @@ -634,17 +634,18 @@ MediaRawDataWriter::SetSize(size_t aSize bool MediaRawDataWriter::Prepend(const uint8_t* aData, size_t aSize) { if (!EnsureSize(aSize + mTarget->mSize)) { return false; } // We ensure sufficient capacity above so this shouldn't fail. - MOZ_ALWAYS_TRUE(mBuffer->InsertElementsAt(mTarget->mPadding, aData, aSize)); + MOZ_ALWAYS_TRUE(mBuffer->InsertElementsAt(mTarget->mPadding, aData, aSize, + fallible)); mTarget->mSize += aSize; mSize = mTarget->mSize; return true; } bool MediaRawDataWriter::Replace(const uint8_t* aData, size_t aSize) {
--- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -267,16 +267,24 @@ MediaDecoderStateMachine::MediaDecoderSt #ifdef XP_WIN // Ensure high precision timers are enabled on Windows, otherwise the state // machine isn't woken up at reliable intervals to set the next frame, // and we drop frames while painting. Note that multiple calls to this // function per-process is OK, provided each call is matched by a corresponding // timeEndPeriod() call. timeBeginPeriod(1); #endif + + AudioQueue().AddPopListener( + NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnAudioPopped), + mTaskQueue); + + VideoQueue().AddPopListener( + NS_NewRunnableMethod(this, &MediaDecoderStateMachine::OnVideoPopped), + mTaskQueue); } MediaDecoderStateMachine::~MediaDecoderStateMachine() { MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread."); MOZ_COUNT_DTOR(MediaDecoderStateMachine); NS_ASSERTION(!mPendingWakeDecoder.get(), "WakeDecoder should have been revoked already"); @@ -309,18 +317,16 @@ MediaDecoderStateMachine::Initialization mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged); mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged); mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged); mWatchManager.Watch(mEstimatedDuration, &MediaDecoderStateMachine::RecomputeDuration); mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration); mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration); mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged); mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::LogicallySeekingChanged); - mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::UpdateStreamBlockingForPlayState); - mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::UpdateStreamBlockingForPlayState); } bool MediaDecoderStateMachine::HasFutureAudio() { MOZ_ASSERT(OnTaskQueue()); AssertCurrentThreadInMonitor(); NS_ASSERTION(HasAudio(), "Should only call HasFutureAudio() when we have audio"); // We've got audio ready to play if: @@ -425,29 +431,16 @@ static bool ZeroDurationAtLastChunk(Vide // Get the last video frame's start time in VideoSegment aInput. // If the start time is equal to the duration of aInput, means the last video // frame's duration is zero. StreamTime lastVideoStratTime; aInput.GetLastFrame(&lastVideoStratTime); return lastVideoStratTime == aInput.GetDuration(); } -static void -UpdateStreamBlocking(MediaStream* aStream, bool aBlocking) -{ - int32_t delta = aBlocking ? 1 : -1; - if (NS_IsMainThread()) { - aStream->ChangeExplicitBlockerCount(delta); - } else { - nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArg<int32_t>( - aStream, &MediaStream::ChangeExplicitBlockerCount, delta); - AbstractThread::MainThread()->Dispatch(r.forget()); - } -} - void MediaDecoderStateMachine::SendStreamData() { MOZ_ASSERT(OnTaskQueue()); AssertCurrentThreadInMonitor(); MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()"); MOZ_ASSERT(mStreamStartTime != -1); DecodedStreamData* stream = GetDecodedStream(); @@ -476,22 +469,16 @@ void MediaDecoderStateMachine::SendStrea SourceMediaStream::ADDTRACK_QUEUED); stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId, TaskQueue(), GetWakeDecoderRunnable()); stream->mNextVideoTime = mStreamStartTime; } mediaStream->FinishAddTracks(); stream->mStreamInitialized = true; - - // Make sure stream blocking is updated before sending stream data so we - // don't 'leak' data when the stream is supposed to be blocked. - UpdateStreamBlockingForPlayState(); - UpdateStreamBlockingForStateMachinePlaying(); - UpdateStreamBlocking(mediaStream, false); } if (mInfo.HasAudio()) { MOZ_ASSERT(stream->mNextAudioTime != -1, "Should've been initialized"); TrackID audioTrackId = mInfo.mAudio.mTrackId; nsAutoTArray<nsRefPtr<AudioData>,10> audio; // It's OK to hold references to the AudioData because AudioData // is ref-counted. @@ -508,16 +495,22 @@ void MediaDecoderStateMachine::SendStrea } if (AudioQueue().IsFinished() && !stream->mHaveSentFinishAudio) { mediaStream->EndTrack(audioTrackId); stream->mHaveSentFinishAudio = true; } endPosition = std::max(endPosition, mediaStream->TicksToTimeRoundDown(mInfo.mAudio.mRate, stream->mAudioFramesWritten)); + + CheckedInt64 playedUsecs = mStreamStartTime + + FramesToUsecs(stream->mAudioFramesWritten, mInfo.mAudio.mRate); + if (playedUsecs.isValid()) { + OnAudioEndTimeUpdate(playedUsecs.value()); + } } if (mInfo.HasVideo()) { MOZ_ASSERT(stream->mNextVideoTime != -1, "Should've been initialized"); TrackID videoTrackId = mInfo.mVideo.mTrackId; nsAutoTArray<nsRefPtr<VideoData>,10> video; // It's OK to hold references to the VideoData because VideoData // is ref-counted. @@ -596,18 +589,17 @@ void MediaDecoderStateMachine::SendStrea const auto clockTime = GetClock(); while (true) { const AudioData* a = AudioQueue().PeekFront(); // If we discard audio samples fed to the stream immediately, we will // keep decoding audio samples till the end and consume a lot of memory. // Therefore we only discard those behind the stream clock to throttle // the decoding speed. if (a && a->mTime <= clockTime) { - OnAudioEndTimeUpdate(std::max(mAudioEndTime, a->GetEndTime())); - nsRefPtr<AudioData> releaseMe = PopAudio(); + nsRefPtr<AudioData> releaseMe = AudioQueue().PopFront(); continue; } break; } // To be consistent with AudioSink, |mAudioCompleted| is not set // until all samples are drained. if (finished && AudioQueue().GetSize() == 0) { @@ -921,32 +913,35 @@ MediaDecoderStateMachine::PushFront(Vide { MOZ_ASSERT(OnTaskQueue()); MOZ_ASSERT(aSample); VideoQueue().PushFront(aSample); UpdateNextFrameStatus(); } -already_AddRefed<AudioData> -MediaDecoderStateMachine::PopAudio() +void +MediaDecoderStateMachine::OnAudioPopped() { MOZ_ASSERT(OnTaskQueue()); - nsRefPtr<AudioData> sample = AudioQueue().PopFront(); + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); UpdateNextFrameStatus(); - return sample.forget(); + DispatchAudioDecodeTaskIfNeeded(); } -already_AddRefed<VideoData> -MediaDecoderStateMachine::PopVideo() +void +MediaDecoderStateMachine::OnVideoPopped() { MOZ_ASSERT(OnTaskQueue()); - nsRefPtr<VideoData> sample = VideoQueue().PopFront(); + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); UpdateNextFrameStatus(); - return sample.forget(); + DispatchVideoDecodeTaskIfNeeded(); + // Notify the decode thread that the video queue's buffers may have + // free'd up space for more frames. + mDecoder->GetReentrantMonitor().NotifyAll(); } void MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType, MediaDecoderReader::NotDecodedReason aReason) { MOZ_ASSERT(OnTaskQueue()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); @@ -1290,17 +1285,16 @@ void MediaDecoderStateMachine::StopPlayb if (IsPlaying()) { mPlayDuration = GetClock() - mStartTime; SetPlayStartTime(TimeStamp()); } // Notify the audio sink, so that it notices that we've stopped playing, // so it can pause audio playback. mDecoder->GetReentrantMonitor().NotifyAll(); NS_ASSERTION(!IsPlaying(), "Should report not playing at end of StopPlayback()"); - UpdateStreamBlockingForStateMachinePlaying(); DispatchDecodeTasksIfNeeded(); } void MediaDecoderStateMachine::MaybeStartPlayback() { MOZ_ASSERT(OnTaskQueue()); AssertCurrentThreadInMonitor(); @@ -1328,17 +1322,16 @@ void MediaDecoderStateMachine::MaybeStar mDecoder->NotifyPlaybackStarted(); SetPlayStartTime(TimeStamp::Now()); MOZ_ASSERT(IsPlaying()); nsresult rv = StartAudioThread(); NS_ENSURE_SUCCESS_VOID(rv); mDecoder->GetReentrantMonitor().NotifyAll(); - UpdateStreamBlockingForStateMachinePlaying(); DispatchDecodeTasksIfNeeded(); } void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime) { MOZ_ASSERT(OnTaskQueue()); SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld) (mStartTime=%lld)", aTime, mStartTime); AssertCurrentThreadInMonitor(); @@ -2301,27 +2294,16 @@ MediaDecoderStateMachine::CallDecodeFirs nsresult MediaDecoderStateMachine::DecodeFirstFrame() { MOZ_ASSERT(OnTaskQueue()); AssertCurrentThreadInMonitor(); MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME); DECODER_LOG("DecodeFirstFrame started"); - if (HasAudio()) { - RefPtr<nsIRunnable> decodeTask( - NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded)); - AudioQueue().AddPopListener(decodeTask, TaskQueue()); - } - if (HasVideo()) { - RefPtr<nsIRunnable> decodeTask( - NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded)); - VideoQueue().AddPopListener(decodeTask, TaskQueue()); - } - if (IsRealTime()) { SetStartTime(0); nsresult res = FinishDecodeFirstFrame(); NS_ENSURE_SUCCESS(res, res); } else if (mSentFirstFrameLoadedEvent) { // We're resuming from dormant state, so we don't need to request // the first samples in order to determine the media start time, // we have the start time from last time we loaded. @@ -2943,20 +2925,17 @@ void MediaDecoderStateMachine::AdvanceFr while (IsRealTime() || clock_time >= frame->mTime) { mVideoFrameEndTime = frame->GetEndTime(); if (currentFrame) { mDecoder->NotifyDecodedFrames(0, 0, 1); VERBOSE_LOG("discarding video frame mTime=%lld clock_time=%lld (%d so far)", currentFrame->mTime, clock_time, ++droppedFrames); } currentFrame = frame; - nsRefPtr<VideoData> releaseMe = PopVideo(); - // Notify the decode thread that the video queue's buffers may have - // free'd up space for more frames. - mDecoder->GetReentrantMonitor().NotifyAll(); + nsRefPtr<VideoData> releaseMe = VideoQueue().PopFront(); OnPlaybackOffsetUpdate(frame->mOffset); if (VideoQueue().GetSize() == 0) break; frame = VideoQueue().PeekFront(); } // Current frame has already been presented, wait until it's time to // present the next frame. if (frame && !currentFrame) { @@ -3291,23 +3270,21 @@ void MediaDecoderStateMachine::StartBuff stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)", stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)"); } void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp) { AssertCurrentThreadInMonitor(); mPlayStartTime = aTimeStamp; - if (!mAudioSink) { - return; - } - if (!mPlayStartTime.IsNull()) { - mAudioSink->StartPlayback(); - } else { - mAudioSink->StopPlayback(); + + if (mAudioSink) { + mAudioSink->SetPlaying(!mPlayStartTime.IsNull()); + } else if (mAudioCaptured) { + mDecodedStream.SetPlaying(!mPlayStartTime.IsNull()); } } void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() { MOZ_ASSERT(OnTaskQueue()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); DispatchAudioDecodeTaskIfNeeded(); @@ -3500,16 +3477,19 @@ void MediaDecoderStateMachine::DispatchA ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor()); if (!self->mAudioCaptured) { // Stop the audio sink if it's running. self->StopAudioThread(); // GetMediaTime() could return -1 because we haven't decoded // the 1st frame. But this is OK since we will update mStreamStartTime // again in SetStartTime(). self->mStreamStartTime = self->GetMediaTime(); + // Reset mAudioEndTime which will be updated as we send audio data to + // stream. Otherwise it will remain -1 if we don't have audio. + self->mAudioEndTime = -1; self->mAudioCaptured = true; self->ScheduleStateMachine(); } }); TaskQueue()->Dispatch(r.forget()); } void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream, @@ -3521,54 +3501,22 @@ void MediaDecoderStateMachine::AddOutput ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); if (!GetDecodedStream()) { RecreateDecodedStream(aStream->Graph()); } mDecodedStream.Connect(aStream, aFinishWhenEnded); DispatchAudioCaptured(); } -void MediaDecoderStateMachine::UpdateStreamBlockingForPlayState() -{ - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - - auto stream = GetDecodedStream(); - if (!stream) { - return; - } - - bool blocking = mPlayState != MediaDecoder::PLAY_STATE_PLAYING || - mLogicallySeeking; - if (blocking != stream->mHaveBlockedForPlayState) { - stream->mHaveBlockedForPlayState = blocking; - UpdateStreamBlocking(stream->mStream, blocking); - } -} - -void MediaDecoderStateMachine::UpdateStreamBlockingForStateMachinePlaying() -{ - AssertCurrentThreadInMonitor(); - - auto stream = GetDecodedStream(); - if (!stream) { - return; - } - - bool blocking = !IsPlaying(); - if (blocking != stream->mHaveBlockedForStateMachineNotPlaying) { - stream->mHaveBlockedForStateMachineNotPlaying = blocking; - UpdateStreamBlocking(stream->mStream, blocking); - } -} - void MediaDecoderStateMachine::RecreateDecodedStream(MediaStreamGraph* aGraph) { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecodedStream.RecreateData(aGraph); + mDecodedStream.SetPlaying(IsPlaying()); } } // namespace mozilla // avoid redefined macro in unified build #undef LOG #undef DECODER_LOG #undef VERBOSE_LOG
--- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -157,23 +157,16 @@ public: private: // Initialization that needs to happen on the task queue. This is the first // task that gets run on the task queue, and is dispatched from the MDSM // constructor immediately after the task queue is created. void InitializationTask(); void DispatchAudioCaptured(); - // Update blocking state of mDecodedStream when mPlayState or - // mLogicallySeeking change. Decoder monitor must be held. - void UpdateStreamBlockingForPlayState(); - - // Call this IsPlaying() changes. Decoder monitor must be held. - void UpdateStreamBlockingForStateMachinePlaying(); - // Recreates mDecodedStream. Call this to create mDecodedStream at first, // and when seeking, to ensure a new stream is set up with fresh buffers. // Decoder monitor must be held. void RecreateDecodedStream(MediaStreamGraph* aGraph); void Shutdown(); public: @@ -422,22 +415,18 @@ protected: // Inserts MediaData* samples into their respective MediaQueues. // aSample must not be null. void Push(AudioData* aSample); void Push(VideoData* aSample); void PushFront(AudioData* aSample); void PushFront(VideoData* aSample); - // Pops MediaData* samples from their respective MediaQueues. - // Note that the audio queue is also drained on the audio thread, - // which we can't easily react to - This should be fixed when we - // remove the audio thread in bug 750596. - already_AddRefed<AudioData> PopAudio(); - already_AddRefed<VideoData> PopVideo(); + void OnAudioPopped(); + void OnVideoPopped(); void VolumeChanged(); void LogicalPlaybackRateChanged(); void PreservesPitchChanged(); class WakeDecoderRunnable : public nsRunnable { public: explicit WakeDecoderRunnable(MediaDecoderStateMachine* aSM)
--- a/dom/media/StateMirroring.h +++ b/dom/media/StateMirroring.h @@ -192,17 +192,17 @@ private: } mValue = aNewValue; // We wait until things have stablized before sending state updates so that // we can avoid sending multiple updates, and possibly avoid sending any // updates at all if the value ends up where it started. if (!alreadyNotifying) { nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &Impl::DoNotify); - AbstractThread::GetCurrent()->TailDispatcher().AddDirectTask(r.forget()); + AbstractThread::DispatchDirectTask(r.forget()); } } Impl& operator=(const T& aNewValue) { Set(aNewValue); return *this; } Impl& operator=(const Impl& aOther) { Set(aOther); return *this; } Impl(const Impl& aOther) = delete; protected: @@ -217,17 +217,17 @@ private: mInitialValue.reset(); if (same) { MIRROR_LOG("%s [%p] unchanged - not sending update", mName, this); return; } for (size_t i = 0; i < mMirrors.Length(); ++i) { - OwnerThread()->TailDispatcher().AddStateChangeTask(mMirrors[i]->OwnerThread(), MakeNotifier(mMirrors[i])); + mMirrors[i]->OwnerThread()->DispatchStateChange(MakeNotifier(mMirrors[i])); } } already_AddRefed<nsIRunnable> MakeNotifier(AbstractMirror<T>* aMirror) { nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArg<T>(aMirror, &AbstractMirror<T>::UpdateValue, mValue); return r.forget();
--- a/dom/media/eme/GMPVideoDecoderTrialCreator.cpp +++ b/dom/media/eme/GMPVideoDecoderTrialCreator.cpp @@ -55,16 +55,20 @@ TrialCreatePrefName(const nsAString& aKe } return nullptr; } /* static */ GMPVideoDecoderTrialCreator::TrialCreateState GMPVideoDecoderTrialCreator::GetCreateTrialState(const nsAString& aKeySystem) { + if (Preferences::GetBool("media.gmp.always-trial-create", false)) { + return Pending; + } + const char* pref = TrialCreatePrefName(aKeySystem); if (!pref) { return Pending; } switch (Preferences::GetInt(pref, (int)Pending)) { case 0: return Pending; case 1: return Succeeded; case 2: return Failed;
--- a/dom/media/gmp/GMPLoader.cpp +++ b/dom/media/gmp/GMPLoader.cpp @@ -4,16 +4,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 "GMPLoader.h" #include <stdio.h> #include "mozilla/Attributes.h" #include "gmp-entrypoints.h" #include "prlink.h" +#include "prenv.h" #include <string> #if defined(XP_WIN) && defined(MOZ_SANDBOX) #include "mozilla/Scoped.h" #include "windows.h" #include <intrin.h> #include <assert.h> @@ -163,32 +164,35 @@ GMPLoaderImpl::Load(const char* aLibPath memset(aOriginSalt, 0, aOriginSaltLen); volumeId = 0; memset(&deviceId[0], '*', sizeof(string16::value_type) * deviceId.size()); deviceId = L""; if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &nodeId)) { return false; } - // We've successfully bound the origin salt to node id. - // rlz_lib::GetRawMachineId and/or the system functions it - // called could have left user identifiable data on the stack, - // so carefully zero the stack down to the guard page. - uint8_t* top; - uint8_t* bottom; - if (!GetStackAfterCurrentFrame(&top, &bottom)) { - return false; - } - assert(top >= bottom); - // Inline instructions equivalent to RtlSecureZeroMemory(). - // We can't just use RtlSecureZeroMemory here directly, as in debug - // builds, RtlSecureZeroMemory() can't be inlined, and the stack - // memory it uses would get wiped by itself running, causing crashes. - for (volatile uint8_t* p = (volatile uint8_t*)bottom; p < top; p++) { - *p = 0; + + if (!PR_GetEnv("MOZ_GMP_DISABLE_NODE_ID_CLEANUP")) { + // We've successfully bound the origin salt to node id. + // rlz_lib::GetRawMachineId and/or the system functions it + // called could have left user identifiable data on the stack, + // so carefully zero the stack down to the guard page. + uint8_t* top; + uint8_t* bottom; + if (!GetStackAfterCurrentFrame(&top, &bottom)) { + return false; + } + assert(top >= bottom); + // Inline instructions equivalent to RtlSecureZeroMemory(). + // We can't just use RtlSecureZeroMemory here directly, as in debug + // builds, RtlSecureZeroMemory() can't be inlined, and the stack + // memory it uses would get wiped by itself running, causing crashes. + for (volatile uint8_t* p = (volatile uint8_t*)bottom; p < top; p++) { + *p = 0; + } } } else #endif { nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen); } #if defined(XP_WIN) && defined(MOZ_SANDBOX)
--- a/dom/network/TCPSocketChild.cpp +++ b/dom/network/TCPSocketChild.cpp @@ -232,17 +232,18 @@ TCPSocketChild::SendSend(JS::Handle<JS:: uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength); FallibleTArray<uint8_t> fallibleArr; { JS::AutoCheckCannotGC nogc; uint8_t* data = JS_GetArrayBufferData(obj, nogc); if (!data) { return NS_ERROR_OUT_OF_MEMORY; } - if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) { + if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes, + fallible)) { return NS_ERROR_OUT_OF_MEMORY; } } InfallibleTArray<uint8_t> arr; arr.SwapElements(fallibleArr); SendData(arr, aTrackingNumber); } return NS_OK;
--- a/dom/network/TCPSocketParent.cpp +++ b/dom/network/TCPSocketParent.cpp @@ -306,17 +306,17 @@ TCPSocketParent::SendEvent(const nsAStri do { JS::AutoCheckCannotGC nogc; uint32_t nbytes = JS_GetArrayBufferByteLength(obj); uint8_t* buffer = JS_GetArrayBufferData(obj, nogc); if (!buffer) { errLine = __LINE__; break; } - if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) { + if (!fallibleArr.InsertElementsAt(0, buffer, nbytes, fallible)) { errLine = __LINE__; break; } } while (false); if (errLine) { FireInteralError(this, errLine); return NS_ERROR_OUT_OF_MEMORY;
--- a/dom/network/UDPSocketChild.cpp +++ b/dom/network/UDPSocketChild.cpp @@ -244,17 +244,17 @@ UDPSocketChild::SendWithAddress(const Ne nsresult UDPSocketChild::SendDataInternal(const UDPSocketAddr& aAddr, const uint8_t* aData, const uint32_t aByteLength) { NS_ENSURE_ARG(aData); FallibleTArray<uint8_t> fallibleArray; - if (!fallibleArray.InsertElementsAt(0, aData, aByteLength)) { + if (!fallibleArray.InsertElementsAt(0, aData, aByteLength, fallible)) { return NS_ERROR_OUT_OF_MEMORY; } InfallibleTArray<uint8_t> array; array.SwapElements(fallibleArray); SendOutgoingData(array, aAddr);
--- a/dom/network/UDPSocketParent.cpp +++ b/dom/network/UDPSocketParent.cpp @@ -446,17 +446,17 @@ UDPSocketParent::OnPacketReceived(nsIUDP if (!allowed) { UDPSOCKET_LOG(("%s: not allowed", __FUNCTION__)); } return NS_OK; } } FallibleTArray<uint8_t> fallibleArray; - if (!fallibleArray.InsertElementsAt(0, buffer, len)) { + if (!fallibleArray.InsertElementsAt(0, buffer, len, fallible)) { FireInternalError(__LINE__); return NS_ERROR_OUT_OF_MEMORY; } InfallibleTArray<uint8_t> infallibleArray; infallibleArray.SwapElements(fallibleArray); // compose callback mozilla::unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray);
--- a/dom/quota/QuotaManager.cpp +++ b/dom/quota/QuotaManager.cpp @@ -5093,17 +5093,19 @@ OriginParser::HandleToken(const nsDepend if (!aToken.IsEmpty()) { QM_WARNING("Expected the third empty token!"); mError = true; return; } - mState = eExpectingDriveLetterOrPathnameComponent; + mState = + mTokenizer.hasMoreTokens() ? eExpectingDriveLetterOrPathnameComponent + : eComplete; return; } case eExpectingHost: { if (aToken.IsEmpty()) { QM_WARNING("Expected a host (not an empty string)!"); @@ -5211,15 +5213,15 @@ OriginParser::HandleToken(const nsDepend default: MOZ_CRASH("Should never get here!"); } } void OriginParser::HandleTrailingSeparator() { - MOZ_ASSERT(mState = eComplete); + MOZ_ASSERT(mState == eComplete); MOZ_ASSERT(mSchemaType == eFile); mPathnameComponents.AppendElement(EmptyCString()); mState = eHandledTrailingSeparator; }
--- a/dom/svg/DOMSVGPathSegList.cpp +++ b/dom/svg/DOMSVGPathSegList.cpp @@ -380,17 +380,18 @@ DOMSVGPathSegList::InsertItemBefore(DOMS // Now that we know we're inserting, keep animVal list in sync as necessary. MaybeInsertNullInAnimValListAt(aIndex, internalIndex, argCount); float segAsRaw[1 + NS_SVG_PATH_SEG_MAX_ARGS]; domItem->ToSVGPathSegEncodedData(segAsRaw); MOZ_ALWAYS_TRUE(InternalList().mData.InsertElementsAt(internalIndex, segAsRaw, - 1 + argCount)); + 1 + argCount, + fallible)); MOZ_ALWAYS_TRUE(mItems.InsertElementAt(aIndex, ItemProxy(domItem.get(), internalIndex), fallible)); // This MUST come after the insertion into InternalList(), or else under the // insertion into InternalList() the values read from domItem would be bad // data from InternalList() itself!:
--- a/dom/tests/mochitest/fetch/mochitest.ini +++ b/dom/tests/mochitest/fetch/mochitest.ini @@ -22,22 +22,20 @@ support-files = skip-if = buildapp == 'b2g' # Bug 1137683 [test_headers_mainthread.html] [test_fetch_app_protocol.html] [test_fetch_basic.html] [test_fetch_basic_sw_reroute.html] skip-if = buildapp == 'b2g' # Bug 1137683 [test_fetch_basic_http.html] [test_fetch_basic_http_sw_reroute.html] -skip-if = true # Bug 1170937, need fully support for redirects -#skip-if = buildapp == 'b2g' # Bug 1137683 +skip-if = e10s || buildapp == 'b2g' # Bug 1173163 for e10s, bug 1137683 for b2g [test_fetch_cors.html] [test_fetch_cors_sw_reroute.html] -skip-if = true # Bug 1170937, need fully support for redirects -#skip-if = buildapp == 'b2g' # Bug 1137683 +skip-if = e10s || buildapp == 'b2g' # Bug 1173163 for e10s, bug 1137683 for b2g [test_formdataparsing.html] [test_formdataparsing_sw_reroute.html] skip-if = buildapp == 'b2g' # Bug 1137683 [test_request.html] [test_request_sw_reroute.html] skip-if = buildapp == 'b2g' # Bug 1137683 [test_response.html] [test_response_sw_reroute.html]
--- a/dom/webidl/WebGL2RenderingContext.webidl +++ b/dom/webidl/WebGL2RenderingContext.webidl @@ -21,21 +21,19 @@ interface WebGLSampler { [Pref="webgl.enable-prototype-webgl2"] interface WebGLSync { }; [Pref="webgl.enable-prototype-webgl2"] interface WebGLTransformFeedback { }; -/* [Pref="webgl.enable-prototype-webgl2"] interface WebGLVertexArrayObject { }; -*/ [Pref="webgl.enable-prototype-webgl2"] interface WebGL2RenderingContext : WebGLRenderingContext { const GLenum READ_BUFFER = 0x0C02; const GLenum UNPACK_ROW_LENGTH = 0x0CF2; const GLenum UNPACK_SKIP_ROWS = 0x0CF3; const GLenum UNPACK_SKIP_PIXELS = 0x0CF4; @@ -233,17 +231,16 @@ interface WebGL2RenderingContext : WebGL const GLenum RG32I = 0x823B; const GLenum RG32UI = 0x823C; const GLenum VERTEX_ARRAY_BINDING = 0x85B5; const GLenum R8_SNORM = 0x8F94; const GLenum RG8_SNORM = 0x8F95; const GLenum RGB8_SNORM = 0x8F96; const GLenum RGBA8_SNORM = 0x8F97; const GLenum SIGNED_NORMALIZED = 0x8F9C; - const GLenum PRIMITIVE_RESTART_FIXED_INDEX = 0x8D69; const GLenum COPY_READ_BUFFER = 0x8F36; const GLenum COPY_WRITE_BUFFER = 0x8F37; const GLenum COPY_READ_BUFFER_BINDING = 0x8F36; /* Same as COPY_READ_BUFFER */ const GLenum COPY_WRITE_BUFFER_BINDING = 0x8F37; /* Same as COPY_WRITE_BUFFER */ const GLenum UNIFORM_BUFFER = 0x8A11; const GLenum UNIFORM_BUFFER_BINDING = 0x8A28; const GLenum UNIFORM_BUFFER_START = 0x8A29; const GLenum UNIFORM_BUFFER_SIZE = 0x8A2A; @@ -286,20 +283,16 @@ interface WebGL2RenderingContext : WebGL const GLenum CONDITION_SATISFIED = 0x911C; const GLenum WAIT_FAILED = 0x911D; const GLenum SYNC_FLUSH_COMMANDS_BIT = 0x00000001; const GLenum VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE; const GLenum ANY_SAMPLES_PASSED = 0x8C2F; const GLenum ANY_SAMPLES_PASSED_CONSERVATIVE = 0x8D6A; const GLenum SAMPLER_BINDING = 0x8919; const GLenum RGB10_A2UI = 0x906F; - const GLenum TEXTURE_SWIZZLE_R = 0x8E42; - const GLenum TEXTURE_SWIZZLE_G = 0x8E43; - const GLenum TEXTURE_SWIZZLE_B = 0x8E44; - const GLenum TEXTURE_SWIZZLE_A = 0x8E45; const GLenum GREEN = 0x1904; const GLenum BLUE = 0x1905; const GLenum INT_2_10_10_10_REV = 0x8D9F; const GLenum TRANSFORM_FEEDBACK = 0x8E22; const GLenum TRANSFORM_FEEDBACK_PAUSED = 0x8E23; const GLenum TRANSFORM_FEEDBACK_ACTIVE = 0x8E24; const GLenum TRANSFORM_FEEDBACK_BINDING = 0x8E25; const GLenum COMPRESSED_R11_EAC = 0x9270; @@ -470,15 +463,13 @@ interface WebGL2RenderingContext : WebGL sequence<GLint>? getActiveUniforms(WebGLProgram? program, sequence<GLuint> uniformIndices, GLenum pname); GLuint getUniformBlockIndex(WebGLProgram? program, DOMString uniformBlockName); [Throws] (GLuint or Uint32Array or GLboolean)? getActiveUniformBlockParameter(WebGLProgram? program, GLuint uniformBlockIndex, GLenum pname); DOMString? getActiveUniformBlockName(WebGLProgram? program, GLuint uniformBlockIndex); void uniformBlockBinding(WebGLProgram? program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); /* Vertex Array Objects */ - /* WebGLVertexArrayObject? createVertexArray(); void deleteVertexArray(WebGLVertexArrayObject? vertexArray); [WebGLHandlesContextLoss] GLboolean isVertexArray(WebGLVertexArrayObject? vertexArray); void bindVertexArray(WebGLVertexArrayObject? array); - */ };
--- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -978,19 +978,21 @@ private: nsCOMPtr<nsILoadGroup> channelLoadGroup; rv = channel->GetLoadGroup(getter_AddRefs(channelLoadGroup)); NS_ENSURE_SUCCESS(rv, rv); MOZ_ASSERT(channelLoadGroup); // If the load principal is the system principal then the channel // principal must also be the system principal (we do not allow chrome - // code to create workers with non-chrome scripts). Otherwise this channel - // principal must be same origin with the load principal (we check again - // here in case redirects changed the location of the script). + // code to create workers with non-chrome scripts, and if we ever decide + // to change this we need to make sure we don't always set + // mPrincipalIsSystem to true in WorkerPrivate::GetLoadInfo()). Otherwise + // this channel principal must be same origin with the load principal (we + // check again here in case redirects changed the location of the script). if (nsContentUtils::IsSystemPrincipal(loadPrincipal)) { if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) { // See if this is a resource URI. Since JSMs usually come from // resource:// URIs we're currently considering all URIs with the // URI_IS_UI_RESOURCE flag as valid for creating privileged workers. bool isResource; rv = NS_URIChainHasFlags(finalURI, nsIProtocolHandler::URI_IS_UI_RESOURCE,
--- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -4880,22 +4880,25 @@ WorkerPrivate::GetLoadInfo(JSContext* aC bool isChrome = nsContentUtils::IsCallerChrome(); // First check to make sure the caller has permission to make a privileged // worker if they called the ChromeWorker/ChromeSharedWorker constructor. if (aIsChromeWorker && !isChrome) { return NS_ERROR_DOM_SECURITY_ERR; } - // Chrome callers (whether ChromeWorker of Worker) always get the system - // principal here as they're allowed to load anything. The script loader may - // change the principal later depending on the script uri. + // Chrome callers (whether creating a ChromeWorker or Worker) always get the + // system principal here as they're allowed to load anything. The script + // loader will refuse to run any script that does not also have the system + // principal. if (isChrome) { rv = ssm->GetSystemPrincipal(getter_AddRefs(loadInfo.mPrincipal)); NS_ENSURE_SUCCESS(rv, rv); + + loadInfo.mPrincipalIsSystem = true; } // See if we're being called from a window. nsCOMPtr<nsPIDOMWindow> globalWindow = aWindow; if (!globalWindow) { nsCOMPtr<nsIScriptGlobalObject> scriptGlobal = nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx)); if (scriptGlobal) {
--- a/gfx/2d/DrawTargetD2D.cpp +++ b/gfx/2d/DrawTargetD2D.cpp @@ -1959,17 +1959,17 @@ DrawTargetD2D::CreateRTForTexture(ID3D10 HRESULT hr; RefPtr<IDXGISurface> surface; RefPtr<ID2D1RenderTarget> rt; hr = aTexture->QueryInterface((IDXGISurface**)byRef(surface)); if (FAILED(hr)) { - gfxCriticalError() << "Failed to QI texture to surface. Code: " << hr; + gfxCriticalError() << "Failed to QI texture to surface. Code: " << hexa(hr); return nullptr; } D3D10_TEXTURE2D_DESC desc; aTexture->GetDesc(&desc); D2D1_ALPHA_MODE alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; @@ -1977,17 +1977,18 @@ DrawTargetD2D::CreateRTForTexture(ID3D10 alphaMode = D2D1_ALPHA_MODE_IGNORE; } D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(desc.Format, alphaMode)); hr = factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt)); if (FAILED(hr)) { - gfxCriticalError() << "Failed to create D2D render target for texture. Code:" << hr << " " << mSize << " Format: " << uint32_t(aFormat); + gfxCriticalError() << "Failed to create D2D render target for texture. Code: " + << hexa(hr) << " " << mSize << " Format: " << uint32_t(aFormat); return nullptr; } return rt.forget(); } void DrawTargetD2D::EnsureViews()
--- a/gfx/layers/d3d11/CompositorD3D11.cpp +++ b/gfx/layers/d3d11/CompositorD3D11.cpp @@ -408,17 +408,18 @@ CompositorD3D11::GetTextureFactoryIdenti { TextureFactoryIdentifier ident; ident.mMaxTextureSize = GetMaxTextureSize(); ident.mParentProcessId = XRE_GetProcessType(); ident.mParentBackend = LayersBackend::LAYERS_D3D11; if (mAttachments->mSyncTexture) { HRESULT hr = mAttachments->mSyncTexture->GetSharedHandle(&ident.mSyncHandle); if (FAILED(hr) || !ident.mSyncHandle) { - gfxCriticalError() << "Failed to get SharedHandle for sync texture. Result: " << hr; + gfxCriticalError() << "Failed to get SharedHandle for sync texture. Result: " + << hexa(hr); MOZ_CRASH(); } } return ident; } bool CompositorD3D11::CanUseCanvasLayerForSize(const gfx::IntSize& aSize) @@ -1337,26 +1338,26 @@ bool CompositorD3D11::UpdateConstantBuffers() { HRESULT hr; D3D11_MAPPED_SUBRESOURCE resource; resource.pData = nullptr; hr = mContext->Map(mAttachments->mVSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); if (Failed(hr) || !resource.pData) { - gfxCriticalError() << "Failed to map VSConstantBuffer. Result: " << hr; + gfxCriticalError() << "Failed to map VSConstantBuffer. Result: " << hexa(hr); return false; } *(VertexShaderConstants*)resource.pData = mVSConstants; mContext->Unmap(mAttachments->mVSConstantBuffer, 0); resource.pData = nullptr; hr = mContext->Map(mAttachments->mPSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource); if (Failed(hr) || !resource.pData) { - gfxCriticalError() << "Failed to map PSConstantBuffer. Result: " << hr; + gfxCriticalError() << "Failed to map PSConstantBuffer. Result: " << hexa(hr); return false; } *(PixelShaderConstants*)resource.pData = mPSConstants; mContext->Unmap(mAttachments->mPSConstantBuffer, 0); ID3D11Buffer *buffer = mAttachments->mVSConstantBuffer; mContext->VSSetConstantBuffers(0, 1, &buffer);
--- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -905,17 +905,20 @@ gfxFontconfigFont::GetGlyphRenderingOpti } // We don't want to force the use of the autohinter over the font's built in hints return mozilla::gfx::Factory::CreateCairoGlyphRenderingOptions(hinting, false); } #endif gfxFcPlatformFontList::gfxFcPlatformFontList() - : mLocalNames(64), mGenericMappings(32), mLastConfig(nullptr) + : mLocalNames(64) + , mGenericMappings(32) + , mFcSubstituteCache(64) + , mLastConfig(nullptr) { // if the rescan interval is set, start the timer int rescanInterval = FcConfigGetRescanInterval(nullptr); if (rescanInterval) { mLastConfig = FcConfigGetCurrent(); mCheckFontUpdatesTimer = do_CreateInstance("@mozilla.org/timer;1"); if (mCheckFontUpdatesTimer) { mCheckFontUpdatesTimer-> @@ -1031,29 +1034,30 @@ gfxFcPlatformFontList::InitFontList() { mLastConfig = FcConfigGetCurrent(); // reset font lists gfxPlatformFontList::InitFontList(); mLocalNames.Clear(); mGenericMappings.Clear(); + mFcSubstituteCache.Clear(); + sSentinelFirstFamily = nullptr; // iterate over available fonts FcFontSet* systemFonts = FcConfigGetFonts(nullptr, FcSetSystem); AddFontSetFamilies(systemFonts); #ifdef MOZ_BUNDLED_FONTS ActivateBundledFonts(); FcFontSet* appFonts = FcConfigGetFonts(nullptr, FcSetApplication); AddFontSetFamilies(appFonts); #endif mOtherFamilyNamesInitialized = true; - sSentinelFirstFamily = nullptr; return NS_OK; } // For displaying the fontlist in UI, use explicit call to FcFontList. Using // FcFontList results in the list containing the localized names as dictated // by system defaults. static void @@ -1235,27 +1239,34 @@ gfxFcPlatformFontList::FindFamily(const // Example: // // serif ==> DejaVu Serif, ... // Helvetica, serif ==> Helvetica, TeX Gyre Heros, Nimbus Sans L, DejaVu Serif // // In this case fontconfig is including Tex Gyre Heros and // Nimbus Sans L as alternatives for Helvetica. + // Because the FcConfigSubstitute call is quite expensive, we cache the + // actual font family found via this process. So check the cache first: + NS_ConvertUTF16toUTF8 familyToFind(familyName); + gfxFontFamily* cached = mFcSubstituteCache.GetWeak(familyToFind); + if (cached) { + return cached; + } + const FcChar8* kSentinelName = ToFcChar8Ptr("-moz-sentinel"); if (!sSentinelFirstFamily) { nsAutoRef<FcPattern> sentinelSubst(FcPatternCreate()); FcPatternAddString(sentinelSubst, FC_FAMILY, kSentinelName); FcConfigSubstitute(nullptr, sentinelSubst, FcMatchPattern); FcPatternGetString(sentinelSubst, FC_FAMILY, 0, &sSentinelFirstFamily); } // substitutions for font, -moz-sentinel pattern nsAutoRef<FcPattern> fontWithSentinel(FcPatternCreate()); - NS_ConvertUTF16toUTF8 familyToFind(familyName); FcPatternAddString(fontWithSentinel, FC_FAMILY, ToFcChar8Ptr(familyToFind.get())); FcPatternAddString(fontWithSentinel, FC_FAMILY, kSentinelName); FcConfigSubstitute(nullptr, fontWithSentinel, FcMatchPattern); // iterate through substitutions until hitting the sentinel FcChar8* substName = nullptr; for (int i = 0; FcPatternGetString(fontWithSentinel, FC_FAMILY, @@ -1264,16 +1275,19 @@ gfxFcPlatformFontList::FindFamily(const { NS_ConvertUTF8toUTF16 subst(ToCharPtr(substName)); if (sSentinelFirstFamily && FcStrCmp(substName, sSentinelFirstFamily) == 0) { break; } gfxFontFamily* foundFamily = gfxPlatformFontList::FindFamily(subst); if (foundFamily) { + // We've figured out what family the given name maps to, after any + // fontconfig subsitutions. Cache it to speed up future lookups. + mFcSubstituteCache.Put(familyToFind, foundFamily); return foundFamily; } } return nullptr; } bool
--- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -251,16 +251,19 @@ protected: // names to family nsBaseHashtable<nsStringHashKey, nsCountedRef<FcPattern>, FcPattern*> mLocalNames; // caching generic/lang ==> font family nsRefPtrHashtable<nsCStringHashKey, gfxFontFamily> mGenericMappings; + // caching family lookups as found by FindFamily after resolving substitutions + nsRefPtrHashtable<nsCStringHashKey, gfxFontFamily> mFcSubstituteCache; + nsCOMPtr<nsITimer> mCheckFontUpdatesTimer; nsCountedRef<FcConfig> mLastConfig; static FT_Library sCairoFTLibrary; static FcChar8* sSentinelFirstFamily; }; #endif /* GFXPLATFORMFONTLIST_H_ */
--- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1975,17 +1975,17 @@ gfxWindowsPlatform::InitD3D11Devices() // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS // to prevent bug 1092260. IE 11 also uses this flag. D3D11_CREATE_DEVICE_BGRA_SUPPORT, featureLevels.Elements(), featureLevels.Length(), D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr); if (FAILED(hr)) { // This should always succeed... in theory. - gfxCriticalError() << "Failed to initialize WARP D3D11 device!" << hr; + gfxCriticalError() << "Failed to initialize WARP D3D11 device! " << hexa(hr); return; } mIsWARP = true; reporterWARP.SetSuccessful(); } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!"; return;
--- a/ipc/bluetooth/BluetoothDaemonConnection.cpp +++ b/ipc/bluetooth/BluetoothDaemonConnection.cpp @@ -209,17 +209,17 @@ BluetoothDaemonPDUConsumer::~BluetoothDa // // BluetoothDaemonConnectionIO // class BluetoothDaemonConnectionIO final : public ConnectionOrientedSocketIO { public: - BluetoothDaemonConnectionIO(nsIThread* aConsumerThread, + BluetoothDaemonConnectionIO(MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, int aFd, ConnectionStatus aConnectionStatus, UnixSocketConnector* aConnector, BluetoothDaemonConnection* aConnection, BluetoothDaemonPDUConsumer* aConsumer); // Methods for |DataSocketIO| // @@ -242,24 +242,24 @@ public: private: BluetoothDaemonConnection* mConnection; BluetoothDaemonPDUConsumer* mConsumer; nsAutoPtr<BluetoothDaemonPDU> mPDU; bool mShuttingDownOnIOThread; }; BluetoothDaemonConnectionIO::BluetoothDaemonConnectionIO( - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, int aFd, ConnectionStatus aConnectionStatus, UnixSocketConnector* aConnector, BluetoothDaemonConnection* aConnection, BluetoothDaemonPDUConsumer* aConsumer) - : ConnectionOrientedSocketIO(aConsumerThread, + : ConnectionOrientedSocketIO(aConsumerLoop, aIOLoop, aFd, aConnectionStatus, aConnector) , mConnection(aConnection) , mConsumer(aConsumer) , mShuttingDownOnIOThread(false) { @@ -356,26 +356,26 @@ BluetoothDaemonConnection::BluetoothDaem BluetoothDaemonConnection::~BluetoothDaemonConnection() { } // |ConnectionOrientedSocket| nsresult BluetoothDaemonConnection::PrepareAccept(UnixSocketConnector* aConnector, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, ConnectionOrientedSocketIO*& aIO) { MOZ_ASSERT(!mIO); SetConnectionStatus(SOCKET_CONNECTING); mIO = new BluetoothDaemonConnectionIO( - aConsumerThread, aIOLoop, -1, UnixSocketWatcher::SOCKET_IS_CONNECTING, + aConsumerLoop, aIOLoop, -1, UnixSocketWatcher::SOCKET_IS_CONNECTING, aConnector, this, mPDUConsumer); aIO = mIO; return NS_OK; } // |DataSocket|
--- a/ipc/bluetooth/BluetoothDaemonConnection.h +++ b/ipc/bluetooth/BluetoothDaemonConnection.h @@ -121,17 +121,17 @@ public: BluetoothDaemonConnectionConsumer* aConsumer, int aIndex); virtual ~BluetoothDaemonConnection(); // Methods for |ConnectionOrientedSocket| // nsresult PrepareAccept(UnixSocketConnector* aConnector, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, ConnectionOrientedSocketIO*& aIO) override; // Methods for |DataSocket| // void SendSocketData(UnixSocketIOBuffer* aBuffer) override;
--- a/ipc/unixsocket/ConnectionOrientedSocket.cpp +++ b/ipc/unixsocket/ConnectionOrientedSocket.cpp @@ -10,34 +10,33 @@ namespace mozilla { namespace ipc { // // ConnectionOrientedSocketIO // ConnectionOrientedSocketIO::ConnectionOrientedSocketIO( - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, - int aFd, - ConnectionStatus aConnectionStatus, + int aFd, ConnectionStatus aConnectionStatus, UnixSocketConnector* aConnector) - : DataSocketIO(aConsumerThread) + : DataSocketIO(aConsumerLoop) , UnixSocketWatcher(aIOLoop, aFd, aConnectionStatus) , mConnector(aConnector) , mPeerAddressLength(0) { MOZ_ASSERT(mConnector); } ConnectionOrientedSocketIO::ConnectionOrientedSocketIO( - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, UnixSocketConnector* aConnector) - : DataSocketIO(aConsumerThread) + : DataSocketIO(aConsumerLoop) , UnixSocketWatcher(aIOLoop) , mConnector(aConnector) , mPeerAddressLength(0) { MOZ_ASSERT(mConnector); } ConnectionOrientedSocketIO::~ConnectionOrientedSocketIO() @@ -74,19 +73,18 @@ ConnectionOrientedSocketIO::Connect() mPeerAddressLength = sizeof(mPeerAddress); int fd; nsresult rv = mConnector->CreateStreamSocket(peerAddress, &mPeerAddressLength, fd); if (NS_FAILED(rv)) { // Tell the consumer thread we've errored - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_ERROR)); return NS_ERROR_FAILURE; } SetFd(fd); // calls OnConnected() on success, or OnError() otherwise rv = UnixSocketWatcher::Connect(peerAddress, mPeerAddressLength); @@ -142,19 +140,18 @@ ConnectionOrientedSocketIO::OnSocketCanS } void ConnectionOrientedSocketIO::OnConnected() { MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED); - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS)); AddWatchers(READ_WATCHER, true); if (HasPendingData()) { AddWatchers(WRITE_WATCHER, false); } } void @@ -171,19 +168,18 @@ ConnectionOrientedSocketIO::OnError(cons MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); UnixFdWatcher::OnError(aFunction, aErrno); // Clean up watchers, status, fd Close(); // Tell the consumer thread we've errored - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_ERROR)); } // // ConnectionOrientedSocket // ConnectionOrientedSocket::~ConnectionOrientedSocket() { }
--- a/ipc/unixsocket/ConnectionOrientedSocket.h +++ b/ipc/unixsocket/ConnectionOrientedSocket.h @@ -48,35 +48,35 @@ public: void OnListening() final; void OnConnected() final; void OnError(const char* aFunction, int aErrno) final; protected: /** * Constructs an instance of |ConnectionOrientedSocketIO| * - * @param aConsumerThread The socket's consumer thread. + * @param aConsumerLoop The socket's consumer thread. * @param aIOLoop The socket's I/O loop. * @param aFd The socket file descriptor. * @param aConnectionStatus The connection status for |aFd|. * @param aConnector Connector object for socket-type-specific methods. */ - ConnectionOrientedSocketIO(nsIThread* aConsumerThread, + ConnectionOrientedSocketIO(MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, int aFd, ConnectionStatus aConnectionStatus, UnixSocketConnector* aConnector); /** * Constructs an instance of |ConnectionOrientedSocketIO| * - * @param aConsumerThread The socket's consumer thread. + * @param aConsumerLoop The socket's consumer thread. * @param aIOLoop The socket's I/O loop. * @param aConnector Connector object for socket-type-specific methods. */ - ConnectionOrientedSocketIO(nsIThread* aConsumerThread, + ConnectionOrientedSocketIO(MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, UnixSocketConnector* aConnector); private: /** * Connector object used to create the connection we are currently using. */ nsAutoPtr<UnixSocketConnector> mConnector; @@ -96,23 +96,23 @@ class ConnectionOrientedSocket : public { public: /** * Prepares an instance of |ConnectionOrientedSocket| in DISCONNECTED * state for accepting a connection. Consumer-thread only. * * @param aConnector The new connector object, owned by the * connection-oriented socket. - * @param aConsumerThread The socket's consumer thread. + * @param aConsumerLoop The socket's consumer thread. * @param aIOLoop The socket's I/O thread. * @param[out] aIO, Returns an instance of |ConnectionOrientedSocketIO|. * @return NS_OK on success, or an XPCOM error code otherwise. */ virtual nsresult PrepareAccept(UnixSocketConnector* aConnector, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, ConnectionOrientedSocketIO*& aIO) = 0; protected: virtual ~ConnectionOrientedSocket(); }; }
--- a/ipc/unixsocket/DataSocket.cpp +++ b/ipc/unixsocket/DataSocket.cpp @@ -45,33 +45,33 @@ ssize_t DataSocketIO::ReceiveData(int aFd) { MOZ_ASSERT(aFd >= 0); UnixSocketIOBuffer* incoming; nsresult rv = QueryReceiveBuffer(&incoming); if (NS_FAILED(rv)) { /* an error occured */ - GetConsumerThread()->Dispatch(new SocketIORequestClosingRunnable(this), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask(FROM_HERE, + new SocketRequestClosingTask(this)); return -1; } ssize_t res = incoming->Receive(aFd); if (res < 0) { /* an I/O error occured */ DiscardBuffer(); - GetConsumerThread()->Dispatch(new SocketIORequestClosingRunnable(this), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask(FROM_HERE, + new SocketRequestClosingTask(this)); return -1; } else if (!res) { /* EOF or peer shut down sending */ DiscardBuffer(); - GetConsumerThread()->Dispatch(new SocketIORequestClosingRunnable(this), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask(FROM_HERE, + new SocketRequestClosingTask(this)); return 0; } #ifdef MOZ_TASK_TRACER /* Make unix socket creation events to be the source events of TaskTracer, * and originate the rest correlation tasks from here. */ AutoSourceEvent taskTracerEvent(SourceEventType::Unixsocket); @@ -88,34 +88,34 @@ DataSocketIO::SendPendingData(int aFd) MOZ_ASSERT(aFd >= 0); while (HasPendingData()) { UnixSocketIOBuffer* outgoing = mOutgoingQ.ElementAt(0); ssize_t res = outgoing->Send(aFd); if (res < 0) { /* an I/O error occured */ - GetConsumerThread()->Dispatch(new SocketIORequestClosingRunnable(this), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask(FROM_HERE, + new SocketRequestClosingTask(this)); return NS_ERROR_FAILURE; } else if (!res && outgoing->GetSize()) { /* I/O is currently blocked; try again later */ return NS_OK; } if (!outgoing->GetSize()) { mOutgoingQ.RemoveElementAt(0); delete outgoing; } } return NS_OK; } -DataSocketIO::DataSocketIO(nsIThread* aConsumerThread) - : SocketIOBase(aConsumerThread) +DataSocketIO::DataSocketIO(MessageLoop* aConsumerLoop) + : SocketIOBase(aConsumerLoop) { } // // DataSocket // DataSocket::~DataSocket() { }
--- a/ipc/unixsocket/DataSocket.h +++ b/ipc/unixsocket/DataSocket.h @@ -5,16 +5,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/. */ #ifndef mozilla_ipc_datasocket_h #define mozilla_ipc_datasocket_h #include "mozilla/ipc/SocketBase.h" +#include "nsTArray.h" namespace mozilla { namespace ipc { // // DataSocket // @@ -85,17 +86,17 @@ public: void EnqueueData(UnixSocketIOBuffer* aBuffer); bool HasPendingData() const; ssize_t ReceiveData(int aFd); nsresult SendPendingData(int aFd); protected: - DataSocketIO(nsIThread* aConsumerThread); + DataSocketIO(MessageLoop* aConsumerLoop); private: /** * Raw data queue. Must be pushed/popped from I/O thread only. */ nsTArray<UnixSocketIOBuffer*> mOutgoingQ; };
--- a/ipc/unixsocket/ListenSocket.cpp +++ b/ipc/unixsocket/ListenSocket.cpp @@ -22,17 +22,17 @@ namespace ipc { class ListenSocketIO final : public UnixSocketWatcher , public SocketIOBase { public: class ListenTask; - ListenSocketIO(nsIThread* aConsumerThread, + ListenSocketIO(MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, ListenSocket* aListenSocket, UnixSocketConnector* aConnector); ~ListenSocketIO(); UnixSocketConnector* GetConnector() const; // Task callback methods @@ -90,22 +90,22 @@ private: /** * Address structure of the socket currently in use */ struct sockaddr_storage mAddress; ConnectionOrientedSocketIO* mCOSocketIO; }; -ListenSocketIO::ListenSocketIO(nsIThread* aConsumerThread, +ListenSocketIO::ListenSocketIO(MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, ListenSocket* aListenSocket, UnixSocketConnector* aConnector) : UnixSocketWatcher(aIOLoop) - , SocketIOBase(aConsumerThread) + , SocketIOBase(aConsumerLoop) , mListenSocket(aListenSocket) , mConnector(aConnector) , mShuttingDownOnIOThread(false) , mAddressLength(0) , mCOSocketIO(nullptr) { MOZ_ASSERT(mListenSocket); MOZ_ASSERT(mConnector); @@ -163,19 +163,18 @@ void ListenSocketIO::OnListening() { MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING); AddWatchers(READ_WATCHER, true); /* We signal a successful 'connection' to a local address for listening. */ - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_SUCCESS), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS)); } void ListenSocketIO::OnError(const char* aFunction, int aErrno) { MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); UnixFdWatcher::OnError(aFunction, aErrno); @@ -186,19 +185,18 @@ void ListenSocketIO::FireSocketError() { MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); // Clean up watchers, statuses, fds Close(); // Tell the consumer thread we've errored - GetConsumerThread()->Dispatch( - new SocketIOEventRunnable(this, SocketIOEventRunnable::CONNECT_ERROR), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask( + FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_ERROR)); } void ListenSocketIO::OnSocketCanAcceptWithoutBlocking() { MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING); MOZ_ASSERT(mCOSocketIO); @@ -306,46 +304,41 @@ ListenSocket::ListenSocket(ListenSocketC ListenSocket::~ListenSocket() { MOZ_ASSERT(!mIO); } nsresult ListenSocket::Listen(UnixSocketConnector* aConnector, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, ConnectionOrientedSocket* aCOSocket) { MOZ_ASSERT(!mIO); - mIO = new ListenSocketIO(aConsumerThread, aIOLoop, this, aConnector); + mIO = new ListenSocketIO(aConsumerLoop, aIOLoop, this, aConnector); // Prepared I/O object, now start listening. nsresult rv = Listen(aCOSocket); if (NS_FAILED(rv)) { delete mIO; mIO = nullptr; return rv; } return NS_OK; } nsresult ListenSocket::Listen(UnixSocketConnector* aConnector, ConnectionOrientedSocket* aCOSocket) { - nsIThread* consumerThread = nullptr; - nsresult rv = NS_GetCurrentThread(&consumerThread); - if (NS_FAILED(rv)) { - return rv; - } - - return Listen(aConnector, consumerThread, XRE_GetIOMessageLoop(), aCOSocket); + return Listen(aConnector, MessageLoop::current(), XRE_GetIOMessageLoop(), + aCOSocket); } nsresult ListenSocket::Listen(ConnectionOrientedSocket* aCOSocket) { MOZ_ASSERT(aCOSocket); MOZ_ASSERT(mIO);
--- a/ipc/unixsocket/ListenSocket.h +++ b/ipc/unixsocket/ListenSocket.h @@ -6,17 +6,16 @@ #ifndef mozilla_ipc_listensocket_h #define mozilla_ipc_listensocket_h #include "nsString.h" #include "mozilla/ipc/SocketBase.h" class MessageLoop; -class nsIThread; namespace mozilla { namespace ipc { class ConnectionOrientedSocket; class ListenSocketConsumer; class ListenSocketIO; class UnixSocketConnector; @@ -32,24 +31,24 @@ public: */ ListenSocket(ListenSocketConsumer* aConsumer, int aIndex); /** * Starts a task on the socket that will try to accept a new connection * in a non-blocking manner. * * @param aConnector Connector object for socket-type-specific functions - * @param aConsumerThread The socket's consumer thread. + * @param aConsumerLoop The socket's consumer thread. * @param aIOLoop The socket's I/O thread. * @param aCOSocket The connection-oriented socket for handling the * accepted connection. * @return NS_OK on success, or an XPCOM error code otherwise. */ nsresult Listen(UnixSocketConnector* aConnector, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, ConnectionOrientedSocket* aCOSocket); /** * Starts a task on the socket that will try to accept a new connection * in a non-blocking manner. * * @param aConnector Connector object for socket-type-specific functions
--- a/ipc/unixsocket/SocketBase.cpp +++ b/ipc/unixsocket/SocketBase.cpp @@ -249,123 +249,112 @@ SocketBase::SetConnectionStatus(SocketCo { mConnectionStatus = aConnectionStatus; } // // SocketIOBase // -SocketIOBase::SocketIOBase(nsIThread* aConsumerThread) - : mConsumerThread(aConsumerThread) +SocketIOBase::SocketIOBase(MessageLoop* aConsumerLoop) + : mConsumerLoop(aConsumerLoop) { - MOZ_ASSERT(mConsumerThread); + MOZ_ASSERT(mConsumerLoop); } SocketIOBase::~SocketIOBase() { } -nsIThread* +MessageLoop* SocketIOBase::GetConsumerThread() const { - return mConsumerThread; + return mConsumerLoop; } bool SocketIOBase::IsConsumerThread() const { - nsIThread* thread = nullptr; - if (NS_FAILED(NS_GetCurrentThread(&thread))) { - return false; - } - return thread == GetConsumerThread(); + return GetConsumerThread() == MessageLoop::current(); } // -// SocketIOEventRunnable +// SocketEventTask // -SocketIOEventRunnable::SocketIOEventRunnable(SocketIOBase* aIO, - SocketEvent aEvent) - : SocketIORunnable<SocketIOBase>(aIO) +SocketEventTask::SocketEventTask(SocketIOBase* aIO, SocketEvent aEvent) + : SocketTask<SocketIOBase>(aIO) , mEvent(aEvent) { } -NS_METHOD -SocketIOEventRunnable::Run() +void +SocketEventTask::Run() { - SocketIOBase* io = SocketIORunnable<SocketIOBase>::GetIO(); + SocketIOBase* io = SocketTask<SocketIOBase>::GetIO(); MOZ_ASSERT(io->IsConsumerThread()); if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) { // Since we've already explicitly closed and the close // happened before this, this isn't really an error. - return NS_OK; + return; } SocketBase* socketBase = io->GetSocketBase(); MOZ_ASSERT(socketBase); if (mEvent == CONNECT_SUCCESS) { socketBase->NotifySuccess(); } else if (mEvent == CONNECT_ERROR) { socketBase->NotifyError(); } else if (mEvent == DISCONNECT) { socketBase->NotifyDisconnect(); } - - return NS_OK; } // -// SocketIORequestClosingRunnable +// SocketRequestClosingTask // -SocketIORequestClosingRunnable::SocketIORequestClosingRunnable( +SocketRequestClosingTask::SocketRequestClosingTask( SocketIOBase* aIO) - : SocketIORunnable<SocketIOBase>(aIO) + : SocketTask<SocketIOBase>(aIO) { } -NS_METHOD -SocketIORequestClosingRunnable::Run() +void +SocketRequestClosingTask::Run() { - SocketIOBase* io = SocketIORunnable<SocketIOBase>::GetIO(); + SocketIOBase* io = SocketTask<SocketIOBase>::GetIO(); MOZ_ASSERT(io->IsConsumerThread()); if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) { // Since we've already explicitly closed and the close // happened before this, this isn't really an error. - return NS_OK; + return; } SocketBase* socketBase = io->GetSocketBase(); MOZ_ASSERT(socketBase); socketBase->Close(); - - return NS_OK; } // -// SocketIODeleteInstanceRunnable +// SocketDeleteInstanceTask // -SocketIODeleteInstanceRunnable::SocketIODeleteInstanceRunnable( +SocketDeleteInstanceTask::SocketDeleteInstanceTask( SocketIOBase* aIO) : mIO(aIO) { } -NS_METHOD -SocketIODeleteInstanceRunnable::Run() +void +SocketDeleteInstanceTask::Run() { mIO = nullptr; // delete instance - - return NS_OK; } // // SocketIOShutdownTask // SocketIOShutdownTask::SocketIOShutdownTask(SocketIOBase* aIO) : SocketIOTask<SocketIOBase>(aIO) @@ -380,14 +369,14 @@ SocketIOShutdownTask::Run() MOZ_ASSERT(!io->IsShutdownOnIOThread()); // At this point, there should be no new events on the I/O thread // after this one with the possible exception of an accept task, // which ShutdownOnIOThread will cancel for us. We are now fully // shut down, so we can send a message to the consumer thread to // delete |io| safely knowing that it's not reference any longer. io->ShutdownOnIOThread(); - io->GetConsumerThread()->Dispatch(new SocketIODeleteInstanceRunnable(io), - NS_DISPATCH_NORMAL); + io->GetConsumerThread()->PostTask(FROM_HERE, + new SocketDeleteInstanceTask(io)); } } }
--- a/ipc/unixsocket/SocketBase.h +++ b/ipc/unixsocket/SocketBase.h @@ -6,18 +6,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_ipc_SocketBase_h #define mozilla_ipc_SocketBase_h #include "base/message_loop.h" #include "nsAutoPtr.h" -#include "nsTArray.h" -#include "nsThreadUtils.h" namespace mozilla { namespace ipc { // // UnixSocketBuffer // @@ -377,104 +375,103 @@ public: */ virtual void ShutdownOnConsumerThread() = 0; /** * Returns the consumer thread. * * @return A pointer to the consumer thread. */ - nsIThread* GetConsumerThread() const; + MessageLoop* GetConsumerThread() const; /** - * @return True if the current thread is thre consumer thread, or false + * @return True if the current thread is the consumer thread, or false * otherwise. */ bool IsConsumerThread() const; protected: - SocketIOBase(nsIThread* nsConsumerThread); + SocketIOBase(MessageLoop* aConsumerLoop); private: - nsCOMPtr<nsIThread> mConsumerThread; + MessageLoop* mConsumerLoop; }; // -// Socket I/O runnables +// Socket tasks // -/* |SocketIORunnable| is a runnable for sending a message from +/* |SocketTask| is a task for sending a message from * the I/O thread to the consumer thread. */ template <typename T> -class SocketIORunnable : public nsRunnable +class SocketTask : public Task { public: - virtual ~SocketIORunnable() + virtual ~SocketTask() { } T* GetIO() const { return mIO; } protected: - SocketIORunnable(T* aIO) - : mIO(aIO) + SocketTask(T* aIO) + : mIO(aIO) { MOZ_ASSERT(aIO); } private: T* mIO; }; /** - * |SocketIOEventRunnable| reports the connection state on the + * |SocketEventTask| reports the connection state on the * I/O thread back to the consumer thread. */ -class SocketIOEventRunnable final : public SocketIORunnable<SocketIOBase> +class SocketEventTask final : public SocketTask<SocketIOBase> { public: enum SocketEvent { CONNECT_SUCCESS, CONNECT_ERROR, DISCONNECT }; - SocketIOEventRunnable(SocketIOBase* aIO, SocketEvent aEvent); + SocketEventTask(SocketIOBase* aIO, SocketEvent aEvent); - NS_IMETHOD Run() override; + void Run() override; private: SocketEvent mEvent; }; /** - * |SocketIORequestClosingRunnable| closes an instance of |SocketBase| - * to the consumer thread. + * |SocketRequestClosingTask| closes an instance of |SocketBase| + * on the consumer thread. */ -class SocketIORequestClosingRunnable final - : public SocketIORunnable<SocketIOBase> +class SocketRequestClosingTask final : public SocketTask<SocketIOBase> { public: - SocketIORequestClosingRunnable(SocketIOBase* aIO); + SocketRequestClosingTask(SocketIOBase* aIO); - NS_IMETHOD Run() override; + void Run() override; }; /** - * |SocketIODeleteInstanceRunnable| deletes an object on the consumer thread. + * |SocketDeleteInstanceTask| deletes an object on the consumer thread. */ -class SocketIODeleteInstanceRunnable final : public nsRunnable +class SocketDeleteInstanceTask final : public Task { public: - SocketIODeleteInstanceRunnable(SocketIOBase* aIO); + SocketDeleteInstanceTask(SocketIOBase* aIO); - NS_IMETHOD Run() override; + void Run() override; private: nsAutoPtr<SocketIOBase> mIO; }; // // Socket I/O tasks //
--- a/ipc/unixsocket/StreamSocket.cpp +++ b/ipc/unixsocket/StreamSocket.cpp @@ -20,25 +20,25 @@ namespace ipc { // StreamSocketIO // class StreamSocketIO final : public ConnectionOrientedSocketIO { public: class ConnectTask; class DelayedConnectTask; - class ReceiveRunnable; + class ReceiveTask; - StreamSocketIO(nsIThread* aConsumerThread, - MessageLoop* mIOLoop, + StreamSocketIO(MessageLoop* aConsumerLoop, + MessageLoop* aIOLoop, StreamSocket* aStreamSocket, UnixSocketConnector* aConnector); - StreamSocketIO(nsIThread* aConsumerThread, - MessageLoop* mIOLoop, int aFd, - ConnectionStatus aConnectionStatus, + StreamSocketIO(MessageLoop* aConsumerLoop, + MessageLoop* aIOLoop, + int aFd, ConnectionStatus aConnectionStatus, StreamSocket* aStreamSocket, UnixSocketConnector* aConnector); ~StreamSocketIO(); StreamSocket* GetStreamSocket(); DataSocket* GetDataSocket(); // Delayed-task handling @@ -86,34 +86,34 @@ private: CancelableTask* mDelayedConnectTask; /** * I/O buffer for received data */ nsAutoPtr<UnixSocketRawData> mBuffer; }; -StreamSocketIO::StreamSocketIO(nsIThread* aConsumerThread, +StreamSocketIO::StreamSocketIO(MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, StreamSocket* aStreamSocket, UnixSocketConnector* aConnector) - : ConnectionOrientedSocketIO(aConsumerThread, aIOLoop, aConnector) + : ConnectionOrientedSocketIO(aConsumerLoop, aIOLoop, aConnector) , mStreamSocket(aStreamSocket) , mShuttingDownOnIOThread(false) , mDelayedConnectTask(nullptr) { MOZ_ASSERT(mStreamSocket); } -StreamSocketIO::StreamSocketIO(nsIThread* aConsumerThread, +StreamSocketIO::StreamSocketIO(MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, int aFd, ConnectionStatus aConnectionStatus, StreamSocket* aStreamSocket, UnixSocketConnector* aConnector) - : ConnectionOrientedSocketIO(aConsumerThread, + : ConnectionOrientedSocketIO(aConsumerLoop, aIOLoop, aFd, aConnectionStatus, aConnector) , mStreamSocket(aStreamSocket) , mShuttingDownOnIOThread(false) , mDelayedConnectTask(nullptr) { @@ -178,57 +178,54 @@ StreamSocketIO::QueryReceiveBuffer(UnixS mBuffer = new UnixSocketRawData(MAX_READ_SIZE); } *aBuffer = mBuffer.get(); return NS_OK; } /** - * |ReceiveRunnable| transfers data received on the I/O thread + * |ReceiveTask| transfers data received on the I/O thread * to an instance of |StreamSocket| on the consumer thread. */ -class StreamSocketIO::ReceiveRunnable final - : public SocketIORunnable<StreamSocketIO> +class StreamSocketIO::ReceiveTask final : public SocketTask<StreamSocketIO> { public: - ReceiveRunnable(StreamSocketIO* aIO, UnixSocketBuffer* aBuffer) - : SocketIORunnable<StreamSocketIO>(aIO) + ReceiveTask(StreamSocketIO* aIO, UnixSocketBuffer* aBuffer) + : SocketTask<StreamSocketIO>(aIO) , mBuffer(aBuffer) { } - NS_IMETHOD Run() override + void Run() override { - StreamSocketIO* io = SocketIORunnable<StreamSocketIO>::GetIO(); + StreamSocketIO* io = SocketTask<StreamSocketIO>::GetIO(); MOZ_ASSERT(io->IsConsumerThread()); if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) { // Since we've already explicitly closed and the close // happened before this, this isn't really an error. - return NS_OK; + return; } StreamSocket* streamSocket = io->GetStreamSocket(); MOZ_ASSERT(streamSocket); streamSocket->ReceiveSocketData(mBuffer); - - return NS_OK; } private: nsAutoPtr<UnixSocketBuffer> mBuffer; }; void StreamSocketIO::ConsumeBuffer() { - GetConsumerThread()->Dispatch(new ReceiveRunnable(this, mBuffer.forget()), - NS_DISPATCH_NORMAL); + GetConsumerThread()->PostTask(FROM_HERE, + new ReceiveTask(this, mBuffer.forget())); } void StreamSocketIO::DiscardBuffer() { // Nothing to do. } @@ -340,21 +337,21 @@ StreamSocket::~StreamSocket() void StreamSocket::ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer) { mConsumer->ReceiveSocketData(mIndex, aBuffer); } nsresult StreamSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs, - nsIThread* aConsumerThread, MessageLoop* aIOLoop) + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop) { MOZ_ASSERT(!mIO); - mIO = new StreamSocketIO(aConsumerThread, aIOLoop, this, aConnector); + mIO = new StreamSocketIO(aConsumerLoop, aIOLoop, this, aConnector); SetConnectionStatus(SOCKET_CONNECTING); if (aDelayMs > 0) { StreamSocketIO::DelayedConnectTask* connectTask = new StreamSocketIO::DelayedConnectTask(mIO); mIO->SetDelayedConnectTask(connectTask); MessageLoop::current()->PostDelayedTask(FROM_HERE, connectTask, aDelayMs); } else { @@ -362,39 +359,34 @@ StreamSocket::Connect(UnixSocketConnecto } return NS_OK; } nsresult StreamSocket::Connect(UnixSocketConnector* aConnector, int aDelayMs) { - nsIThread* consumerThread = nullptr; - nsresult rv = NS_GetCurrentThread(&consumerThread); - if (NS_FAILED(rv)) { - return rv; - } - - return Connect(aConnector, aDelayMs, consumerThread, XRE_GetIOMessageLoop()); + return Connect(aConnector, aDelayMs, + MessageLoop::current(), XRE_GetIOMessageLoop()); } // |ConnectionOrientedSocket| nsresult StreamSocket::PrepareAccept(UnixSocketConnector* aConnector, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, ConnectionOrientedSocketIO*& aIO) { MOZ_ASSERT(!mIO); MOZ_ASSERT(aConnector); SetConnectionStatus(SOCKET_CONNECTING); - mIO = new StreamSocketIO(aConsumerThread, aIOLoop, + mIO = new StreamSocketIO(aConsumerLoop, aIOLoop, -1, UnixSocketWatcher::SOCKET_IS_CONNECTING, this, aConnector); aIO = mIO; return NS_OK; } // |DataSocket|
--- a/ipc/unixsocket/StreamSocket.h +++ b/ipc/unixsocket/StreamSocket.h @@ -37,38 +37,38 @@ public: void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer); /** * Starts a task on the socket that will try to connect to a socket in a * non-blocking manner. * * @param aConnector Connector object for socket type specific functions * @param aDelayMs Time delay in milliseconds. - * @param aConsumerThread The socket's consumer thread. + * @param aConsumerLoop The socket's consumer thread. * @param aIOLoop The socket's I/O thread. * @return NS_OK on success, or an XPCOM error code otherwise. */ nsresult Connect(UnixSocketConnector* aConnector, int aDelayMs, - nsIThread* aConsumerThread, MessageLoop* aIOLoop); + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop); /** * Starts a task on the socket that will try to connect to a socket in a * non-blocking manner. * * @param aConnector Connector object for socket type specific functions * @param aDelayMs Time delay in milliseconds. * @return NS_OK on success, or an XPCOM error code otherwise. */ nsresult Connect(UnixSocketConnector* aConnector, int aDelayMs = 0); // Methods for |ConnectionOrientedSocket| // nsresult PrepareAccept(UnixSocketConnector* aConnector, - nsIThread* aConsumerThread, + MessageLoop* aConsumerLoop, MessageLoop* aIOLoop, ConnectionOrientedSocketIO*& aIO) override; // Methods for |DataSocket| // void SendSocketData(UnixSocketIOBuffer* aBuffer) override;
--- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -7,18 +7,16 @@ ifeq (,$(MAKE_VERSION)) $(error GNU Make is required) endif make_min_ver := 3.81 ifneq ($(make_min_ver),$(firstword $(sort $(make_min_ver) $(MAKE_VERSION)))) $(error GNU Make $(make_min_ver) or higher is required) endif -TOPLEVEL_BUILD := 1 - run_for_side_effects := $(shell echo 'MAKE: $(MAKE)') ifdef JS_HAS_CTYPES ifdef MOZ_NATIVE_FFI LOCAL_INCLUDES = $(MOZ_FFI_CFLAGS) endif # Windows needs this to be linked with a static library.
--- a/js/src/aclocal.m4 +++ b/js/src/aclocal.m4 @@ -27,16 +27,17 @@ builtin(include, ../../build/autoconf/ar builtin(include, ../../build/autoconf/android.m4)dnl builtin(include, ../../build/autoconf/zlib.m4)dnl builtin(include, ../../build/autoconf/linux.m4)dnl builtin(include, ../../build/autoconf/python-virtualenv.m4)dnl builtin(include, ../../build/autoconf/winsdk.m4)dnl builtin(include, ../../build/autoconf/icu.m4)dnl builtin(include, ../../build/autoconf/ffi.m4)dnl builtin(include, ../../build/autoconf/clang-plugin.m4)dnl +builtin(include, ../../build/autoconf/alloc.m4)dnl define([__MOZ_AC_INIT_PREPARE], defn([AC_INIT_PREPARE])) define([AC_INIT_PREPARE], [if test -z "$srcdir"; then srcdir=`dirname "[$]0"` fi srcdir="$srcdir/../.." __MOZ_AC_INIT_PREPARE($1)
--- a/js/src/configure.in +++ b/js/src/configure.in @@ -3842,28 +3842,19 @@ dnl top-level configure may override thi MOZ_CONFIG_ICU() MOZ_SUBCONFIGURE_ICU() dnl ======================================================== dnl JavaScript shell dnl ======================================================== -MALLOC_HEADERS="malloc.h malloc_np.h malloc/malloc.h sys/malloc.h" -MALLOC_H= - -for file in $MALLOC_HEADERS; do - MOZ_CHECK_HEADER($file, [MALLOC_H=$file]) - if test "$MALLOC_H" != ""; then - AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>) - break - fi -done - -AC_CHECK_FUNCS(setlocale localeconv malloc_size malloc_usable_size) +MOZ_CHECK_ALLOCATOR + +AC_CHECK_FUNCS(setlocale localeconv) AC_SUBST(MOZILLA_VERSION) AC_SUBST(ac_configure_args) AC_SUBST(TOOLCHAIN_PREFIX) if test -n "$JS_STANDALONE"; then
--- a/js/src/devtools/rootAnalysis/analyzeRoots.js +++ b/js/src/devtools/rootAnalysis/analyzeRoots.js @@ -3,20 +3,27 @@ "use strict"; loadRelativeToScript('utility.js'); loadRelativeToScript('annotations.js'); loadRelativeToScript('CFG.js'); var sourceRoot = (os.getenv('SOURCE') || '') + '/' +var functionName; var functionBodies; if (typeof scriptArgs[0] != 'string' || typeof scriptArgs[1] != 'string') - throw "Usage: analyzeRoots.js <gcFunctions.lst> <gcEdges.txt> <suppressedFunctions.lst> <gcTypes.txt> [start end [tmpfile]]"; + throw "Usage: analyzeRoots.js [-f function_name] <gcFunctions.lst> <gcEdges.txt> <suppressedFunctions.lst> <gcTypes.txt> [start end [tmpfile]]"; + +var theFunctionNameToFind; +if (scriptArgs[0] == '--function') { + theFunctionNameToFind = scriptArgs[1]; + scriptArgs = scriptArgs.slice(2); +} var gcFunctionsFile = scriptArgs[0]; var gcEdgesFile = scriptArgs[1]; var suppressedFunctionsFile = scriptArgs[2]; var gcTypesFile = scriptArgs[3]; var batch = (scriptArgs[4]|0) || 1; var numBatches = (scriptArgs[5]|0) || 1; var tmpfile = scriptArgs[6] || "tmp.txt"; @@ -204,17 +211,17 @@ function edgeTakesVariableAddress(edge, return false; default: return false; } } function edgeKillsVariable(edge, variable) { - // Direct assignments kill their lhs. + // Direct assignments kill their lhs: var = value if (edge.Kind == "Assign") { var lhs = edge.Exp[0]; if (lhs.Kind == "Var" && sameVariable(lhs.Variable, variable)) return !isReturningImmobileValue(edge, variable); } if (edge.Kind != "Call") return false; @@ -291,105 +298,143 @@ function edgeCanGC(edge) return null; return (fullFieldName in suppressedFunctions) ? null : fullFieldName; } assert(callee.Exp[0].Kind == "Var"); var varName = callee.Exp[0].Variable.Name[0]; return indirectCallCannotGC(functionName, varName) ? null : "*" + varName; } -function variableUsePrecedesGC(suppressed, variable, worklist) +// Search recursively through predecessors from a variable use, returning +// whether a GC call is reachable (in the reverse direction; this means that +// the variable use is reachable from the GC call, and therefore the variable +// is live after the GC call), along with some additional information. What +// info we want depends on whether the variable turns out to be live across any +// GC call. We are looking for both hazards (unrooted variables live across GC +// calls) and unnecessary roots (rooted variables that have no GC calls in +// their live ranges.) +// +// If not: +// +// - 'minimumUse': the earliest point in each body that uses the variable, for +// reporting on unnecessary roots. +// +// If so: +// +// - 'why': a path from the GC call to a use of the variable after the GC +// call, chained through a 'why' field in the returned edge descriptor +// +// - 'gcInfo': a direct pointer to the GC call edge +// +function findGCBeforeVariableUse(suppressed, variable, worklist) { // Scan through all edges preceding an unrooted variable use, using an - // explicit worklist. A worklist contains an incoming edge together with a - // description of where it or one of its successors GC'd (if any). + // explicit worklist, looking for a GC call. A worklist contains an + // incoming edge together with a description of where it or one of its + // successors GC'd (if any). while (worklist.length) { var entry = worklist.pop(); - var body = entry.body, ppoint = entry.ppoint; + var { body, ppoint, gcInfo } = entry; if (body.seen) { if (ppoint in body.seen) { var seenEntry = body.seen[ppoint]; - if (!entry.gcInfo || seenEntry.gcInfo) + if (!gcInfo || seenEntry.gcInfo) continue; } } else { body.seen = []; } - body.seen[ppoint] = {body:body, gcInfo:entry.gcInfo}; + body.seen[ppoint] = {body: body, gcInfo: gcInfo}; if (ppoint == body.Index[0]) { if (body.BlockId.Kind == "Loop") { // propagate to parents that enter the loop body. if ("BlockPPoint" in body) { for (var parent of body.BlockPPoint) { var found = false; for (var xbody of functionBodies) { if (sameBlockId(xbody.BlockId, parent.BlockId)) { assert(!found); found = true; - worklist.push({body:xbody, ppoint:parent.Index, - gcInfo:entry.gcInfo, why:entry}); + worklist.push({body: xbody, ppoint: parent.Index, + gcInfo: gcInfo, why: entry}); } } assert(found); } } - } else if (variable.Kind == "Arg" && entry.gcInfo) { + } else if (variable.Kind == "Arg" && gcInfo) { // The scope of arguments starts at the beginning of the // function - return {gcInfo:entry.gcInfo, why:entry}; + return {gcInfo: gcInfo, why: entry}; } } var predecessors = getPredecessors(body); if (!(ppoint in predecessors)) continue; for (var edge of predecessors[ppoint]) { var source = edge.Index[0]; - if (edgeKillsVariable(edge, variable)) { - if (entry.gcInfo) - return {gcInfo: entry.gcInfo, why: {body:body, ppoint:source, gcInfo:entry.gcInfo, why:entry } } + var edge_kills = edgeKillsVariable(edge, variable); + var edge_uses = edgeUsesVariable(edge, variable, body); + + if (edge_kills || edge_uses) { if (!body.minimumUse || source < body.minimumUse) body.minimumUse = source; + } + + if (edge_kills) { + // This is a beginning of the variable's live range. If we can + // reach a GC call from here, then we're done -- we have a path + // from the beginning of the live range, through the GC call, + // to a use after the GC call that proves its live range + // extends at least that far. + if (gcInfo) + return {gcInfo: gcInfo, why: {body: body, ppoint: source, gcInfo: gcInfo, why: entry } } + + // Otherwise, we want to continue searching for the true + // minimumUse, for use in reporting unnecessary rooting, but we + // truncate this particular branch of the search at this edge. continue; } - var gcInfo = entry.gcInfo; if (!gcInfo && !(source in body.suppressed) && !suppressed) { var gcName = edgeCanGC(edge, body); if (gcName) gcInfo = {name:gcName, body:body, ppoint:source}; } - if (edgeUsesVariable(edge, variable, body)) { + if (edge_uses) { + // The live range starts at least this far back, so we're done + // for the same reason as with edge_kills. if (gcInfo) return {gcInfo:gcInfo, why:entry}; - if (!body.minimumUse || source < body.minimumUse) - body.minimumUse = source; } if (edge.Kind == "Loop") { - // propagate to exit points of the loop body, in addition to the - // predecessor of the loop edge itself. + // Additionally propagate the search into a loop body, starting + // with the exit point. var found = false; for (var xbody of functionBodies) { if (sameBlockId(xbody.BlockId, edge.BlockId)) { assert(!found); found = true; worklist.push({body:xbody, ppoint:xbody.Index[1], gcInfo:gcInfo, why:entry}); } } assert(found); break; } + + // Propagate the search to the predecessors of this edge. worklist.push({body:body, ppoint:source, gcInfo:gcInfo, why:entry}); } } return null; } function variableLiveAcrossGC(suppressed, variable) @@ -402,24 +447,31 @@ function variableLiveAcrossGC(suppressed body.minimumUse = 0; } for (var body of functionBodies) { if (!("PEdge" in body)) continue; for (var edge of body.PEdge) { var usePoint = edgeUsesVariable(edge, variable, body); + // Example for !edgeKillsVariable: + // + // JSObject* obj = NewObject(); + // cangc(); + // obj = NewObject(); <-- uses 'obj', but kills previous value + // if (usePoint && !edgeKillsVariable(edge, variable)) { // Found a use, possibly after a GC. var worklist = [{body:body, ppoint:usePoint, gcInfo:null, why:null}]; - var call = variableUsePrecedesGC(suppressed, variable, worklist); - if (call) { - call.afterGCUse = usePoint; - return call; - } + var call = findGCBeforeVariableUse(suppressed, variable, worklist); + if (!call) + continue; + + call.afterGCUse = usePoint; + return call; } } } return null; } // An unrooted variable has its address stored in another variable via // assignment, or passed into a function that can GC. If the address is @@ -630,34 +682,38 @@ var end = Math.min(minStream + each * ba // For debugging: Set this variable to the function name you're interested in // debugging and run once. That will print out the nameIndex of that function. // Insert that into the following statement to go directly to just that // function. Add your debugging printouts or debugger; statements or whatever. var theFunctionNameToFind; // var start = end = 12345; -for (var nameIndex = start; nameIndex <= end; nameIndex++) { - var name = xdb.read_key(nameIndex); - var functionName = name.readString(); - var data = xdb.read_entry(name); - xdb.free_string(name); - var json = data.readString(); - xdb.free_string(data); +function process(name, json) { + functionName = name; functionBodies = JSON.parse(json); - if (theFunctionNameToFind) { - if (functionName == theFunctionNameToFind) { - printErr("nameIndex = " + nameIndex); - quit(1); - } else { - continue; - } - } - for (var body of functionBodies) body.suppressed = []; for (var body of functionBodies) { for (var [pbody, id] of allRAIIGuardedCallPoints(body, isSuppressConstructor)) pbody.suppressed[id] = true; } processBodies(functionName); } + +if (theFunctionNameToFind) { + var data = xdb.read_entry(theFunctionNameToFind); + var json = data.readString(); + process(theFunctionNameToFind, json); + xdb.free_string(data); + quit(0); +} + +for (var nameIndex = start; nameIndex <= end; nameIndex++) { + var name = xdb.read_key(nameIndex); + var functionName = name.readString(); + var data = xdb.read_entry(name); + xdb.free_string(name); + var json = data.readString(); + process(functionName, json); + xdb.free_string(data); +}
--- a/js/src/jit-test/tests/asm.js/testBug1164391.js +++ b/js/src/jit-test/tests/asm.js/testBug1164391.js @@ -1,8 +1,11 @@ +if (!this.SharedArrayBuffer) + quit(0); + function m(stdlib, ffi, heap) { "use asm"; var HEAP32 = new stdlib.SharedInt32Array(heap); var add = stdlib.Atomics.add; var load = stdlib.Atomics.load; function add_sharedEv(i1) { i1 = i1 | 0; load(HEAP32, i1 >> 2);
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1139376.js @@ -0,0 +1,13 @@ +// |jit-test| error:ReferenceError + +(function() { + var $10=0; + while (1) { + switch (stack.label & 2) { + case 1: + return $8|0; + case 49: + if ($10) {} + } + } +})()()
--- a/js/src/jit/JitSpewer.h +++ b/js/src/jit/JitSpewer.h @@ -166,17 +166,17 @@ void DisableChannel(JitSpewChannel chann void EnableIonDebugSyncLogging(); void EnableIonDebugAsyncLogging(); #else class GraphSpewer { public: - GraphSpewer(TempAllocator *alloc) { } + explicit GraphSpewer(TempAllocator *alloc) { } bool isSpewing() { return false; } void init(MIRGraph* graph, JSScript* function) { } void beginFunction(JSScript* function) { } void spewPass(const char* pass) { } void spewPass(const char* pass, BacktrackingAllocator* ra) { } void endFunction() { }
--- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -3330,25 +3330,26 @@ RangeAnalysis::prepareForUCE(bool* shoul test->id()); *shouldRemoveDeadCode = true; } return tryRemovingGuards(); } -bool RangeAnalysis::tryRemovingGuards() { - +bool RangeAnalysis::tryRemovingGuards() +{ MDefinitionVector guards(alloc()); for (ReversePostorderIterator block = graph_.rpoBegin(); block != graph_.rpoEnd(); block++) { for (MInstructionReverseIterator iter = block->rbegin(); iter != block->rend(); iter++) { if (!iter->isGuardRangeBailouts()) continue; + iter->setInWorklist(); if (!guards.append(*iter)) return false; } } // Flag all fallible instructions which were indirectly used in the // computation of the condition, such that we do not ignore // bailout-paths which are used to shrink the input range of the @@ -3359,46 +3360,56 @@ bool RangeAnalysis::tryRemovingGuards() #ifdef DEBUG // There is no need to mark an instructions if there is // already a more restrictive flag on it. guard->setNotGuardRangeBailouts(); MOZ_ASSERT(DeadIfUnused(guard)); guard->setGuardRangeBailouts(); #endif - if (!guard->range()) - continue; - - // Filter the range of the instruction based on its MIRType. - Range typeFilteredRange(guard); - - // If the output range is updated by adding the inner range, - // then the MIRType act as an effectful filter. As we do not know if - // this filtered Range might change or not the result of the - // previous comparison, we have to keep this instruction as a guard - // because it has to bailout in order to restrict the Range to its - // MIRType. - if (typeFilteredRange.update(guard->range())) - continue; + if (!guard->isPhi()) { + if (!guard->range()) + continue; + + // Filter the range of the instruction based on its MIRType. + Range typeFilteredRange(guard); + + // If the output range is updated by adding the inner range, + // then the MIRType act as an effectful filter. As we do not know if + // this filtered Range might change or not the result of the + // previous comparison, we have to keep this instruction as a guard + // because it has to bailout in order to restrict the Range to its + // MIRType. + if (typeFilteredRange.update(guard->range())) + continue; + } guard->setNotGuardRangeBailouts(); // Propagate the guard to its operands. for (size_t op = 0, e = guard->numOperands(); op < e; op++) { MDefinition* operand = guard->getOperand(op); // Already marked. - if (operand->isGuardRangeBailouts()) + if (operand->isInWorklist()) continue; + MOZ_ASSERT(!operand->isGuardRangeBailouts()); + // No need to mark as a guard, since it is has already an even more // restrictive flag set. if (!DeadIfUnused(operand)) continue; + operand->setInWorklist(); operand->setGuardRangeBailouts(); if (!guards.append(operand)) return false; } } + for (size_t i = 0; i < guards.length(); i++) { + MDefinition* guard = guards[i]; + guard->setNotInWorklist(); + } + return true; }
--- a/js/src/jit/ValueNumbering.cpp +++ b/js/src/jit/ValueNumbering.cpp @@ -677,17 +677,17 @@ ValueNumberer::loopHasOptimizablePhi(MBa // If the header is unreachable, don't bother re-optimizing it. if (header->isMarked()) return false; // Rescan the phis for any that can be simplified, since they may be reading // values from backedges. for (MPhiIterator iter(header->phisBegin()), end(header->phisEnd()); iter != end; ++iter) { MPhi* phi = *iter; - MOZ_ASSERT(phi->hasUses(), "Missed an unused phi"); + MOZ_ASSERT_IF(!phi->hasUses(), !DeadIfUnused(phi)); if (phi->operandIfRedundant() || hasLeader(phi, header)) return true; // Phi can be simplified. } return false; } // Visit |def|.
--- a/js/src/shell/OSObject.cpp +++ b/js/src/shell/OSObject.cpp @@ -262,16 +262,20 @@ static const JSFunctionSpecWithHelp osfi " Read filename into returned string. Filename is relative to the current\n" " working directory."), JS_FN_HELP("readRelativeToScript", osfile_readRelativeToScript, 1, 0, "readRelativeToScript(filename, [\"binary\"])", " Read filename into returned string. Filename is relative to the directory\n" " containing the current script."), + JS_FS_HELP_END +}; + +static const JSFunctionSpecWithHelp osfile_unsafe_functions[] = { JS_FN_HELP("redirect", osfile_redirect, 2, 0, "redirect(stdoutFilename[, stderrFilename])", " Redirect stdout and/or stderr to the named file. Pass undefined to avoid\n" " redirecting. Filenames are relative to the current working directory."), JS_FS_HELP_END }; @@ -561,16 +565,21 @@ DefineOS(JSContext* cx, HandleObject glo RootedObject osfile(cx, JS_NewPlainObject(cx)); if (!osfile || !JS_DefineFunctionsWithHelp(cx, osfile, osfile_functions) || !JS_DefineProperty(cx, obj, "file", osfile, 0)) { return false; } + if (!fuzzingSafe) { + if (!JS_DefineFunctionsWithHelp(cx, osfile, osfile_unsafe_functions)) + return false; + } + // For backwards compatibility, expose various os.file.* functions as // direct methods on the global. RootedValue val(cx); struct { const char* src; const char* dst; } osfile_exports[] = { @@ -578,18 +587,20 @@ DefineOS(JSContext* cx, HandleObject glo { "readFile", "snarf" }, { "readRelativeToScript", "readRelativeToScript" }, { "redirect", "redirect" } }; for (auto pair : osfile_exports) { if (!JS_GetProperty(cx, osfile, pair.src, &val)) return false; - RootedObject function(cx, &val.toObject()); - if (!JS_DefineProperty(cx, global, pair.dst, function, 0)) - return false; + if (val.isObject()) { + RootedObject function(cx, &val.toObject()); + if (!JS_DefineProperty(cx, global, pair.dst, function, 0)) + return false; + } } return true; } } }
--- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -2388,17 +2388,18 @@ nsCSSOffsetState::InitOffsets(const Logi nsTableFrame *tableFrame = static_cast<nsTableFrame*>(frame); if (tableFrame->IsBorderCollapse()) { // border-collapsed tables don't use any of their padding, and // only part of their border. We need to do this here before we // try to do anything like handling 'auto' widths, // 'box-sizing', or 'auto' margins. ComputedPhysicalPadding().SizeTo(0,0,0,0); - ComputedPhysicalBorderPadding() = tableFrame->GetIncludedOuterBCBorder(); + SetComputedLogicalBorderPadding( + tableFrame->GetIncludedOuterBCBorder(mWritingMode)); } // The margin is inherited to the outer table frame via // the ::-moz-table-outer rule in ua.css. ComputedPhysicalMargin().SizeTo(0, 0, 0, 0); } else if (aFrameType == nsGkAtoms::scrollbarFrame) { // scrollbars may have had their width or height smashed to zero // by the associated scrollframe, in which case we must not report
--- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -74,35 +74,36 @@ struct nsTableReflowState { nscoord aAvailWidth, nscoord aAvailHeight) : reflowState(aReflowState) { MOZ_ASSERT(reflowState.frame->GetType() == nsGkAtoms::tableFrame, "nsTableReflowState should only be created for nsTableFrame"); nsTableFrame* table = static_cast<nsTableFrame*>(reflowState.frame->FirstInFlow()); - nsMargin borderPadding = table->GetChildAreaOffset(&reflowState); - - x = borderPadding.left + table->GetColSpacing(-1); - y = borderPadding.top; //cellspacing added during reflow + WritingMode wm = aReflowState.GetWritingMode(); + LogicalMargin borderPadding = table->GetChildAreaOffset(wm, &reflowState); + + x = borderPadding.IStart(wm) + table->GetColSpacing(-1); + y = borderPadding.BStart(wm); //cellspacing added during reflow availSize.width = aAvailWidth; if (NS_UNCONSTRAINEDSIZE != availSize.width) { int32_t colCount = table->GetColCount(); - availSize.width -= borderPadding.left + borderPadding.right - + table->GetColSpacing(-1) - + table->GetColSpacing(colCount); + availSize.width -= borderPadding.IStartEnd(wm) + + table->GetColSpacing(-1) + + table->GetColSpacing(colCount); availSize.width = std::max(0, availSize.width); } availSize.height = aAvailHeight; if (NS_UNCONSTRAINEDSIZE != availSize.height) { - availSize.height -= borderPadding.top + borderPadding.bottom - + table->GetRowSpacing(-1) - + table->GetRowSpacing(table->GetRowCount()); + availSize.height -= borderPadding.BStartEnd(wm) + + table->GetRowSpacing(-1) + + table->GetRowSpacing(table->GetRowCount()); availSize.height = std::max(0, availSize.height); } } }; /******************************************************************************** ** nsTableFrame ** ********************************************************************************/ @@ -1345,17 +1346,18 @@ nsTableFrame::BuildDisplayList(nsDisplay nsMargin nsTableFrame::GetDeflationForBackground(nsPresContext* aPresContext) const { if (eCompatibility_NavQuirks != aPresContext->CompatibilityMode() || !IsBorderCollapse()) return nsMargin(0,0,0,0); - return GetOuterBCBorder(); + WritingMode wm = GetWritingMode(); + return GetOuterBCBorder(wm).GetPhysicalMargin(wm); } // XXX We don't put the borders and backgrounds in tree order like we should. // That requires some major surgery which we aren't going to do right now. DrawResult nsTableFrame::PaintTableBorderBackground(nsRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsPoint aPt, uint32_t aBGPaintFlags) @@ -1413,31 +1415,31 @@ nsTableFrame::GetLogicalSkipSides(const } if (nullptr != GetNextInFlow()) { skip |= eLogicalSideBitsBEnd; } return skip; } void -nsTableFrame::SetColumnDimensions(nscoord aHeight, - const nsMargin& aBorderPadding) -{ - nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom + +nsTableFrame::SetColumnDimensions(nscoord aHeight, WritingMode aWM, + const LogicalMargin& aBorderPadding) +{ + nscoord colHeight = aHeight -= aBorderPadding.BStartEnd(aWM) + GetRowSpacing(-1) + GetRowSpacing(GetRowCount()); nsTableIterator iter(mColGroups); nsIFrame* colGroupFrame = iter.First(); bool tableIsLTR = StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR; int32_t colX =tableIsLTR ? 0 : std::max(0, GetColCount() - 1); nscoord cellSpacingX = GetColSpacing(colX); int32_t tableColIncr = tableIsLTR ? 1 : -1; - nsPoint colGroupOrigin(aBorderPadding.left + GetColSpacing(-1), - aBorderPadding.top + GetRowSpacing(-1)); + nsPoint colGroupOrigin(aBorderPadding.IStart(aWM) + GetColSpacing(-1), + aBorderPadding.BStart(aWM) + GetRowSpacing(-1)); while (colGroupFrame) { MOZ_ASSERT(colGroupFrame->GetType() == nsGkAtoms::tableColGroupFrame); nscoord colGroupWidth = 0; nsTableIterator iterCol(*colGroupFrame); nsIFrame* colFrame = iterCol.First(); nsPoint colOrigin(0,0); while (colFrame) { if (NS_STYLE_DISPLAY_TABLE_COLUMN == @@ -1547,18 +1549,19 @@ nsTableFrame::IntrinsicISizeOffsets(nsRe result.hMargin = 0; result.hPctMargin = 0; if (IsBorderCollapse()) { result.hPadding = 0; result.hPctPadding = 0; - nsMargin outerBC = GetIncludedOuterBCBorder(); - result.hBorder = outerBC.LeftRight(); + WritingMode wm = GetWritingMode(); + LogicalMargin outerBC = GetIncludedOuterBCBorder(wm); + result.hBorder = outerBC.IStartEnd(wm); } return result; } /* virtual */ LogicalSize nsTableFrame::ComputeSize(nsRenderingContext *aRenderingContext, @@ -1780,16 +1783,17 @@ nsTableFrame::Reflow(nsPresContext* nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { MarkInReflow(); DO_GLOBAL_REFLOW_COUNT("nsTableFrame"); DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); bool isPaginated = aPresContext->IsPaginated(); + WritingMode wm = aReflowState.GetWritingMode(); aStatus = NS_FRAME_COMPLETE; if (!GetPrevInFlow() && !mTableLayoutStrategy) { NS_ERROR("strategy should have been created in Init"); return; } // see if collapsing borders need to be calculated @@ -1872,18 +1876,18 @@ nsTableFrame::Reflow(nsPresContext* CalcDesiredHeight(aReflowState, aDesiredSize); mutable_rs.mFlags.mSpecialHeightReflow = true; ReflowTable(aDesiredSize, aReflowState, aReflowState.AvailableHeight(), lastChildReflowed, aStatus); if (lastChildReflowed && NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // if there is an incomplete child, then set the desired height to include it but not the next one - nsMargin borderPadding = GetChildAreaOffset(&aReflowState); - aDesiredSize.Height() = borderPadding.bottom + GetRowSpacing(GetRowCount()) + + LogicalMargin borderPadding = GetChildAreaOffset(wm, &aReflowState); + aDesiredSize.Height() = borderPadding.BEnd(wm) + GetRowSpacing(GetRowCount()) + lastChildReflowed->GetNormalRect().YMost(); } haveDesiredHeight = true; mutable_rs.mFlags.mSpecialHeightReflow = false; } } else { @@ -1897,34 +1901,34 @@ nsTableFrame::Reflow(nsPresContext* aReflowState.ComputedPhysicalBorderPadding().LeftRight(); if (!haveDesiredHeight) { CalcDesiredHeight(aReflowState, aDesiredSize); } if (IsRowInserted()) { ProcessRowInserted(aDesiredSize.Height()); } - nsMargin borderPadding = GetChildAreaOffset(&aReflowState); - SetColumnDimensions(aDesiredSize.Height(), borderPadding); + LogicalMargin borderPadding = GetChildAreaOffset(wm, &aReflowState); + SetColumnDimensions(aDesiredSize.Height(), wm, borderPadding); if (NeedToCollapse() && (NS_UNCONSTRAINEDSIZE != aReflowState.AvailableWidth())) { - AdjustForCollapsingRowsCols(aDesiredSize, borderPadding); + AdjustForCollapsingRowsCols(aDesiredSize, wm, borderPadding); } // If there are any relatively-positioned table parts, we need to reflow their // absolutely-positioned descendants now that their dimensions are final. FixupPositionedTableParts(aPresContext, aDesiredSize, aReflowState); // make sure the table overflow area does include the table rect. nsRect tableRect(0, 0, aDesiredSize.Width(), aDesiredSize.Height()) ; if (!ShouldApplyOverflowClipping(this, aReflowState.mStyleDisplay)) { // collapsed border may leak out - nsMargin bcMargin = GetExcludedOuterBCBorder(); - tableRect.Inflate(bcMargin); + LogicalMargin bcMargin = GetExcludedOuterBCBorder(wm); + tableRect.Inflate(bcMargin.GetPhysicalMargin(wm)); } aDesiredSize.mOverflowAreas.UnionAllWith(tableRect); if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) || nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) { nsIFrame::InvalidateFrame(); } @@ -2002,18 +2006,19 @@ nsTableFrame::FixupPositionedTableParts( bool nsTableFrame::UpdateOverflow() { nsRect bounds(nsPoint(0, 0), GetSize()); // As above in Reflow, make sure the table overflow area includes the table // rect, and check for collapsed borders leaking out. if (!ShouldApplyOverflowClipping(this, StyleDisplay())) { - nsMargin bcMargin = GetExcludedOuterBCBorder(); - bounds.Inflate(bcMargin); + WritingMode wm = GetWritingMode(); + LogicalMargin bcMargin = GetExcludedOuterBCBorder(wm); + bounds.Inflate(bcMargin.GetPhysicalMargin(wm)); } nsOverflowAreas overflowAreas(bounds, bounds); nsLayoutUtils::UnionChildOverflow(this, overflowAreas); return FinishAndStoreOverflow(overflowAreas, GetSize()); } @@ -2118,31 +2123,32 @@ nsTableFrame::PushChildren(const RowGrou SetOverflowFrames(frames); } } // collapsing row groups, rows, col groups and cols are accounted for after both passes of // reflow so that it has no effect on the calculations of reflow. void nsTableFrame::AdjustForCollapsingRowsCols(nsHTMLReflowMetrics& aDesiredSize, - nsMargin aBorderPadding) + const WritingMode aWM, + const LogicalMargin& aBorderPadding) { nscoord yTotalOffset = 0; // total offset among all rows in all row groups // reset the bit, it will be set again if row/rowgroup or col/colgroup are // collapsed SetNeedToCollapse(false); // collapse the rows and/or row groups as necessary // Get the ordered children RowGroupArray rowGroups; OrderRowGroups(rowGroups); nsTableFrame* firstInFlow = static_cast<nsTableFrame*>(FirstInFlow()); - nscoord width = firstInFlow->GetCollapsedWidth(aBorderPadding); + nscoord width = firstInFlow->GetCollapsedWidth(aWM, aBorderPadding); nscoord rgWidth = width - GetColSpacing(-1) - GetColSpacing(GetColCount()); nsOverflowAreas overflow; // Walk the list of children for (uint32_t childX = 0; childX < rowGroups.Length(); childX++) { nsTableRowGroupFrame* rgFrame = rowGroups[childX]; NS_ASSERTION(rgFrame, "Must have row group frame here"); yTotalOffset += rgFrame->CollapseRowGroupIfNecessary(yTotalOffset, rgWidth); @@ -2153,21 +2159,22 @@ nsTableFrame::AdjustForCollapsingRowsCol aDesiredSize.Width() = width; overflow.UnionAllWith(nsRect(0, 0, aDesiredSize.Width(), aDesiredSize.Height())); FinishAndStoreOverflow(overflow, nsSize(aDesiredSize.Width(), aDesiredSize.Height())); } nscoord -nsTableFrame::GetCollapsedWidth(nsMargin aBorderPadding) +nsTableFrame::GetCollapsedWidth(const WritingMode aWM, + const LogicalMargin& aBorderPadding) { NS_ASSERTION(!GetPrevInFlow(), "GetCollapsedWidth called on next in flow"); nscoord width = GetColSpacing(GetColCount()); - width += aBorderPadding.left + aBorderPadding.right; + width += aBorderPadding.IStartEnd(aWM); for (nsIFrame* groupFrame : mColGroups) { const nsStyleVisibility* groupVis = groupFrame->StyleVisibility(); bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible); nsTableColGroupFrame* cgFrame = (nsTableColGroupFrame*)groupFrame; for (nsTableColFrame* colFrame = cgFrame->GetFirstColumn(); colFrame; colFrame = colFrame->GetNextCol()) { const nsStyleDisplay* colDisplay = colFrame->StyleDisplay(); int32_t colX = colFrame->GetColIndex(); @@ -2545,17 +2552,18 @@ nsTableFrame::RemoveFrame(ChildListID } /* virtual */ nsMargin nsTableFrame::GetUsedBorder() const { if (!IsBorderCollapse()) return nsContainerFrame::GetUsedBorder(); - return GetIncludedOuterBCBorder(); + WritingMode wm = GetWritingMode(); + return GetIncludedOuterBCBorder(wm).GetPhysicalMargin(wm); } /* virtual */ nsMargin nsTableFrame::GetUsedPadding() const { if (!IsBorderCollapse()) return nsContainerFrame::GetUsedPadding(); @@ -2590,84 +2598,82 @@ static void DivideBCBorderSize(BCPixelSize aPixelSize, BCPixelSize& aSmallHalf, BCPixelSize& aLargeHalf) { aSmallHalf = aPixelSize / 2; aLargeHalf = aPixelSize - aSmallHalf; } -nsMargin -nsTableFrame::GetOuterBCBorder() const +LogicalMargin +nsTableFrame::GetOuterBCBorder(const WritingMode aWM) const { if (NeedToCalcBCBorders()) const_cast<nsTableFrame*>(this)->CalcBCBorders(); - nsMargin border(0, 0, 0, 0); int32_t p2t = nsPresContext::AppUnitsPerCSSPixel(); BCPropertyData* propData = GetBCProperty(); if (propData) { - border.top = BC_BORDER_START_HALF_COORD(p2t, propData->mTopBorderWidth); - border.right = BC_BORDER_END_HALF_COORD(p2t, propData->mRightBorderWidth); - border.bottom = BC_BORDER_END_HALF_COORD(p2t, propData->mBottomBorderWidth); - border.left = BC_BORDER_START_HALF_COORD(p2t, propData->mLeftBorderWidth); - } - return border; -} - -nsMargin -nsTableFrame::GetIncludedOuterBCBorder() const + return LogicalMargin( + aWM, + BC_BORDER_START_HALF_COORD(p2t, propData->mTopBorderWidth), + BC_BORDER_END_HALF_COORD(p2t, propData->mRightBorderWidth), + BC_BORDER_END_HALF_COORD(p2t, propData->mBottomBorderWidth), + BC_BORDER_START_HALF_COORD(p2t, propData->mLeftBorderWidth)); + } + return LogicalMargin(GetWritingMode()); +} + +LogicalMargin +nsTableFrame::GetIncludedOuterBCBorder(const WritingMode aWM) const { if (NeedToCalcBCBorders()) const_cast<nsTableFrame*>(this)->CalcBCBorders(); - nsMargin border(0, 0, 0, 0); int32_t p2t = nsPresContext::AppUnitsPerCSSPixel(); BCPropertyData* propData = GetBCProperty(); if (propData) { - border.top += BC_BORDER_START_HALF_COORD(p2t, propData->mTopBorderWidth); - border.right += BC_BORDER_END_HALF_COORD(p2t, propData->mRightCellBorderWidth); - border.bottom += BC_BORDER_END_HALF_COORD(p2t, propData->mBottomBorderWidth); - border.left += BC_BORDER_START_HALF_COORD(p2t, propData->mLeftCellBorderWidth); - } - return border; -} - -nsMargin -nsTableFrame::GetExcludedOuterBCBorder() const -{ - return GetOuterBCBorder() - GetIncludedOuterBCBorder(); -} - -static -void GetSeparateModelBorderPadding(const nsHTMLReflowState* aReflowState, - nsStyleContext& aStyleContext, - nsMargin& aBorderPadding) + return LogicalMargin( + aWM, + BC_BORDER_START_HALF_COORD(p2t, propData->mTopBorderWidth), + BC_BORDER_END_HALF_COORD(p2t, propData->mRightCellBorderWidth), + BC_BORDER_END_HALF_COORD(p2t, propData->mBottomBorderWidth), + BC_BORDER_START_HALF_COORD(p2t, propData->mLeftCellBorderWidth)); + } + return LogicalMargin(GetWritingMode()); +} + +LogicalMargin +nsTableFrame::GetExcludedOuterBCBorder(const WritingMode aWM) const +{ + return GetOuterBCBorder(aWM) - GetIncludedOuterBCBorder(aWM); +} + +static LogicalMargin +GetSeparateModelBorderPadding(const WritingMode aWM, + const nsHTMLReflowState* aReflowState, + nsStyleContext* aStyleContext) { // XXXbz Either we _do_ have a reflow state and then we can use its // mComputedBorderPadding or we don't and then we get the padding // wrong! - const nsStyleBorder* border = aStyleContext.StyleBorder(); - aBorderPadding = border->GetComputedBorder(); + const nsStyleBorder* border = aStyleContext->StyleBorder(); + LogicalMargin borderPadding(aWM, border->GetComputedBorder()); if (aReflowState) { - aBorderPadding += aReflowState->ComputedPhysicalPadding(); - } -} - -nsMargin -nsTableFrame::GetChildAreaOffset(const nsHTMLReflowState* aReflowState) const -{ - nsMargin offset(0,0,0,0); - if (IsBorderCollapse()) { - offset = GetIncludedOuterBCBorder(); - } - else { - GetSeparateModelBorderPadding(aReflowState, *mStyleContext, offset); - } - return offset; + borderPadding += aReflowState->ComputedLogicalPadding(); + } + return borderPadding; +} + +LogicalMargin +nsTableFrame::GetChildAreaOffset(const WritingMode aWM, + const nsHTMLReflowState* aReflowState) const +{ + return IsBorderCollapse() ? GetIncludedOuterBCBorder(aWM) : + GetSeparateModelBorderPadding(aWM, aReflowState, mStyleContext); } void nsTableFrame::InitChildReflowState(nsHTMLReflowState& aReflowState) { nsMargin collapseBorder; nsMargin padding(0,0,0,0); nsMargin* pCollapseBorder = nullptr; @@ -3213,17 +3219,18 @@ nsTableFrame::CalcDesiredHeight(const ns nsHTMLReflowMetrics& aDesiredSize) { nsTableCellMap* cellMap = GetCellMap(); if (!cellMap) { NS_ERROR("never ever call me until the cell map is built!"); aDesiredSize.Height() = 0; return; } - nsMargin borderPadding = GetChildAreaOffset(&aReflowState); + WritingMode wm = aReflowState.GetWritingMode(); + LogicalMargin borderPadding = GetChildAreaOffset(wm, &aReflowState); // get the natural height based on the last child's (row group) rect RowGroupArray rowGroups; OrderRowGroups(rowGroups); if (rowGroups.IsEmpty()) { // tables can be used as rectangular items without content nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState); if ((NS_UNCONSTRAINEDSIZE != tableSpecifiedHeight) && @@ -3233,17 +3240,17 @@ nsTableFrame::CalcDesiredHeight(const ns aDesiredSize.Height() = tableSpecifiedHeight; } else aDesiredSize.Height() = 0; return; } int32_t rowCount = cellMap->GetRowCount(); int32_t colCount = cellMap->GetColCount(); - nscoord desiredHeight = borderPadding.top + borderPadding.bottom; + nscoord desiredHeight = borderPadding.BStartEnd(wm); if (rowCount > 0 && colCount > 0) { desiredHeight += GetRowSpacing(-1); for (uint32_t rgX = 0; rgX < rowGroups.Length(); rgX++) { desiredHeight += rowGroups[rgX]->GetSize().height + GetRowSpacing(rowGroups[rgX]->GetRowCount() + rowGroups[rgX]->GetStartRowIndex()); } } @@ -3296,27 +3303,28 @@ void ResizeCells(nsTableFrame& aTableFra } aTableFrame.FinishAndStoreOverflow(&tableDesiredSize); } void nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, nscoord aAmount) { - nsMargin borderPadding = GetChildAreaOffset(&aReflowState); + WritingMode wm = aReflowState.GetWritingMode(); + LogicalMargin borderPadding = GetChildAreaOffset(wm, &aReflowState); RowGroupArray rowGroups; OrderRowGroups(rowGroups); nscoord amountUsed = 0; // distribute space to each pct height row whose row group doesn't have a computed // height, and base the pct on the table height. If the row group had a computed // height, then this was already done in nsTableRowGroupFrame::CalculateRowHeights nscoord pctBasis = aReflowState.ComputedHeight() - GetRowSpacing(-1, GetRowCount()); - nscoord yOriginRG = borderPadding.top + GetRowSpacing(0); + nscoord yOriginRG = borderPadding.BStart(wm) + GetRowSpacing(0); nscoord yEndRG = yOriginRG; uint32_t rgX; for (rgX = 0; rgX < rowGroups.Length(); rgX++) { nsTableRowGroupFrame* rgFrame = rowGroups[rgX]; nscoord amountUsedByRG = 0; nscoord yOriginRow = 0; nsRect rgNormalRect = rgFrame->GetNormalRect(); if (!rgFrame->HasStyleHeight()) { @@ -3444,17 +3452,17 @@ nsTableFrame::DistributeHeightToRows(con else { NS_ERROR("invalid divisor"); return; } } } // allocate the extra height to the unstyled row groups and rows nscoord heightToDistribute = aAmount - amountUsed; - yOriginRG = borderPadding.top + GetRowSpacing(-1); + yOriginRG = borderPadding.BStart(wm) + GetRowSpacing(-1); yEndRG = yOriginRG; for (rgX = 0; rgX < rowGroups.Length(); rgX++) { nsTableRowGroupFrame* rgFrame = rowGroups[rgX]; nscoord amountUsedByRG = 0; nscoord yOriginRow = 0; nsRect rgNormalRect = rgFrame->GetNormalRect(); nsRect rgVisualOverflow = rgFrame->GetVisualOverflowRect(); // see if there is an eligible row group or we distribute to all rows @@ -3721,18 +3729,19 @@ nsTableFrame::IsAutoHeight() height.GetPercentValue() <= 0.0f); } nscoord nsTableFrame::CalcBorderBoxHeight(const nsHTMLReflowState& aState) { nscoord height = aState.ComputedHeight(); if (NS_AUTOHEIGHT != height) { - nsMargin borderPadding = GetChildAreaOffset(&aState); - height += borderPadding.top + borderPadding.bottom; + WritingMode wm = aState.GetWritingMode(); + LogicalMargin borderPadding = GetChildAreaOffset(wm, &aState); + height += borderPadding.BStartEnd(wm); } height = std::max(0, height); return height; } bool nsTableFrame::IsAutoLayout() @@ -6381,19 +6390,20 @@ private: BCPaintBorderIterator::BCPaintBorderIterator(nsTableFrame* aTable) : mTable(aTable) , mTableFirstInFlow(static_cast<nsTableFrame*>(aTable->FirstInFlow())) , mTableCellMap(aTable->GetCellMap()) , mTableWM(aTable->StyleContext()) { mVerInfo = nullptr; - nsMargin childAreaOffset = mTable->GetChildAreaOffset(nullptr); + LogicalMargin childAreaOffset = mTable->GetChildAreaOffset(mTableWM, nullptr); // y position of first row in damage area - mInitialOffsetY = mTable->GetPrevInFlow() ? 0 : childAreaOffset.top; + mInitialOffsetY = + mTable->GetPrevInFlow() ? 0 : childAreaOffset.BStart(mTableWM); mNumTableRows = mTable->GetRowCount(); mNumTableCols = mTable->GetColCount(); // Get the ordered row groups mTable->OrderRowGroups(mRowGroups); // initialize to a non existing index mRepeatedHeaderRowIndex = -99; @@ -6460,25 +6470,26 @@ BCPaintBorderIterator::SetDamageArea(con if (!haveIntersect) return false; // find startColIndex, endColIndex, startColX haveIntersect = false; if (0 == mNumTableCols) return false; int32_t leftCol, rightCol; // columns are in the range [leftCol, rightCol) - nsMargin childAreaOffset = mTable->GetChildAreaOffset(nullptr); + LogicalMargin childAreaOffset = mTable->GetChildAreaOffset(mTableWM, nullptr); if (mTableWM.IsBidiLTR()) { - mInitialOffsetX = childAreaOffset.left; // x position of first col in - // damage area + // x position of first col in damage area + mInitialOffsetX = childAreaOffset.IStart(mTableWM); leftCol = 0; rightCol = mNumTableCols; } else { // x position of first col in damage area - mInitialOffsetX = mTable->GetRect().width - childAreaOffset.right; + mInitialOffsetX = + mTable->GetRect().width - childAreaOffset.IStart(mTableWM); leftCol = mNumTableCols-1; rightCol = -1; } nscoord x = 0; int32_t colX; for (colX = leftCol; colX != rightCol; colX += mColInc) { nsTableColFrame* colFrame = mTableFirstInFlow->GetColFrame(colX); if (!colFrame) ABORT1(false); @@ -6504,17 +6515,18 @@ BCPaintBorderIterator::SetDamageArea(con else { mInitialOffsetX += mColInc * size.width; } } x += size.width; } if (!mTableWM.IsBidiLTR()) { uint32_t temp; - mInitialOffsetX = mTable->GetRect().width - childAreaOffset.right; + mInitialOffsetX = + mTable->GetRect().width - childAreaOffset.IStart(mTableWM); temp = startColIndex; startColIndex = endColIndex; endColIndex = temp; for (uint32_t column = 0; column < startColIndex; column++) { nsTableColFrame* colFrame = mTableFirstInFlow->GetColFrame(column); if (!colFrame) ABORT1(false); nsSize size = colFrame->GetSize(); mInitialOffsetX += mColInc * size.width; } }
--- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -20,16 +20,20 @@ class nsTableCellFrame; class nsTableCellMap; class nsTableColFrame; class nsTableRowGroupFrame; class nsTableRowFrame; class nsTableColGroupFrame; class nsITableLayoutStrategy; class nsStyleContext; +namespace mozilla { +class WritingMode; +class LogicalMargin; +} struct nsTableReflowState; struct BCPropertyData; static inline bool IS_TABLE_CELL(nsIAtom* frameType) { return nsGkAtoms::tableCellFrame == frameType || nsGkAtoms::bcTableCellFrame == frameType; } @@ -118,16 +122,18 @@ enum nsTableColType { * stand-alone as the top-level frame. * * The principal child list contains row group frames. There is also an * additional child list, kColGroupList, which contains the col group frames. */ class nsTableFrame : public nsContainerFrame { typedef mozilla::image::DrawResult DrawResult; + typedef mozilla::WritingMode WritingMode; + typedef mozilla::LogicalMargin LogicalMargin; public: NS_DECL_QUERYFRAME_TARGET(nsTableFrame) NS_DECL_FRAMEARENA_HELPERS NS_DECLARE_FRAME_PROPERTY(PositionedTablePartArray, DeleteValue<nsTArray<nsIFrame*>>) @@ -201,17 +207,18 @@ public: virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override; virtual nsMargin GetUsedBorder() const override; virtual nsMargin GetUsedPadding() const override; virtual nsMargin GetUsedMargin() const override; // Get the offset from the border box to the area where the row groups fit - nsMargin GetChildAreaOffset(const nsHTMLReflowState* aReflowState) const; + LogicalMargin GetChildAreaOffset(const WritingMode aWM, + const nsHTMLReflowState* aReflowState) const; /** helper method to find the table parent of any table frame object */ static nsTableFrame* GetTableFrame(nsIFrame* aSourceFrame); /* Like GetTableFrame, but will return nullptr if we don't pass through * aMustPassThrough on the way to the table. */ static nsTableFrame* GetTableFramePassingThrough(nsIFrame* aMustPassThrough, @@ -268,28 +275,28 @@ public: DrawResult PaintTableBorderBackground(nsRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsPoint aPt, uint32_t aBGPaintFlags); /** Get the outer half (i.e., the part outside the height and width of * the table) of the largest segment (?) of border-collapsed border on * the table on each side, or 0 for non border-collapsed tables. */ - nsMargin GetOuterBCBorder() const; + LogicalMargin GetOuterBCBorder(const WritingMode aWM) const; /** Same as above, but only if it's included from the border-box width * of the table. */ - nsMargin GetIncludedOuterBCBorder() const; + LogicalMargin GetIncludedOuterBCBorder(const WritingMode aWM) const; /** Same as above, but only if it's excluded from the border-box width * of the table. This is the area that leaks out into the margin * (or potentially past it, if there is no margin). */ - nsMargin GetExcludedOuterBCBorder() const; + LogicalMargin GetExcludedOuterBCBorder(const WritingMode aWM) const; /** * In quirks mode, the size of the table background is reduced * by the outer BC border. Compute the reduction needed. */ nsMargin GetDeflationForBackground(nsPresContext* aPresContext) const; /** Get width of table + colgroup + col collapse: elements that @@ -627,26 +634,28 @@ protected: // (1) set all the dimensions to 0 // (2) notify the table about colgroups or columns with hidden visibility void ReflowColGroups(nsRenderingContext* aRenderingContext); /** return the width of the table taking into account visibility collapse * on columns and colgroups * @param aBorderPadding the border and padding of the table */ - nscoord GetCollapsedWidth(nsMargin aBorderPadding); + nscoord GetCollapsedWidth(const WritingMode aWM, + const LogicalMargin& aBorderPadding); /** Adjust the table for visibility.collapse set on rowgroups, rows, * colgroups and cols * @param aDesiredSize the metrics of the table * @param aBorderPadding the border and padding of the table */ void AdjustForCollapsingRowsCols(nsHTMLReflowMetrics& aDesiredSize, - nsMargin aBorderPadding); + const WritingMode aWM, + const LogicalMargin& aBorderPadding); /** FixupPositionedTableParts is called at the end of table reflow to reflow * the absolutely positioned descendants of positioned table parts. This is * necessary because the dimensions of table parts may change after they've * been reflowed (e.g. in AdjustForCollapsingRowsCols). */ void FixupPositionedTableParts(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -796,18 +805,18 @@ protected: void SetBorderCollapse(bool aValue); BCPropertyData* GetBCProperty(bool aCreateIfNecessary = false) const; void SetFullBCDamageArea(); void CalcBCBorders(); void ExpandBCDamageArea(mozilla::TableArea& aRect) const; - void SetColumnDimensions(nscoord aHeight, - const nsMargin& aReflowState); + void SetColumnDimensions(nscoord aHeight, WritingMode aWM, + const LogicalMargin& aBorderPadding); int32_t CollectRows(nsIFrame* aFrame, nsTArray<nsTableRowFrame*>& aCollection); public: /* ----- Cell Map public methods ----- */ int32_t GetStartRowIndex(nsTableRowGroupFrame* aRowGroupFrame);
--- a/layout/tables/nsTableOuterFrame.cpp +++ b/layout/tables/nsTableOuterFrame.cpp @@ -237,17 +237,19 @@ nsTableOuterFrame::InitChildReflowState( { nsMargin collapseBorder; nsMargin collapsePadding(0,0,0,0); nsMargin* pCollapseBorder = nullptr; nsMargin* pCollapsePadding = nullptr; if (aReflowState.frame == InnerTableFrame() && InnerTableFrame()->IsBorderCollapse()) { - collapseBorder = InnerTableFrame()->GetIncludedOuterBCBorder(); + WritingMode wm = aReflowState.GetWritingMode(); + LogicalMargin border = InnerTableFrame()->GetIncludedOuterBCBorder(wm); + collapseBorder = border.GetPhysicalMargin(wm); pCollapseBorder = &collapseBorder; pCollapsePadding = &collapsePadding; } aReflowState.Init(&aPresContext, nullptr, pCollapseBorder, pCollapsePadding); } // get the margin and padding data. nsHTMLReflowState doesn't handle the // case of auto margins
--- a/memory/mozjemalloc/jemalloc.c +++ b/memory/mozjemalloc/jemalloc.c @@ -6509,23 +6509,18 @@ malloc_good_size_impl(size_t size) * malloc_good_size(n). */ size = PAGE_CEILING(size); } return size; } -#if defined(MOZ_MEMORY_ANDROID) && (ANDROID_VERSION < 19) MOZ_MEMORY_API size_t -malloc_usable_size_impl(void *ptr) -#else -MOZ_MEMORY_API size_t -malloc_usable_size_impl(const void *ptr) -#endif +malloc_usable_size_impl(MALLOC_USABLE_SIZE_CONST_PTR void *ptr) { DARWIN_ONLY(return (szone->size)(szone, ptr)); #ifdef MALLOC_VALIDATE return (isalloc_validate(ptr)); #else assert(ptr != NULL);
--- a/memory/replace/dummy/moz.build +++ b/memory/replace/dummy/moz.build @@ -4,11 +4,11 @@ # 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/. DIST_INSTALL = False SOURCES += [ 'dummy_replace_malloc.c', ] -SharedLibrary('replace_malloc') +SharedLibrary('dummy_replace_malloc') DISABLE_STL_WRAPPING = True
--- a/mobile/android/base/BrowserLocaleManager.java +++ b/mobile/android/base/BrowserLocaleManager.java @@ -395,17 +395,17 @@ public class BrowserLocaleManager implem * "pt-PT", "ro", "ru", "sk", "sl", "sv-SE", "th", * "tr", "uk", "zh-CN", "zh-TW", "en-US"]} * </code> */ public static Collection<String> getPackagedLocaleTags(final Context context) { final String resPath = "res/multilocale.json"; final String jarURL = GeckoJarReader.getJarURL(context, resPath); - final String contents = GeckoJarReader.getText(jarURL); + final String contents = GeckoJarReader.getText(context, jarURL); if (contents == null) { // GeckoJarReader logs and swallows exceptions. return null; } try { final JSONObject multilocale = new JSONObject(contents); final JSONArray locales = multilocale.getJSONArray("locales");
--- a/mobile/android/base/GeckoApplication.java +++ b/mobile/android/base/GeckoApplication.java @@ -6,17 +6,16 @@ package org.mozilla.gecko; import org.mozilla.gecko.AdjustConstants; import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.db.BrowserContract; import org.mozilla.gecko.db.BrowserDB; import org.mozilla.gecko.db.LocalBrowserDB; import org.mozilla.gecko.home.HomePanelsManager; import org.mozilla.gecko.lwt.LightweightTheme; -import org.mozilla.gecko.mozglue.GeckoLoader; import org.mozilla.gecko.util.Clipboard; import org.mozilla.gecko.util.HardwareUtils; import org.mozilla.gecko.util.ThreadUtils; import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; @@ -122,17 +121,16 @@ public class GeckoApplication extends Ap } @Override public void onCreate() { final Context context = getApplicationContext(); HardwareUtils.init(context); Clipboard.init(context); FilePicker.init(context); - GeckoLoader.loadMozGlue(context); DownloadsIntegration.init(); HomePanelsManager.getInstance().init(context); // This getInstance call will force initialization of the NotificationHelper, but does nothing with the result NotificationHelper.getInstance(context).init(); // Make sure that all browser-ish applications default to the real LocalBrowserDB. // GeckoView consumers use their own Application class, so this doesn't affect them.
--- a/mobile/android/base/GeckoThread.java +++ b/mobile/android/base/GeckoThread.java @@ -85,16 +85,18 @@ public class GeckoThread extends Thread public static boolean isLaunched() { return !checkLaunchState(LaunchState.Launching); } private String initGeckoEnvironment() { final Locale locale = Locale.getDefault(); final Context context = GeckoAppShell.getContext(); + GeckoLoader.loadMozGlue(context); + final Resources res = context.getResources(); if (locale.toString().equalsIgnoreCase("zh_hk")) { final Locale mappedLocale = Locale.TRADITIONAL_CHINESE; Locale.setDefault(mappedLocale); Configuration config = res.getConfiguration(); config.locale = mappedLocale; res.updateConfiguration(config, null); }
--- a/mobile/android/base/GeckoView.java +++ b/mobile/android/base/GeckoView.java @@ -114,16 +114,24 @@ public class GeckoView extends LayerView TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GeckoView); String url = a.getString(R.styleable.GeckoView_url); boolean doInit = a.getBoolean(R.styleable.GeckoView_doinit, true); a.recycle(); init(context, url, doInit); } private void init(Context context, String url, boolean doInit) { + + // Set the GeckoInterface if the context is an activity and the GeckoInterface + // has not already been set + if (context instanceof Activity && getGeckoInterface() == null) { + setGeckoInterface(new BaseGeckoInterface(context)); + GeckoAppShell.setContextGetter(this); + } + // Perform common initialization for Fennec/GeckoView. GeckoAppShell.setLayerView(this); initializeView(EventDispatcher.getInstance()); GeckoAppShell.sendEventToGecko(GeckoEvent.createObjectEvent( GeckoEvent.ACTION_OBJECT_LAYER_CLIENT, getLayerClientObject())); // TODO: Fennec currently takes care of its own initialization, so this @@ -136,40 +144,31 @@ public class GeckoView extends LayerView // If running outside of a GeckoActivity (eg, from a library project), // load the native code and disable content providers boolean isGeckoActivity = false; try { isGeckoActivity = context instanceof GeckoActivity; } catch (NoClassDefFoundError ex) {} if (!isGeckoActivity) { - // Set the GeckoInterface if the context is an activity and the GeckoInterface - // has not already been set - if (context instanceof Activity && getGeckoInterface() == null) { - setGeckoInterface(new BaseGeckoInterface(context)); - } - Clipboard.init(context); HardwareUtils.init(context); // If you want to use GeckoNetworkManager, start it. - GeckoLoader.loadMozGlue(context); - final GeckoProfile profile = GeckoProfile.get(context); } if (url != null) { GeckoThread.ensureInit(null, Intent.ACTION_VIEW, url); GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(url)); } else { GeckoThread.ensureInit(null, null, null); } - GeckoAppShell.setContextGetter(this); if (context instanceof Activity) { Tabs tabs = Tabs.getInstance(); tabs.attachToContext(context); } EventDispatcher.getInstance().registerGeckoThreadListener(mGeckoEventListener, "Gecko:Ready", "Accessibility:Event",
--- a/mobile/android/base/db/LocalBrowserDB.java +++ b/mobile/android/base/db/LocalBrowserDB.java @@ -478,17 +478,17 @@ public class LocalBrowserDB implements B */ private static ConsumedInputStream getDefaultFaviconFromPath(Context context, String name) { final int faviconId = getFaviconId(name); if (faviconId == FAVICON_ID_NOT_FOUND) { return null; } final String bitmapPath = GeckoJarReader.getJarURL(context, context.getString(faviconId)); - final InputStream iStream = GeckoJarReader.getStream(bitmapPath); + final InputStream iStream = GeckoJarReader.getStream(context, bitmapPath); return IOUtils.readFully(iStream, DEFAULT_FAVICON_BUFFER_SIZE); } private static ConsumedInputStream getDefaultFaviconFromDrawable(Context context, String name) { int faviconId = getFaviconId(name); if (faviconId == FAVICON_ID_NOT_FOUND) { return null;
--- a/mobile/android/base/favicons/Favicons.java +++ b/mobile/android/base/favicons/Favicons.java @@ -489,17 +489,18 @@ public class Favicons { * Compute a string like: * "jar:jar:file:///data/app/org.mozilla.firefox-1.apk!/assets/omni.ja!/chrome/chrome/content/branding/favicon64.png" */ private static String getBrandingBitmapPath(Context context, String name) { return GeckoJarReader.getJarURL(context, "chrome/chrome/content/branding/" + name); } private static Bitmap loadBrandingBitmap(Context context, String name) { - Bitmap b = GeckoJarReader.getBitmap(context.getResources(), + Bitmap b = GeckoJarReader.getBitmap(context, + context.getResources(), getBrandingBitmapPath(context, name)); if (b == null) { throw new IllegalStateException("Bitmap " + name + " missing from JAR!"); } return b; } /**
--- a/mobile/android/base/favicons/LoadFaviconTask.java +++ b/mobile/android/base/favicons/LoadFaviconTask.java @@ -191,17 +191,17 @@ public class LoadFaviconTask { */ private Bitmap fetchJARFavicon(String uri) { if (uri == null) { return null; } if (uri.startsWith("jar:jar:")) { Log.d(LOGTAG, "Fetching favicon from JAR."); try { - return GeckoJarReader.getBitmap(context.getResources(), uri); + return GeckoJarReader.getBitmap(context, context.getResources(), uri); } catch (Exception e) { // Just about anything could happen here. Log.w(LOGTAG, "Error fetching favicon from JAR.", e); return null; } } return null; }
--- a/mobile/android/base/gfx/BitmapUtils.java +++ b/mobile/android/base/gfx/BitmapUtils.java @@ -81,22 +81,24 @@ public final class BitmapUtils { } if (data.startsWith("jar:") || data.startsWith("file://")) { (new UIAsyncTask.WithoutParams<Drawable>(ThreadUtils.getBackgroundHandler()) { @Override public Drawable doInBackground() { try { if (data.startsWith("jar:jar")) { - return GeckoJarReader.getBitmapDrawable(context.getResources(), data); + return GeckoJarReader.getBitmapDrawable( + context, context.getResources(), data); } // Don't attempt to validate the JAR signature when loading an add-on icon if (data.startsWith("jar:file")) { - return GeckoJarReader.getBitmapDrawable(context.getResources(), Uri.decode(data)); + return GeckoJarReader.getBitmapDrawable( + context, context.getResources(), Uri.decode(data)); } final URL url = new URL(data); final InputStream is = (InputStream) url.getContent(); try { return Drawable.createFromStream(is, "src"); } finally { is.close();
--- a/mobile/android/base/gfx/BufferedImage.java +++ b/mobile/android/base/gfx/BufferedImage.java @@ -10,49 +10,58 @@ import org.mozilla.gecko.mozglue.DirectB import android.graphics.Bitmap; import android.util.Log; import java.nio.ByteBuffer; /** A buffered image that simply saves a buffer of pixel data. */ public class BufferedImage { private ByteBuffer mBuffer; + private Bitmap mBitmap; private IntSize mSize; private int mFormat; private static final String LOGTAG = "GeckoBufferedImage"; /** Creates an empty buffered image */ public BufferedImage() { mSize = new IntSize(0, 0); } /** Creates a buffered image from an Android bitmap. */ public BufferedImage(Bitmap bitmap) { mFormat = bitmapConfigToFormat(bitmap.getConfig()); mSize = new IntSize(bitmap.getWidth(), bitmap.getHeight()); - - int bpp = bitsPerPixelForFormat(mFormat); - mBuffer = DirectBufferAllocator.allocate(mSize.getArea() * bpp); - bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer()); + mBitmap = bitmap; } private synchronized void freeBuffer() { - mBuffer = DirectBufferAllocator.free(mBuffer); + if (mBuffer != null) { + mBuffer = DirectBufferAllocator.free(mBuffer); + } } public void destroy() { try { freeBuffer(); } catch (Exception ex) { Log.e(LOGTAG, "error clearing buffer: ", ex); } } - public ByteBuffer getBuffer() { return mBuffer; } + public ByteBuffer getBuffer() { + if (mBuffer == null) { + int bpp = bitsPerPixelForFormat(mFormat); + mBuffer = DirectBufferAllocator.allocate(mSize.getArea() * bpp); + mBitmap.copyPixelsToBuffer(mBuffer.asIntBuffer()); + mBitmap = null; + } + return mBuffer; + } + public IntSize getSize() { return mSize; } public int getFormat() { return mFormat; } public static final int FORMAT_INVALID = -1; public static final int FORMAT_ARGB32 = 0; public static final int FORMAT_RGB24 = 1; public static final int FORMAT_A8 = 2; public static final int FORMAT_A1 = 3;
--- a/mobile/android/base/gfx/LayerRenderer.java +++ b/mobile/android/base/gfx/LayerRenderer.java @@ -156,22 +156,16 @@ public class LayerRenderer implements Ta mVertScrollLayer = new ScrollbarLayer(this, scrollbarImage, size, true); mHorizScrollLayer = new ScrollbarLayer(this, diagonalFlip(scrollbarImage), new IntSize(size.height, size.width), false); mFadeRunnable = new FadeRunnable(); mFrameTimings = new int[60]; mCurrentFrame = mFrameTimingsSum = mDroppedFrames = 0; - // Initialize the FloatBuffer that will be used to store all vertices and texture - // coordinates in draw() commands. - mCoordByteBuffer = DirectBufferAllocator.allocate(COORD_BUFFER_SIZE * 4); - mCoordByteBuffer.order(ByteOrder.nativeOrder()); - mCoordBuffer = mCoordByteBuffer.asFloatBuffer(); - Tabs.registerOnTabsChangedListener(this); mZoomedViewListeners = new ArrayList<LayerView.ZoomedViewListener>(); } private Bitmap expandCanvasToPowerOfTwo(Bitmap image, IntSize size) { IntSize potSize = size.nextPowerOfTwo(); if (size.equals(potSize)) { return image; @@ -185,19 +179,21 @@ public class LayerRenderer implements Ta private Bitmap diagonalFlip(Bitmap image) { Matrix rotation = new Matrix(); rotation.setValues(new float[] { 0, 1, 0, 1, 0, 0, 0, 0, 1 }); // transform (x,y) into (y,x) Bitmap rotated = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), rotation, true); return rotated; } public void destroy() { - DirectBufferAllocator.free(mCoordByteBuffer); - mCoordByteBuffer = null; - mCoordBuffer = null; + if (mCoordByteBuffer != null) { + DirectBufferAllocator.free(mCoordByteBuffer); + mCoordByteBuffer = null; + mCoordBuffer = null; + } mHorizScrollLayer.destroy(); mVertScrollLayer.destroy(); Tabs.unregisterOnTabsChangedListener(this); mZoomedViewListeners.clear(); } void onSurfaceCreated(EGLConfig config) { checkMonitoringEnabled(); @@ -343,20 +339,27 @@ public class LayerRenderer implements Ta RectF pageRect = metrics.getPageRect(); float zoomFactor = metrics.zoomFactor; return createContext(new RectF(RectUtils.round(viewport)), pageRect, zoomFactor, offset); } private RenderContext createContext(RectF viewport, RectF pageRect, float zoomFactor, PointF offset) { if (mCoordBuffer == null) { - throw new IllegalStateException(); + // Initialize the FloatBuffer that will be used to store all vertices and texture + // coordinates in draw() commands. + mCoordByteBuffer = DirectBufferAllocator.allocate(COORD_BUFFER_SIZE * 4); + mCoordByteBuffer.order(ByteOrder.nativeOrder()); + mCoordBuffer = mCoordByteBuffer.asFloatBuffer(); + if (mCoordBuffer == null) { + throw new IllegalStateException(); + } } - return new RenderContext(viewport, pageRect, zoomFactor, offset, mPositionHandle, mTextureHandle, - mCoordBuffer); + return new RenderContext(viewport, pageRect, zoomFactor, offset, + mPositionHandle, mTextureHandle, mCoordBuffer); } private void updateDroppedFrames(long frameStartTime) { int frameElapsedTime = (int)((System.nanoTime() - frameStartTime) / NANOS_PER_MS); /* Update the running statistics. */ mFrameTimingsSum -= mFrameTimings[mCurrentFrame]; mFrameTimingsSum += frameElapsedTime;
--- a/mobile/android/base/updater/UpdateServiceHelper.java +++ b/mobile/android/base/updater/UpdateServiceHelper.java @@ -98,17 +98,17 @@ public class UpdateServiceHelper { "-" + AppConstants.MOZ_PKG_SPECIAL : ""; String locale = DEFAULT_UPDATE_LOCALE; try { ApplicationInfo info = pm.getApplicationInfo(AppConstants.ANDROID_PACKAGE_NAME, 0); String updateLocaleUrl = "jar:jar:file://" + info.sourceDir + "!/" + AppConstants.OMNIJAR_NAME + "!/update.locale"; - final String jarLocale = GeckoJarReader.getText(updateLocaleUrl); + final String jarLocale = GeckoJarReader.getText(context, updateLocaleUrl); if (jarLocale != null) { locale = jarLocale.trim(); } } catch (android.content.pm.PackageManager.NameNotFoundException e) { // Shouldn't really be possible, but fallback to default locale Log.i(LOGTAG, "Failed to read update locale file, falling back to " + locale); }
--- a/mobile/android/base/util/GeckoJarReader.java +++ b/mobile/android/base/util/GeckoJarReader.java @@ -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/. */ package org.mozilla.gecko.util; import android.content.Context; import org.mozilla.gecko.AppConstants; +import org.mozilla.gecko.mozglue.GeckoLoader; import org.mozilla.gecko.mozglue.NativeZip; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.util.Log; import org.mozilla.gecko.mozglue.RobocopTarget; @@ -26,30 +27,31 @@ import java.util.Stack; /* Reads out of a multiple level deep jar file such as * jar:jar:file:///data/app/org.mozilla.fennec.apk!/omni.ja!/chrome/chrome/content/branding/favicon32.png */ public final class GeckoJarReader { private static final String LOGTAG = "GeckoJarReader"; private GeckoJarReader() {} - public static Bitmap getBitmap(Resources resources, String url) { - BitmapDrawable drawable = getBitmapDrawable(resources, url); + public static Bitmap getBitmap(Context context, Resources resources, String url) { + BitmapDrawable drawable = getBitmapDrawable(context, resources, url); return (drawable != null) ? drawable.getBitmap() : null; } - public static BitmapDrawable getBitmapDrawable(Resources resources, String url) { + public static BitmapDrawable getBitmapDrawable(Context context, Resources resources, + String url) { Stack<String> jarUrls = parseUrl(url); InputStream inputStream = null; BitmapDrawable bitmap = null; NativeZip zip = null; try { // Load the initial jar file as a zip - zip = getZipFile(jarUrls.pop()); + zip = getZipFile(context, jarUrls.pop()); inputStream = getStream(zip, jarUrls, url); if (inputStream != null) { bitmap = new BitmapDrawable(resources, inputStream); } } catch (IOException | URISyntaxException ex) { Log.e(LOGTAG, "Exception ", ex); } finally { if (inputStream != null) { @@ -62,24 +64,24 @@ public final class GeckoJarReader { if (zip != null) { zip.close(); } } return bitmap; } - public static String getText(String url) { + public static String getText(Context context, String url) { Stack<String> jarUrls = parseUrl(url); NativeZip zip = null; BufferedReader reader = null; String text = null; try { - zip = getZipFile(jarUrls.pop()); + zip = getZipFile(context, jarUrls.pop()); InputStream input = getStream(zip, jarUrls, url); if (input != null) { reader = new BufferedReader(new InputStreamReader(input)); text = reader.readLine(); } } catch (IOException | URISyntaxException ex) { Log.e(LOGTAG, "Exception ", ex); } finally { @@ -93,26 +95,28 @@ public final class GeckoJarReader { if (zip != null) { zip.close(); } } return text; } - private static NativeZip getZipFile(String url) throws IOException, URISyntaxException { + private static NativeZip getZipFile(Context context, String url) + throws IOException, URISyntaxException { URI fileUrl = new URI(url); + GeckoLoader.loadMozGlue(context); return new NativeZip(fileUrl.getPath()); } @RobocopTarget - public static InputStream getStream(String url) { + public static InputStream getStream(Context context, String url) { Stack<String> jarUrls = parseUrl(url); try { - NativeZip zip = getZipFile(jarUrls.pop()); + NativeZip zip = getZipFile(context, jarUrls.pop()); return getStream(zip, jarUrls, url); } catch (Exception ex) { // Some JNI code throws IllegalArgumentException on a bad file name; // swallow the error and return null. We could also see legitimate // IOExceptions here. Log.e(LOGTAG, "Exception getting input stream from jar URL: " + url, ex); return null; }
--- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -8,16 +8,17 @@ let Cc = Components.classes; let Ci = Components.interfaces; let Cu = Components.utils; let Cr = Components.results; Cu.import("resource://gre/modules/AppConstants.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/AddonManager.jsm"); +Cu.import("resource://gre/modules/DelayedInit.jsm"); Cu.import('resource://gre/modules/Payment.jsm'); Cu.import("resource://gre/modules/NotificationDB.jsm"); Cu.import("resource://gre/modules/SpatialNavigation.jsm"); if (AppConstants.ACCESSIBILITY) { Cu.import("resource://gre/modules/accessibility/AccessFu.jsm"); } @@ -370,51 +371,16 @@ var BrowserApp = { deck: null, startup: function startup() { window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = new nsBrowserAccess(); dump("zerdatime " + Date.now() + " - browser chrome startup finished."); this.deck = document.getElementById("browsers"); - this.deck.addEventListener("DOMContentLoaded", function BrowserApp_delayedStartup() { - try { - BrowserApp.deck.removeEventListener("DOMContentLoaded", BrowserApp_delayedStartup, false); - Services.obs.notifyObservers(window, "browser-delayed-startup-finished", ""); - Messaging.sendRequest({ type: "Gecko:DelayedStartup" }); - - // Queue up some other performance-impacting initializations - Services.tm.mainThread.dispatch(function() { - // Spin up some services which impact performance. - Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); - Services.search.init(); - - // Spin up some features which impact performance. - CastingApps.init(); - DownloadNotifications.init(); - - if (AppConstants.MOZ_SAFE_BROWSING) { - // Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008. - SafeBrowsing.init(); - }; - - // Delay this a minute because there's no rush - setTimeout(() => { - BrowserApp.gmpInstallManager = new GMPInstallManager(); - BrowserApp.gmpInstallManager.simpleCheckAndInstall().then(null, () => {}); - }, 1000 * 60); - }, Ci.nsIThread.DISPATCH_NORMAL); - - if (AppConstants.NIGHTLY_BUILD) { - WebcompatReporter.init(); - Telemetry.addData("TRACKING_PROTECTION_ENABLED", - Services.prefs.getBoolPref("privacy.trackingprotection.enabled")); - } - } catch(ex) { console.log(ex); } - }, false); BrowserEventHandler.init(); ViewportHandler.init(); Services.androidBridge.browserApp = this; Services.obs.addObserver(this, "Locale:OS", false); Services.obs.addObserver(this, "Locale:Changed", false); @@ -548,16 +514,50 @@ var BrowserApp = { // Tiles reporting is disabled. } let mm = window.getGroupMessageManager("browsers"); mm.loadFrameScript("chrome://browser/content/content.js", true); // Notify Java that Gecko has loaded. Messaging.sendRequest({ type: "Gecko:Ready" }); + + this.deck.addEventListener("DOMContentLoaded", function BrowserApp_delayedStartup() { + BrowserApp.deck.removeEventListener("DOMContentLoaded", BrowserApp_delayedStartup, false); + + function InitLater(fn, object, name) { + return DelayedInit.schedule(fn, object, name, 15000 /* 15s max wait */); + } + + InitLater(() => Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "")); + InitLater(() => Messaging.sendRequest({ type: "Gecko:DelayedStartup" })); + + if (AppConstants.NIGHTLY_BUILD) { + InitLater(() => Telemetry.addData("TRACKING_PROTECTION_ENABLED", + Services.prefs.getBoolPref("privacy.trackingprotection.enabled"))); + InitLater(() => WebcompatReporter.init()); + } + + InitLater(() => CastingApps.init(), window, "CastingApps"); + InitLater(() => Services.search.init(), Services, "search"); + InitLater(() => DownloadNotifications.init(), window, "DownloadNotifications"); + + if (AppConstants.MOZ_SAFE_BROWSING) { + // Bug 778855 - Perf regression if we do this here. To be addressed in bug 779008. + InitLater(() => SafeBrowsing.init(), window, "SafeBrowsing"); + } + + InitLater(() => Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager)); + + InitLater(() => { + BrowserApp.gmpInstallManager = new GMPInstallManager(); + BrowserApp.gmpInstallManager.simpleCheckAndInstall().then(null, () => {}); + }, BrowserApp, "gmpInstallManager"); + + }, false); }, get _startupStatus() { delete this._startupStatus; let savedMilestone = null; try { savedMilestone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone");
new file mode 100644 --- /dev/null +++ b/mobile/android/modules/DelayedInit.jsm @@ -0,0 +1,175 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict" + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +this.EXPORTED_SYMBOLS = ["DelayedInit"]; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyServiceGetter(this, "MessageLoop", + "@mozilla.org/message-loop;1", + "nsIMessageLoop"); + +/** + * Use DelayedInit to schedule initializers to run some time after startup. + * Initializers are added to a list of pending inits. Whenever the main thread + * message loop is idle, DelayedInit will start running initializers from the + * pending list. To prevent monopolizing the message loop, every idling period + * has a maximum duration. When that's reached, we give up the message loop and + * wait for the next idle. + * + * DelayedInit is compatible with lazy getters like those from XPCOMUtils. When + * the lazy getter is first accessed, its corresponding initializer is run + * automatically if it hasn't been run already. Each initializer also has a + * maximum wait parameter that specifies a mandatory timeout; when the timeout + * is reached, the initializer is forced to run. + * + * DelayedInit.schedule(() => Foo.init(), null, null, 5000); + * + * In the example above, Foo.init will run automatically when the message loop + * becomes idle, or when 5000ms has elapsed, whichever comes first. + * + * DelayedInit.schedule(() => Foo.init(), this, "Foo", 5000); + * + * In the example above, Foo.init will run automatically when the message loop + * becomes idle, when |this.Foo| is accessed, or when 5000ms has elapsed, + * whichever comes first. + * + * It may be simpler to have a wrapper for DelayedInit.schedule. For example, + * + * function InitLater(fn, obj, name) { + * return DelayedInit.schedule(fn, obj, name, 5000); // constant max wait + * } + * InitLater(() => Foo.init()); + * InitLater(() => Bar.init(), this, "Bar"); + */ +let DelayedInit = { + schedule: function (fn, object, name, maxWait) { + return Impl.scheduleInit(fn, object, name, maxWait); + }, +}; + +// Maximum duration for each idling period. Pending inits are run until this +// duration is exceeded; then we wait for next idling period. +const MAX_IDLE_RUN_MS = 50; + +let Impl = { + pendingInits: [], + + onIdle: function () { + let startTime = Cu.now(); + let time = startTime; + let nextDue; + + // Go through all the pending inits. Even if we don't run them, + // we still need to find out when the next timeout should be. + for (let init of this.pendingInits) { + if (init.complete) { + continue; + } + + if (time - startTime < MAX_IDLE_RUN_MS) { + init.maybeInit(); + time = Cu.now(); + } else { + // We ran out of time; find when the next closest due time is. + nextDue = nextDue ? Math.min(nextDue, init.due) : init.due; + } + } + + // Get rid of completed ones. + this.pendingInits = this.pendingInits.filter((init) => !init.complete); + + if (nextDue !== undefined) { + // Schedule the next idle, if we still have pending inits. + MessageLoop.postIdleTask(() => this.onIdle(), + Math.max(0, nextDue - time)); + } + }, + + addPendingInit: function (fn, wait) { + let init = { + fn: fn, + due: Cu.now() + wait, + complete: false, + maybeInit: function () { + if (this.complete) { + return false; + } + this.complete = true; + this.fn.call(); + this.fn = null; + return true; + }, + }; + + if (!this.pendingInits.length) { + // Schedule for the first idle. + MessageLoop.postIdleTask(() => this.onIdle(), wait); + } + this.pendingInits.push(init); + return init; + }, + + scheduleInit: function (fn, object, name, wait) { + let init = this.addPendingInit(fn, wait); + + if (!object || !name) { + // No lazy getter needed. + return; + } + + // Get any existing information about the property. + let prop = Object.getOwnPropertyDescriptor(object, name) || + { configurable: true, enumerable: true, writable: true }; + + if (!prop.configurable) { + // Object.defineProperty won't work, so just perform init here. + init.maybeInit(); + return; + } + + // Define proxy getter/setter that will call first initializer first, + // before delegating the get/set to the original target. + Object.defineProperty(object, name, { + get: function proxy_getter() { + init.maybeInit(); + + // If the initializer actually ran, it may have replaced our proxy + // property with a real one, so we need to reload he property. + let newProp = Object.getOwnPropertyDescriptor(object, name); + if (newProp.get !== proxy_getter) { + // Set prop if newProp doesn't refer to our proxy property. + prop = newProp; + } else { + // Otherwise, reset to the original property. + Object.defineProperty(object, name, prop); + } + + if (prop.get) { + return prop.get.call(object); + } + return prop.value; + }, + set: function (newVal) { + init.maybeInit(); + + // Since our initializer already ran, + // we can get rid of our proxy property. + if (prop.get || prop.set) { + Object.defineProperty(object, name, prop); + return prop.set.call(object); + } + + prop.value = newVal; + Object.defineProperty(object, name, prop); + return newVal; + }, + configurable: true, + enumerable: true, + }); + } +};
--- a/mobile/android/modules/moz.build +++ b/mobile/android/modules/moz.build @@ -4,16 +4,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/. EXTRA_JS_MODULES += [ 'Accounts.jsm', 'AndroidLog.jsm', 'ContactService.jsm', 'dbg-browser-actors.js', + 'DelayedInit.jsm', 'DownloadNotifications.jsm', 'HelperApps.jsm', 'Home.jsm', 'HomeProvider.jsm', 'JNI.jsm', 'LightweightThemeConsumer.jsm', 'MatchstickApp.jsm', 'MediaPlayerApp.jsm',
--- a/mobile/android/search/java/org/mozilla/search/providers/SearchEngineManager.java +++ b/mobile/android/search/java/org/mozilla/search/providers/SearchEngineManager.java @@ -614,48 +614,49 @@ public class SearchEngineManager impleme */ private InputStream getInputStreamFromSearchPluginsJar(String fileName) { final Locale locale = Locale.getDefault(); // First, try a file path for the full locale. final String languageTag = Locales.getLanguageTag(locale); String url = getSearchPluginsJarURL(context, languageTag, fileName); - InputStream in = GeckoJarReader.getStream(url); + InputStream in = GeckoJarReader.getStream(context, url); if (in != null) { return in; } // If that doesn't work, try a file path for just the language. final String language = Locales.getLanguage(locale); if (!languageTag.equals(language)) { url = getSearchPluginsJarURL(context, language, fileName); - in = GeckoJarReader.getStream(url); + in = GeckoJarReader.getStream(context, url); if (in != null) { return in; } } // Finally, fall back to default locale defined in chrome registry. url = getSearchPluginsJarURL(context, getFallbackLocale(), fileName); - return GeckoJarReader.getStream(url); + return GeckoJarReader.getStream(context, url); } /** * Finds a fallback locale in the Gecko chrome registry. If a locale is declared * here, we should be guaranteed to find a searchplugins directory for it. * * This method should only be accessed from the background thread. */ private String getFallbackLocale() { if (fallbackLocale != null) { return fallbackLocale; } - final InputStream in = GeckoJarReader.getStream(GeckoJarReader.getJarURL(context, "chrome/chrome.manifest")); + final InputStream in = GeckoJarReader.getStream( + context, GeckoJarReader.getJarURL(context, "chrome/chrome.manifest")); final BufferedReader br = getBufferedReader(in); try { String line; while ((line = br.readLine()) != null) { // We're looking for a line like "locale global en-US en-US/locale/en-US/global/" // https://developer.mozilla.org/en/docs/Chrome_Registration#locale if (line.startsWith("locale global ")) {
--- a/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestJarReader.java +++ b/mobile/android/tests/browser/junit3/src/org/mozilla/tests/browser/junit3/TestJarReader.java @@ -4,43 +4,46 @@ package org.mozilla.tests.browser.junit3; import java.io.InputStream; import android.test.InstrumentationTestCase; import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.util.GeckoJarReader; +import android.content.Context; + /** * A basic jar reader test. Tests reading a png from fennec's apk, as well as * loading some invalid jar urls. */ public class TestJarReader extends InstrumentationTestCase { public void testJarReader() { + final Context context = getInstrumentation().getTargetContext().getApplicationContext(); String appPath = getInstrumentation().getTargetContext().getPackageResourcePath(); assertNotNull(appPath); // Test reading a file from a jar url that looks correct. String url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME; - InputStream stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + InputStream stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); assertNotNull(stream); // Test looking for an non-existent file in a jar. url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME; - stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); assertNull(stream); // Test looking for a file that doesn't exist in the APK. url = "jar:file://" + appPath + "!/" + "BAD" + AppConstants.OMNIJAR_NAME; - stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); assertNull(stream); // Test looking for an jar with an invalid url. url = "jar:file://" + appPath + "!" + "!/" + AppConstants.OMNIJAR_NAME; - stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); assertNull(stream); // Test looking for a file that doesn't exist on disk. url = "jar:file://" + appPath + "BAD" + "!/" + AppConstants.OMNIJAR_NAME; - stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); assertNull(stream); } }
--- a/mobile/android/tests/browser/robocop/testJarReader.java +++ b/mobile/android/tests/browser/robocop/testJarReader.java @@ -4,55 +4,58 @@ package org.mozilla.gecko.tests; import java.io.InputStream; import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.util.GeckoJarReader; +import android.content.Context; + /** * A basic jar reader test. Tests reading a png from fennec's apk, as well * as loading some invalid jar urls. */ public class testJarReader extends BaseTest { public void testGetJarURL() { // Invalid characters are escaped. final String s = GeckoJarReader.computeJarURI("some[1].apk", "something/else"); mAsserter.ok(!s.contains("["), "Illegal characters are escaped away.", null); mAsserter.ok(!s.toLowerCase().contains("%2f"), "Path characters aren't escaped.", null); } public void testJarReader() { + final Context context = getInstrumentation().getTargetContext().getApplicationContext(); String appPath = getActivity().getApplication().getPackageResourcePath(); mAsserter.isnot(appPath, null, "getPackageResourcePath is non-null"); // Test reading a file from a jar url that looks correct. String url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME; - InputStream stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + InputStream stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); mAsserter.isnot(stream, null, "JarReader returned non-null for valid file in valid jar"); // Test looking for an non-existent file in a jar. url = "jar:file://" + appPath + "!/" + AppConstants.OMNIJAR_NAME; - stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); mAsserter.is(stream, null, "JarReader returned null for non-existent file in valid jar"); // Test looking for a file that doesn't exist in the APK. url = "jar:file://" + appPath + "!/" + "BAD" + AppConstants.OMNIJAR_NAME; - stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); mAsserter.is(stream, null, "JarReader returned null for valid file in invalid jar file"); // Test looking for an jar with an invalid url. url = "jar:file://" + appPath + "!" + "!/" + AppConstants.OMNIJAR_NAME; - stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/nonexistent_file.png"); mAsserter.is(stream, null, "JarReader returned null for bad jar url"); // Test looking for a file that doesn't exist on disk. url = "jar:file://" + appPath + "BAD" + "!/" + AppConstants.OMNIJAR_NAME; - stream = GeckoJarReader.getStream("jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); + stream = GeckoJarReader.getStream(context, "jar:" + url + "!/chrome/chrome/content/branding/favicon32.png"); mAsserter.is(stream, null, "JarReader returned null for a non-existent APK"); // This test completes very quickly. If it completes too soon, the // minidumps directory may not be created before the process is // taken down, causing bug 722166. blockForGeckoReady(); }
--- a/modules/libmar/tool/mar.c +++ b/modules/libmar/tool/mar.c @@ -407,11 +407,9 @@ int main(int argc, char **argv) { case 'r': return strip_signature_block(argv[2], argv[3]); #endif /* endif NO_SIGN_VERIFY disabled */ default: print_usage(); return -1; } - - return 0; }
--- a/mozglue/build/replace_malloc.mk +++ b/mozglue/build/replace_malloc.mk @@ -20,11 +20,13 @@ OS_LDFLAGS += \ -Wl,-U,_replace_jemalloc_purge_freed_pages \ -Wl,-U,_replace_jemalloc_free_dirty_pages \ $(NULL) ifneq ($(MOZ_REPLACE_MALLOC_LINKAGE),compiler support) OS_LDFLAGS += -flat_namespace endif ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library) -OS_LDFLAGS += -Wl,-weak_library,$(DEPTH)/memory/replace/dummy/$(DLL_PREFIX)replace_malloc$(DLL_SUFFIX) +OS_LDFLAGS += -Wl,-weak_library,$(DEPTH)/memory/replace/dummy/$(DLL_PREFIX)dummy_replace_malloc$(DLL_SUFFIX) endif + +EXTRA_DEPS += $(topsrcdir)/mozglue/build/replace_malloc.mk endif
--- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -2,18 +2,21 @@ /* 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/. */ #include "mozilla/LoadInfo.h" #include "mozilla/Assertions.h" +#include "nsFrameLoader.h" +#include "nsIDocShell.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" +#include "nsIFrameLoader.h" #include "nsISupportsImpl.h" #include "nsISupportsUtils.h" namespace mozilla { LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, nsINode* aLoadingContext, @@ -23,43 +26,77 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadin : mLoadingPrincipal(aLoadingContext ? aLoadingContext->NodePrincipal() : aLoadingPrincipal) , mTriggeringPrincipal(aTriggeringPrincipal ? aTriggeringPrincipal : mLoadingPrincipal.get()) , mLoadingContext(do_GetWeakReference(aLoadingContext)) , mSecurityFlags(aSecurityFlags) , mContentPolicyType(aContentPolicyType) , mBaseURI(aBaseURI) - , mInnerWindowID(aLoadingContext ? - aLoadingContext->OwnerDoc()->InnerWindowID() : 0) + , mInnerWindowID(0) + , mOuterWindowID(0) + , mParentOuterWindowID(0) { MOZ_ASSERT(mLoadingPrincipal); MOZ_ASSERT(mTriggeringPrincipal); // if consumers pass both, aLoadingContext and aLoadingPrincipal // then the loadingPrincipal must be the same as the node's principal MOZ_ASSERT(!aLoadingContext || !aLoadingPrincipal || aLoadingContext->NodePrincipal() == aLoadingPrincipal); // if the load is sandboxed, we can not also inherit the principal if (mSecurityFlags & nsILoadInfo::SEC_SANDBOXED) { mSecurityFlags ^= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL; } + + if (aLoadingContext) { + nsCOMPtr<nsPIDOMWindow> outerWindow; + + // When the element being loaded is a frame, we choose the frame's window + // for the window ID and the frame element's window as the parent + // window. This is the behavior that Chrome exposes to add-ons. + nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner = do_QueryInterface(aLoadingContext); + if (frameLoaderOwner) { + nsCOMPtr<nsIFrameLoader> fl = frameLoaderOwner->GetFrameLoader(); + nsCOMPtr<nsIDocShell> docShell; + if (fl && NS_SUCCEEDED(fl->GetDocShell(getter_AddRefs(docShell))) && docShell) { + outerWindow = do_GetInterface(docShell); + } + } else { + outerWindow = aLoadingContext->OwnerDoc()->GetWindow(); + } + + if (outerWindow) { + nsCOMPtr<nsPIDOMWindow> inner = outerWindow->GetCurrentInnerWindow(); + mInnerWindowID = inner ? inner->WindowID() : 0; + mOuterWindowID = outerWindow->WindowID(); + + nsCOMPtr<nsIDOMWindow> parent; + outerWindow->GetParent(getter_AddRefs(parent)); + nsCOMPtr<nsPIDOMWindow> piParent = do_QueryInterface(parent); + mParentOuterWindowID = piParent->WindowID(); + } + } } LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType, - uint32_t aInnerWindowID) + uint64_t aInnerWindowID, + uint64_t aOuterWindowID, + uint64_t aParentOuterWindowID) : mLoadingPrincipal(aLoadingPrincipal) , mTriggeringPrincipal(aTriggeringPrincipal) , mSecurityFlags(aSecurityFlags) , mContentPolicyType(aContentPolicyType) , mInnerWindowID(aInnerWindowID) + , mOuterWindowID(aOuterWindowID) + , mParentOuterWindowID(aParentOuterWindowID) { MOZ_ASSERT(mLoadingPrincipal); MOZ_ASSERT(mTriggeringPrincipal); } LoadInfo::~LoadInfo() { } @@ -149,15 +186,29 @@ LoadInfo::GetBaseURI(nsIURI** aBaseURI) nsIURI* LoadInfo::BaseURI() { return mBaseURI; } NS_IMETHODIMP -LoadInfo::GetInnerWindowID(uint32_t* aResult) +LoadInfo::GetInnerWindowID(uint64_t* aResult) { *aResult = mInnerWindowID; return NS_OK; } +NS_IMETHODIMP +LoadInfo::GetOuterWindowID(uint64_t* aResult) +{ + *aResult = mOuterWindowID; + return NS_OK; +} + +NS_IMETHODIMP +LoadInfo::GetParentOuterWindowID(uint64_t* aResult) +{ + *aResult = mParentOuterWindowID; + return NS_OK; +} + } // namespace mozilla
--- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -48,29 +48,33 @@ public: private: // private constructor that is only allowed to be called from within // HttpChannelParent and FTPChannelParent declared as friends undeneath. // In e10s we can not serialize nsINode, hence we store the innerWindowID. LoadInfo(nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType, - uint32_t aInnerWindowID); + uint64_t aInnerWindowID, + uint64_t aOuterWindowID, + uint64_t aParentOuterWindowID); friend class net::HttpChannelParent; friend class net::FTPChannelParent; friend class net::WebSocketChannelParent; ~LoadInfo(); nsCOMPtr<nsIPrincipal> mLoadingPrincipal; nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; nsWeakPtr mLoadingContext; nsSecurityFlags mSecurityFlags; nsContentPolicyType mContentPolicyType; nsCOMPtr<nsIURI> mBaseURI; - uint32_t mInnerWindowID; + uint64_t mInnerWindowID; + uint64_t mOuterWindowID; + uint64_t mParentOuterWindowID; }; } // namespace mozilla #endif // mozilla_LoadInfo_h
--- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -12,17 +12,17 @@ interface nsINode; interface nsIPrincipal; interface nsIURI; typedef unsigned long nsSecurityFlags; /** * An nsILoadOwner represents per-load information about who started the load. */ -[scriptable, builtinclass, uuid(768a1f20-57d4-462a-812a-41c04e5d1e19)] +[scriptable, builtinclass, uuid(dcf54f49-2d63-4c34-9da1-54df235f354c)] interface nsILoadInfo : nsISupports { /** * No special security flags: */ const unsigned long SEC_NORMAL = 0; /** @@ -177,27 +177,49 @@ interface nsILoadInfo : nsISupports /** * A C++-friendly version of baseURI. */ [noscript, notxpcom, nostdcall, binaryname(BaseURI)] nsIURI binaryBaseURI(); /** - * The innerWindowId of the loadingDocument, used to identify - * the loadingDocument in e10s where the loadingDocument is - * not available. + * Typically these are the window IDs of the window in which the element being + * loaded lives. However, if the element being loaded is <frame + * src="foo.html"> (or, more generally, if the element QIs to + * nsIFrameLoaderOwner) then the window IDs are for the window containing the + * foo.html document. In this case, parentOuterWindowID is the window ID of + * the window containing the <frame> element. * - * Warning: If the loadingDocument is null, then the - * innerWindowId is 0. + * Note that these window IDs can be 0 if the window is not + * available. parentOuterWindowID will be the same as outerWindowID if the + * window has no parent. */ - readonly attribute unsigned long innerWindowID; + readonly attribute unsigned long long innerWindowID; + readonly attribute unsigned long long outerWindowID; + readonly attribute unsigned long long parentOuterWindowID; %{ C++ - inline uint32_t GetInnerWindowID() + inline uint64_t GetInnerWindowID() { - uint32_t result; + uint64_t result; mozilla::DebugOnly<nsresult> rv = GetInnerWindowID(&result); MOZ_ASSERT(NS_SUCCEEDED(rv)); return result; } -%} + + inline uint64_t GetOuterWindowID() + { + uint64_t result; + mozilla::DebugOnly<nsresult> rv = GetOuterWindowID(&result); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + return result; + } + + inline uint64_t GetParentOuterWindowID() + { + uint64_t result; + mozilla::DebugOnly<nsresult> rv = GetParentOuterWindowID(&result); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + return result; + } + %} };
--- a/netwerk/base/nsUDPSocket.cpp +++ b/netwerk/base/nsUDPSocket.cpp @@ -1306,17 +1306,17 @@ nsUDPSocket::Send(const nsACString &aHos uint32_t *_retval) { NS_ENSURE_ARG(aData); NS_ENSURE_ARG_POINTER(_retval); *_retval = 0; FallibleTArray<uint8_t> fallibleArray; - if (!fallibleArray.InsertElementsAt(0, aData, aDataLength)) { + if (!fallibleArray.InsertElementsAt(0, aData, aDataLength, fallible)) { return NS_ERROR_OUT_OF_MEMORY; } nsCOMPtr<nsIDNSListener> listener = new PendingSend(this, aPort, fallibleArray); nsresult rv = ResolveHost(aHost, listener); NS_ENSURE_SUCCESS(rv, rv); @@ -1364,17 +1364,17 @@ nsUDPSocket::SendWithAddress(const NetAd if (count < 0) { PRErrorCode code = PR_GetError(); return ErrorAccordingToNSPR(code); } this->AddOutputBytes(count); *_retval = count; } else { FallibleTArray<uint8_t> fallibleArray; - if (!fallibleArray.InsertElementsAt(0, aData, aDataLength)) { + if (!fallibleArray.InsertElementsAt(0, aData, aDataLength, fallible)) { return NS_ERROR_OUT_OF_MEMORY; } nsresult rv = mSts->Dispatch(new SendRequestRunnable(this, *aAddr, fallibleArray), NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); *_retval = aDataLength; }
--- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -60,17 +60,19 @@ struct HttpChannelOpenArgs nsCString appCacheClientID; bool allowSpdy; bool allowAltSvc; OptionalFileDescriptorSet fds; PrincipalInfo requestingPrincipalInfo; PrincipalInfo triggeringPrincipalInfo; uint32_t securityFlags; uint32_t contentPolicyType; - uint32_t innerWindowID; + uint64_t innerWindowID; + uint64_t outerWindowID; + uint64_t parentOuterWindowID; OptionalHttpResponseHead synthesizedResponseHead; uint32_t cacheKey; }; struct HttpChannelConnectArgs { uint32_t channelId; bool shouldIntercept; @@ -91,17 +93,19 @@ struct FTPChannelOpenArgs URIParams uri; uint64_t startPos; nsCString entityID; OptionalInputStreamParams uploadStream; PrincipalInfo requestingPrincipalInfo; PrincipalInfo triggeringPrincipalInfo; uint32_t securityFlags; uint32_t contentPolicyType; - uint32_t innerWindowID; + uint64_t innerWindowID; + uint64_t outerWindowID; + uint64_t parentOuterWindowID; }; struct FTPChannelConnectArgs { uint32_t channelId; }; union FTPChannelCreationArgs @@ -137,13 +141,15 @@ struct RtspChannelConnectArgs //----------------------------------------------------------------------------- struct WebSocketLoadInfoArgs { PrincipalInfo requestingPrincipalInfo; PrincipalInfo triggeringPrincipalInfo; uint32_t securityFlags; uint32_t contentPolicyType; - uint32_t innerWindowID; + uint64_t innerWindowID; + uint64_t outerWindowID; + uint64_t parentOuterWindowID; }; } // namespace ipc } // namespace mozilla
--- a/netwerk/protocol/ftp/FTPChannelChild.cpp +++ b/netwerk/protocol/ftp/FTPChannelChild.cpp @@ -158,27 +158,31 @@ propagateLoadInfo(nsILoadInfo *aLoadInfo mozilla::ipc::PrincipalToPrincipalInfo(aLoadInfo->TriggeringPrincipal(), &triggeringPrincipalInfo); openArgs.triggeringPrincipalInfo() = triggeringPrincipalInfo; openArgs.securityFlags() = aLoadInfo->GetSecurityFlags(); openArgs.contentPolicyType() = aLoadInfo->GetContentPolicyType(); openArgs.innerWindowID() = aLoadInfo->GetInnerWindowID(); + openArgs.outerWindowID() = aLoadInfo->GetOuterWindowID(); + openArgs.parentOuterWindowID() = aLoadInfo->GetParentOuterWindowID(); return; } // use default values if no loadInfo is provided mozilla::ipc::PrincipalToPrincipalInfo(nsContentUtils::GetSystemPrincipal(), &requestingPrincipalInfo); openArgs.requestingPrincipalInfo() = requestingPrincipalInfo; openArgs.triggeringPrincipalInfo() = requestingPrincipalInfo; openArgs.securityFlags() = nsILoadInfo::SEC_NORMAL; openArgs.contentPolicyType() = nsIContentPolicy::TYPE_OTHER; openArgs.innerWindowID() = 0; + openArgs.outerWindowID() = 0; + openArgs.parentOuterWindowID() = 0; } NS_IMETHODIMP FTPChannelChild::AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext) { LOG(("FTPChannelChild::AsyncOpen [this=%p]\n", this)); NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -84,17 +84,18 @@ bool FTPChannelParent::Init(const FTPChannelCreationArgs& aArgs) { switch (aArgs.type()) { case FTPChannelCreationArgs::TFTPChannelOpenArgs: { const FTPChannelOpenArgs& a = aArgs.get_FTPChannelOpenArgs(); return DoAsyncOpen(a.uri(), a.startPos(), a.entityID(), a.uploadStream(), a.requestingPrincipalInfo(), a.triggeringPrincipalInfo(), - a.securityFlags(), a.contentPolicyType(), a.innerWindowID()); + a.securityFlags(), a.contentPolicyType(), + a.innerWindowID(), a.outerWindowID(), a.parentOuterWindowID()); } case FTPChannelCreationArgs::TFTPChannelConnectArgs: { const FTPChannelConnectArgs& cArgs = aArgs.get_FTPChannelConnectArgs(); return ConnectChannel(cArgs.channelId()); } default: NS_NOTREACHED("unknown open type"); @@ -106,17 +107,19 @@ bool FTPChannelParent::DoAsyncOpen(const URIParams& aURI, const uint64_t& aStartPos, const nsCString& aEntityID, const OptionalInputStreamParams& aUploadStream, const ipc::PrincipalInfo& aRequestingPrincipalInfo, const ipc::PrincipalInfo& aTriggeringPrincipalInfo, const uint32_t& aSecurityFlags, const uint32_t& aContentPolicyType, - const uint32_t& aInnerWindowID) + const uint64_t& aInnerWindowID, + const uint64_t& aOuterWindowID, + const uint64_t& aParentOuterWindowID) { nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); if (!uri) return false; #ifdef DEBUG nsCString uriSpec; uri->GetSpec(uriSpec); @@ -149,17 +152,17 @@ FTPChannelParent::DoAsyncOpen(const URIP mozilla::ipc::PrincipalInfoToPrincipal(aTriggeringPrincipalInfo, &rv); if (NS_FAILED(rv)) { return SendFailedAsyncOpen(rv); } nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::LoadInfo(requestingPrincipal, triggeringPrincipal, aSecurityFlags, aContentPolicyType, - aInnerWindowID); + aInnerWindowID, aOuterWindowID, aParentOuterWindowID); nsCOMPtr<nsIChannel> chan; rv = NS_NewChannelInternal(getter_AddRefs(chan), uri, loadInfo, nullptr, nullptr, nsIRequest::LOAD_NORMAL, ios); if (NS_FAILED(rv)) return SendFailedAsyncOpen(rv);
--- a/netwerk/protocol/ftp/FTPChannelParent.h +++ b/netwerk/protocol/ftp/FTPChannelParent.h @@ -63,17 +63,19 @@ protected: bool DoAsyncOpen(const URIParams& aURI, const uint64_t& aStartPos, const nsCString& aEntityID, const OptionalInputStreamParams& aUploadStream, const ipc::PrincipalInfo& aRequestingPrincipalInfo, const ipc::PrincipalInfo& aTriggeringPrincipalInfo, const uint32_t& aSecurityFlags, const uint32_t& aContentPolicyType, - const uint32_t& aInnerWindowID); + const uint64_t& aInnerWindowID, + const uint64_t& aOuterWindowID, + const uint64_t& aParentOuterWindowID); // used to connect redirected-to channel in parent with just created // ChildChannel. Used during HTTP->FTP redirects. bool ConnectChannel(const uint32_t& channelId); virtual bool RecvCancel(const nsresult& status) override; virtual bool RecvSuspend() override; virtual bool RecvResume() override;
--- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -1484,27 +1484,31 @@ propagateLoadInfo(nsILoadInfo *aLoadInfo mozilla::ipc::PrincipalToPrincipalInfo(aLoadInfo->TriggeringPrincipal(), &triggeringPrincipalInfo); openArgs.triggeringPrincipalInfo() = triggeringPrincipalInfo; openArgs.securityFlags() = aLoadInfo->GetSecurityFlags(); openArgs.contentPolicyType() = aLoadInfo->GetContentPolicyType(); openArgs.innerWindowID() = aLoadInfo->GetInnerWindowID(); + openArgs.outerWindowID() = aLoadInfo->GetOuterWindowID(); + openArgs.parentOuterWindowID() = aLoadInfo->GetParentOuterWindowID(); return; } // use default values if no loadInfo is provided mozilla::ipc::PrincipalToPrincipalInfo(nsContentUtils::GetSystemPrincipal(), &requestingPrincipalInfo); openArgs.requestingPrincipalInfo() = requestingPrincipalInfo; openArgs.triggeringPrincipalInfo() = requestingPrincipalInfo; openArgs.securityFlags() = nsILoadInfo::SEC_NORMAL; openArgs.contentPolicyType() = nsIContentPolicy::TYPE_OTHER; openArgs.innerWindowID() = 0; + openArgs.outerWindowID() = 0; + openArgs.parentOuterWindowID() = 0; } NS_IMETHODIMP HttpChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo) { NS_ENSURE_ARG_POINTER(aSecurityInfo); NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo); return NS_OK;
--- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -116,17 +116,18 @@ HttpChannelParent::Init(const HttpChanne a.loadFlags(), a.requestHeaders(), a.requestMethod(), a.uploadStream(), a.uploadStreamHasHeaders(), a.priority(), a.classOfService(), a.redirectionLimit(), a.allowPipelining(), a.allowSTS(), a.thirdPartyFlags(), a.resumeAt(), a.startPos(), a.entityID(), a.chooseApplicationCache(), a.appCacheClientID(), a.allowSpdy(), a.allowAltSvc(), a.fds(), a.requestingPrincipalInfo(), a.triggeringPrincipalInfo(), - a.securityFlags(), a.contentPolicyType(), a.innerWindowID(), + a.securityFlags(), a.contentPolicyType(), + a.innerWindowID(), a.outerWindowID(), a.parentOuterWindowID(), a.synthesizedResponseHead(), a.cacheKey()); } case HttpChannelCreationArgs::THttpChannelConnectArgs: { const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs(); return ConnectChannel(cArgs.channelId(), cArgs.shouldIntercept()); } default: @@ -275,17 +276,19 @@ HttpChannelParent::DoAsyncOpen( const U const nsCString& appCacheClientID, const bool& allowSpdy, const bool& allowAltSvc, const OptionalFileDescriptorSet& aFds, const ipc::PrincipalInfo& aRequestingPrincipalInfo, const ipc::PrincipalInfo& aTriggeringPrincipalInfo, const uint32_t& aSecurityFlags, const uint32_t& aContentPolicyType, - const uint32_t& aInnerWindowID, + const uint64_t& aInnerWindowID, + const uint64_t& aOuterWindowID, + const uint64_t& aParentOuterWindowID, const OptionalHttpResponseHead& aSynthesizedResponseHead, const uint32_t& aCacheKey) { nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); if (!uri) { // URIParams does MOZ_ASSERT if null, but we need to protect opt builds from // null deref here. return false; @@ -330,17 +333,17 @@ HttpChannelParent::DoAsyncOpen( const U loadFlags |= nsICachingChannel::LOAD_ONLY_FROM_CACHE; loadFlags |= nsIRequest::LOAD_FROM_CACHE; loadFlags |= nsICachingChannel::LOAD_NO_NETWORK_IO; } nsCOMPtr<nsILoadInfo> loadInfo = new mozilla::LoadInfo(requestingPrincipal, triggeringPrincipal, aSecurityFlags, aContentPolicyType, - aInnerWindowID); + aInnerWindowID, aOuterWindowID, aParentOuterWindowID); nsCOMPtr<nsIChannel> channel; rv = NS_NewChannelInternal(getter_AddRefs(channel), uri, loadInfo, nullptr, nullptr, loadFlags, ios); if (NS_FAILED(rv)) return SendFailedAsyncOpen(rv);
--- a/netwerk/protocol/http/HttpChannelParent.h +++ b/netwerk/protocol/http/HttpChannelParent.h @@ -115,17 +115,19 @@ protected: const nsCString& appCacheClientID, const bool& allowSpdy, const bool& allowAltSvc, const OptionalFileDescriptorSet& aFds, const ipc::PrincipalInfo& aRequestingPrincipalInfo, const ipc::PrincipalInfo& aTriggeringPrincipalInfo, const uint32_t& aSecurityFlags, const uint32_t& aContentPolicyType, - const uint32_t& aInnerWindowID, + const uint64_t& aInnerWindowID, + const uint64_t& aOuterWindowID, + const uint64_t& aParentOuterWindowID, const OptionalHttpResponseHead& aSynthesizedResponseHead, const uint32_t& aCacheKey); virtual bool RecvSetPriority(const uint16_t& priority) override; virtual bool RecvSetClassOfService(const uint32_t& cos) override; virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset) override; virtual bool RecvSuspend() override; virtual bool RecvResume() override;
--- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp @@ -465,16 +465,18 @@ propagateLoadInfo(nsILoadInfo *aLoadInfo &requestingPrincipalInfo); wsArgs.requestingPrincipalInfo() = requestingPrincipalInfo; mozilla::ipc::PrincipalToPrincipalInfo(aLoadInfo->TriggeringPrincipal(), &triggeringPrincipalInfo); wsArgs.triggeringPrincipalInfo() = triggeringPrincipalInfo; wsArgs.securityFlags() = aLoadInfo->GetSecurityFlags(); wsArgs.contentPolicyType() = aLoadInfo->GetContentPolicyType(); wsArgs.innerWindowID() = aLoadInfo->GetInnerWindowID(); + wsArgs.outerWindowID() = aLoadInfo->GetOuterWindowID(); + wsArgs.parentOuterWindowID() = aLoadInfo->GetParentOuterWindowID(); } NS_IMETHODIMP WebSocketChannelChild::AsyncOpen(nsIURI *aURI, const nsACString &aOrigin, nsIWebSocketListener *aListener, nsISupports *aContext) {
--- a/netwerk/protocol/websocket/WebSocketChannelParent.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelParent.cpp @@ -106,17 +106,19 @@ WebSocketChannelParent::RecvAsyncOpen(co if (NS_FAILED(rv)) { goto fail; } loadInfo = new LoadInfo(requestingPrincipal, triggeringPrincipal, aLoadInfoArgs.securityFlags(), aLoadInfoArgs.contentPolicyType(), - aLoadInfoArgs.innerWindowID()); + aLoadInfoArgs.innerWindowID(), + aLoadInfoArgs.outerWindowID(), + aLoadInfoArgs.parentOuterWindowID()); rv = mChannel->SetLoadInfo(loadInfo); if (NS_FAILED(rv)) { goto fail; } rv = mChannel->SetNotificationCallbacks(this); if (NS_FAILED(rv)) goto fail;
--- a/python/mozbuild/mozbuild/base.py +++ b/python/mozbuild/mozbuild/base.py @@ -695,16 +695,30 @@ class MachCommandBase(MozbuildObject): print('') print('mozconfig output:') print('') for line in e.output: print(line) sys.exit(1) + # Always keep a log of the last command, but don't do that for mach + # invokations from scripts (especially not the ones done by the build + # system itself). + if (self.log_manager and self.log_manager.terminal and + not getattr(self, 'NO_AUTO_LOG', False)): + self._ensure_state_subdir_exists('.') + logfile = self._get_state_filename('last_log.json') + try: + fd = open(logfile, "wb") + self.log_manager.add_json_handler(fd) + except Exception as e: + self.log(logging.WARNING, 'mach', {'error': e}, + 'Log will not be kept for this command: {error}.') + class MachCommandConditions(object): """A series of commonly used condition functions which can be applied to mach commands with providers deriving from MachCommandBase. """ @staticmethod def is_firefox(cls): """Must have a Firefox build."""
--- a/python/mozbuild/mozbuild/frontend/mach_commands.py +++ b/python/mozbuild/mozbuild/frontend/mach_commands.py @@ -1,15 +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/. from __future__ import print_function, unicode_literals from collections import defaultdict +import os from mach.decorators import ( CommandArgument, CommandProvider, Command, SubCommand, ) @@ -83,70 +84,98 @@ class MozbuildFileCommands(MachCommandBa @Command('file-info', category='build-dev', description='Query for metadata about files.') def file_info(self): pass @SubCommand('file-info', 'bugzilla-component', 'Show Bugzilla component info for files listed.') + @CommandArgument('-r', '--rev', + help='Version control revision to look up info from') @CommandArgument('paths', nargs='+', help='Paths whose data to query') - def file_info_bugzilla(self, paths): + def file_info_bugzilla(self, paths, rev=None): components = defaultdict(set) try: - for p, m in self._get_files_info(paths).items(): + for p, m in self._get_files_info(paths, rev=rev).items(): components[m.get('BUG_COMPONENT')].add(p) except InvalidPathException as e: print(e.message) return 1 for component, files in sorted(components.items(), key=lambda x: (x is None, x)): print('%s :: %s' % (component.product, component.component) if component else 'UNKNOWN') for f in sorted(files): print(' %s' % f) @SubCommand('file-info', 'missing-bugzilla', 'Show files missing Bugzilla component info') + @CommandArgument('-r', '--rev', + help='Version control revision to look up info from') @CommandArgument('paths', nargs='+', help='Paths whose data to query') - def file_info_missing_bugzilla(self, paths): + def file_info_missing_bugzilla(self, paths, rev=None): try: - for p, m in sorted(self._get_files_info(paths).items()): + for p, m in sorted(self._get_files_info(paths, rev=rev).items()): if 'BUG_COMPONENT' not in m: print(p) except InvalidPathException as e: print(e.message) return 1 - def _get_reader(self): - from mozbuild.frontend.reader import BuildReader, EmptyConfig + def _get_reader(self, finder): + from mozbuild.frontend.reader import ( + BuildReader, + EmptyConfig, + ) + config = EmptyConfig(self.topsrcdir) - return BuildReader(config) + return BuildReader(config, finder=finder) - def _get_files_info(self, paths): - from mozpack.files import FileFinder + def _get_files_info(self, paths, rev=None): + from mozbuild.frontend.reader import default_finder + from mozpack.files import FileFinder, MercurialRevisionFinder # Normalize to relative from topsrcdir. relpaths = [] for p in paths: a = mozpath.abspath(p) if not mozpath.basedir(a, [self.topsrcdir]): raise InvalidPathException('path is outside topsrcdir: %s' % p) relpaths.append(mozpath.relpath(a, self.topsrcdir)) + repo = None + if rev: + hg_path = os.path.join(self.topsrcdir, '.hg') + if not os.path.exists(hg_path): + raise InvalidPathException('a Mercurial repo is required ' + 'when specifying a revision') + + repo = self.topsrcdir + + # We need two finders because the reader's finder operates on + # absolute paths. finder = FileFinder(self.topsrcdir, find_executables=False) + if repo: + reader_finder = MercurialRevisionFinder(repo, rev=rev, + recognize_repo_paths=True) + else: + reader_finder = default_finder # Expand wildcards. allpaths = [] for p in relpaths: if '*' not in p: if p not in allpaths: allpaths.append(p) continue + if repo: + raise InvalidPathException('cannot use wildcard in version control mode') + for path, f in finder.find(p): if path not in allpaths: allpaths.append(path) - reader = self._get_reader() + reader = self._get_reader(finder=reader_finder) return reader.files_info(allpaths)
--- a/python/mozbuild/mozbuild/frontend/reader.py +++ b/python/mozbuild/mozbuild/frontend/reader.py @@ -34,30 +34,30 @@ from collections import ( OrderedDict, ) from io import StringIO from mozbuild.util import ( EmptyValue, memoize, ReadOnlyDefaultDict, - ReadOnlyDict, ) from mozbuild.backend.configenvironment import ConfigEnvironment from mozpack.files import FileFinder import mozpack.path as mozpath from .data import ( AndroidEclipseProjectData, JavaJarData, ) from .sandbox import ( + default_finder, SandboxError, SandboxExecutionError, SandboxLoadError, Sandbox, ) from .context import ( Context, @@ -167,20 +167,20 @@ class MozbuildSandbox(Sandbox): We expose a few useful functions and expose the set of variables defining Mozilla's build system. context is a Context instance. metadata is a dict of metadata that can be used during the sandbox evaluation. """ - def __init__(self, context, metadata={}): + def __init__(self, context, metadata={}, finder=default_finder): assert isinstance(context, Context) - Sandbox.__init__(self, context) + Sandbox.__init__(self, context, finder=finder) self._log = logging.getLogger(__name__) self.metadata = dict(metadata) exports = self.metadata.get('exports', {}) self.exports = set(exports.keys()) context.update(exports) self.templates = self.metadata.setdefault('templates', {}) @@ -193,19 +193,26 @@ class MozbuildSandbox(Sandbox): def __getitem__(self, key): if key in self.special_variables: return self.special_variables[key][0](self._context) if key in self.functions: return self._create_function(self.functions[key]) if key in self.subcontext_types: return self._create_subcontext(self.subcontext_types[key]) if key in self.templates: - return self._create_template_function(self.templates[key]) + return self._create_template_wrapper(self.templates[key]) return Sandbox.__getitem__(self, key) + def __contains__(self, key): + if any(key in d for d in (self.special_variables, self.functions, + self.subcontext_types, self.templates)): + return True + + return Sandbox.__contains__(self, key) + def __setitem__(self, key, value): if key in self.special_variables or key in self.functions or key in self.subcontext_types: raise KeyError('Cannot set "%s" because it is a reserved keyword' % key) if key in self.exports: self._context[key] = value self.exports.remove(key) return @@ -303,75 +310,33 @@ class MozbuildSandbox(Sandbox): def _warning(self, message): # FUTURE consider capturing warnings in a variable instead of printing. print('WARNING: %s' % message, file=sys.stderr) def _error(self, message): raise SandboxCalledError(self._context.source_stack, message) def _template_decorator(self, func): - """Registers template as expected by _create_template_function. - - The template data consists of: - - the function object as it comes from the sandbox evaluation of the - template declaration. - - its code, modified as described in the comments of this method. - - the path of the file containing the template definition. - """ + """Registers a template function.""" if not inspect.isfunction(func): raise Exception('`template` is a function decorator. You must ' 'use it as `@template` preceding a function declaration.') name = func.func_name if name in self.templates: raise KeyError( 'A template named "%s" was already declared in %s.' % (name, - self.templates[name][2])) + self.templates[name].path)) if name.islower() or name.isupper() or name[0].islower(): raise NameError('Template function names must be CamelCase.') - lines, firstlineno = inspect.getsourcelines(func) - first_op = None - generator = tokenize.generate_tokens(iter(lines).next) - # Find the first indent token in the source of this template function, - # which corresponds to the beginning of the function body. - for typ, s, begin, end, line in generator: - if typ == tokenize.OP: - first_op = True - if first_op and typ == tokenize.INDENT: - break - if typ != tokenize.INDENT: - # This should never happen. - raise Exception('Could not find the first line of the template %s' % - func.func_name) - # The code of the template in moz.build looks like this: - # m def Foo(args): - # n FOO = 'bar' - # n+1 (...) - # - # where, - # - m is firstlineno - 1, - # - n is usually m + 1, but in case the function signature takes more - # lines, is really m + begin[0] - 1 - # - # We want that to be replaced with: - # m if True: - # n FOO = 'bar' - # n+1 (...) - # - # (this is simpler than trying to deindent the function body) - # So we need to prepend with n - 1 newlines so that line numbers - # are unchanged. - code = '\n' * (firstlineno + begin[0] - 3) + 'if True:\n' - code += ''.join(lines[begin[0] - 1:]) - - self.templates[name] = func, code, self._context.current_path + self.templates[name] = TemplateFunction(func, self) @memoize def _create_subcontext(self, cls): """Return a function object that creates SubContext instances.""" def fn(*args, **kwargs): return cls(self._context, *args, **kwargs) return fn @@ -393,51 +358,47 @@ class MozbuildSandbox(Sandbox): arg = type(arg) return arg args = [coerce(arg, type) for arg, type in zip(args, args_def)] return func(self)(*args) return function @memoize - def _create_template_function(self, template): + def _create_template_wrapper(self, template): """Returns a function object for use within the sandbox for the given - template. + TemplateFunction instance.. When a moz.build file contains a reference to a template call, the sandbox needs a function to execute. This is what this method returns. That function creates a new sandbox for execution of the template. After the template is executed, the data from its execution is merged with the context of the calling sandbox. """ - func, code, path = template - - def template_function(*args, **kwargs): + def template_wrapper(*args, **kwargs): context = TemplateContext( - template=func.func_name, + template=template.name, allowed_variables=self._context._allowed_variables, config=self._context.config) context.add_source(self._context.current_path) for p in self._context.all_paths: context.add_source(p) sandbox = MozbuildSandbox(context, metadata={ # We should arguably set these defaults to something else. # Templates, for example, should arguably come from the state # of the sandbox from when the template was declared, not when # it was instantiated. Bug 1137319. 'functions': self.metadata.get('functions', {}), 'special_variables': self.metadata.get('special_variables', {}), 'subcontexts': self.metadata.get('subcontexts', {}), 'templates': self.metadata.get('templates', {}) - }) - for k, v in inspect.getcallargs(func, *args, **kwargs).items(): - sandbox[k] = v + }, finder=self._finder) - sandbox.exec_source(code, path, becomes_current_path=False) + template.exec_in_sandbox(sandbox, *args, **kwargs) # This is gross, but allows the merge to happen. Eventually, the # merging will go away and template contexts emitted independently. klass = self._context.__class__ self._context.__class__ = TemplateContext # The sandbox will do all the necessary checks for these merges. for key, value in context.items(): if isinstance(value, dict): @@ -446,17 +407,115 @@ class MozbuildSandbox(Sandbox): self[key] += value else: self[key] = value self._context.__class__ = klass for p in context.all_paths: self._context.add_source(p) - return template_function + return template_wrapper + + +class TemplateFunction(object): + def __init__(self, func, sandbox): + self.path = func.func_code.co_filename + self.name = func.func_name + + code = func.func_code + firstlineno = code.co_firstlineno + lines = sandbox._current_source.splitlines(True) + lines = inspect.getblock(lines[firstlineno - 1:]) + + # The code lines we get out of inspect.getsourcelines look like + # @template + # def Template(*args, **kwargs): + # VAR = 'value' + # ... + func_ast = ast.parse(''.join(lines), self.path) + # Remove decorators + func_ast.body[0].decorator_list = [] + # Adjust line numbers accordingly + ast.increment_lineno(func_ast, firstlineno - 1) + + # When using a custom dictionary for function globals/locals, Cpython + # actually never calls __getitem__ and __setitem__, so we need to + # modify the AST so that accesses to globals are properly directed + # to a dict. + self._global_name = b'_data' # AST wants str for this, not unicode + # In case '_data' is a name used for a variable in the function code, + # prepend more underscores until we find an unused name. + while (self._global_name in code.co_names or + self._global_name in code.co_varnames): + self._global_name += '_' + func_ast = self.RewriteName(sandbox, self._global_name).visit(func_ast) + + # Execute the rewritten code. That code now looks like: + # def Template(*args, **kwargs): + # _data['VAR'] = 'value' + # ... + # The result of executing this code is the creation of a 'Template' + # function object in the global namespace. + glob = {'__builtins__': sandbox._builtins} + func = types.FunctionType( + compile(func_ast, self.path, 'exec'), + glob, + self.name, + func.func_defaults, + func.func_closure, + ) + func() + + self._func = glob[self.name] + + def exec_in_sandbox(self, sandbox, *args, **kwargs): + """Executes the template function in the given sandbox.""" + # Create a new function object associated with the execution sandbox + glob = { + self._global_name: sandbox, + '__builtins__': sandbox._builtins + } + func = types.FunctionType( + self._func.func_code, + glob, + self.name, + self._func.func_defaults, + self._func.func_closure + ) + sandbox.exec_function(func, args, kwargs, self.path, + becomes_current_path=False) + + class RewriteName(ast.NodeTransformer): + """AST Node Transformer to rewrite variable accesses to go through + a dict. + """ + def __init__(self, sandbox, global_name): + self._sandbox = sandbox + self._global_name = global_name + + def visit_Str(self, node): + # String nodes we got from the AST parser are str, but we want + # unicode literals everywhere, so transform them. + node.s = unicode(node.s) + return node + + def visit_Name(self, node): + # Modify uppercase variable references and names known to the + # sandbox as if they were retrieved from a dict instead. + if not node.id.isupper() and node.id not in self._sandbox: + return node + + def c(new_node): + return ast.copy_location(new_node, node) + + return c(ast.Subscript( + value=c(ast.Name(id=self._global_name, ctx=ast.Load())), + slice=c(ast.Index(value=c(ast.Str(s=node.id)))), + ctx=node.ctx + )) class SandboxValidationError(Exception): """Represents an error encountered when validating sandbox results.""" def __init__(self, message, context): Exception.__init__(self, message) self.context = context @@ -584,17 +643,17 @@ class BuildReaderError(Exception): if trace: frames = traceback.extract_tb(trace) for frame in frames: if frame[0] == self.actual_file: script_frame = frame # Reset if we enter a new execution context. This prevents errors # in this module from being attributes to a script. - elif frame[0] == __file__ and frame[2] == 'exec_source': + elif frame[0] == __file__ and frame[2] == 'exec_function': script_frame = None if script_frame is not None: s.write('The error was triggered on line %d ' % script_frame[1]) s.write('of this file:\n') s.write('\n') s.write(' %s\n' % script_frame[3]) s.write('\n') @@ -790,22 +849,23 @@ class BuildReader(object): The reader can optionally call a callable after each sandbox is evaluated but before its evaluated content is processed. This gives callers the opportunity to modify contexts before side-effects occur from their content. This callback receives the ``Context`` containing the result of each sandbox evaluation. Its return value is ignored. """ - def __init__(self, config): + def __init__(self, config, finder=default_finder): self.config = config self._log = logging.getLogger(__name__) self._read_files = set() self._execution_stack = [] + self._finder = finder def read_topsrcdir(self): """Read the tree of linked moz.build files. This starts with the tree's top-most moz.build file and descends into all linked moz.build files until all relevant files have been evaluated. This is a generator of Context instances. As each moz.build file is @@ -1028,17 +1088,18 @@ class BuildReader(object): if mozpath.dirname(relpath) == 'js/src' and \ not config.substs.get('JS_STANDALONE'): config = ConfigEnvironment.from_config_status( mozpath.join(topobjdir, reldir, 'config.status')) config.topobjdir = topobjdir config.external_source_dir = None context = Context(VARIABLES, config) - sandbox = MozbuildSandbox(context, metadata=metadata) + sandbox = MozbuildSandbox(context, metadata=metadata, + finder=self._finder) sandbox.exec_file(path) context.execution_time = time.time() - time_start # Yield main context before doing any processing. This gives immediate # consumers an opportunity to change state before our remaining # processing is performed. yield context @@ -1064,17 +1125,17 @@ class BuildReader(object): # emitted after their parent, so accumulate the gyp contexts. # We could emit the parent context before processing gyp # configuration, but we need to add the gyp objdirs to that context # first. from .gyp_reader import read_from_gyp non_unified_sources = set() for s in gyp_dir.non_unified_sources: source = SourcePath(context, s)