merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-09-23 12:05:53 +02:00
commit a65e4225ef
360 changed files with 6893 additions and 5357 deletions

View File

@ -259,12 +259,12 @@
onpopuphidden="SocialShare.onHidden()"
hidden="true">
<hbox class="social-share-toolbar">
<toolbarbutton id="manage-share-providers" class="toolbarbutton share-provider-button"
<toolbarbutton id="manage-share-providers" class="share-provider-button"
tooltiptext="&social.addons.label;"
oncommand="BrowserOpenAddonsMgr('addons://list/service');
this.parentNode.parentNode.hidePopup();"/>
<arrowscrollbox id="social-share-provider-buttons" orient="horizontal" flex="1" pack="end">
<toolbarbutton id="add-share-provider" class="toolbarbutton share-provider-button" type="radio"
<toolbarbutton id="add-share-provider" class="share-provider-button" type="radio"
group="share-providers" tooltiptext="&findShareServices.label;"
oncommand="SocialShare.showDirectory()"/>
</arrowscrollbox>

View File

@ -303,10 +303,12 @@ function test() {
Services.prefs.setBoolPref(PREF_ACTIVE, true);
Services.prefs.setBoolPref(PREF_DISPLAY, true);
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
newTab.linkedBrowser.stop();
pushPrefs(["dom.ipc.processCount", 1]).then(() => {
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
newTab.linkedBrowser.stop();
executeSoon(test1);
executeSoon(test1);
});
}

View File

@ -1,5 +1,11 @@
"use strict";
add_task(function* setup() {
yield SpecialPowers.pushPrefEnv({
set: [["dom.ipc.processCount", 1]]
});
})
add_task(function* () {
/** Test for Bug 350525 **/

View File

@ -69,7 +69,7 @@ add_task(function* setup() {
// This test takes some time to run, and it could timeout randomly.
// So we require a longer timeout. See bug 528219.
requestLongerTimeout(2);
requestLongerTimeout(3);
// Make the main test window not count as a browser window any longer
let oldWinType = document.documentElement.getAttribute("windowtype");

View File

@ -81,6 +81,7 @@ function defineCohort() {
let disqualified = (Services.appinfo.multiprocessBlockPolicy != 0);
let testGroup = (getUserSample() < TEST_THRESHOLD[updateChannel]);
let hasNonExemptAddon = Preferences.get(PREF_E10S_HAS_NONEXEMPT_ADDON, false);
let temporaryDisqualification = getTemporaryDisqualification();
let cohortPrefix = "";
if (disqualified) {
@ -93,6 +94,17 @@ function defineCohort() {
setCohort("optedOut");
} else if (userOptedIn) {
setCohort("optedIn");
} else if (temporaryDisqualification != "") {
// Users who are disqualified by the backend (from multiprocessBlockPolicy)
// can be put into either the test or control groups, because e10s will
// still be denied by the backend, which is useful so that the E10S_STATUS
// telemetry probe can be correctly set.
// For these volatile disqualification reasons, however, we must not try
// to activate e10s because the backend doesn't know about it. E10S_STATUS
// here will be accumulated as "2 - Disabled", which is fine too.
setCohort(`temp-disqualified-${temporaryDisqualification}`);
Preferences.reset(PREF_TOGGLE_E10S);
} else if (testGroup) {
setCohort(`${cohortPrefix}test`);
Preferences.set(PREF_TOGGLE_E10S, true);
@ -150,3 +162,23 @@ function optedOut() {
(Preferences.isSet(PREF_TOGGLE_E10S) &&
Preferences.get(PREF_TOGGLE_E10S) == false);
}
/* If this function returns a non-empty string, it
* means that this particular user should be temporarily
* disqualified due to some particular reason.
* If a user shouldn't be disqualified, then an empty
* string must be returned.
*/
function getTemporaryDisqualification() {
let applicationLanguage =
Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry)
.getSelectedLocale("global")
.split("-")[0];
if (applicationLanguage == "ru") {
return "ru";
}
return "";
}

View File

@ -10,7 +10,7 @@
<Description about="urn:mozilla:install-manifest">
<em:id>e10srollout@mozilla.org</em:id>
<em:version>1.2</em:version>
<em:version>1.3</em:version>
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

View File

@ -3,5 +3,6 @@
- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="highlighttext" points="12,3.5 10.5,2 4.625,8 10.5,14 12,12.5 7.625,8" />
#include ../icon-colors.inc.svg
<polygon class="highlighttext" points="12,3.5 10.5,2 4.625,8 10.5,14 12,12.5 7.625,8"/>
</svg>

Before

Width:  |  Height:  |  Size: 432 B

After

Width:  |  Height:  |  Size: 464 B

View File

@ -3,5 +3,6 @@
- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="-moz-fieldtext" fill-opacity=".7" points="5,3.5 6.5,2 12.375,8 6.5,14 5,12.5 9.375,8"/>
#include ../icon-colors.inc.svg
<polygon class="fieldtext" points="5,3.5 6.5,2 12.375,8 6.5,14 5,12.5 9.375,8"/>
</svg>

Before

Width:  |  Height:  |  Size: 447 B

After

Width:  |  Height:  |  Size: 457 B

View File

@ -3,13 +3,7 @@
- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<style>
.icon-default {
fill: -moz-fieldtext;
fill-opacity: .5;
}
</style>
#include ../icon-colors.inc.svg
<defs>
<mask id="mask-globe">
<circle fill="#fff" cx="12" cy="12" r="11"/>
@ -17,5 +11,5 @@
</mask>
</defs>
<rect width="24" height="24" mask="url(#mask-globe)" class="icon-default"/>
<rect width="24" height="24" mask="url(#mask-globe)" class="fieldtext"/>
</svg>

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -4,16 +4,12 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="24" height="24" viewBox="0 0 24 24">
#include ../icon-colors.inc.svg
<style>
svg > rect:not(:target) {
display: none;
}
#connection-degraded {
fill: -moz-fieldtext;
fill-opacity: .5;
}
#connection-secure {
fill: #4d9a26;
}
@ -36,6 +32,6 @@
</mask>
</defs>
<rect id="connection-degraded" width="24" height="24" mask="url(#mask-lock)"/>
<rect id="connection-degraded" class="fieldtext" width="24" height="24" mask="url(#mask-lock)"/>
<rect id="connection-secure" width="24" height="24" mask="url(#mask-lock)"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -5,12 +5,7 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="24" height="24" viewBox="0 0 24 24">
<style>
.icon-default {
fill: -moz-fieldtext;
fill-opacity: .5;
}
</style>
#include ../icon-colors.inc.svg
<defs>
<rect id="shape-lock-clasp-outer" x="5" y="1" width="14" height="20" rx="7" ry="7" />
<rect id="shape-lock-clasp-inner" x="8" y="4" width="8" height="14" rx="4" ry="4" />
@ -32,8 +27,8 @@
</mask>
</defs>
<use xlink:href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)" class="icon-default"/>
<use xlink:href="#shape-lock-base" mask="url(#mask-base-cutout)" class="icon-default"/>
<use class="fieldtext" xlink:href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)"/>
<use class="fieldtext" xlink:href="#shape-lock-base" mask="url(#mask-base-cutout)"/>
<line x1="2.25" y1="22.75" x2="21.5" y2="2.5" stroke="#d92d21" stroke-width="3" />
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -2,13 +2,9 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<style>
#permissions {
fill: -moz-fieldtext;
fill-opacity: .5;
}
</style>
<svg xmlns="http://www.w3.org/2000/svg"
width="24" height="24" viewBox="0 0 24 24">
#include ../icon-colors.inc.svg
<defs>
<mask id="mask-permissions">
@ -20,5 +16,5 @@
</mask>
</defs>
<rect id="permissions" width="24" height="24" mask="url(#mask-permissions)"/>
<rect class="fieldtext" id="permissions" width="24" height="24" mask="url(#mask-permissions)"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -4,14 +4,11 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="24" height="24" viewBox="0 0 24 24">
#include ../icon-colors.inc.svg
<style>
g:not(:target) {
display: none;
}
.shield {
fill: -moz-fieldtext;
fill-opacity: .5;
}
</style>
<defs>
@ -36,11 +33,11 @@
</defs>
<g id="enabled">
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
<use class="fieldtext" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
</g>
<g id="disabled">
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
<use class="fieldtext" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
<line x1="3" y1="22" x2="23" y2="1" stroke="#d92d21" stroke-width="3"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,39 @@
<style>
.fieldtext {
fill: -moz-fieldtext;
#ifdef XP_LINUX
/* The fill-opacity needs to be sufficient for high-contrast settings, and
pathological Gtk themes where -moz-fieldtext provides low contrast by
default. */
fill-opacity: .7;
#else
fill-opacity: .5;
#endif
}
#ifdef XP_WIN
@media (-moz-windows-default-theme: 0) {
/* more opacity for high-contrast themes */
.fieldtext {
fill-opacity: .8;
}
}
#endif
.highlighttext {
fill: highlighttext;
fill-opacity: 1;
}
.black {
fill: black;
fill-opacity: .6;
}
.white {
fill: white;
fill-opacity: .7;
}
</style>

View File

@ -4,22 +4,11 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="16" height="16" viewBox="0 0 16 16">
#include ../icon-colors.inc.svg
<style>
svg > g:not(:target) {
display: none;
}
.icon-default {
fill: -moz-fieldtext;
fill-opacity: .5;
}
#icon-black > .icon-default {
fill: black;
fill-opacity: .6;
}
#icon-white > .icon-default {
fill: white;
fill-opacity: .7;
}
</style>
<defs>
@ -49,17 +38,17 @@
</defs>
<g id="icon">
<use xlink:href="#lock" class="icon-default"/>
<use xlink:href="#lock" class="fieldtext"/>
<use xlink:href="#strike-through-red"/>
</g>
<g id="icon-black">
<use xlink:href="#lock" class="icon-default"/>
<use xlink:href="#lock" class="black"/>
<use xlink:href="#strike-through-red"/>
</g>
<g id="icon-white">
<use xlink:href="#lock" class="icon-default"/>
<use xlink:href="#lock" class="white"/>
<use xlink:href="#strike-through-red"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -4,22 +4,11 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="16" height="16" viewBox="0 0 16 16">
#include ../icon-colors.inc.svg
<style>
svg > g:not(:target) {
display: none;
}
.icon-default {
fill: -moz-fieldtext;
fill-opacity: .5;
}
#icon-black > .icon-default {
fill: black;
fill-opacity: .6;
}
#icon-white > .icon-default {
fill: white;
fill-opacity: .7;
}
</style>
<defs>
@ -47,17 +36,17 @@
</defs>
<g id="icon">
<rect width="16" height="16" mask="url(#mask-lock)" class="icon-default"/>
<rect width="16" height="16" mask="url(#mask-lock)" class="fieldtext"/>
<use xlink:href="#warning-triangle"/>
</g>
<g id="icon-black">
<rect width="16" height="16" mask="url(#mask-lock)" class="icon-default"/>
<rect width="16" height="16" mask="url(#mask-lock)" class="black"/>
<use xlink:href="#warning-triangle"/>
</g>
<g id="icon-white">
<rect width="16" height="16" mask="url(#mask-lock)" class="icon-default"/>
<rect width="16" height="16" mask="url(#mask-lock)" class="white"/>
<use xlink:href="#warning-triangle"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1,47 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="16" height="16" viewBox="0 0 16 16">
<style>
use:not(:target) {
display: none;
}
use {
fill-rule: evenodd;
fill: -moz-fieldtext;
fill-opacity: .5;
}
use[id$="-black"] {
fill: black;
fill-opacity: .6;
}
use[id$="-white"] {
fill: white;
fill-opacity: .7;
}
</style>
<defs>
<path id="glyph-normal" d="M128,193a7,7,0,1,1,7-7A7,7,0,0,1,128,193Zm0-13a6,6,0,1,0,6,6A6,6,0,0,0,128,180Zm0,10a1,1,0,0,1-1-1v-3a1,1,0,0,1,2,0v3A1,1,0,0,1,128,190Zm0-6a1,1,0,1,1,1-1A1,1,0,0,1,128,184Z" transform="translate(-120 -178)"/>
<path id="glyph-hover" d="M102,179a7,7,0,1,1-7,7A7,7,0,0,1,102,179Zm0,3a1,1,0,1,1-1,1A1,1,0,0,1,102,182Zm0,3a1,1,0,0,1,1,1v3a1,1,0,0,1-2,0v-3A1,1,0,0,1,102,185Z" transform="translate(-94 -178)"/>
<path id="glyph-notice" d="M133.5,202a2.5,2.5,0,1,1,2.5-2.5A2.5,2.5,0,0,1,133.5,202Zm-5.5,1a1,1,0,1,1,1-1A1,1,0,0,1,128,203Zm1,5a1,1,0,0,1-2,0v-3a1,1,0,0,1,2,0v3Zm-1-9a6.08,6.08,0,1,0,5.629,3.987,3.452,3.452,0,0,0,.984-0.185A6.9,6.9,0,0,1,135,205a7,7,0,1,1-7-7,6.9,6.9,0,0,1,2.2.387,3.452,3.452,0,0,0-.185.984A5.951,5.951,0,0,0,128,199Z" transform="translate(-120 -197)"/>
<path id="glyph-notice-hover" d="M107.5,202a2.5,2.5,0,1,1,2.5-2.5A2.5,2.5,0,0,1,107.5,202Zm0,1.039a3.5,3.5,0,0,0,1.125-.2,7.124,7.124,0,1,1-4.464-4.464,3.5,3.5,0,0,0-.2,1.125A3.54,3.54,0,0,0,107.5,203.039ZM102,201a1,1,0,1,0,1,1A1,1,0,0,0,102,201Zm1,4a1,1,0,0,0-2,0v3a1,1,0,0,0,2,0v-3Z" transform="translate(-94 -197)"/>
</defs>
<use id="normal" xlink:href="#glyph-normal"/>
<use id="hover" xlink:href="#glyph-hover"/>
<use id="notice" xlink:href="#glyph-notice"/>
<use id="notice-hover" xlink:href="#glyph-notice-hover"/>
<use id="normal-black" xlink:href="#glyph-normal"/>
<use id="hover-black" xlink:href="#glyph-hover"/>
<use id="notice-black" xlink:href="#glyph-notice"/>
<use id="notice-hover-black" xlink:href="#glyph-notice-hover"/>
<use id="normal-white" xlink:href="#glyph-normal"/>
<use id="hover-white" xlink:href="#glyph-hover"/>
<use id="notice-white" xlink:href="#glyph-notice"/>
<use id="notice-hover-white" xlink:href="#glyph-notice-hover"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
class="fieldtext"
width="16" height="16" viewBox="0 0 16 16">
#include ../icon-colors.inc.svg
<style>
use:not(:target) {
display: none;
}
use {
fill-rule: evenodd;
}
</style>
<defs>
<path id="glyph-normal" d="M128,193a7,7,0,1,1,7-7A7,7,0,0,1,128,193Zm0-13a6,6,0,1,0,6,6A6,6,0,0,0,128,180Zm0,10a1,1,0,0,1-1-1v-3a1,1,0,0,1,2,0v3A1,1,0,0,1,128,190Zm0-6a1,1,0,1,1,1-1A1,1,0,0,1,128,184Z" transform="translate(-120 -178)"/>
<path id="glyph-hover" d="M102,179a7,7,0,1,1-7,7A7,7,0,0,1,102,179Zm0,3a1,1,0,1,1-1,1A1,1,0,0,1,102,182Zm0,3a1,1,0,0,1,1,1v3a1,1,0,0,1-2,0v-3A1,1,0,0,1,102,185Z" transform="translate(-94 -178)"/>
<path id="glyph-notice" d="M133.5,202a2.5,2.5,0,1,1,2.5-2.5A2.5,2.5,0,0,1,133.5,202Zm-5.5,1a1,1,0,1,1,1-1A1,1,0,0,1,128,203Zm1,5a1,1,0,0,1-2,0v-3a1,1,0,0,1,2,0v3Zm-1-9a6.08,6.08,0,1,0,5.629,3.987,3.452,3.452,0,0,0,.984-0.185A6.9,6.9,0,0,1,135,205a7,7,0,1,1-7-7,6.9,6.9,0,0,1,2.2.387,3.452,3.452,0,0,0-.185.984A5.951,5.951,0,0,0,128,199Z" transform="translate(-120 -197)"/>
<path id="glyph-notice-hover" d="M107.5,202a2.5,2.5,0,1,1,2.5-2.5A2.5,2.5,0,0,1,107.5,202Zm0,1.039a3.5,3.5,0,0,0,1.125-.2,7.124,7.124,0,1,1-4.464-4.464,3.5,3.5,0,0,0-.2,1.125A3.54,3.54,0,0,0,107.5,203.039ZM102,201a1,1,0,1,0,1,1A1,1,0,0,0,102,201Zm1,4a1,1,0,0,0-2,0v3a1,1,0,0,0,2,0v-3Z" transform="translate(-94 -197)"/>
</defs>
<use id="normal" xlink:href="#glyph-normal"/>
<use id="hover" xlink:href="#glyph-hover"/>
<use id="notice" xlink:href="#glyph-notice"/>
<use id="notice-hover" xlink:href="#glyph-notice-hover"/>
<use class="black" id="normal-black" xlink:href="#glyph-normal"/>
<use class="black" id="hover-black" xlink:href="#glyph-hover"/>
<use class="black" id="notice-black" xlink:href="#glyph-notice"/>
<use class="black" id="notice-hover-black" xlink:href="#glyph-notice-hover"/>
<use class="white" id="normal-white" xlink:href="#glyph-normal"/>
<use class="white" id="hover-white" xlink:href="#glyph-hover"/>
<use class="white" id="notice-white" xlink:href="#glyph-notice"/>
<use class="white" id="notice-hover-white" xlink:href="#glyph-notice-hover"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,70 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="16" height="16" viewBox="0 0 16 16">
<style>
g:not(:target) {
display: none;
}
.shield {
fill: -moz-fieldtext;
fill-opacity: .5;
}
g[id$="-black"] > .shield {
fill: black;
fill-opacity: .6;
}
g[id$="-white"] > .shield {
fill: white;
fill-opacity: .7;
}
</style>
<defs>
<path id="shape-shield-outer" d="M8,1L2.8,1.9C2.4,1.9,2,2.4,2,2.8C2,4,2,6.1,2.1,7.1c0.3,2.7,0.8,4,1.9,5.6C5.6,14.7,8,15,8,15s2.4-0.3,4-2.4 c1.2-1.5,1.7-2.9,1.9-5.6C14,6.1,14,4,14,2.8c0-0.5-0.4-0.9-0.8-1L8,1L8,1z"/>
<path id="shape-shield-inner" d="M8,2l5,0.8c0,2,0,3.5-0.1,4.1c-0.3,2.7-0.8,3.8-1.7,5.1c-1.1,1.5-2.7,1.9-3.2,2c-0.4-0.1-2.1-0.5-3.2-2 c-1-1.3-1.5-2.4-1.7-5.1C3,6.3,3,4.8,3,2.8L8,2"/>
<path id="shape-shield-detail" d="M8,13c-0.5-0.1-1.6-0.5-2.4-1.5c-0.9-1.2-1.3-2.1-1.5-4.6C4,6.3,4,5.2,4,3.7L8,3 V13z"/>
<mask id="mask-shield-cutout">
<rect width="16" height="16" fill="#000" />
<use xlink:href="#shape-shield-outer" fill="#fff" />
<use xlink:href="#shape-shield-inner" fill="#000" />
<use xlink:href="#shape-shield-detail" fill="#fff" />
</mask>
<mask id="mask-shield-cutout-disabled">
<rect width="16" height="16" fill="#000"/>
<use xlink:href="#shape-shield-outer" fill="#fff"/>
<use xlink:href="#shape-shield-inner" fill="#000"/>
<use xlink:href="#shape-shield-detail" fill="#fff"/>
<line x1="3" y1="15" x2="15" y2="3" stroke="#000" stroke-width="2"/>
</mask>
<line id="strike-through-red" x1="3" y1="14" x2="15" y2="2" stroke="#d92d21" stroke-width="2"/>
</defs>
<g id="enabled">
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
</g>
<g id="enabled-black">
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
</g>
<g id="enabled-white">
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
</g>
<g id="disabled">
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
<use xlink:href="#strike-through-red"/>
</g>
<g id="disabled-black">
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
<use xlink:href="#strike-through-red"/>
</g>
<g id="disabled-white">
<use class="shield" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
<use xlink:href="#strike-through-red"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="16" height="16" viewBox="0 0 16 16">
#include ../icon-colors.inc.svg
<style>
g:not(:target) {
display: none;
}
</style>
<defs>
<path id="shape-shield-outer" d="M8,1L2.8,1.9C2.4,1.9,2,2.4,2,2.8C2,4,2,6.1,2.1,7.1c0.3,2.7,0.8,4,1.9,5.6C5.6,14.7,8,15,8,15s2.4-0.3,4-2.4 c1.2-1.5,1.7-2.9,1.9-5.6C14,6.1,14,4,14,2.8c0-0.5-0.4-0.9-0.8-1L8,1L8,1z"/>
<path id="shape-shield-inner" d="M8,2l5,0.8c0,2,0,3.5-0.1,4.1c-0.3,2.7-0.8,3.8-1.7,5.1c-1.1,1.5-2.7,1.9-3.2,2c-0.4-0.1-2.1-0.5-3.2-2 c-1-1.3-1.5-2.4-1.7-5.1C3,6.3,3,4.8,3,2.8L8,2"/>
<path id="shape-shield-detail" d="M8,13c-0.5-0.1-1.6-0.5-2.4-1.5c-0.9-1.2-1.3-2.1-1.5-4.6C4,6.3,4,5.2,4,3.7L8,3 V13z"/>
<mask id="mask-shield-cutout">
<rect width="16" height="16" fill="#000" />
<use xlink:href="#shape-shield-outer" fill="#fff" />
<use xlink:href="#shape-shield-inner" fill="#000" />
<use xlink:href="#shape-shield-detail" fill="#fff" />
</mask>
<mask id="mask-shield-cutout-disabled">
<rect width="16" height="16" fill="#000"/>
<use xlink:href="#shape-shield-outer" fill="#fff"/>
<use xlink:href="#shape-shield-inner" fill="#000"/>
<use xlink:href="#shape-shield-detail" fill="#fff"/>
<line x1="3" y1="15" x2="15" y2="3" stroke="#000" stroke-width="2"/>
</mask>
<line id="strike-through-red" x1="3" y1="14" x2="15" y2="2" stroke="#d92d21" stroke-width="2"/>
</defs>
<g id="enabled">
<use class="fieldtext" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
</g>
<g id="enabled-black">
<use class="black" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
</g>
<g id="enabled-white">
<use class="white" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)"/>
</g>
<g id="disabled">
<use class="fieldtext" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
<use xlink:href="#strike-through-red"/>
</g>
<g id="disabled-black">
<use class="black" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
<use xlink:href="#strike-through-red"/>
</g>
<g id="disabled-white">
<use class="white" xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout-disabled)"/>
<use xlink:href="#strike-through-red"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -24,13 +24,13 @@
skin/classic/browser/addons/addon-install-restart.svg (../shared/addons/addon-install-restart.svg)
skin/classic/browser/addons/addon-install-warning.svg (../shared/addons/addon-install-warning.svg)
skin/classic/browser/addons/addon-install-anchor.svg (../shared/addons/addon-install-anchor.svg)
skin/classic/browser/controlcenter/arrow-subview.svg (../shared/controlcenter/arrow-subview.svg)
skin/classic/browser/controlcenter/arrow-subview-back.svg (../shared/controlcenter/arrow-subview-back.svg)
skin/classic/browser/controlcenter/connection.svg (../shared/controlcenter/connection.svg)
skin/classic/browser/controlcenter/conn-not-secure.svg (../shared/controlcenter/conn-not-secure.svg)
skin/classic/browser/controlcenter/mcb-disabled.svg (../shared/controlcenter/mcb-disabled.svg)
skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
* skin/classic/browser/controlcenter/arrow-subview.svg (../shared/controlcenter/arrow-subview.svg)
* skin/classic/browser/controlcenter/arrow-subview-back.svg (../shared/controlcenter/arrow-subview-back.svg)
* skin/classic/browser/controlcenter/conn-not-secure.svg (../shared/controlcenter/conn-not-secure.svg)
* skin/classic/browser/controlcenter/connection.svg (../shared/controlcenter/connection.svg)
* skin/classic/browser/controlcenter/mcb-disabled.svg (../shared/controlcenter/mcb-disabled.svg)
* skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
* skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
skin/classic/browser/controlcenter/warning-gray.svg (../shared/controlcenter/warning-gray.svg)
skin/classic/browser/controlcenter/warning-yellow.svg (../shared/controlcenter/warning-yellow.svg)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
@ -61,15 +61,15 @@
skin/classic/browser/heartbeat-icon.svg (../shared/heartbeat-icon.svg)
skin/classic/browser/heartbeat-star-lit.svg (../shared/heartbeat-star-lit.svg)
skin/classic/browser/heartbeat-star-off.svg (../shared/heartbeat-star-off.svg)
skin/classic/browser/identity-icon.svg (../shared/identity-block/identity-icon.svg)
skin/classic/browser/connection-secure.svg (../shared/identity-block/connection-secure.svg)
skin/classic/browser/connection-mixed-passive-loaded.svg (../shared/identity-block/connection-mixed-passive-loaded.svg)
skin/classic/browser/connection-mixed-active-loaded.svg (../shared/identity-block/connection-mixed-active-loaded.svg)
* skin/classic/browser/connection-mixed-passive-loaded.svg (../shared/identity-block/connection-mixed-passive-loaded.svg)
* skin/classic/browser/connection-mixed-active-loaded.svg (../shared/identity-block/connection-mixed-active-loaded.svg)
* skin/classic/browser/identity-icon.svg (../shared/identity-block/identity-icon.svg)
skin/classic/browser/info.svg (../shared/info.svg)
skin/classic/browser/menuPanel.svg (../shared/menuPanel.svg)
skin/classic/browser/menuPanel-small.svg (../shared/menuPanel-small.svg)
* skin/classic/browser/menuPanel.svg (../shared/menuPanel.svg)
* skin/classic/browser/menuPanel-small.svg (../shared/menuPanel-small.svg)
skin/classic/browser/notification-icons.svg (../shared/notification-icons.svg)
skin/classic/browser/tracking-protection-16.svg (../shared/identity-block/tracking-protection-16.svg)
* skin/classic/browser/tracking-protection-16.svg (../shared/identity-block/tracking-protection-16.svg)
skin/classic/browser/newtab/close.png (../shared/newtab/close.png)
skin/classic/browser/newtab/controls.svg (../shared/newtab/controls.svg)
skin/classic/browser/newtab/whimsycorn.png (../shared/newtab/whimsycorn.png)

View File

@ -2,14 +2,10 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="16" viewBox="0 0 96 16">
<style>
path,
rect {
fill: -moz-fieldText;
fill-opacity: .5;
}
</style>
<svg xmlns="http://www.w3.org/2000/svg"
width="96" height="16" viewBox="0 0 96 16"
class="fieldtext">
#include icon-colors.inc.svg
<path id="placeholder" d="M8,16a8,8,0,1,1,8-8A8,8,0,0,1,8,16ZM12,4H4v8h8V4ZM5,9.939V6.061L6.939,8ZM9.939,11H6.061L8,9.061ZM11,11h0Zm0-4.939V9.939L9.061,8ZM11,5h0ZM6.061,5H9.939L8,6.939Z"/>
<path id="cut" d="M29.63,15a2.426,2.426,0,0,1-2.282-1.277c-0.761-1.109-1.694-2.488-1.694-2.488S25,10.329,24.549,9.623a1.05,1.05,0,0,0-1.106-.538S20.6,4.437,20.124,3.706C19.465,2.689,20.7,1,20.7,1l4.4,7.044a19.333,19.333,0,0,0,1.867,2.286c0.519,0.4,1.382-.373,2.8.908C31.7,12.984,31.048,15,29.63,15ZM29.423,12.11c-0.933-1.042-1.728-.908-1.936-0.639a2.093,2.093,0,0,0,.38,1.748,1.612,1.612,0,0,0,1.383.74C29.838,13.959,30.356,13.153,29.423,12.11ZM25.582,7.372L24.4,5.6,27.276,1s1.233,1.69.575,2.708C27.568,4.142,26.445,5.967,25.582,7.372Zm-4.576,2.956A12.482,12.482,0,0,0,22.43,8.645l0.826,1.239c-0.428.65-.937,1.352-0.937,1.352s-0.933,1.378-1.694,2.488A2.426,2.426,0,0,1,18.344,15c-1.417,0-2.074-2.017-.138-3.765C19.624,9.956,20.487,10.732,21.006,10.329ZM18.551,12.11c-0.933,1.042-.415,1.849.173,1.849a1.612,1.612,0,0,0,1.383-.74,2.093,2.093,0,0,0,.38-1.748C20.28,11.2,19.485,11.068,18.551,12.11Z"/>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -2,13 +2,10 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="1056" height="32" viewBox="0 0 1056 32">
<style>
path {
fill: -moz-fieldText;
fill-opacity: .5;
}
</style>
<svg xmlns="http://www.w3.org/2000/svg"
width="1056" height="32" viewBox="0 0 1056 32"
class="fieldtext">
#include icon-colors.inc.svg
<path id="containers" d="M1050,30h-20a2,2,0,0,1-2-2V4.414a1.03,1.03,0,0,1,.29-0.707L1030,2h20l1.71,1.707a1.03,1.03,0,0,1,.29.707V28A2,2,0,0,1,1050,30Zm0-24h-20V28h20V6Zm-2,10h-16V8h16v8Zm-4-4.5a0.5,0.5,0,0,0-1,0V13h-6V11.5a0.5,0.5,0,0,0-1,0v2a0.5,0.5,0,0,0,.5.5h7a0.5,0.5,0,0,0,.5-0.5v-2Zm4,14.5h-16V18h16v8Zm-4-4.5a0.5,0.5,0,0,0-1,0V23h-6V21.5a0.5,0.5,0,0,0-1,0v2a0.5,0.5,0,0,0,.5.5h7a0.5,0.5,0,0,0,.5-0.5v-2Z"/>
<path id="tabs" d="M1021.98,28h-28a2,2,0,0,1-2-2V22a2,2,0,0,1,2-2H994c4.591,0,4-3,4.009-8,0.009-4.686.166-8,6.261-8h7.41c6.13,0,6.27,3.314,6.3,8,0.02,5-.59,8,4.02,8h-0.02a2,2,0,0,1,2,2v4A2,2,0,0,1,1021.98,28Z"/>

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -200,20 +200,6 @@ interface nsIScriptSecurityManager : nsISupports
[implicit_jscontext]
nsIPrincipal createNullPrincipal(in jsval originAttributes);
/**
* Creates an expanded principal whose capabilities are the union of the
* given principals. An expanded principal has an asymmetric privilege
* relationship with its sub-principals (that is to say, it subsumes the
* sub-principals, but the sub-principals do not subsume it), even if
* there's only one. This presents a legitimate use-case for making an
* expanded principal around a single sub-principal, which we do frequently.
*
* Expanded principals cannot have origin attributes themselves, but rather
* have them through their sub-principals - so we don't accept them here.
*/
nsIPrincipal createExpandedPrincipal([array, size_is(aLength)] in nsIPrincipal aPrincipalArray,
[optional] in unsigned long aLength);
/**
* Returns OK if aSourceURI and target have the same "origin"
* (scheme, host, and port).

View File

@ -674,7 +674,8 @@ struct OriginComparator
}
};
nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr <nsIPrincipal> > &aWhiteList)
nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
const PrincipalOriginAttributes& aAttrs)
{
// We force the principals to be sorted by origin so that nsExpandedPrincipal
// origins can have a canonical form.
@ -682,6 +683,7 @@ nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr <nsIPrincipal> > &aWh
for (size_t i = 0; i < aWhiteList.Length(); ++i) {
mPrincipals.InsertElementSorted(aWhiteList[i], c);
}
mOriginAttributes = aAttrs;
}
nsExpandedPrincipal::~nsExpandedPrincipal()

View File

@ -67,7 +67,8 @@ protected:
class nsExpandedPrincipal : public nsIExpandedPrincipal, public mozilla::BasePrincipal
{
public:
explicit nsExpandedPrincipal(nsTArray< nsCOMPtr<nsIPrincipal> > &aWhiteList);
nsExpandedPrincipal(nsTArray<nsCOMPtr<nsIPrincipal>> &aWhiteList,
const mozilla::PrincipalOriginAttributes& aAttrs);
NS_DECL_NSIEXPANDEDPRINCIPAL
NS_DECL_NSISERIALIZABLE

View File

@ -1181,21 +1181,6 @@ nsScriptSecurityManager::CreateNullPrincipal(JS::Handle<JS::Value> aOriginAttrib
return NS_OK;
}
NS_IMETHODIMP
nsScriptSecurityManager::CreateExpandedPrincipal(nsIPrincipal** aPrincipalArray, uint32_t aLength,
nsIPrincipal** aResult)
{
nsTArray<nsCOMPtr<nsIPrincipal>> principals;
principals.SetCapacity(aLength);
for (uint32_t i = 0; i < aLength; ++i) {
principals.AppendElement(aPrincipalArray[i]);
}
nsCOMPtr<nsIPrincipal> p = new nsExpandedPrincipal(principals);
p.forget(aResult);
return NS_OK;
}
NS_IMETHODIMP
nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
uint32_t aAppId,

View File

@ -35,6 +35,13 @@ function checkOriginAttributes(prin, attrs, suffix) {
}
}
function checkSandboxOriginAttributes(arr, attrs, options) {
options = options || {};
var sandbox = Cu.Sandbox(arr, options);
checkOriginAttributes(Cu.getObjectPrincipal(sandbox), attrs,
ChromeUtils.originAttributesToSuffix(attrs));
}
// utility function useful for debugging
function printAttrs(name, attrs) {
do_print(name + " {\n" +
@ -80,7 +87,7 @@ function run_test() {
var ipv6NPPrin = ssm.createCodebasePrincipal(makeURI('https://[2001:db8::ff00:42:8329]'), {});
do_check_eq(ipv6NPPrin.origin, 'https://[2001:db8::ff00:42:8329]');
checkOriginAttributes(ipv6NPPrin);
var ep = ssm.createExpandedPrincipal([exampleCom, nullPrin, exampleOrg]);
var ep = Cu.getObjectPrincipal(Cu.Sandbox([exampleCom, nullPrin, exampleOrg]));
checkOriginAttributes(ep);
checkCrossOrigin(exampleCom, exampleOrg);
checkCrossOrigin(exampleOrg, nullPrin);
@ -177,6 +184,30 @@ function run_test() {
// Just signedPkg (but different value from 'exampleOrg_signedPkg_app')
var exampleOrg_signedPkg_another = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatup'});
checkSandboxOriginAttributes(null, {});
checkSandboxOriginAttributes('http://example.org', {});
checkSandboxOriginAttributes('http://example.org', {}, {originAttributes: {}});
checkSandboxOriginAttributes('http://example.org', {appId: 42}, {originAttributes: {appId: 42}});
checkSandboxOriginAttributes(['http://example.org'], {});
checkSandboxOriginAttributes(['http://example.org'], {}, {originAttributes: {}});
checkSandboxOriginAttributes(['http://example.org'], {appId: 42}, {originAttributes: {appId: 42}});
checkSandboxOriginAttributes([exampleOrg_signedPkg, 'http://example.org'], {signedPkg: 'whatever'});
checkSandboxOriginAttributes(['http://example.org', exampleOrg_signedPkg], {signedPkg: 'whatever'});
checkSandboxOriginAttributes(['http://example.org', exampleOrg_app, exampleOrg_signedPkg], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
checkSandboxOriginAttributes(['http://example.org', exampleOrg_signedPkg, exampleOrg_app], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
checkSandboxOriginAttributes([exampleOrg_app, exampleOrg_signedPkg, 'http://example.org'], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
checkSandboxOriginAttributes([exampleOrg_app, 'http://example.org', exampleOrg_signedPkg], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
checkSandboxOriginAttributes([exampleOrg_signedPkg, exampleOrg_app, 'http://example.org'], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
checkSandboxOriginAttributes([exampleOrg_signedPkg, 'http://example.org', exampleOrg_app], {signedPkg: 'whatever'}, {originAttributes: {signedPkg: 'whatever'}});
checkThrows(() => Cu.Sandbox([exampleOrg_app, exampleOrg_signedPkg]));
checkThrows(() => Cu.Sandbox([exampleOrg_signedPkg, exampleOrg_app]));
checkThrows(() => Cu.Sandbox(['http://example.org', exampleOrg_app, exampleOrg_signedPkg]));
checkThrows(() => Cu.Sandbox(['http://example.org', exampleOrg_signedPkg, exampleOrg_app]));
checkThrows(() => Cu.Sandbox([exampleOrg_app, exampleOrg_signedPkg, 'http://example.org']));
checkThrows(() => Cu.Sandbox([exampleOrg_app, 'http://example.org', exampleOrg_signedPkg]));
checkThrows(() => Cu.Sandbox([exampleOrg_signedPkg, exampleOrg_app, 'http://example.org']));
checkThrows(() => Cu.Sandbox([exampleOrg_signedPkg, 'http://example.org', exampleOrg_app]));
// Check that all of the above are cross-origin.
checkCrossOrigin(exampleOrg_app, exampleOrg);
checkCrossOrigin(exampleOrg_app, nullPrin_app);
@ -204,7 +235,7 @@ function run_test() {
}
checkKind(ssm.createNullPrincipal({}), 'nullPrincipal');
checkKind(ssm.createCodebasePrincipal(makeURI('http://www.example.com'), {}), 'codebasePrincipal');
checkKind(ssm.createExpandedPrincipal([ssm.createCodebasePrincipal(makeURI('http://www.example.com'), {})]), 'expandedPrincipal');
checkKind(Cu.getObjectPrincipal(Cu.Sandbox([ssm.createCodebasePrincipal(makeURI('http://www.example.com'), {})])), 'expandedPrincipal');
checkKind(ssm.getSystemPrincipal(), 'systemPrincipal');
//

View File

@ -282,7 +282,6 @@ bool nsContentUtils::sEncodeDecodeURLHash = false;
bool nsContentUtils::sGettersDecodeURLHash = false;
bool nsContentUtils::sPrivacyResistFingerprinting = false;
bool nsContentUtils::sSendPerformanceTimingNotifications = false;
bool nsContentUtils::sAppendLFInSerialization = false;
bool nsContentUtils::sUseActivityCursor = false;
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
@ -600,8 +599,6 @@ nsContentUtils::Init()
"network.cookie.cookieBehavior",
nsICookieService::BEHAVIOR_ACCEPT);
Preferences::AddBoolVarCache(&sAppendLFInSerialization,
"dom.html_fragment_serialisation.appendLF");
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled,
"browser.dom.window.dump.enabled");
@ -9142,12 +9139,12 @@ StartElement(Element* aContent, StringBuilder& aBuilder)
aBuilder.Append(">");
/*
// Per HTML spec we should append one \n if the first child of
// pre/textarea/listing is a textnode and starts with a \n.
// But because browsers haven't traditionally had that behavior,
// we're not changing our behavior either - yet.
if (nsContentUtils::AppendLFInSerialization() && aContent->IsHTMLElement()) {
if (aContent->IsHTMLElement()) {
if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
localName == nsGkAtoms::listing) {
nsIContent* fc = aContent->GetFirstChild();
@ -9160,7 +9157,7 @@ StartElement(Element* aContent, StringBuilder& aBuilder)
}
}
}
}
}*/
}
static inline bool

View File

@ -1967,10 +1967,6 @@ public:
static already_AddRefed<mozilla::layers::LayerManager>
PersistentLayerManagerForDocument(nsIDocument *aDoc);
/* static */
static bool AppendLFInSerialization()
{ return sAppendLFInSerialization; }
/**
* Determine whether a content node is focused or not,
*
@ -2824,7 +2820,6 @@ private:
static bool sGettersDecodeURLHash;
static bool sPrivacyResistFingerprinting;
static bool sSendPerformanceTimingNotifications;
static bool sAppendLFInSerialization;
static bool sUseActivityCursor;
static uint32_t sCookiesLifetimePolicy;
static uint32_t sCookiesBehavior;

View File

@ -2099,6 +2099,8 @@ GK_ATOM(onenter, "onenter")
GK_ATOM(onexit, "onexit")
GK_ATOM(onencrypted, "onencrypted")
GK_ATOM(encrypted, "encrypted")
GK_ATOM(onwaitingforkey, "onwaitingforkey")
GK_ATOM(onkeystatuseschange, "onkeystatuseschange")
GK_ATOM(onremovetrack, "onremovetrack")
GK_ATOM(loadstart, "loadstart")
GK_ATOM(suspend, "suspend")

View File

@ -596,21 +596,21 @@ nsImageLoadingContent::GetCurrentURI(nsIURI** aURI)
return result.StealNSResult();
}
already_AddRefed<nsIStreamListener>
NS_IMETHODIMP
nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
ErrorResult& aError)
nsIStreamListener** aListener)
{
imgLoader* loader =
nsContentUtils::GetImgLoaderForChannel(aChannel, GetOurOwnerDoc());
if (!loader) {
aError.Throw(NS_ERROR_NULL_POINTER);
return nullptr;
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIDocument> doc = GetOurOwnerDoc();
if (!doc) {
// Don't bother
return nullptr;
*aListener = nullptr;
return NS_OK;
}
// XXX what should we do with content policies here, if anything?
@ -621,38 +621,24 @@ nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
AutoStateChanger changer(this, true);
// Do the load.
nsCOMPtr<nsIStreamListener> listener;
RefPtr<imgRequestProxy>& req = PrepareNextRequest(eImageLoadType_Normal);
nsresult rv = loader->
LoadImageWithChannel(aChannel, this, doc,
getter_AddRefs(listener),
getter_AddRefs(req));
LoadImageWithChannel(aChannel, this, doc, aListener, getter_AddRefs(req));
if (NS_SUCCEEDED(rv)) {
TrackImage(req);
ResetAnimationIfNeeded();
} else {
MOZ_ASSERT(!req, "Shouldn't have non-null request here");
// If we don't have a current URI, we might as well store this URI so people
// know what we tried (and failed) to load.
if (!mCurrentRequest)
aChannel->GetURI(getter_AddRefs(mCurrentURI));
FireEvent(NS_LITERAL_STRING("error"));
FireEvent(NS_LITERAL_STRING("loadend"));
aError.Throw(rv);
return NS_OK;
}
return listener.forget();
}
NS_IMETHODIMP
nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
nsIStreamListener** aListener)
{
NS_ENSURE_ARG_POINTER(aListener);
MOZ_ASSERT(!req, "Shouldn't have non-null request here");
// If we don't have a current URI, we might as well store this URI so people
// know what we tried (and failed) to load.
if (!mCurrentRequest)
aChannel->GetURI(getter_AddRefs(mCurrentURI));
ErrorResult result;
*aListener = LoadImageWithChannel(aChannel, result).take();
return result.StealNSResult();
FireEvent(NS_LITERAL_STRING("error"));
FireEvent(NS_LITERAL_STRING("loadend"));
return rv;
}
void

View File

@ -77,13 +77,6 @@ public:
return ForceReload(aNotify, 1);
}
/**
* Used to initialize content with a previously opened channel. Assumes
* eImageLoadType_Normal
*/
already_AddRefed<nsIStreamListener>
LoadImageWithChannel(nsIChannel* aChannel, mozilla::ErrorResult& aError);
protected:
enum ImageLoadType {
// Most normal image loads

View File

@ -22,9 +22,7 @@ class nsICycleCollectorListener;
class nsScriptNameSpaceManager;
namespace JS {
template <typename T>
class AutoVectorRooter;
typedef AutoVectorRooter<Value> AutoValueVector;
class AutoValueVector;
} // namespace JS
namespace mozilla {

View File

@ -2893,8 +2893,11 @@ nsScriptLoadHandler::TryDecodeRawData(const uint8_t* aData,
NS_ENSURE_SUCCESS(rv, rv);
uint32_t haveRead = mBuffer.length();
uint32_t capacity = haveRead + dstLen;
if (!mBuffer.reserve(capacity)) {
CheckedInt<uint32_t> capacity = haveRead;
capacity += dstLen;
if (!capacity.isValid() || !mBuffer.reserve(capacity.value())) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -2906,7 +2909,7 @@ nsScriptLoadHandler::TryDecodeRawData(const uint8_t* aData,
NS_ENSURE_SUCCESS(rv, rv);
haveRead += dstLen;
MOZ_ASSERT(haveRead <= capacity, "mDecoder produced more data than expected");
MOZ_ASSERT(haveRead <= capacity.value(), "mDecoder produced more data than expected");
MOZ_ALWAYS_TRUE(mBuffer.resizeUninitialized(haveRead));
return NS_OK;

View File

@ -26,7 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=744830
t.appendChild(document.createElement("textarea"));
t.firstChild.appendChild(document.createTextNode("\nhello"));
// This is the old behavior. Spec requires something else.
is(t.innerHTML, "<textarea>\n\nhello</textarea>",
is(t.innerHTML, "<textarea>\nhello</textarea>",
"No extra newlines should be inserted to the textarea!");
t.innerHTML = null;

View File

@ -3061,6 +3061,13 @@ UnwrapArgImpl(JS::Handle<JSObject*> src,
return NS_OK;
}
// Only allow XPCWrappedJS stuff in system code. Ideally we would remove this
// even there, but that involves converting some things to WebIDL callback
// interfaces and making some other things builtinclass...
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
RefPtr<nsXPCWrappedJS> wrappedJS;
nsresult rv = nsXPCWrappedJS::GetNewOrUsed(src, iid, getter_AddRefs(wrappedJS));
if (NS_FAILED(rv) || !wrappedJS) {

View File

@ -349,21 +349,10 @@ public:
nsIntRegion fillPaintNeededRegion;
nsIntRegion strokePaintNeededRegion;
if (aCtx->CurrentState().updateFilterOnWriteOnly) {
aCtx->UpdateFilter();
aCtx->CurrentState().updateFilterOnWriteOnly = false;
}
// This should not be empty, but if it is, we want to handle it
// rather than crash, as UpdateFilter() call above could have changed
// the number of filter primitives.
MOZ_ASSERT(!aCtx->CurrentState().filter.mPrimitives.IsEmpty());
if (!aCtx->CurrentState().filter.mPrimitives.IsEmpty()) {
FilterSupport::ComputeSourceNeededRegions(
aCtx->CurrentState().filter, mPostFilterBounds,
sourceGraphicNeededRegion, fillPaintNeededRegion,
strokePaintNeededRegion);
}
FilterSupport::ComputeSourceNeededRegions(
aCtx->CurrentState().filter, mPostFilterBounds,
sourceGraphicNeededRegion, fillPaintNeededRegion,
strokePaintNeededRegion);
mSourceGraphicRect = sourceGraphicNeededRegion.GetBounds();
mFillPaintRect = fillPaintNeededRegion.GetBounds();
@ -2796,9 +2785,6 @@ CanvasRenderingContext2D::SetFilter(const nsAString& aFilter, ErrorResult& aErro
UpdateFilter();
}
}
if (mCanvasElement && !mCanvasElement->IsWriteOnly()) {
CurrentState().updateFilterOnWriteOnly = true;
}
}
class CanvasUserSpaceMetrics : public UserSpaceMetricsWithSize
@ -2867,6 +2853,8 @@ CanvasRenderingContext2D::UpdateFilter()
presShell->GetPresContext()),
gfxRect(0, 0, mWidth, mHeight),
CurrentState().filterAdditionalImages);
CurrentState().filterSourceGraphicTainted =
(mCanvasElement && mCanvasElement->IsWriteOnly());
}
//

View File

@ -875,8 +875,21 @@ protected:
*/
bool NeedToApplyFilter()
{
return EnsureUpdatedFilter().mPrimitives.Length() > 0;
}
/**
* Calls UpdateFilter if the canvas's WriteOnly state has changed between the
* last call to UpdateFilter and now.
*/
const gfx::FilterDescription& EnsureUpdatedFilter() {
const ContextState& state = CurrentState();
return state.filter.mPrimitives.Length() > 0;
bool isWriteOnly = mCanvasElement && mCanvasElement->IsWriteOnly();
if (state.filterSourceGraphicTainted != isWriteOnly) {
UpdateFilter();
}
MOZ_ASSERT(state.filterSourceGraphicTainted == isWriteOnly);
return state.filter;
}
bool NeedToCalculateBounds()
@ -968,7 +981,7 @@ protected:
lineCap(mozilla::gfx::CapStyle::BUTT),
lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL),
filterString(u"none"),
updateFilterOnWriteOnly(false),
filterSourceGraphicTainted(false),
imageSmoothingEnabled(true),
fontExplicitLanguage(false)
{ }
@ -1001,7 +1014,7 @@ protected:
filterChainObserver(aOther.filterChainObserver),
filter(aOther.filter),
filterAdditionalImages(aOther.filterAdditionalImages),
updateFilterOnWriteOnly(aOther.updateFilterOnWriteOnly),
filterSourceGraphicTainted(aOther.filterSourceGraphicTainted),
imageSmoothingEnabled(aOther.imageSmoothingEnabled),
fontExplicitLanguage(aOther.fontExplicitLanguage)
{ }
@ -1079,7 +1092,7 @@ protected:
RefPtr<nsSVGFilterChainObserver> filterChainObserver;
mozilla::gfx::FilterDescription filter;
nsTArray<RefPtr<mozilla::gfx::SourceSurface>> filterAdditionalImages;
bool updateFilterOnWriteOnly;
bool filterSourceGraphicTainted;
bool imageSmoothingEnabled;
bool fontExplicitLanguage;

View File

@ -41,7 +41,6 @@ WebGL1Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
bool
WebGL1Context::ValidateQueryTarget(GLenum target, const char* info)
{
// TODO: Implement this for EXT_disjoint_timer
return false;
}

View File

@ -36,9 +36,6 @@ private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type,
uint32_t* 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 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;
};

View File

@ -1,51 +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/. */
#include "WebGL1Context.h"
namespace mozilla {
// -------------------------------------------------------------------------
// Buffer objects
/** Target validation for BindBuffer, etc */
bool
WebGL1Context::ValidateBufferTarget(GLenum target, const char* info)
{
switch (target) {
case LOCAL_GL_ARRAY_BUFFER:
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
return true;
default:
ErrorInvalidEnumInfo(info, target);
return false;
}
}
bool
WebGL1Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
{
ErrorInvalidEnumInfo(info, target);
return false;
}
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;
default:
break;
}
ErrorInvalidEnumInfo(info, usage);
return false;
}
} // namespace mozilla

View File

@ -158,8 +158,7 @@ WebGLContext::InitWebGL2(FailureReason* const out_failReason)
gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
&mGLMaxUniformBufferBindings);
mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);
mIndexedUniformBufferBindings.resize(mGLMaxUniformBufferBindings);
mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
mBoundTransformFeedback = mDefaultTransformFeedback;

View File

@ -273,21 +273,20 @@ public:
// -------------------------------------------------------------------------
// Writing to the drawing buffer
// TODO(djg): Implemented in WebGLContext
/*
/* Implemented in WebGLContext
void VertexAttribDivisor(GLuint index, GLuint divisor);
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei instanceCount);
*/
*/
void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLintptr offset);
// ------------------------------------------------------------------------
// Multiple Render Targets - WebGL2ContextMRTs.cpp
// TODO(djg): Implemented in WebGLContext
/*
/* Implemented in WebGLContext
void DrawBuffers(const dom::Sequence<GLenum>& buffers);
*/
*/
void ClearBufferiv_base(GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearBufferuiv_base(GLenum buffer, GLint drawbuffer, const GLuint* value);
@ -412,9 +411,6 @@ private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type,
uint32_t* 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 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;
};

View File

@ -11,62 +11,6 @@
namespace mozilla {
bool
WebGL2Context::ValidateBufferTarget(GLenum target, const char* funcName)
{
switch (target) {
case LOCAL_GL_ARRAY_BUFFER:
case LOCAL_GL_COPY_READ_BUFFER:
case LOCAL_GL_COPY_WRITE_BUFFER:
case LOCAL_GL_ELEMENT_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 true;
default:
ErrorInvalidEnumInfo(funcName, target);
return false;
}
}
bool
WebGL2Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
{
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
case LOCAL_GL_UNIFORM_BUFFER:
return true;
default:
ErrorInvalidEnumInfo(info, target);
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:
case LOCAL_GL_STATIC_READ:
case LOCAL_GL_STREAM_COPY:
case LOCAL_GL_STREAM_DRAW:
case LOCAL_GL_STREAM_READ:
return true;
default:
break;
}
ErrorInvalidEnumInfo(info, usage);
return false;
}
// -------------------------------------------------------------------------
// Buffer objects
@ -79,48 +23,58 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
if (IsContextLost())
return;
if (!ValidateBufferTarget(readTarget, funcName) ||
!ValidateBufferTarget(writeTarget, funcName))
const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
if (!readBuffer)
return;
const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
if (!writeBuffer)
return;
if (readBuffer->mNumActiveTFOs ||
writeBuffer->mNumActiveTFOs)
{
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
" object.",
funcName);
return;
}
if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
!ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
!ValidateNonNegative(funcName, "size", size))
{
return;
}
const WebGLRefPtr<WebGLBuffer>& readBufferSlot = GetBufferSlotByTarget(readTarget);
const WebGLRefPtr<WebGLBuffer>& writeBufferSlot = GetBufferSlotByTarget(writeTarget);
if (!readBufferSlot || !writeBufferSlot)
return;
const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
const WebGLBuffer* buffer)
{
const auto neededBytes = CheckedInt<size_t>(offset) + size;
if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
ErrorInvalidValue("%s: Invalid %s range.", funcName, info);
return false;
}
return true;
};
const WebGLBuffer* readBuffer = readBufferSlot.get();
if (!readBuffer) {
ErrorInvalidOperation("%s: No buffer bound to readTarget.", funcName);
if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
!fnValidateOffsetSize("write", writeOffset, writeBuffer))
{
return;
}
WebGLBuffer* writeBuffer = writeBufferSlot.get();
if (!writeBuffer) {
ErrorInvalidOperation("%s: No buffer bound to writeTarget.", funcName);
return;
}
if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(), funcName))
return;
if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(), funcName))
return;
if (readTarget == writeTarget &&
if (readBuffer == writeBuffer &&
!ValidateDataRanges(readOffset, writeOffset, size, funcName))
{
return;
}
WebGLBuffer::Kind readType = readBuffer->Content();
WebGLBuffer::Kind writeType = writeBuffer->Content();
if (readType != WebGLBuffer::Kind::Undefined &&
writeType != WebGLBuffer::Kind::Undefined &&
writeType != readType)
{
const auto& readType = readBuffer->Content();
const auto& writeType = writeBuffer->Content();
MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
if (writeType != readType) {
ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
funcName,
(readType == WebGLBuffer::Kind::OtherData) ? "other"
@ -130,14 +84,8 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
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);
}
gl->MakeCurrent();
gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
}
void
@ -148,88 +96,59 @@ WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
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, funcName))
if (!ValidateNonNegative(funcName, "offset", offset))
return;
// If offset is less than zero, an INVALID_VALUE error is
// generated.
if (offset < 0) {
ErrorInvalidValue("%s: Offset must be non-negative.", funcName);
const auto& buffer = ValidateBufferSelection(funcName, target);
if (!buffer)
return;
}
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
WebGLBuffer* boundBuffer = bufferSlot.get();
if (!boundBuffer) {
ErrorInvalidOperation("%s: No buffer bound.", funcName);
return;
}
////
// If offset + returnedData.byteLength would extend beyond the end
// of the buffer an INVALID_VALUE error is generated.
data.ComputeLengthAndData();
CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.LengthAllowShared();
const auto neededByteLength = CheckedInt<size_t>(offset) + data.LengthAllowShared();
if (!neededByteLength.isValid()) {
ErrorInvalidValue("%s: Integer overflow computing the needed byte length.",
funcName);
return;
}
if (neededByteLength.value() > boundBuffer->ByteLength()) {
if (neededByteLength.value() > buffer->ByteLength()) {
ErrorInvalidValue("%s: Not enough data. Operation requires %d bytes, but buffer"
" only has %d bytes.",
funcName, neededByteLength.value(), boundBuffer->ByteLength());
funcName, neededByteLength.value(), buffer->ByteLength());
return;
}
// If target is TRANSFORM_FEEDBACK_BUFFER, and any transform
// feedback object is currently active, an INVALID_OPERATION error
// is generated.
WebGLTransformFeedback* currentTF = mBoundTransformFeedback;
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
if (currentTF->mIsActive) {
ErrorInvalidOperation("%s: Currently bound transform feedback is active.",
funcName);
return;
}
////
// https://github.com/NVIDIA/WebGL/commit/63aff5e58c1d79825a596f0f4aa46174b9a5f72c
// Performing reads and writes on a buffer that is currently
// bound for transform feedback causes undefined results in
// GLES3.0 and OpenGL 4.5. In practice results of reads and
// writes might be consistent as long as transform feedback
// objects are not active, but neither GLES3.0 nor OpenGL 4.5
// spec guarantees this - just being bound for transform
// feedback is sufficient to cause undefined results.
BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, nullptr);
if (buffer->mNumActiveTFOs) {
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
" object.",
funcName);
return;
}
/* If the buffer is written and read sequentially by other
* operations and getBufferSubData, it is the responsibility of
* the WebGL API to ensure that data are access
* consistently. This applies even if the buffer is currently
* bound to a transform feedback binding point.
*/
void* ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(),
LOCAL_GL_MAP_READ_BIT);
// Warning: Possibly shared memory. See bug 1225033.
memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared());
gl->fUnmapBuffer(target);
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
mBoundTransformFeedback->mIsActive)
{
ErrorInvalidOperation("%s: Currently bound transform feedback is active.",
funcName);
return;
}
////
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF);
}
gl->MakeCurrent();
const auto ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(),
LOCAL_GL_MAP_READ_BIT);
// Warning: Possibly shared memory. See bug 1225033.
memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared());
gl->fUnmapBuffer(target);
}
} // namespace mozilla

View File

@ -13,71 +13,6 @@
namespace mozilla {
static bool
GetFBInfoForBlit(const WebGLFramebuffer* fb, const char* const fbInfo,
GLsizei* const out_samples,
const webgl::FormatInfo** const out_colorFormat,
const webgl::FormatInfo** const out_depthFormat,
const webgl::FormatInfo** const out_stencilFormat)
{
*out_samples = 0;
*out_colorFormat = nullptr;
*out_depthFormat = nullptr;
*out_stencilFormat = nullptr;
if (fb->ColorAttachment(0).IsDefined()) {
const auto& attachment = fb->ColorAttachment(0);
*out_samples = attachment.Samples();
*out_colorFormat = attachment.Format()->format;
}
if (fb->DepthStencilAttachment().IsDefined()) {
const auto& attachment = fb->DepthStencilAttachment();
*out_samples = attachment.Samples();
*out_depthFormat = attachment.Format()->format;
*out_stencilFormat = *out_depthFormat;
} else {
if (fb->DepthAttachment().IsDefined()) {
const auto& attachment = fb->DepthAttachment();
*out_samples = attachment.Samples();
*out_depthFormat = attachment.Format()->format;
}
if (fb->StencilAttachment().IsDefined()) {
const auto& attachment = fb->StencilAttachment();
*out_samples = attachment.Samples();
*out_stencilFormat = attachment.Format()->format;
}
}
return true;
}
static void
GetBackbufferFormats(const WebGLContextOptions& options,
const webgl::FormatInfo** const out_color,
const webgl::FormatInfo** const out_depth,
const webgl::FormatInfo** const out_stencil)
{
const auto effFormat = options.alpha ? webgl::EffectiveFormat::RGBA8
: webgl::EffectiveFormat::RGB8;
*out_color = webgl::GetFormat(effFormat);
*out_depth = nullptr;
*out_stencil = nullptr;
if (options.depth && options.stencil) {
*out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH24_STENCIL8);
*out_stencil = *out_depth;
} else {
if (options.depth) {
*out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH_COMPONENT16);
}
if (options.stencil) {
*out_stencil = webgl::GetFormat(webgl::EffectiveFormat::STENCIL_INDEX8);
}
}
}
void
WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
@ -103,238 +38,41 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
return;
}
const GLbitfield depthAndStencilBits = LOCAL_GL_DEPTH_BUFFER_BIT |
LOCAL_GL_STENCIL_BUFFER_BIT;
if (mask & depthAndStencilBits &&
filter != LOCAL_GL_NEAREST)
////
const auto& readFB = mBoundReadFramebuffer;
if (readFB &&
!readFB->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER"))
{
ErrorInvalidOperation("blitFramebuffer: DEPTH_BUFFER_BIT and"
" STENCIL_BUFFER_BIT can only be used with"
" NEAREST filtering.");
return;
}
if (mBoundReadFramebuffer == mBoundDrawFramebuffer) {
// TODO: It's actually more complicated than this. We need to check that
// the underlying buffers are not the same, not the framebuffers
// themselves.
ErrorInvalidOperation("blitFramebuffer: Source and destination must"
" differ.");
return;
}
GLsizei srcSamples;
const webgl::FormatInfo* srcColorFormat = nullptr;
const webgl::FormatInfo* srcDepthFormat = nullptr;
const webgl::FormatInfo* srcStencilFormat = nullptr;
if (mBoundReadFramebuffer) {
if (!mBoundReadFramebuffer->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER"))
return;
if (!GetFBInfoForBlit(mBoundReadFramebuffer, "READ_FRAMEBUFFER", &srcSamples,
&srcColorFormat, &srcDepthFormat, &srcStencilFormat))
{
return;
}
} else {
srcSamples = 0; // Always 0.
GetBackbufferFormats(mOptions, &srcColorFormat, &srcDepthFormat,
&srcStencilFormat);
}
GLsizei dstSamples;
const webgl::FormatInfo* dstColorFormat = nullptr;
const webgl::FormatInfo* dstDepthFormat = nullptr;
const webgl::FormatInfo* dstStencilFormat = nullptr;
if (mBoundDrawFramebuffer) {
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
return;
if (!GetFBInfoForBlit(mBoundDrawFramebuffer, "DRAW_FRAMEBUFFER", &dstSamples,
&dstColorFormat, &dstDepthFormat, &dstStencilFormat))
{
return;
}
} else {
dstSamples = gl->Screen()->Samples();
GetBackbufferFormats(mOptions, &dstColorFormat, &dstDepthFormat,
&dstStencilFormat);
}
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
const auto fnSignlessType = [](const webgl::FormatInfo* format)
-> webgl::ComponentType
{
if (!format)
return webgl::ComponentType::None;
switch (format->componentType) {
case webgl::ComponentType::UInt:
return webgl::ComponentType::Int;
case webgl::ComponentType::NormUInt:
return webgl::ComponentType::NormInt;
default:
return format->componentType;
}
};
const auto srcType = fnSignlessType(srcColorFormat);
const auto dstType = fnSignlessType(dstColorFormat);
if (srcType != dstType) {
ErrorInvalidOperation("blitFramebuffer: Color buffer format component type"
" mismatch.");
return;
}
const bool srcIsInt = (srcType == webgl::ComponentType::Int);
if (srcIsInt && filter != LOCAL_GL_NEAREST) {
ErrorInvalidOperation("blitFramebuffer: Integer read buffers can only"
" be filtered with NEAREST.");
return;
}
}
/* GLES 3.0.4, p199:
* Calling BlitFramebuffer will result in an INVALID_OPERATION error if
* mask includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT, and the source
* and destination depth and stencil buffer formats do not match.
*
* jgilbert: The wording is such that if only DEPTH_BUFFER_BIT is specified,
* the stencil formats must match. This seems wrong. It could be a spec bug,
* or I could be missing an interaction in one of the earlier paragraphs.
*/
if (mask & LOCAL_GL_DEPTH_BUFFER_BIT &&
dstDepthFormat != srcDepthFormat)
const auto& drawFB = mBoundDrawFramebuffer;
if (drawFB &&
!drawFB->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
{
ErrorInvalidOperation("blitFramebuffer: Depth buffer formats must match"
" if selected.");
return;
}
if (mask & LOCAL_GL_STENCIL_BUFFER_BIT &&
dstStencilFormat != srcStencilFormat)
{
ErrorInvalidOperation("blitFramebuffer: Stencil buffer formats must"
" match if selected.");
return;
}
////
if (dstSamples != 0) {
ErrorInvalidOperation("blitFramebuffer: DRAW_FRAMEBUFFER may not have"
" multiple samples.");
return;
}
if (srcSamples != 0) {
if (mask & LOCAL_GL_COLOR_BUFFER_BIT &&
dstColorFormat != srcColorFormat)
{
ErrorInvalidOperation("blitFramebuffer: Color buffer formats must"
" match if selected, when reading from a"
" multisampled source.");
return;
}
if (dstX0 != srcX0 ||
dstX1 != srcX1 ||
dstY0 != srcY0 ||
dstY1 != srcY1)
{
ErrorInvalidOperation("blitFramebuffer: If the source is"
" multisampled, then the source and dest"
" regions must match exactly.");
return;
}
}
MakeContextCurrent();
gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
static bool
ValidateTextureLayerAttachment(GLenum attachment)
{
if (LOCAL_GL_COLOR_ATTACHMENT0 <= attachment &&
attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
{
return true;
}
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
case LOCAL_GL_STENCIL_ATTACHMENT:
return true;
}
return false;
WebGLFramebuffer::BlitFramebuffer(this,
readFB, srcX0, srcY0, srcX1, srcY1,
drawFB, dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
void
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
WebGLTexture* texture, GLint level, GLint layer)
{
const char funcName[] = "framebufferTextureLayer";
if (IsContextLost())
return;
if (!ValidateFramebufferTarget(target, "framebufferTextureLayer"))
if (!ValidateFramebufferTarget(target, funcName))
return;
if (!ValidateTextureLayerAttachment(attachment))
return ErrorInvalidEnumInfo("framebufferTextureLayer: attachment:", attachment);
if (texture) {
if (texture->IsDeleted()) {
return ErrorInvalidValue("framebufferTextureLayer: texture must be a valid "
"texture object.");
}
if (layer < 0)
return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");
if (level < 0)
return ErrorInvalidValue("framebufferTextureLayer: level must be >= 0.");
switch (texture->Target().get()) {
case LOCAL_GL_TEXTURE_3D:
if (uint32_t(layer) >= mImplMax3DTextureSize) {
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_3D_TEXTURE_SIZE");
}
if (uint32_t(level) > FloorLog2(mImplMax3DTextureSize)) {
return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
"log2(MAX_3D_TEXTURE_SIZE");
}
break;
case LOCAL_GL_TEXTURE_2D_ARRAY:
if (uint32_t(layer) >= mImplMaxArrayTextureLayers) {
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_ARRAY_TEXTURE_LAYERS");
}
if (uint32_t(level) > FloorLog2(mImplMaxTextureSize)) {
return ErrorInvalidValue("framebufferTextureLayer: layer mube be <= "
"log2(MAX_TEXTURE_SIZE");
}
break;
default:
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
"existing 3D texture, or a 2D texture array.");
}
}
WebGLFramebuffer* fb;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
@ -350,12 +88,10 @@ WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
MOZ_CRASH("GFX: Bad target.");
}
if (!fb) {
return ErrorInvalidOperation("framebufferTextureLayer: cannot modify"
" framebuffer 0.");
}
if (!fb)
return ErrorInvalidOperation("%a: Xannot modify framebuffer 0.");
fb->FramebufferTextureLayer(attachment, texture, level, layer);
fb->FramebufferTextureLayer(funcName, attachment, texture, level, layer);
}
JS::Value
@ -532,32 +268,12 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
void
WebGL2Context::ReadBuffer(GLenum mode)
{
const char funcName[] = "readBuffer";
if (IsContextLost())
return;
const bool isColorAttachment = (mode >= LOCAL_GL_COLOR_ATTACHMENT0 &&
mode <= LastColorAttachmentEnum());
if (mode != LOCAL_GL_NONE && mode != LOCAL_GL_BACK && !isColorAttachment) {
ErrorInvalidEnum("readBuffer: `mode` must be one of NONE, BACK, or "
"COLOR_ATTACHMENTi. Was %s",
EnumName(mode));
return;
}
if (mBoundReadFramebuffer) {
if (mode != LOCAL_GL_NONE &&
!isColorAttachment)
{
ErrorInvalidOperation("readBuffer: If READ_FRAMEBUFFER is non-null, `mode` "
"must be COLOR_ATTACHMENTi or NONE. Was %s",
EnumName(mode));
return;
}
MakeContextCurrent();
mBoundReadFramebuffer->SetReadBufferMode(mode);
gl->fReadBuffer(mode);
mBoundReadFramebuffer->ReadBuffer(funcName, mode);
return;
}
@ -565,9 +281,9 @@ WebGL2Context::ReadBuffer(GLenum mode)
if (mode != LOCAL_GL_NONE &&
mode != LOCAL_GL_BACK)
{
ErrorInvalidOperation("readBuffer: If READ_FRAMEBUFFER is null, `mode`"
" must be BACK or NONE. Was %s",
EnumName(mode));
ErrorInvalidOperation("%s: If READ_FRAMEBUFFER is null, `mode` must be BACK or"
" NONE. Was %s",
funcName, EnumName(mode));
return;
}

View File

@ -33,20 +33,26 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
/* GLboolean */
case LOCAL_GL_RASTERIZER_DISCARD:
case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
case LOCAL_GL_SAMPLE_COVERAGE:
case LOCAL_GL_TRANSFORM_FEEDBACK_PAUSED:
case LOCAL_GL_TRANSFORM_FEEDBACK_ACTIVE: {
case LOCAL_GL_SAMPLE_COVERAGE: {
realGLboolean b = 0;
gl->fGetBooleanv(pname, &b);
return JS::BooleanValue(bool(b));
}
case LOCAL_GL_TRANSFORM_FEEDBACK_ACTIVE:
return JS::BooleanValue(mBoundTransformFeedback->mIsActive);
case LOCAL_GL_TRANSFORM_FEEDBACK_PAUSED:
return JS::BooleanValue(mBoundTransformFeedback->mIsPaused);
/* GLenum */
case LOCAL_GL_READ_BUFFER: {
if (mBoundReadFramebuffer)
return JS::Int32Value(mBoundReadFramebuffer->ReadBufferMode());
if (!mBoundReadFramebuffer)
return JS::Int32Value(gl->Screen()->GetReadBufferMode());
return JS::Int32Value(LOCAL_GL_BACK);
if (!mBoundReadFramebuffer->ColorReadBuffer())
return JS::Int32Value(LOCAL_GL_NONE);
return JS::Int32Value(mBoundReadFramebuffer->ColorReadBuffer()->mAttachmentPoint);
}
case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
@ -146,7 +152,10 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
return WebGLObjectAsJSValue(cx, mBoundPixelUnpackBuffer.get(), rv);
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv);
{
const auto& tf = mBoundTransformFeedback;
return WebGLObjectAsJSValue(cx, tf->mGenericBufferBinding.get(), rv);
}
case LOCAL_GL_UNIFORM_BUFFER_BINDING:
return WebGLObjectAsJSValue(cx, mBoundUniformBuffer.get(), rv);
@ -164,11 +173,14 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
case LOCAL_GL_TEXTURE_BINDING_3D:
return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv);
case LOCAL_GL_TRANSFORM_FEEDBACK_BINDING: {
WebGLTransformFeedback* tf =
(mBoundTransformFeedback != mDefaultTransformFeedback) ? mBoundTransformFeedback.get() : nullptr;
return WebGLObjectAsJSValue(cx, tf, rv);
}
case LOCAL_GL_TRANSFORM_FEEDBACK_BINDING:
{
const WebGLTransformFeedback* tf = mBoundTransformFeedback;
if (tf == mDefaultTransformFeedback) {
tf = nullptr;
}
return WebGLObjectAsJSValue(cx, tf, rv);
}
case LOCAL_GL_VERTEX_ARRAY_BINDING: {
WebGLVertexArray* vao =

View File

@ -20,28 +20,32 @@ WebGL2Context::CreateTransformFeedback()
if (IsContextLost())
return nullptr;
GLuint tf = 0;
MakeContextCurrent();
GLuint tf = 0;
gl->fGenTransformFeedbacks(1, &tf);
RefPtr<WebGLTransformFeedback> globj = new WebGLTransformFeedback(this, tf);
return globj.forget();
RefPtr<WebGLTransformFeedback> ret = new WebGLTransformFeedback(this, tf);
return ret.forget();
}
void
WebGL2Context::DeleteTransformFeedback(WebGLTransformFeedback* tf)
{
const char funcName[] = "deleteTransformFeedback";
if (IsContextLost())
return;
if (!ValidateObjectAllowDeletedOrNull("deleteTransformFeedback", tf))
if (!ValidateObject(funcName, tf))
return;
if (!tf || tf->IsDeleted())
if (tf->mIsActive) {
ErrorInvalidOperation("%s: Cannot delete active transform feedbacks.", funcName);
return;
}
if (mBoundTransformFeedback == tf)
if (mBoundTransformFeedback == tf) {
BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, nullptr);
}
tf->RequestDelete();
}
@ -65,67 +69,43 @@ WebGL2Context::IsTransformFeedback(WebGLTransformFeedback* tf)
void
WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf)
{
const char funcName[] = "bindTransformFeedback";
if (IsContextLost())
return;
if (!ValidateObjectAllowDeletedOrNull("bindTransformFeedback", tf))
if (target != LOCAL_GL_TRANSFORM_FEEDBACK)
return ErrorInvalidEnum("%s: `target` must be TRANSFORM_FEEDBACK.", funcName);
if (!ValidateObjectAllowDeletedOrNull(funcName, tf))
return;
if (target != LOCAL_GL_TRANSFORM_FEEDBACK)
return ErrorInvalidEnum("bindTransformFeedback: target must be TRANSFORM_FEEDBACK");
if (tf && tf->IsDeleted())
return ErrorInvalidOperation("%s: TFO already deleted.", funcName);
WebGLRefPtr<WebGLTransformFeedback> currentTF = mBoundTransformFeedback;
if (currentTF && currentTF->mIsActive && !currentTF->mIsPaused) {
return ErrorInvalidOperation("bindTransformFeedback: Currently bound transform "
"feedback is active and not paused");
if (mBoundTransformFeedback->mIsActive &&
!mBoundTransformFeedback->mIsPaused)
{
ErrorInvalidOperation("%s: Currently bound transform feedback is active and not"
" paused.",
funcName);
return;
}
if (tf && tf->IsDeleted())
return ErrorInvalidOperation("bindTransformFeedback: Attempt to bind deleted id");
////
mBoundTransformFeedback = (tf ? tf : mDefaultTransformFeedback);
MakeContextCurrent();
gl->fBindTransformFeedback(target, tf ? tf->mGLName : 0);
if (tf)
mBoundTransformFeedback = tf;
else
mBoundTransformFeedback = mDefaultTransformFeedback;
gl->fBindTransformFeedback(target, mBoundTransformFeedback->mGLName);
}
void
WebGL2Context::BeginTransformFeedback(GLenum primitiveMode)
WebGL2Context::BeginTransformFeedback(GLenum primMode)
{
if (IsContextLost())
return;
WebGLTransformFeedback* tf = mBoundTransformFeedback;
MOZ_ASSERT(tf);
if (!tf)
return;
if (tf->mIsActive)
return ErrorInvalidOperation("beginTransformFeedback: transform feedback is active");
const GLenum mode = tf->mMode;
if (mode != LOCAL_GL_POINTS && mode != LOCAL_GL_LINES && mode != LOCAL_GL_TRIANGLES)
return ErrorInvalidEnum("beginTransformFeedback: primitive must be one of POINTS, LINES, or TRIANGLES");
// TODO:
// GL_INVALID_OPERATION is generated by glBeginTransformFeedback
// if any binding point used in transform feedback mode does not
// have a buffer object bound. In interleaved mode, only the first
// buffer object binding point is ever written to.
// GL_INVALID_OPERATION is generated by glBeginTransformFeedback
// if no binding points would be used, either because no program
// object is active of because the active program object has
// specified no varying variables to record.
if (!mCurrentProgram)
return ErrorInvalidOperation("beginTransformFeedback: no program is active");
MakeContextCurrent();
gl->fBeginTransformFeedback(primitiveMode);
tf->mIsActive = true;
tf->mIsPaused = false;
mBoundTransformFeedback->BeginTransformFeedback(primMode);
}
void
@ -134,20 +114,7 @@ WebGL2Context::EndTransformFeedback()
if (IsContextLost())
return;
WebGLTransformFeedback* tf = mBoundTransformFeedback;
MOZ_ASSERT(tf);
if (!tf)
return;
if (!tf->mIsActive)
return ErrorInvalidOperation("%s: transform feedback in not active",
"endTransformFeedback");
MakeContextCurrent();
gl->fEndTransformFeedback();
tf->mIsActive = false;
tf->mIsPaused = false;
mBoundTransformFeedback->EndTransformFeedback();
}
void
@ -156,19 +123,7 @@ WebGL2Context::PauseTransformFeedback()
if (IsContextLost())
return;
WebGLTransformFeedback* tf = mBoundTransformFeedback;
MOZ_ASSERT(tf);
if (!tf)
return;
if (!tf->mIsActive || tf->mIsPaused) {
return ErrorInvalidOperation("%s: transform feedback is not active or is paused",
"pauseTransformFeedback");
}
MakeContextCurrent();
gl->fPauseTransformFeedback();
tf->mIsPaused = true;
mBoundTransformFeedback->PauseTransformFeedback();
}
void
@ -177,17 +132,7 @@ WebGL2Context::ResumeTransformFeedback()
if (IsContextLost())
return;
WebGLTransformFeedback* tf = mBoundTransformFeedback;
MOZ_ASSERT(tf);
if (!tf)
return;
if (!tf->mIsActive || !tf->mIsPaused)
return ErrorInvalidOperation("resumeTransformFeedback: transform feedback is not active or is not paused");
MakeContextCurrent();
gl->fResumeTransformFeedback();
tf->mIsPaused = false;
mBoundTransformFeedback->ResumeTransformFeedback();
}
void

View File

@ -70,57 +70,60 @@ WebGL2Context::Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuin
// -------------------------------------------------------------------------
// Uniform Buffer Objects and Transform Feedback Buffers
// TODO(djg): Implemented in WebGLContext
/*
void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
GLintptr offset, GLsizeiptr size);
*/
/* This doesn't belong here. It's part of state querying */
void
WebGL2Context::GetIndexedParameter(GLenum target, GLuint index,
dom::Nullable<dom::OwningWebGLBufferOrLongLong>& retval)
{
const char funcName[] = "getIndexedParameter";
retval.SetNull();
if (IsContextLost())
return;
GLint64 data = 0;
MakeContextCurrent();
const std::vector<IndexedBufferBinding>* bindings;
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
if (index >= mGLMaxTransformFeedbackSeparateAttribs)
return ErrorInvalidValue("getIndexedParameter: index should be less than "
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
if (mBoundTransformFeedbackBuffers[index].get()) {
retval.SetValue().SetAsWebGLBuffer() =
mBoundTransformFeedbackBuffers[index].get();
}
return;
case LOCAL_GL_UNIFORM_BUFFER_BINDING:
if (index >= mGLMaxUniformBufferBindings)
return ErrorInvalidValue("getIndexedParameter: index should be than "
"MAX_UNIFORM_BUFFER_BINDINGS");
if (mBoundUniformBuffers[index].get())
retval.SetValue().SetAsWebGLBuffer() = mBoundUniformBuffers[index].get();
return;
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START:
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
bindings = &(mBoundTransformFeedback->mIndexedBindings);
break;
case LOCAL_GL_UNIFORM_BUFFER_BINDING:
case LOCAL_GL_UNIFORM_BUFFER_START:
case LOCAL_GL_UNIFORM_BUFFER_SIZE:
gl->fGetInteger64i_v(target, index, &data);
retval.SetValue().SetAsLongLong() = data;
bindings = &mIndexedUniformBufferBindings;
break;
default:
ErrorInvalidEnumInfo("getIndexedParameter: target", target);
return;
}
ErrorInvalidEnumInfo("getIndexedParameter: target", target);
if (index >= bindings->size()) {
ErrorInvalidValue("%s: `index` must be < %s.", funcName,
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
return;
}
const auto& binding = (*bindings)[index];
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
case LOCAL_GL_UNIFORM_BUFFER_BINDING:
if (binding.mBufferBinding) {
retval.SetValue().SetAsWebGLBuffer() = binding.mBufferBinding;
}
break;
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START:
case LOCAL_GL_UNIFORM_BUFFER_START:
retval.SetValue().SetAsLongLong() = binding.mRangeStart;
break;
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
case LOCAL_GL_UNIFORM_BUFFER_SIZE:
retval.SetValue().SetAsLongLong() = binding.mRangeSize;
break;
}
}
void

View File

@ -17,23 +17,30 @@ WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf)
, mGLName(buf)
, mContent(Kind::Undefined)
, mByteLength(0)
, mNumActiveTFOs(0)
, mBoundForTF(false)
{
mContext->mBuffers.insertBack(this);
}
WebGLBuffer::~WebGLBuffer()
{
MOZ_ASSERT(!mNumActiveTFOs);
DeleteOnce();
}
void
WebGLBuffer::BindTo(GLenum target)
WebGLBuffer::SetContentAfterBind(GLenum target)
{
if (mContent != Kind::Undefined)
return;
switch (target) {
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
mContent = Kind::ElementArray;
if (!mCache)
mCache = new WebGLElementArrayCache;
if (!mCache) {
mCache.reset(new WebGLElementArrayCache);
}
break;
case LOCAL_GL_ARRAY_BUFFER:
@ -41,14 +48,9 @@ WebGLBuffer::BindTo(GLenum target)
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:
if (mContent == Kind::Undefined) {
mContent = Kind::OtherData;
}
mContent = Kind::OtherData;
break;
default:
@ -66,6 +68,90 @@ WebGLBuffer::Delete()
LinkedListElement<WebGLBuffer>::remove(); // remove from mContext->mBuffers
}
////////////////////////////////////////
static bool
ValidateBufferUsageEnum(WebGLContext* webgl, const char* funcName, GLenum usage)
{
switch (usage) {
case LOCAL_GL_STREAM_DRAW:
case LOCAL_GL_STATIC_DRAW:
case LOCAL_GL_DYNAMIC_DRAW:
return true;
case LOCAL_GL_DYNAMIC_COPY:
case LOCAL_GL_DYNAMIC_READ:
case LOCAL_GL_STATIC_COPY:
case LOCAL_GL_STATIC_READ:
case LOCAL_GL_STREAM_COPY:
case LOCAL_GL_STREAM_READ:
if (MOZ_LIKELY(webgl->IsWebGL2()))
return true;
break;
default:
break;
}
webgl->ErrorInvalidEnum("%s: Invalid `usage`: 0x%04x", funcName, usage);
return false;
}
void
WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usage)
{
const char funcName[] = "bufferData";
if (!ValidateBufferUsageEnum(mContext, funcName, usage))
return;
if (mNumActiveTFOs) {
mContext->ErrorInvalidOperation("%s: Buffer is bound to an active transform"
" feedback object.",
funcName);
return;
}
const auto& gl = mContext->gl;
gl->MakeCurrent();
mContext->InvalidateBufferFetching();
#ifdef XP_MACOSX
// bug 790879
if (gl->WorkAroundDriverBugs() &&
size > INT32_MAX)
{
mContext->ErrorOutOfMemory("%s: Allocation size too large.", funcName);
return;
}
#endif
const bool sizeChanges = (size != ByteLength());
if (sizeChanges) {
gl::GLContext::LocalErrorScope errorScope(*gl);
gl->fBufferData(target, size, data, usage);
const auto error = errorScope.GetError();
if (error) {
MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY);
mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error);
return;
}
} else {
gl->fBufferData(target, size, data, usage);
}
mByteLength = size;
// Warning: Possibly shared memory. See bug 1225033.
if (!ElementArrayCacheBufferData(data, size)) {
mByteLength = 0;
mContext->ErrorOutOfMemory("%s: Failed update index buffer cache.", funcName);
}
}
////////////////////////////////////////
bool
WebGLBuffer::ElementArrayCacheBufferData(const void* ptr,
size_t bufferSizeInBytes)
@ -93,10 +179,9 @@ WebGLBuffer::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
}
bool
WebGLBuffer::Validate(GLenum type, uint32_t maxAllowed, size_t first,
size_t count, uint32_t* const out_upperBound)
WebGLBuffer::Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count) const
{
return mCache->Validate(type, maxAllowed, first, count, out_upperBound);
return mCache->Validate(type, maxAllowed, first, count);
}
bool
@ -105,6 +190,68 @@ WebGLBuffer::IsElementArrayUsedWithMultipleTypes() const
return mCache->BeenUsedWithMultipleTypes();
}
bool
WebGLBuffer::ValidateCanBindToTarget(const char* funcName, GLenum target)
{
const bool wouldBeTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
if (mWebGLRefCnt && wouldBeTF != mBoundForTF) {
mContext->ErrorInvalidOperation("%s: Buffers cannot be simultaneously bound to "
" transform feedback and bound elsewhere.",
funcName);
return false;
}
mBoundForTF = wouldBeTF;
/* 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 (mContent == 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 (mContent == 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 (mContent == WebGLBuffer::Kind::OtherData)
return true;
break;
default:
MOZ_CRASH();
}
const auto dataType = (mContent == WebGLBuffer::Kind::OtherData) ? "other"
: "element";
mContext->ErrorInvalidOperation("%s: Buffer already contains %s data.", funcName,
dataType);
return false;
}
JSObject*
WebGLBuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{

View File

@ -8,7 +8,7 @@
#include "GLDefs.h"
#include "mozilla/LinkedList.h"
#include "nsAutoPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsWrapperCache.h"
#include "WebGLObjectModel.h"
@ -24,8 +24,12 @@ class WebGLBuffer final
, public LinkedListElement<WebGLBuffer>
, public WebGLContextBoundObject
{
public:
friend class WebGLContext;
friend class WebGL2Context;
friend class WebGLTexture;
friend class WebGLTransformFeedback;
public:
enum class Kind {
Undefined,
ElementArray,
@ -34,23 +38,21 @@ public:
WebGLBuffer(WebGLContext* webgl, GLuint buf);
void BindTo(GLenum target);
void SetContentAfterBind(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; }
size_t ByteLength() const { return mByteLength; }
bool ElementArrayCacheBufferData(const void* ptr, size_t bufferSizeInBytes);
void ElementArrayCacheBufferSubData(size_t pos, const void* ptr,
size_t updateSizeInBytes);
bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count,
uint32_t* const out_upperBound);
bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count) const;
bool IsElementArrayUsedWithMultipleTypes() const;
@ -60,6 +62,9 @@ public:
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
bool ValidateCanBindToTarget(const char* funcName, GLenum target);
void BufferData(GLenum target, size_t size, const void* data, GLenum usage);
const GLenum mGLName;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
@ -69,8 +74,10 @@ protected:
~WebGLBuffer();
Kind mContent;
WebGLsizeiptr mByteLength;
nsAutoPtr<WebGLElementArrayCache> mCache;
size_t mByteLength;
UniquePtr<WebGLElementArrayCache> mCache;
size_t mNumActiveTFOs;
bool mBoundForTF;
};
} // namespace mozilla

View File

@ -247,7 +247,6 @@ WebGLContext::DestroyResourcesAndContext()
mBoundCopyWriteBuffer = nullptr;
mBoundPixelPackBuffer = nullptr;
mBoundPixelUnpackBuffer = nullptr;
mBoundTransformFeedbackBuffer = nullptr;
mBoundUniformBuffer = nullptr;
mCurrentProgram = nullptr;
mActiveProgramLinkInfo = nullptr;
@ -260,8 +259,7 @@ WebGLContext::DestroyResourcesAndContext()
mBoundTransformFeedback = nullptr;
mDefaultTransformFeedback = nullptr;
mBoundTransformFeedbackBuffers.Clear();
mBoundUniformBuffers.Clear();
mIndexedUniformBufferBindings.clear();
//////
@ -1637,18 +1635,11 @@ WebGLContext::DummyReadFramebufferOperation(const char* funcName)
if (!mBoundReadFramebuffer)
return; // Infallible.
nsCString fbStatusInfo;
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(&fbStatusInfo);
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus(funcName);
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
nsCString errorText("Incomplete framebuffer");
if (fbStatusInfo.Length()) {
errorText += ": ";
errorText += fbStatusInfo;
}
ErrorInvalidFramebufferOperation("%s: %s.", funcName, errorText.BeginReading());
ErrorInvalidFramebufferOperation("%s: Framebuffer must be complete.",
funcName);
}
}
@ -1951,8 +1942,18 @@ WebGLContext::GetSurfaceSnapshot(bool* out_premultAlpha)
{
ScopedBindFramebuffer autoFB(gl, 0);
ClearBackbufferIfNeeded();
// TODO: Save, override, then restore glReadBuffer if present.
// Save, override, then restore glReadBuffer.
const GLenum readBufferMode = gl->Screen()->GetReadBufferMode();
if (readBufferMode != LOCAL_GL_BACK) {
gl->fReadBuffer(LOCAL_GL_BACK);
}
ReadPixelsIntoDataSurface(gl, surf);
if (readBufferMode != LOCAL_GL_BACK) {
gl->fReadBuffer(readBufferMode);
}
}
if (out_premultAlpha) {
@ -2078,6 +2079,30 @@ WebGLContext::ScopedMaskWorkaround::HasDepthButNoStencil(const WebGLFramebuffer*
////////////////////////////////////////
IndexedBufferBinding::IndexedBufferBinding()
: mRangeStart(0)
, mRangeSize(0)
{ }
uint64_t
IndexedBufferBinding::ByteCount() const
{
if (!mBufferBinding)
return 0;
uint64_t bufferSize = mBufferBinding->ByteLength();
if (!mRangeSize) // BindBufferBase
return bufferSize;
if (mRangeStart >= bufferSize)
return 0;
bufferSize -= mRangeStart;
return std::min(bufferSize, mRangeSize);
}
////////////////////////////////////////
ScopedUnpackReset::ScopedUnpackReset(WebGLContext* webgl)
: ScopedGLWrapper<ScopedUnpackReset>(webgl->gl)
, mWebGL(webgl)
@ -2116,6 +2141,24 @@ ScopedUnpackReset::UnwrapImpl()
}
}
////////////////////
void
ScopedFBRebinder::UnwrapImpl()
{
const auto fnName = [&](WebGLFramebuffer* fb) {
return fb ? fb->mGLName : 0;
};
if (mWebGL->IsWebGL2()) {
mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fnName(mWebGL->mBoundReadFramebuffer));
} else {
MOZ_ASSERT(mWebGL->mBoundDrawFramebuffer == mWebGL->mBoundReadFramebuffer);
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
}
}
////////////////////////////////////////
void
@ -2435,6 +2478,24 @@ WebGLContext::StartVRPresentation()
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const std::vector<IndexedBufferBinding>& field,
const char* name, uint32_t flags)
{
for (const auto& cur : field) {
ImplCycleCollectionTraverse(callback, cur.mBufferBinding, name, flags);
}
}
void
ImplCycleCollectionUnlink(std::vector<IndexedBufferBinding>& field)
{
field.clear();
}
////
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
@ -2452,7 +2513,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
mBoundCopyWriteBuffer,
mBoundPixelPackBuffer,
mBoundPixelUnpackBuffer,
mBoundTransformFeedbackBuffer,
mBoundTransformFeedback,
mBoundUniformBuffer,
mCurrentProgram,
mBoundDrawFramebuffer,

View File

@ -124,6 +124,7 @@ struct LinkedProgramInfo;
class ShaderValidator;
class TexUnpackBlob;
struct UniformInfo;
struct UniformBlockInfo;
} // namespace webgl
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
@ -181,6 +182,19 @@ public:
GLfloat AsFloat() const { return (mType == Float) ? mValue.f : GLfloat(mValue.i); }
};
struct IndexedBufferBinding
{
WebGLRefPtr<WebGLBuffer> mBufferBinding;
uint64_t mRangeStart;
uint64_t mRangeSize;
IndexedBufferBinding();
uint64_t ByteCount() const;
};
////////////////////////////////////////////////////////////////////////////////
class WebGLContext
: public nsIDOMWebGLRenderingContext
, public nsICanvasRenderingContextInternal
@ -189,6 +203,9 @@ class WebGLContext
, public WebGLRectangleObject
, public nsWrapperCache
{
friend class ScopedDrawHelper;
friend class ScopedDrawWithTransformFeedback;
friend class ScopedFBRebinder;
friend class WebGL2Context;
friend class WebGLContextUserData;
friend class WebGLExtensionCompressedTextureATC;
@ -202,6 +219,7 @@ class WebGLContext
friend class WebGLExtensionLoseContext;
friend class WebGLExtensionVertexArray;
friend class WebGLMemoryTracker;
friend struct webgl::UniformBlockInfo;
enum {
UNPACK_FLIP_Y_WEBGL = 0x9240,
@ -725,11 +743,6 @@ public:
// -----------------------------------------------------------------------------
// Buffer Objects (WebGLContextBuffers.cpp)
private:
void UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer);
void UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer);
public:
void BindBuffer(GLenum target, WebGLBuffer* buffer);
void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buf);
void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buf,
@ -771,18 +784,14 @@ protected:
WebGLRefPtr<WebGLBuffer> mBoundCopyWriteBuffer;
WebGLRefPtr<WebGLBuffer> mBoundPixelPackBuffer;
WebGLRefPtr<WebGLBuffer> mBoundPixelUnpackBuffer;
WebGLRefPtr<WebGLBuffer> mBoundTransformFeedbackBuffer;
WebGLRefPtr<WebGLBuffer> mBoundUniformBuffer;
nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundUniformBuffers;
nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundTransformFeedbackBuffers;
std::vector<IndexedBufferBinding> mIndexedUniformBufferBindings;
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTarget(GLenum target);
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTargetIndexed(GLenum target,
GLuint index);
GLenum GetCurrentBinding(WebGLBuffer* buffer) const;
// -----------------------------------------------------------------------------
// Queries (WebGL2ContextQueries.cpp)
protected:
@ -1045,11 +1054,11 @@ private:
uint32_t mMaxFetchedInstances;
bool mBufferFetch_IsAttrib0Active;
bool DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
const char* info);
bool DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOffset,
GLsizei primcount, const char* info,
GLuint* out_upperBound);
bool DrawArrays_check(const char* funcName, GLenum mode, GLint first,
GLsizei vertCount, GLsizei instanceCount);
bool DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
GLenum type, WebGLintptr byteOffset,
GLsizei instanceCount);
bool DrawInstanced_check(const char* info);
void Draw_cleanup(const char* funcName);
@ -1138,6 +1147,8 @@ public:
return LOCAL_GL_COLOR_ATTACHMENT0 + mImplMaxColorAttachments - 1;
}
const decltype(mOptions)& Options() const { return mOptions; }
protected:
// Texture sizes are often not actually the GL values. Let's be explicit that these
@ -1252,7 +1263,6 @@ protected:
bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info);
bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor,
const char* info);
bool ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info);
bool ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info);
bool ValidateTextureTargetEnum(GLenum target, const char* info);
bool ValidateComparisonEnum(GLenum target, const char* info);
@ -1319,6 +1329,28 @@ protected:
const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height);
bool HasDrawBuffers() const {
return IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
}
WebGLRefPtr<WebGLBuffer>* ValidateBufferSlot(const char* funcName, GLenum target);
WebGLBuffer* ValidateBufferSelection(const char* funcName, GLenum target);
IndexedBufferBinding* ValidateIndexedBufferSlot(const char* funcName, GLenum target,
GLuint index);
bool ValidateIndexedBufferBinding(const char* funcName, GLenum target, GLuint index,
WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
IndexedBufferBinding** const out_indexedBinding);
bool ValidateNonNegative(const char* funcName, const char* argName, int64_t val) {
if (MOZ_UNLIKELY(val < 0)) {
ErrorInvalidValue("%s: `%s` must be non-negative.", funcName, argName);
return false;
}
return true;
}
void Invalidate();
void DestroyResourcesAndContext();
@ -1364,20 +1396,9 @@ private:
virtual WebGLVertexArray* CreateVertexArrayImpl();
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, uint32_t* 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);
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:
/** Like glBufferData, but if the call may change the buffer size, checks
* any GL error generated by this glBufferData call and returns it.
*/
GLenum CheckedBufferData(GLenum target, GLsizeiptr size, const GLvoid* data,
GLenum usage);
public:
void ForceLoseContext(bool simulateLoss = false);
@ -1780,18 +1801,36 @@ public:
void operator =(const UniqueBuffer& other) = delete; // assign using Move()!
};
class ScopedUnpackReset
class ScopedUnpackReset final
: public gl::ScopedGLWrapper<ScopedUnpackReset>
{
friend struct gl::ScopedGLWrapper<ScopedUnpackReset>;
protected:
private:
WebGLContext* const mWebGL;
public:
explicit ScopedUnpackReset(WebGLContext* webgl);
protected:
private:
void UnwrapImpl();
};
class ScopedFBRebinder final
: public gl::ScopedGLWrapper<ScopedFBRebinder>
{
friend struct gl::ScopedGLWrapper<ScopedFBRebinder>;
private:
WebGLContext* const mWebGL;
public:
explicit ScopedFBRebinder(WebGLContext* webgl)
: ScopedGLWrapper<ScopedFBRebinder>(webgl->gl)
, mWebGL(webgl)
{ }
private:
void UnwrapImpl();
};
@ -1811,6 +1850,16 @@ ZeroTextureData(WebGLContext* webgl, const char* funcName, GLuint tex,
const webgl::FormatUsageInfo* usage, uint32_t xOffset, uint32_t yOffset,
uint32_t zOffset, uint32_t width, uint32_t height, uint32_t depth);
////
void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const std::vector<IndexedBufferBinding>& field,
const char* name, uint32_t flags = 0);
void
ImplCycleCollectionUnlink(std::vector<IndexedBufferBinding>& field);
} // namespace mozilla
#endif

View File

@ -11,177 +11,316 @@
namespace mozilla {
void
WebGLContext::UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer)
WebGLRefPtr<WebGLBuffer>*
WebGLContext::ValidateBufferSlot(const char* funcName, GLenum target)
{
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
bufferSlot = buffer;
WebGLRefPtr<WebGLBuffer>* slot = nullptr;
if (!buffer)
return;
switch (target) {
case LOCAL_GL_ARRAY_BUFFER:
slot = &mBoundArrayBuffer;
break;
buffer->BindTo(target);
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
slot = &(mBoundVertexArray->mElementArrayBuffer);
break;
}
if (IsWebGL2()) {
switch (target) {
case LOCAL_GL_COPY_READ_BUFFER:
slot = &mBoundCopyReadBuffer;
break;
case LOCAL_GL_COPY_WRITE_BUFFER:
slot = &mBoundCopyWriteBuffer;
break;
case LOCAL_GL_PIXEL_PACK_BUFFER:
slot = &mBoundPixelPackBuffer;
break;
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
slot = &mBoundPixelUnpackBuffer;
break;
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
slot = &(mBoundTransformFeedback->mGenericBufferBinding);
break;
case LOCAL_GL_UNIFORM_BUFFER:
slot = &mBoundUniformBuffer;
break;
}
}
if (!slot) {
ErrorInvalidEnum("%s: Bad `target`: 0x%04x", funcName, target);
return nullptr;
}
return slot;
}
void
WebGLContext::UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer)
WebGLBuffer*
WebGLContext::ValidateBufferSelection(const char* funcName, GLenum target)
{
UpdateBoundBuffer(target, buffer);
const auto& slot = ValidateBufferSlot(funcName, target);
if (!slot)
return nullptr;
const auto& buffer = *slot;
WebGLRefPtr<WebGLBuffer>& bufferIndexSlot =
GetBufferSlotByTargetIndexed(target, index);
bufferIndexSlot = buffer;
if (!buffer) {
ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
return nullptr;
}
return buffer.get();
}
IndexedBufferBinding*
WebGLContext::ValidateIndexedBufferSlot(const char* funcName, GLenum target, GLuint index)
{
decltype(mIndexedUniformBufferBindings)* bindings;
const char* maxIndexEnum;
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
bindings = &(mBoundTransformFeedback->mIndexedBindings);
maxIndexEnum = "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS";
break;
case LOCAL_GL_UNIFORM_BUFFER:
bindings = &mIndexedUniformBufferBindings;
maxIndexEnum = "MAX_UNIFORM_BUFFER_BINDINGS";
break;
default:
ErrorInvalidEnum("%s: Bad `target`: 0x%04x", funcName, target);
return nullptr;
}
if (index >= bindings->size()) {
ErrorInvalidOperation("%s: `index` >= %s.", funcName, maxIndexEnum);
return nullptr;
}
return &(*bindings)[index];
}
////////////////////////////////////////
void
WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer)
{
const char funcName[] = "bindBuffer";
if (IsContextLost())
return;
if (!ValidateObjectAllowDeletedOrNull("bindBuffer", buffer))
if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
return;
// silently ignore a deleted buffer
if (buffer && buffer->IsDeleted())
return;
if (!ValidateBufferTarget(target, "bindBuffer"))
const auto& slot = ValidateBufferSlot(funcName, target);
if (!slot)
return;
if (!ValidateBufferForTarget(target, buffer, "bindBuffer"))
if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
return;
WebGLContextUnchecked::BindBuffer(target, buffer);
gl->MakeCurrent();
gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
UpdateBoundBuffer(target, buffer);
*slot = buffer;
if (buffer) {
buffer->SetContentAfterBind(target);
}
}
////////////////////////////////////////
bool
WebGLContext::ValidateIndexedBufferBinding(const char* funcName, GLenum target,
GLuint index,
WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
IndexedBufferBinding** const out_indexedBinding)
{
*out_genericBinding = ValidateBufferSlot(funcName, target);
if (!*out_genericBinding)
return false;
*out_indexedBinding = ValidateIndexedBufferSlot(funcName, target, index);
if (!*out_indexedBinding)
return false;
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
mBoundTransformFeedback->mIsActive)
{
ErrorInvalidOperation("%s: Cannot update indexed buffer bindings on active"
" transform feedback objects.",
funcName);
return false;
}
return true;
}
void
WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
{
const char funcName[] = "bindBufferBase";
if (IsContextLost())
return;
if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
return;
// silently ignore a deleted buffer
if (buffer && buffer->IsDeleted())
return;
// ValidateBufferTarget
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
if (index >= mGLMaxTransformFeedbackSeparateAttribs)
return ErrorInvalidValue("bindBufferBase: index should be less than "
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
break;
case LOCAL_GL_UNIFORM_BUFFER:
if (index >= mGLMaxUniformBufferBindings)
return ErrorInvalidValue("bindBufferBase: index should be less than "
"MAX_UNIFORM_BUFFER_BINDINGS");
break;
default:
return ErrorInvalidEnumInfo("bindBufferBase: target", target);
WebGLRefPtr<WebGLBuffer>* genericBinding;
IndexedBufferBinding* indexedBinding;
if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
&indexedBinding))
{
return;
}
if (!ValidateBufferForTarget(target, buffer, "bindBufferBase"))
if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
return;
WebGLContextUnchecked::BindBufferBase(target, index, buffer);
////
UpdateBoundBufferIndexed(target, index, buffer);
gl->MakeCurrent();
gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
////
*genericBinding = buffer;
indexedBinding->mBufferBinding = buffer;
indexedBinding->mRangeStart = 0;
indexedBinding->mRangeSize = 0;
if (buffer) {
buffer->SetContentAfterBind(target);
}
}
void
WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
WebGLintptr offset, WebGLsizeiptr size)
{
const char funcName[] = "bindBufferRange";
if (IsContextLost())
return;
if (!ValidateObjectAllowDeletedOrNull("bindBufferRange", buffer))
if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
return;
// silently ignore a deleted buffer
if (buffer && buffer->IsDeleted())
return;
// ValidateBufferTarget
if (!ValidateNonNegative(funcName, "offset", offset) ||
!ValidateNonNegative(funcName, "size", size))
{
return;
}
WebGLRefPtr<WebGLBuffer>* genericBinding;
IndexedBufferBinding* indexedBinding;
if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
&indexedBinding))
{
return;
}
if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
return;
////
gl->MakeCurrent();
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
if (index >= mGLMaxTransformFeedbackSeparateAttribs)
return ErrorInvalidValue("bindBufferRange: index should be less than "
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
if (offset % 4 != 0 || size % 4 != 0) {
ErrorInvalidValue("%s: For %s, `offset` and `size` must be multiples of 4.",
funcName, "TRANSFORM_FEEDBACK_BUFFER");
return;
}
break;
case LOCAL_GL_UNIFORM_BUFFER:
if (index >= mGLMaxUniformBufferBindings)
return ErrorInvalidValue("bindBufferRange: index should be less than "
"MAX_UNIFORM_BUFFER_BINDINGS");
{
GLuint offsetAlignment = 0;
gl->GetUIntegerv(LOCAL_GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offsetAlignment);
if (offset % offsetAlignment != 0) {
ErrorInvalidValue("%s: For %s, `offset` must be a multiple of %s.",
funcName, "UNIFORM_BUFFER",
"UNIFORM_BUFFER_OFFSET_ALIGNMENT");
return;
}
}
break;
default:
return ErrorInvalidEnumInfo("bindBufferRange: target", target);
}
if (!ValidateBufferForTarget(target, buffer, "bindBufferRange"))
return;
////
WebGLContextUnchecked::BindBufferRange(target, index, buffer, 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
UpdateBoundBufferIndexed(target, index, buffer);
gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset, size);
////
*genericBinding = buffer;
indexedBinding->mBufferBinding = buffer;
indexedBinding->mRangeStart = offset;
indexedBinding->mRangeSize = size;
if (buffer) {
buffer->SetContentAfterBind(target);
}
}
////////////////////////////////////////
void
WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
{
const char funcName[] = "bufferData";
if (IsContextLost())
return;
if (!ValidateBufferTarget(target, "bufferData"))
return;
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
if (size < 0)
return ErrorInvalidValue("bufferData: negative size");
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
if (!ValidateNonNegative(funcName, "size", size))
return;
// careful: WebGLsizeiptr is always 64-bit, but GLsizeiptr is like intptr_t.
if (!CheckedInt<GLsizeiptr>(size).isValid())
return ErrorOutOfMemory("bufferData: bad size");
return ErrorOutOfMemory("%s: bad size", funcName);
WebGLBuffer* boundBuffer = bufferSlot.get();
const auto& buffer = ValidateBufferSelection(funcName, target);
if (!buffer)
return;
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
////
UniquePtr<uint8_t> zeroBuffer((uint8_t*)calloc(size, 1));
if (!zeroBuffer)
return ErrorOutOfMemory("bufferData: out of memory");
return ErrorOutOfMemory("%s: Failed to allocate zeros.", funcName);
MakeContextCurrent();
InvalidateBufferFetching();
GLenum error = CheckedBufferData(target, size, zeroBuffer.get(), usage);
if (error) {
GenerateWarning("bufferData generated error %s", ErrorName(error));
return;
}
boundBuffer->SetByteLength(size);
if (!boundBuffer->ElementArrayCacheBufferData(nullptr, size)) {
boundBuffer->SetByteLength(0);
return ErrorOutOfMemory("bufferData: out of memory");
}
buffer->BufferData(target, size_t(size), zeroBuffer.get(), usage);
}
// BufferT may be one of
@ -194,14 +333,10 @@ WebGLContext::BufferDataT(GLenum target,
const BufferT& data,
GLenum usage)
{
const char funcName[] = "bufferData";
if (IsContextLost())
return;
if (!ValidateBufferTarget(target, "bufferData"))
return;
const WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
data.ComputeLengthAndData();
// Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
@ -209,32 +344,12 @@ WebGLContext::BufferDataT(GLenum target,
if (!CheckedInt<GLsizeiptr>(data.LengthAllowShared()).isValid())
return ErrorOutOfMemory("bufferData: bad size");
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
const auto& buffer = ValidateBufferSelection(funcName, target);
if (!buffer)
return;
WebGLBuffer* boundBuffer = bufferSlot.get();
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
MakeContextCurrent();
InvalidateBufferFetching();
// Warning: Possibly shared memory. See bug 1225033.
GLenum error = CheckedBufferData(target, data.LengthAllowShared(), data.DataAllowShared(), usage);
if (error) {
GenerateWarning("bufferData generated error %s", ErrorName(error));
return;
}
boundBuffer->SetByteLength(data.LengthAllowShared());
// Warning: Possibly shared memory. See bug 1225033.
if (!boundBuffer->ElementArrayCacheBufferData(data.DataAllowShared(), data.LengthAllowShared())) {
boundBuffer->SetByteLength(0);
return ErrorOutOfMemory("bufferData: out of memory");
}
buffer->BufferData(target, data.LengthAllowShared(), data.DataAllowShared(), usage);
}
void
@ -264,6 +379,8 @@ WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& data,
BufferDataT(target, data, usage);
}
////////////////////////////////////////
// BufferT may be one of
// const dom::ArrayBuffer&
// const dom::SharedArrayBuffer&
@ -274,25 +391,28 @@ WebGLContext::BufferSubDataT(GLenum target,
WebGLsizeiptr byteOffset,
const BufferT& data)
{
const char funcName[] = "bufferSubData";
if (IsContextLost())
return;
if (!ValidateBufferTarget(target, "bufferSubData"))
if (!ValidateNonNegative(funcName, "byteOffset", byteOffset))
return;
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
const auto& buffer = ValidateBufferSelection(funcName, target);
if (!buffer)
return;
if (byteOffset < 0)
return ErrorInvalidValue("bufferSubData: negative offset");
WebGLBuffer* boundBuffer = bufferSlot.get();
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
if (buffer->mNumActiveTFOs) {
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
" object.",
"bufferSubData");
return;
}
data.ComputeLengthAndData();
CheckedInt<WebGLsizeiptr> checked_neededByteLength =
CheckedInt<WebGLsizeiptr>(byteOffset) + data.LengthAllowShared();
const auto checked_neededByteLength =
CheckedInt<size_t>(byteOffset) + data.LengthAllowShared();
if (!checked_neededByteLength.isValid()) {
ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
@ -300,21 +420,22 @@ WebGLContext::BufferSubDataT(GLenum target,
return;
}
if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
if (checked_neededByteLength.value() > buffer->ByteLength()) {
ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
" %d bytes, but buffer only has %d bytes.",
checked_neededByteLength.value(),
boundBuffer->ByteLength());
buffer->ByteLength());
return;
}
// Warning: Possibly shared memory. See bug 1225033.
boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
data.LengthAllowShared());
MakeContextCurrent();
// Warning: Possibly shared memory. See bug 1225033.
gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(), data.DataAllowShared());
gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(),
data.DataAllowShared());
// Warning: Possibly shared memory. See bug 1225033.
buffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
data.LengthAllowShared());
}
void
@ -342,6 +463,8 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
BufferSubDataT(target, byteOffset, data);
}
////////////////////////////////////////
already_AddRefed<WebGLBuffer>
WebGLContext::CreateBuffer()
{
@ -368,60 +491,45 @@ WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
if (!buffer || buffer->IsDeleted())
return;
// TODO: Extract this into a helper function?
if (mBoundArrayBuffer == buffer) {
WebGLContextUnchecked::BindBuffer(LOCAL_GL_ARRAY_BUFFER, nullptr);
mBoundArrayBuffer = nullptr;
}
////
if (mBoundVertexArray->mElementArrayBuffer == buffer) {
WebGLContextUnchecked::BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nullptr);
mBoundVertexArray->mElementArrayBuffer = nullptr;
}
const auto fnClearIfBuffer = [&](WebGLRefPtr<WebGLBuffer>& bindPoint) {
if (bindPoint == buffer) {
bindPoint = nullptr;
}
};
fnClearIfBuffer(mBoundArrayBuffer);
fnClearIfBuffer(mBoundVertexArray->mElementArrayBuffer);
// WebGL binding points
if (IsWebGL2()) {
if (mBoundCopyReadBuffer == buffer)
mBoundCopyReadBuffer = nullptr;
fnClearIfBuffer(mBoundCopyReadBuffer);
fnClearIfBuffer(mBoundCopyWriteBuffer);
fnClearIfBuffer(mBoundPixelPackBuffer);
fnClearIfBuffer(mBoundPixelUnpackBuffer);
fnClearIfBuffer(mBoundUniformBuffer);
fnClearIfBuffer(mBoundTransformFeedback->mGenericBufferBinding);
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;
if (!mBoundTransformFeedback->mIsActive) {
for (auto& binding : mBoundTransformFeedback->mIndexedBindings) {
fnClearIfBuffer(binding.mBufferBinding);
}
}
const size_t uniformBufferCount = mBoundUniformBuffers.Length();
for (size_t n = 0; n < uniformBufferCount; n++) {
if (mBoundUniformBuffers[n] == buffer) {
mBoundUniformBuffers[n] = nullptr;
}
for (auto& binding : mIndexedUniformBufferBindings) {
fnClearIfBuffer(binding.mBufferBinding);
}
}
for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) {
if (mBoundVertexArray->HasAttrib(i) &&
mBoundVertexArray->mAttribs[i].buf == buffer)
{
mBoundVertexArray->mAttribs[i].buf = nullptr;
if (mBoundVertexArray->HasAttrib(i)) {
fnClearIfBuffer(mBoundVertexArray->mAttribs[i].buf);
}
}
////
buffer->RequestDelete();
}
@ -441,211 +549,4 @@ WebGLContext::IsBuffer(WebGLBuffer* buffer)
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:
case LOCAL_GL_DYNAMIC_DRAW:
return true;
default:
break;
}
ErrorInvalidEnumInfo(info, target);
return false;
}
WebGLRefPtr<WebGLBuffer>&
WebGLContext::GetBufferSlotByTarget(GLenum target)
{
/* This function assumes that target has been validated for either
* WebGL1 or WebGL2.
*/
switch (target) {
case LOCAL_GL_ARRAY_BUFFER:
return mBoundArrayBuffer;
case LOCAL_GL_COPY_READ_BUFFER:
return mBoundCopyReadBuffer;
case LOCAL_GL_COPY_WRITE_BUFFER:
return mBoundCopyWriteBuffer;
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
return mBoundVertexArray->mElementArrayBuffer;
case LOCAL_GL_PIXEL_PACK_BUFFER:
return mBoundPixelPackBuffer;
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
return mBoundPixelUnpackBuffer;
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
return mBoundTransformFeedbackBuffer;
case LOCAL_GL_UNIFORM_BUFFER:
return mBoundUniformBuffer;
default:
MOZ_CRASH("GFX: Should not get here.");
}
}
WebGLRefPtr<WebGLBuffer>&
WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index)
{
/* This function assumes that target has been validated for either WebGL1 or WebGL. */
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
MOZ_ASSERT(index < mGLMaxTransformFeedbackSeparateAttribs);
return mBoundTransformFeedbackBuffers[index];
case LOCAL_GL_UNIFORM_BUFFER:
MOZ_ASSERT(index < mGLMaxUniformBufferBindings);
return mBoundUniformBuffers[index];
default:
MOZ_CRASH("GFX: 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
{
GenerateWarning("Rejecting valid bufferData call with size %lu to avoid"
" a Mac bug", size);
return LOCAL_GL_INVALID_VALUE;
}
#endif
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
WebGLBuffer* boundBuffer = bufferSlot.get();
MOZ_ASSERT(boundBuffer, "No buffer bound for this target.");
bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
if (sizeChanges) {
GetAndFlushUnderlyingGLErrors();
gl->fBufferData(target, size, data, usage);
GLenum error = GetAndFlushUnderlyingGLErrors();
return error;
} else {
gl->fBufferData(target, size, data, usage);
return LOCAL_GL_NO_ERROR;
}
}
} // namespace mozilla

View File

@ -101,10 +101,17 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
return;
}
std::vector<const WebGLFBAttachPoint*> fbAttachments;
if (mWebGL->mBoundDrawFramebuffer) {
const auto& fb = mWebGL->mBoundDrawFramebuffer;
fb->GatherAttachments(&fbAttachments);
const std::vector<const WebGLFBAttachPoint*>* attachList = nullptr;
const auto& fb = mWebGL->mBoundDrawFramebuffer;
if (fb) {
if (!fb->ValidateAndInitAttachments(funcName)) {
*out_error = true;
return;
}
attachList = &(fb->ResolvedCompleteData()->texDrawBuffers);
} else {
webgl->ClearBackbufferIfNeeded();
}
MOZ_ASSERT(mWebGL->mActiveProgramLinkInfo);
@ -120,7 +127,9 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
if (!tex)
continue;
if (tex->IsFeedback(mWebGL, funcName, texUnit, fbAttachments)) {
if (attachList &&
tex->IsFeedback(mWebGL, funcName, texUnit, *attachList))
{
*out_error = true;
return;
}
@ -241,22 +250,21 @@ WebGLContext::DrawInstanced_check(const char* info)
}
bool
WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
const char* info)
WebGLContext::DrawArrays_check(const char* funcName, GLenum mode, GLint first,
GLsizei vertCount, GLsizei instanceCount)
{
if (first < 0 || count < 0) {
ErrorInvalidValue("%s: negative first or count", info);
if (!ValidateDrawModeEnum(mode, funcName))
return false;
if (!ValidateNonNegative(funcName, "first", first) ||
!ValidateNonNegative(funcName, "vertCount", vertCount) ||
!ValidateNonNegative(funcName, "instanceCount", instanceCount))
{
return false;
}
if (primcount < 0) {
ErrorInvalidValue("%s: negative primcount", info);
if (!ValidateStencilParamsForDrawCall())
return false;
}
if (!ValidateStencilParamsForDrawCall()) {
return false;
}
if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
@ -268,133 +276,295 @@ WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
}
}
// If count is 0, there's nothing to do.
if (count == 0 || primcount == 0) {
if (!vertCount || !instanceCount)
return false; // No error, just early out.
if (!ValidateBufferFetching(funcName))
return false;
}
if (!ValidateBufferFetching(info)) {
return false;
}
CheckedInt<GLsizei> checked_firstPlusCount = CheckedInt<GLsizei>(first) + count;
const auto checked_firstPlusCount = CheckedInt<GLsizei>(first) + vertCount;
if (!checked_firstPlusCount.isValid()) {
ErrorInvalidOperation("%s: overflow in first+count", info);
ErrorInvalidOperation("%s: overflow in first+vertCount", funcName);
return false;
}
if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info);
return false;
}
if (uint32_t(primcount) > mMaxFetchedInstances) {
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
return false;
}
MOZ_ASSERT(gl->IsCurrent());
if (mBoundDrawFramebuffer) {
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
return false;
} else {
ClearBackbufferIfNeeded();
}
if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
ErrorInvalidOperation("%s: Bound vertex attribute buffers do not have sufficient"
" size for given first and count.",
funcName);
return false;
}
return true;
}
////////////////////////////////////////
class ScopedDrawHelper final
{
WebGLContext* const mWebGL;
bool mDidFake;
public:
ScopedDrawHelper(WebGLContext* webgl, const char* funcName, uint32_t firstVertex,
uint32_t vertCount, uint32_t instanceCount, bool* const out_error)
: mWebGL(webgl)
, mDidFake(false)
{
if (instanceCount > mWebGL->mMaxFetchedInstances) {
mWebGL->ErrorInvalidOperation("%s: Bound instance attribute buffers do not"
" have sufficient size for given"
" `instanceCount`.",
funcName);
*out_error = true;
return;
}
MOZ_ASSERT(mWebGL->gl->IsCurrent());
if (mWebGL->mBoundDrawFramebuffer) {
if (!mWebGL->mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName)) {
*out_error = true;
return;
}
} else {
mWebGL->ClearBackbufferIfNeeded();
}
////
const size_t requiredVerts = firstVertex + vertCount;
if (!mWebGL->DoFakeVertexAttrib0(requiredVerts)) {
*out_error = true;
return;
}
mDidFake = true;
////
// Check UBO sizes.
const auto& linkInfo = webgl->mActiveProgramLinkInfo;
for (const auto& cur : linkInfo->uniformBlocks) {
const auto& dataSize = cur->mDataSize;
const auto& binding = cur->mBinding;
if (!binding) {
mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is null.",
funcName);
*out_error = true;
return;
}
const auto availByteCount = binding->ByteCount();
if (dataSize > availByteCount) {
mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is smaller"
" than UNIFORM_BLOCK_DATA_SIZE.",
funcName);
*out_error = true;
return;
}
}
////
mWebGL->RunContextLossTimer();
}
~ScopedDrawHelper() {
if (mDidFake) {
mWebGL->UndoFakeVertexAttrib0();
}
}
};
////////////////////////////////////////
static uint32_t
UsedVertsForTFDraw(GLenum mode, uint32_t vertCount)
{
uint8_t vertsPerPrim;
switch (mode) {
case LOCAL_GL_POINTS:
vertsPerPrim = 1;
break;
case LOCAL_GL_LINES:
vertsPerPrim = 2;
break;
case LOCAL_GL_TRIANGLES:
vertsPerPrim = 3;
break;
default:
MOZ_CRASH("`mode`");
}
return vertCount / vertsPerPrim * vertsPerPrim;
}
class ScopedDrawWithTransformFeedback final
{
WebGLContext* const mWebGL;
WebGLTransformFeedback* const mTFO;
const bool mWithTF;
uint32_t mUsedVerts;
public:
ScopedDrawWithTransformFeedback(WebGLContext* webgl, const char* funcName,
GLenum mode, uint32_t vertCount,
uint32_t instanceCount, bool* const out_error)
: mWebGL(webgl)
, mTFO(mWebGL->mBoundTransformFeedback)
, mWithTF(mTFO &&
mTFO->mIsActive &&
!mTFO->mIsPaused)
, mUsedVerts(0)
{
*out_error = false;
if (!mWithTF)
return;
if (mode != mTFO->mActive_PrimMode) {
mWebGL->ErrorInvalidOperation("%s: Drawing with transform feedback requires"
" `mode` to match BeginTransformFeedback's"
" `primitiveMode`.",
funcName);
*out_error = true;
return;
}
const auto usedVertsPerInstance = UsedVertsForTFDraw(mode, vertCount);
const auto usedVerts = CheckedInt<uint32_t>(usedVertsPerInstance) * instanceCount;
const auto remainingCapacity = mTFO->mActive_VertCapacity - mTFO->mActive_VertPosition;
if (!usedVerts.isValid() ||
usedVerts.value() > remainingCapacity)
{
mWebGL->ErrorInvalidOperation("%s: Insufficient buffer capacity remaining for"
" transform feedback.",
funcName);
*out_error = true;
return;
}
mUsedVerts = usedVerts.value();
}
void Advance() const {
if (!mWithTF)
return;
mTFO->mActive_VertPosition += mUsedVerts;
}
};
////////////////////////////////////////
void
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei vertCount)
{
const char funcName[] = "drawArrays";
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, funcName))
return;
MakeContextCurrent();
bool error;
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
if (!DrawArrays_check(first, count, 1, funcName))
const GLsizei instanceCount = 1;
if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
return;
RunContextLossTimer();
const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
if (error)
return;
const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
instanceCount, &error);
if (error)
return;
{
ScopedMaskWorkaround autoMask(*this);
gl->fDrawArrays(mode, first, count);
gl->fDrawArrays(mode, first, vertCount);
}
Draw_cleanup(funcName);
scopedTF.Advance();
}
void
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
GLsizei instanceCount)
{
const char funcName[] = "drawArraysInstanced";
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, funcName))
return;
MakeContextCurrent();
bool error;
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
if (!DrawArrays_check(first, count, primcount, funcName))
if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
return;
if (!DrawInstanced_check(funcName))
return;
RunContextLossTimer();
const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
if (error)
return;
const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
instanceCount, &error);
if (error)
return;
{
ScopedMaskWorkaround autoMask(*this);
gl->fDrawArraysInstanced(mode, first, count, primcount);
gl->fDrawArraysInstanced(mode, first, vertCount, instanceCount);
}
Draw_cleanup(funcName);
scopedTF.Advance();
}
////////////////////////////////////////
bool
WebGLContext::DrawElements_check(GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount,
const char* info, GLuint* out_upperBound)
WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
GLenum type, WebGLintptr byteOffset,
GLsizei instanceCount)
{
if (count < 0 || byteOffset < 0) {
ErrorInvalidValue("%s: negative count or offset", info);
if (!ValidateDrawModeEnum(mode, funcName))
return false;
if (mBoundTransformFeedback &&
mBoundTransformFeedback->mIsActive &&
!mBoundTransformFeedback->mIsPaused)
{
ErrorInvalidOperation("%s: DrawElements* functions are incompatible with"
" transform feedback.",
funcName);
return false;
}
if (primcount < 0) {
ErrorInvalidValue("%s: negative primcount", info);
if (!ValidateNonNegative(funcName, "vertCount", vertCount) ||
!ValidateNonNegative(funcName, "byteOffset", byteOffset) ||
!ValidateNonNegative(funcName, "instanceCount", instanceCount))
{
return false;
}
if (!ValidateStencilParamsForDrawCall()) {
if (!ValidateStencilParamsForDrawCall())
return false;
}
// If count is 0, there's nothing to do.
if (count == 0 || primcount == 0)
return false;
if (!vertCount || !instanceCount)
return false; // No error, just early out.
uint8_t bytesPerElem = 0;
switch (type) {
@ -414,13 +584,13 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
}
if (!bytesPerElem) {
ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", info, type);
ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", funcName, type);
return false;
}
if (byteOffset % bytesPerElem != 0) {
ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
info);
funcName);
return false;
}
@ -439,51 +609,49 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
////
const GLsizei first = byteOffset / bytesPerElem;
const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(count);
const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(vertCount);
if (!checked_byteCount.isValid()) {
ErrorInvalidValue("%s: overflow in byteCount", info);
ErrorInvalidValue("%s: Overflow in byteCount.", funcName);
return false;
}
if (!mBoundVertexArray->mElementArrayBuffer) {
ErrorInvalidOperation("%s: must have element array buffer binding", info);
ErrorInvalidOperation("%s: Must have element array buffer binding.", funcName);
return false;
}
WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mElementArrayBuffer;
if (!elemArrayBuffer.ByteLength()) {
ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
ErrorInvalidOperation("%s: Bound element array buffer doesn't have any data.",
funcName);
return false;
}
CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
if (!checked_neededByteCount.isValid()) {
ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
ErrorInvalidOperation("%s: Overflow in byteOffset+byteCount.", funcName);
return false;
}
if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
ErrorInvalidOperation("%s: Bound element array buffer is too small for given"
" count and offset.",
funcName);
return false;
}
if (!ValidateBufferFetching(info))
if (!ValidateBufferFetching(funcName))
return false;
if (!mMaxFetchedVertices ||
!elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
!elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, vertCount))
{
ErrorInvalidOperation(
"%s: bound vertex attribute buffers do not have sufficient "
"size for given indices from the bound element array", info);
return false;
}
if (uint32_t(primcount) > mMaxFetchedInstances) {
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient "
"size for given indices from the bound element array",
funcName);
return false;
}
@ -491,106 +659,86 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
if (elemArrayBuffer.IsElementArrayUsedWithMultipleTypes()) {
GenerateWarning("%s: bound element array buffer previously used with a type other than "
"%s, this will affect performance.",
info,
WebGLContext::EnumName(type));
}
MOZ_ASSERT(gl->IsCurrent());
if (mBoundDrawFramebuffer) {
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
return false;
} else {
ClearBackbufferIfNeeded();
}
if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
return false;
funcName, WebGLContext::EnumName(type));
}
return true;
}
void
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
WebGLContext::DrawElements(GLenum mode, GLsizei vertCount, GLenum type,
WebGLintptr byteOffset)
{
const char funcName[] = "drawElements";
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, funcName))
return;
MakeContextCurrent();
bool error;
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
GLuint upperBound = 0;
if (!DrawElements_check(count, type, byteOffset, 1, funcName, &upperBound))
const GLsizei instanceCount = 1;
if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
return;
RunContextLossTimer();
const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
&error);
if (error)
return;
{
ScopedMaskWorkaround autoMask(*this);
if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
gl->fDrawRangeElements(mode, 0, upperBound, count, type,
reinterpret_cast<GLvoid*>(byteOffset));
} else {
gl->fDrawElements(mode, count, type,
reinterpret_cast<GLvoid*>(byteOffset));
}
gl->fDrawElements(mode, vertCount, type,
reinterpret_cast<GLvoid*>(byteOffset));
}
Draw_cleanup(funcName);
}
void
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount)
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
WebGLintptr byteOffset, GLsizei instanceCount)
{
const char funcName[] = "drawElementsInstanced";
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, funcName))
return;
MakeContextCurrent();
bool error;
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
GLuint upperBound = 0;
if (!DrawElements_check(count, type, byteOffset, primcount, funcName, &upperBound))
if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
return;
if (!DrawInstanced_check(funcName))
return;
RunContextLossTimer();
const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
&error);
if (error)
return;
{
ScopedMaskWorkaround autoMask(*this);
gl->fDrawElementsInstanced(mode, count, type,
gl->fDrawElementsInstanced(mode, vertCount, type,
reinterpret_cast<GLvoid*>(byteOffset),
primcount);
instanceCount);
}
Draw_cleanup(funcName);
}
void WebGLContext::Draw_cleanup(const char* funcName)
{
UndoFakeVertexAttrib0();
////////////////////////////////////////
void
WebGLContext::Draw_cleanup(const char* funcName)
{
if (!mBoundDrawFramebuffer) {
Invalidate();
mShouldPresent = true;
@ -614,9 +762,12 @@ void WebGLContext::Draw_cleanup(const char* funcName)
uint32_t destHeight = mViewportHeight;
if (mBoundDrawFramebuffer) {
const auto& fba = mBoundDrawFramebuffer->ColorAttachment(0);
if (fba.IsDefined()) {
fba.Size(&destWidth, &destHeight);
const auto& drawBuffers = mBoundDrawFramebuffer->ColorDrawBuffers();
for (const auto& cur : drawBuffers) {
if (!cur->IsDefined())
continue;
cur->Size(&destWidth, &destHeight);
break;
}
} else {
destWidth = mWidth;

View File

@ -144,76 +144,37 @@ WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
if (IsContextLost())
return;
if (!mBoundDrawFramebuffer) {
// GLES 3.0.4 p186:
// "If the GL is bound to the default framebuffer, then `n` must be 1 and the
// constant must be BACK or NONE. [...] If DrawBuffers is supplied with a
// constant other than BACK and NONE, or with a value of `n` other than 1, the
// error INVALID_OPERATION is generated."
if (buffers.Length() != 1) {
ErrorInvalidOperation("%s: For the default framebuffer, `buffers` must have a"
" length of 1.",
funcName);
return;
}
switch (buffers[0]) {
case LOCAL_GL_NONE:
case LOCAL_GL_BACK:
break;
default:
ErrorInvalidOperation("%s: For the default framebuffer, `buffers[0]` must be"
" BACK or NONE.",
funcName);
return;
}
mDefaultFB_DrawBuffer0 = buffers[0];
gl->Screen()->SetDrawBuffer(buffers[0]);
if (mBoundDrawFramebuffer) {
mBoundDrawFramebuffer->DrawBuffers(funcName, buffers);
return;
}
// Framebuffer object (not default framebuffer)
if (buffers.Length() > mImplMaxDrawBuffers) {
// "An INVALID_VALUE error is generated if `n` is greater than MAX_DRAW_BUFFERS."
ErrorInvalidValue("%s: `buffers` must have a length <= MAX_DRAW_BUFFERS.",
funcName);
// GLES 3.0.4 p186:
// "If the GL is bound to the default framebuffer, then `n` must be 1 and the
// constant must be BACK or NONE. [...] If DrawBuffers is supplied with a
// constant other than BACK and NONE, or with a value of `n` other than 1, the
// error INVALID_OPERATION is generated."
if (buffers.Length() != 1) {
ErrorInvalidOperation("%s: For the default framebuffer, `buffers` must have a"
" length of 1.",
funcName);
return;
}
for (size_t i = 0; i < buffers.Length(); i++) {
// "If the GL is bound to a draw framebuffer object, the `i`th buffer listed in
// bufs must be COLOR_ATTACHMENTi or NONE. Specifying a buffer out of order,
// BACK, or COLOR_ATTACHMENTm where `m` is greater than or equal to the value of
// MAX_COLOR_ATTACHMENTS, will generate the error INVALID_OPERATION.
switch (buffers[0]) {
case LOCAL_GL_NONE:
case LOCAL_GL_BACK:
break;
// WEBGL_draw_buffers:
// "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
// equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
// This means that if buffers.Length() isn't larger than MaxDrawBuffers, it won't
// be larger than MaxColorAttachments.
if (buffers[i] != LOCAL_GL_NONE &&
buffers[i] != LOCAL_GL_COLOR_ATTACHMENT0 + i)
{
ErrorInvalidOperation("%s: `buffers[i]` must be NONE or COLOR_ATTACHMENTi.",
funcName);
return;
}
default:
ErrorInvalidOperation("%s: For the default framebuffer, `buffers[0]` must be"
" BACK or NONE.",
funcName);
return;
}
MakeContextCurrent();
const GLenum* ptr = nullptr;
if (buffers.Length()) {
ptr = buffers.Elements();
}
gl->fDrawBuffers(buffers.Length(), ptr);
const auto end = ptr + buffers.Length();
mBoundDrawFramebuffer->mDrawBuffers.assign(ptr, end);
mDefaultFB_DrawBuffer0 = buffers[0];
gl->Screen()->SetDrawBuffer(buffers[0]);
}
void

View File

@ -252,10 +252,11 @@ WebGLContext::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
GLenum
WebGLContext::CheckFramebufferStatus(GLenum target)
{
const char funcName[] = "checkFramebufferStatus";
if (IsContextLost())
return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
if (!ValidateFramebufferTarget(target, "invalidateFramebuffer"))
if (!ValidateFramebufferTarget(target, funcName))
return 0;
WebGLFramebuffer* fb;
@ -276,8 +277,7 @@ WebGLContext::CheckFramebufferStatus(GLenum target)
if (!fb)
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
nsCString fbErrorInfo;
return fb->CheckFramebufferStatus(&fbErrorInfo).get();
return fb->CheckFramebufferStatus(funcName).get();
}
already_AddRefed<WebGLProgram>
@ -484,10 +484,11 @@ void
WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
GLenum rbtarget, WebGLRenderbuffer* wrb)
{
const char funcName[] = "framebufferRenderbuffer";
if (IsContextLost())
return;
if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
if (!ValidateFramebufferTarget(target, funcName))
return;
WebGLFramebuffer* fb;
@ -505,20 +506,10 @@ WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
MOZ_CRASH("GFX: Bad target.");
}
if (!fb) {
return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify"
" framebuffer 0.");
}
if (!fb)
return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
if (rbtarget != LOCAL_GL_RENDERBUFFER) {
return ErrorInvalidEnumInfo("framebufferRenderbuffer: rbtarget:",
rbtarget);
}
if (!ValidateFramebufferAttachment(fb, attachment, "framebufferRenderbuffer"))
return;
fb->FramebufferRenderbuffer(attachment, rbtarget, wrb);
fb->FramebufferRenderbuffer(funcName, attachment, rbtarget, wrb);
}
void
@ -528,57 +519,13 @@ WebGLContext::FramebufferTexture2D(GLenum target,
WebGLTexture* tobj,
GLint level)
{
const char funcName[] = "framebufferTexture2D";
if (IsContextLost())
return;
if (!ValidateFramebufferTarget(target, "framebufferTexture2D"))
if (!ValidateFramebufferTarget(target, funcName))
return;
if (level < 0) {
ErrorInvalidValue("framebufferTexture2D: level must not be negative.");
return;
}
if (textarget != LOCAL_GL_TEXTURE_2D &&
(textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
{
return ErrorInvalidEnumInfo("framebufferTexture2D: textarget:",
textarget);
}
if (IsWebGL2()) {
/* GLES 3.0.4 p208:
* If textarget is one of TEXTURE_CUBE_MAP_POSITIVE_X,
* TEXTURE_CUBE_MAP_POSITIVE_Y, TEXTURE_CUBE_MAP_POSITIVE_Z,
* TEXTURE_CUBE_MAP_NEGATIVE_X, TEXTURE_CUBE_MAP_NEGATIVE_Y,
* or TEXTURE_CUBE_MAP_NEGATIVE_Z, then level must be greater
* than or equal to zero and less than or equal to log2 of the
* value of MAX_CUBE_MAP_TEXTURE_SIZE. If textarget is TEXTURE_2D,
* level must be greater than or equal to zero and no larger than
* log2 of the value of MAX_TEXTURE_SIZE. Otherwise, an
* INVALID_VALUE error is generated.
*/
if (textarget == LOCAL_GL_TEXTURE_2D) {
if (uint32_t(level) > FloorLog2(mImplMaxTextureSize)) {
ErrorInvalidValue("framebufferTexture2D: level is too large.");
return;
}
} else {
MOZ_ASSERT(textarget >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
textarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
if (uint32_t(level) > FloorLog2(mImplMaxCubeMapTextureSize)) {
ErrorInvalidValue("framebufferTexture2D: level is too large.");
return;
}
}
} else if (level != 0) {
ErrorInvalidValue("framebufferTexture2D: level must be 0.");
return;
}
WebGLFramebuffer* fb;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
@ -594,15 +541,10 @@ WebGLContext::FramebufferTexture2D(GLenum target,
MOZ_CRASH("GFX: Bad target.");
}
if (!fb) {
return ErrorInvalidOperation("framebufferTexture2D: cannot modify"
" framebuffer 0.");
}
if (!fb)
return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
if (!ValidateFramebufferAttachment(fb, attachment, "framebufferTexture2D"))
return;
fb->FramebufferTexture2D(attachment, textarget, tobj, level);
fb->FramebufferTexture2D(funcName, attachment, textarget, tobj, level);
}
void
@ -684,15 +626,10 @@ WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
if (IsContextLost())
return JS::NullValue();
if (!ValidateBufferTarget(target, "getBufferParameter"))
const auto& buffer = ValidateBufferSelection("getBufferParameter", target);
if (!buffer)
return JS::NullValue();
WebGLRefPtr<WebGLBuffer>& slot = GetBufferSlotByTarget(target);
if (!slot) {
ErrorInvalidOperation("No buffer bound to `target` (0x%4x).", target);
return JS::NullValue();
}
MakeContextCurrent();
switch (pname) {
@ -1557,6 +1494,13 @@ WebGL2Context::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenu
return;
}
if (mBoundPixelPackBuffer->mNumActiveTFOs) {
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
" object.",
"readPixels");
return;
}
//////
if (offset < 0) {

View File

@ -7,7 +7,6 @@
#include "WebGLContextUnchecked.h"
#include "GLContext.h"
#include "WebGLBuffer.h"
#include "WebGLSampler.h"
namespace mozilla {
@ -17,50 +16,6 @@ WebGLContextUnchecked::WebGLContextUnchecked(gl::GLContext* _gl)
, gl(mGL_OnlyClearInDestroyResourcesAndContext) // const reference
{ }
// -----------------------------------------------------------------------------
// Buffer Objects
void
WebGLContextUnchecked::BindBuffer(GLenum target, WebGLBuffer* buffer)
{
gl->MakeCurrent();
gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
}
void
WebGLContextUnchecked::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
{
gl->MakeCurrent();
gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
}
void
WebGLContextUnchecked::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size)
{
gl->MakeCurrent();
#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);
}
// -----------------------------------------------------------------------------
// Sampler Objects

View File

@ -20,13 +20,6 @@ class WebGLContextUnchecked
public:
explicit WebGLContextUnchecked(gl::GLContext* gl);
// -------------------------------------------------------------------------
// Buffer Objects
void BindBuffer(GLenum target, WebGLBuffer* buffer);
void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
void BindBufferRange(GLenum taret, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size);
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
// -------------------------------------------------------------------------
// Sampler Objects
void BindSampler(GLuint unit, WebGLSampler* sampler);

View File

@ -122,36 +122,11 @@ WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor,
return true;
}
bool
WebGLContext::ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info)
{
if (offset < 0) {
ErrorInvalidValue("%s: offset must be positive", info);
return false;
}
if (size < 0) {
ErrorInvalidValue("%s: size must be positive", info);
return false;
}
// *** Careful *** WebGLsizeiptr is always 64-bits but GLsizeiptr
// is like intptr_t. On some platforms it is 32-bits.
CheckedInt<GLsizeiptr> neededBytes = CheckedInt<GLsizeiptr>(offset) + size;
if (!neededBytes.isValid() || neededBytes.value() > bufferSize) {
ErrorInvalidValue("%s: invalid range", info);
return false;
}
return true;
}
/**
* Check data ranges [readOffset, readOffset + size] and [writeOffset,
* writeOffset + size] for overlap.
*
* It is assumed that offset and size have already been validated with
* ValidateDataOffsetSize().
* It is assumed that offset and size have already been validated.
*/
bool
WebGLContext::ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info)
@ -738,7 +713,6 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
mBoundSamplers.Clear();
mBoundArrayBuffer = nullptr;
mBoundTransformFeedbackBuffer = nullptr;
mCurrentProgram = nullptr;
mBoundDrawFramebuffer = nullptr;
@ -980,7 +954,6 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
// vertex array object (the name zero) is also deprecated. [...]"
if (gl->IsCoreProfile()) {
MakeContextCurrent();
mDefaultVertexArray->GenVertexArray();
mDefaultVertexArray->BindVertexArray();
}

View File

@ -15,16 +15,6 @@
namespace mozilla {
static void
UpdateUpperBound(uint32_t* const out_upperBound, uint32_t newBound)
{
MOZ_ASSERT(out_upperBound);
// Move *out_upperBound to a local variable to work around a false positive
// -Wuninitialized gcc warning about std::max() in PGO builds.
uint32_t upperBound = *out_upperBound;
*out_upperBound = std::max(upperBound, newBound);
}
/* WebGLElementArrayCacheTree contains most of the implementation of
* WebGLElementArrayCache, which performs WebGL element array buffer validation
* for drawElements.
@ -245,8 +235,7 @@ public:
return ((numElements - 1) | kElementsPerLeafMask) + 1;
}
bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf,
uint32_t* const out_upperBound)
bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf)
{
size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
size_t lastTreeIndex = TreeIndexForLeaf(lastLeaf);
@ -260,7 +249,6 @@ public:
// current tree level:
if (lastTreeIndex == firstTreeIndex) {
const T& curData = mTreeData[firstTreeIndex];
UpdateUpperBound(out_upperBound, curData);
return curData <= maxAllowed;
}
@ -269,7 +257,6 @@ public:
// a left node.
if (IsRightNode(firstTreeIndex)) {
const T& curData = mTreeData[firstTreeIndex];
UpdateUpperBound(out_upperBound, curData);
if (curData > maxAllowed)
return false;
@ -281,7 +268,6 @@ public:
// right node.
if (IsLeftNode(lastTreeIndex)) {
const T& curData = mTreeData[lastTreeIndex];
UpdateUpperBound(out_upperBound, curData);
if (curData > maxAllowed)
return false;
@ -514,18 +500,13 @@ WebGLElementArrayCache::UpdateTrees(size_t firstByte, size_t lastByte)
template<typename T>
bool
WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
size_t countElements,
uint32_t* const out_upperBound)
size_t countElements)
{
*out_upperBound = 0;
// If maxAllowed is >= the max T value, then there is no way that a T index
// could be invalid.
uint32_t maxTSize = std::numeric_limits<T>::max();
if (maxAllowed >= maxTSize) {
UpdateUpperBound(out_upperBound, maxTSize);
if (maxAllowed >= maxTSize)
return true;
}
T maxAllowedT(maxAllowed);
@ -556,10 +537,8 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
// Fast-exit path when the global maximum for the whole element array buffer
// falls in the allowed range:
T globalMax = tree->GlobalMaximum();
if (globalMax <= maxAllowedT) {
UpdateUpperBound(out_upperBound, globalMax);
if (globalMax <= maxAllowedT)
return true;
}
const T* elements = Elements<T>();
@ -570,7 +549,6 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
tree->LastElementUnderSameLeaf(firstElement));
while (firstElement <= firstElementAdjustmentEnd) {
const T& curData = elements[firstElement];
UpdateUpperBound(out_upperBound, curData);
if (curData > maxAllowedT)
return false;
@ -580,7 +558,6 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
tree->FirstElementUnderSameLeaf(lastElement));
while (lastElement >= lastElementAdjustmentEnd) {
const T& curData = elements[lastElement];
UpdateUpperBound(out_upperBound, curData);
if (curData > maxAllowedT)
return false;
@ -593,23 +570,19 @@ WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
// general case
return tree->Validate(maxAllowedT, tree->LeafForElement(firstElement),
tree->LeafForElement(lastElement), out_upperBound);
tree->LeafForElement(lastElement));
}
bool
WebGLElementArrayCache::Validate(GLenum type, uint32_t maxAllowed,
size_t firstElement, size_t countElements,
uint32_t* const out_upperBound)
size_t firstElement, size_t countElements)
{
if (type == LOCAL_GL_UNSIGNED_BYTE)
return Validate<uint8_t>(maxAllowed, firstElement, countElements,
out_upperBound);
return Validate<uint8_t>(maxAllowed, firstElement, countElements);
if (type == LOCAL_GL_UNSIGNED_SHORT)
return Validate<uint16_t>(maxAllowed, firstElement, countElements,
out_upperBound);
return Validate<uint16_t>(maxAllowed, firstElement, countElements);
if (type == LOCAL_GL_UNSIGNED_INT)
return Validate<uint32_t>(maxAllowed, firstElement, countElements,
out_upperBound);
return Validate<uint32_t>(maxAllowed, firstElement, countElements);
MOZ_ASSERT(false, "Invalid type.");
return false;

View File

@ -37,8 +37,7 @@ public:
bool BufferData(const void* ptr, size_t byteLength);
bool BufferSubData(size_t pos, const void* ptr, size_t updateByteSize);
bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count,
uint32_t* const out_upperBound);
bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count);
template<typename T>
T Element(size_t i) const { return Elements<T>()[i]; }
@ -74,8 +73,7 @@ private:
* than maxAllowed.
*/
template<typename T>
bool Validate(uint32_t maxAllowed, size_t first, size_t count,
uint32_t* const out_upperBound);
bool Validate(uint32_t maxAllowed, size_t first, size_t count);
template<typename T>
const T* Elements() const {

File diff suppressed because it is too large Load Diff

View File

@ -27,31 +27,34 @@ class WebGLTexture;
template<typename T>
class PlacementArray;
class WebGLFBAttachPoint
namespace gl {
class GLContext;
} // namespace gl
class WebGLFBAttachPoint final
{
friend class WebGLFramebuffer;
public:
WebGLFramebuffer* const mFB;
const GLenum mAttachmentPoint;
private:
protected:
WebGLRefPtr<WebGLTexture> mTexturePtr;
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
TexImageTarget mTexImageTarget;
GLint mTexImageLayer;
uint32_t mTexImageLevel;
// PlacementArray needs a default constructor.
template<typename T>
friend class PlacementArray;
////
WebGLFBAttachPoint()
: mFB(nullptr)
, mAttachmentPoint(0)
{ }
WebGLFBAttachPoint();
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
public:
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
~WebGLFBAttachPoint();
////
void Unlink();
bool IsDefined() const;
@ -65,23 +68,13 @@ public:
void Clear();
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
void SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, GLint level,
GLint layer);
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level,
GLint layer = 0);
void SetRenderbuffer(WebGLRenderbuffer* rb);
const WebGLTexture* Texture() const {
return mTexturePtr;
}
WebGLTexture* Texture() {
return mTexturePtr;
}
const WebGLRenderbuffer* Renderbuffer() const {
return mRenderbufferPtr;
}
WebGLRenderbuffer* Renderbuffer() {
return mRenderbufferPtr;
}
WebGLTexture* Texture() const { return mTexturePtr; }
WebGLRenderbuffer* Renderbuffer() const { return mRenderbufferPtr; }
TexImageTarget ImageTarget() const {
return mTexImageTarget;
}
@ -94,69 +87,45 @@ public:
void AttachmentName(nsCString* out) const;
bool HasUninitializedImageData() const;
void SetImageDataStatus(WebGLImageDataStatus x);
void SetImageDataStatus(WebGLImageDataStatus x) const;
void Size(uint32_t* const out_width, uint32_t* const out_height) const;
bool HasImage() const;
bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const;
void FinalizeAttachment(gl::GLContext* gl, GLenum attachmentLoc) const;
void Resolve(gl::GLContext* gl) const;
JS::Value GetParameter(const char* funcName, WebGLContext* webgl, JSContext* cx,
GLenum target, GLenum attachment, GLenum pname,
ErrorResult* const out_error);
ErrorResult* const out_error) const;
void OnBackingStoreRespecified() const;
};
template<typename T>
class PlacementArray
{
public:
const size_t mCapacity;
protected:
size_t mSize;
T* const mArray;
////
public:
explicit PlacementArray(size_t capacity)
: mCapacity(capacity)
, mSize(0)
, mArray((T*)moz_xmalloc(sizeof(T) * capacity))
{ }
struct Ordered {
const WebGLFBAttachPoint& mRef;
~PlacementArray() {
for (auto& cur : *this) {
cur.~T();
explicit Ordered(const WebGLFBAttachPoint& ref)
: mRef(ref)
{ }
bool operator<(const Ordered& other) const {
MOZ_ASSERT(mRef.IsDefined() && other.mRef.IsDefined());
#define ORDER_BY(X) if (X != other.X) return X < other.X;
ORDER_BY(mRef.mRenderbufferPtr)
ORDER_BY(mRef.mTexturePtr)
ORDER_BY(mRef.mTexImageTarget.get())
ORDER_BY(mRef.mTexImageLevel)
ORDER_BY(mRef.mTexImageLayer)
#undef ORDER_BY
return false;
}
free(mArray);
}
T* begin() const {
return mArray;
}
T* end() const {
return mArray + mSize;
}
T& operator [](size_t offset) const {
MOZ_ASSERT(offset < mSize);
return mArray[offset];
}
const size_t& Size() const { return mSize; }
template<typename A, typename B>
void AppendNew(A a, B b) {
if (mSize == mCapacity)
MOZ_CRASH("GFX: Bad EmplaceAppend.");
// Placement `new`:
new (&(mArray[mSize])) T(a, b);
++mSize;
}
};
};
class WebGLFramebuffer final
@ -173,28 +142,7 @@ public:
const GLuint mGLName;
private:
mutable bool mIsKnownFBComplete;
GLenum mReadBufferMode;
// No need to chase pointers for the oft-used color0.
WebGLFBAttachPoint mColorAttachment0;
WebGLFBAttachPoint mDepthAttachment;
WebGLFBAttachPoint mStencilAttachment;
WebGLFBAttachPoint mDepthStencilAttachment;
PlacementArray<WebGLFBAttachPoint> mMoreColorAttachments;
std::vector<GLenum> mDrawBuffers;
bool IsDrawBuffer(size_t n) const {
if (n < mDrawBuffers.size())
return bool(mDrawBuffers[n]);
return false;
}
protected:
#ifdef ANDROID
// Bug 1140459: Some drivers (including our test slaves!) don't
// give reasonable answers for IsRenderbuffer, maybe others.
@ -204,94 +152,133 @@ private:
bool mIsFB;
#endif
////
WebGLFBAttachPoint mDepthAttachment;
WebGLFBAttachPoint mStencilAttachment;
WebGLFBAttachPoint mDepthStencilAttachment;
// In theory, this number can be unbounded based on the driver. However, no driver
// appears to expose more than 8. We might as well stop there too, for now.
// (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
static const size_t kMaxColorAttachments = 8; // jgilbert's MacBook Pro exposes 8.
WebGLFBAttachPoint mColorAttachments[kMaxColorAttachments];
////
std::vector<const WebGLFBAttachPoint*> mColorDrawBuffers; // Non-null
const WebGLFBAttachPoint* mColorReadBuffer; // Null if NONE
////
struct ResolvedData {
// BlitFramebuffer
bool hasSampleBuffers;
const WebGLFBAttachPoint* depthBuffer;
const WebGLFBAttachPoint* stencilBuffer;
// IsFeedback
std::vector<const WebGLFBAttachPoint*> texDrawBuffers; // Non-null
std::set<WebGLFBAttachPoint::Ordered> drawSet;
std::set<WebGLFBAttachPoint::Ordered> readSet;
explicit ResolvedData(const WebGLFramebuffer& parent);
};
UniquePtr<const ResolvedData> mResolvedCompleteData;
////
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
WebGLFramebuffer(WebGLContext* webgl, GLuint fbo);
WebGLContext* GetParentObject() const { return mContext; }
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
private:
~WebGLFramebuffer() {
DeleteOnce();
}
const WebGLRectangleObject& GetAnyRectObject() const;
public:
void Delete();
void FramebufferRenderbuffer(GLenum attachment, RBTarget rbtarget,
WebGLRenderbuffer* rb);
void FramebufferTexture2D(GLenum attachment, TexImageTarget texImageTarget,
WebGLTexture* tex, GLint level);
void FramebufferTextureLayer(GLenum attachment, WebGLTexture* tex, GLint level,
GLint layer);
////
bool HasDefinedAttachments() const;
bool HasIncompleteAttachments(nsCString* const out_info) const;
bool AllImageRectsMatch() const;
bool AllImageSamplesMatch() const;
FBStatus PrecheckFramebufferStatus(nsCString* const out_info) const;
FBStatus CheckFramebufferStatus(nsCString* const out_info) const;
const webgl::FormatUsageInfo*
GetFormatForAttachment(const WebGLFBAttachPoint& attachment) const;
const WebGLFBAttachPoint& ColorAttachment(size_t colorAttachmentId) const {
MOZ_ASSERT(colorAttachmentId < 1 + mMoreColorAttachments.Size());
return colorAttachmentId ? mMoreColorAttachments[colorAttachmentId - 1]
: mColorAttachment0;
}
const WebGLFBAttachPoint& DepthAttachment() const {
return mDepthAttachment;
}
const WebGLFBAttachPoint& StencilAttachment() const {
return mStencilAttachment;
}
const WebGLFBAttachPoint& DepthStencilAttachment() const {
return mDepthStencilAttachment;
}
void SetReadBufferMode(GLenum readBufferMode) {
mReadBufferMode = readBufferMode;
}
GLenum ReadBufferMode() const { return mReadBufferMode; }
void GatherAttachments(std::vector<const WebGLFBAttachPoint*>* const out) const;
protected:
WebGLFBAttachPoint* GetAttachPoint(GLenum attachment); // Fallible
Maybe<WebGLFBAttachPoint*> GetAttachPoint(GLenum attachment); // Fallible
Maybe<WebGLFBAttachPoint*> GetColorAttachPoint(GLenum attachment); // Fallible
void ResolveAttachments() const;
void RefreshDrawBuffers() const;
void RefreshReadBuffer() const;
bool ResolveAttachmentData(const char* funcName) const;
public:
void DetachTexture(const WebGLTexture* tex);
void DetachRenderbuffer(const WebGLRenderbuffer* rb);
WebGLContext* GetParentObject() const {
return mContext;
}
void FinalizeAttachments() const;
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
bool ValidateAndInitAttachments(const char* funcName);
void InvalidateFramebufferStatus() const {
mIsKnownFBComplete = false;
}
bool ValidateForRead(const char* info,
const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height);
////////////////
// Getters
#define GETTER(X) const decltype(m##X)& X() const { return m##X; }
GETTER(DepthAttachment)
GETTER(StencilAttachment)
GETTER(DepthStencilAttachment)
GETTER(ColorDrawBuffers)
GETTER(ColorReadBuffer)
GETTER(ResolvedCompleteData)
#undef GETTER
////////////////
// Invalidation
bool IsResolvedComplete() const { return bool(mResolvedCompleteData); }
void InvalidateFramebufferStatus() {
mResolvedCompleteData = nullptr;
}
void RefreshResolvedData();
////////////////
// WebGL funcs
FBStatus CheckFramebufferStatus(const char* funcName);
void FramebufferRenderbuffer(const char* funcName, GLenum attachment, GLenum rbtarget,
WebGLRenderbuffer* rb);
void FramebufferTexture2D(const char* funcName, GLenum attachment,
GLenum texImageTarget, WebGLTexture* tex, GLint level);
void FramebufferTextureLayer(const char* funcName, GLenum attachment,
WebGLTexture* tex, GLint level, GLint layer);
void DrawBuffers(const char* funcName, const dom::Sequence<GLenum>& buffers);
void ReadBuffer(const char* funcName, GLenum attachPoint);
JS::Value GetAttachmentParameter(const char* funcName, JSContext* cx, GLenum target,
GLenum attachment, GLenum pname,
ErrorResult* const out_error);
static void BlitFramebuffer(WebGLContext* webgl,
const WebGLFramebuffer* src, GLint srcX0, GLint srcY0,
GLint srcX1, GLint srcY1,
const WebGLFramebuffer* dst, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
};
} // namespace mozilla

View File

@ -331,7 +331,7 @@ ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& field)
template <typename T>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
mozilla::WebGLRefPtr<T>& field,
const mozilla::WebGLRefPtr<T>& field,
const char* name,
uint32_t flags = 0)
{

View File

@ -14,6 +14,7 @@
#include "WebGLActiveInfo.h"
#include "WebGLContext.h"
#include "WebGLShader.h"
#include "WebGLTransformFeedback.h"
#include "WebGLUniformLocation.h"
#include "WebGLValidateStrings.h"
@ -331,6 +332,13 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
}
}
////
GLuint dataSize = 0;
gl->fGetActiveUniformBlockiv(prog->mGLName, i,
LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE,
(GLint*)&dataSize);
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i,
mappedName.BeginReading(), (int)isArray,
@ -339,7 +347,8 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
printf_stderr(" isArray: %d\n", (int)isArray);
#endif
const auto* block = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
auto* block = new webgl::UniformBlockInfo(webgl, baseUserName, baseMappedName,
dataSize);
info->uniformBlocks.push_back(block);
}
}
@ -436,7 +445,8 @@ CreateProgram(gl::GLContext* gl)
WebGLProgram::WebGLProgram(WebGLContext* webgl)
: WebGLContextBoundObject(webgl)
, mGLName(CreateProgram(webgl->GL()))
, mTransformFeedbackBufferMode(LOCAL_GL_NONE)
, mNumActiveTFOs(0)
, mNextLink_TransformFeedbackBufferMode(LOCAL_GL_SEPARATE_ATTRIBS)
{
mContext->mPrograms.insertBack(this);
}
@ -517,7 +527,7 @@ WebGLProgram::BindAttribLocation(GLuint loc, const nsAString& name)
NS_LossyConvertUTF16toASCII asciiName(name);
auto res = mBoundAttribLocs.insert(std::pair<nsCString, GLuint>(asciiName, loc));
auto res = mNextLink_BoundAttribLocs.insert({asciiName, loc});
const bool wasInserted = res.second;
if (!wasInserted) {
@ -675,11 +685,13 @@ WebGLProgram::GetProgramParameter(GLenum pname) const
if (mContext->IsWebGL2()) {
switch (pname) {
case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:
return JS::Int32Value(mTransformFeedbackVaryings.size());
return JS::Int32Value(mNextLink_TransformFeedbackVaryings.size());
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
return JS::Int32Value(mNextLink_TransformFeedbackBufferMode);
}
}
@ -936,57 +948,58 @@ WebGLProgram::GetUniformIndices(const dom::Sequence<nsString>& uniformNames,
void
WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const
WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex,
GLuint uniformBlockBinding) const
{
const char funcName[] = "getActiveUniformBlockName";
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
return;
}
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
if (uniformBlockIndex >= linkInfo->uniformBlocks.size()) {
mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
const auto& uniformBlocks = LinkInfo()->uniformBlocks;
if (uniformBlockIndex >= uniformBlocks.size()) {
mContext->ErrorInvalidValue("%s: Index %u invalid.", funcName, uniformBlockIndex);
return;
}
const auto& uniformBlock = uniformBlocks[uniformBlockIndex];
if (uniformBlockBinding > mContext->mGLMaxUniformBufferBindings) {
mContext->ErrorInvalidEnum("getActiveUniformBlockName: binding %u invalid.", uniformBlockBinding);
const auto& indexedBindings = mContext->mIndexedUniformBufferBindings;
if (uniformBlockBinding >= indexedBindings.size()) {
mContext->ErrorInvalidValue("%s: Binding %u invalid.", funcName,
uniformBlockBinding);
return;
}
const auto& indexedBinding = indexedBindings[uniformBlockBinding];
////
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
gl->fUniformBlockBinding(mGLName, uniformBlockIndex, uniformBlockBinding);
////
uniformBlock->mBinding = &indexedBinding;
}
void
WebGLProgram::LinkProgram()
bool
WebGLProgram::ValidateForLink()
{
mContext->InvalidateBufferFetching(); // we do it early in this function
// as some of the validation below changes program state
mLinkLog.Truncate();
mMostRecentLinkInfo = nullptr;
if (!mVertShader || !mVertShader->IsCompiled()) {
mLinkLog.AssignLiteral("Must have a compiled vertex shader attached.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return;
return false;
}
if (!mFragShader || !mFragShader->IsCompiled()) {
mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return;
return false;
}
if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) {
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return;
}
if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog))
return false;
gl::GLContext* gl = mContext->gl;
gl->MakeCurrent();
const auto& gl = mContext->gl;
if (gl->WorkAroundDriverBugs() &&
mContext->mIsMesa)
@ -998,34 +1011,70 @@ WebGLProgram::LinkProgram()
if (numSamplerUniforms_upperBound > 16) {
mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
" Mesa drivers to avoid crashing.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return;
return false;
}
// Bug 1203135: Mesa crashes internally if we exceed the reported maximum attribute count.
if (mVertShader->NumAttributes() > mContext->MaxVertexAttribs()) {
mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max attribute count.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return;
mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max"
" attribute count.");
return false;
}
}
return true;
}
void
WebGLProgram::LinkProgram()
{
const char funcName[] = "linkProgram";
if (mNumActiveTFOs) {
mContext->ErrorInvalidOperation("%s: Program is in-use by one or more active"
" transform feedback objects.",
funcName);
return;
}
mContext->MakeContextCurrent();
mContext->InvalidateBufferFetching(); // we do it early in this function
// as some of the validation changes program state
mLinkLog.Truncate();
mMostRecentLinkInfo = nullptr;
if (!ValidateForLink()) {
mContext->GenerateWarning("%s: %s", funcName, mLinkLog.BeginReading());
return;
}
// Bind the attrib locations.
// This can't be done trivially, because we have to deal with mapped attrib names.
for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) {
const nsCString& name = itr->first;
GLuint index = itr->second;
for (const auto& pair : mNextLink_BoundAttribLocs) {
const auto& name = pair.first;
const auto& index = pair.second;
mVertShader->BindAttribLocation(mGLName, name, index);
}
if (!mTransformFeedbackVaryings.empty()) {
// Bind the transform feedback varyings.
// This can't be done trivially, because we have to deal with mapped names too.
mVertShader->ApplyTransformFeedbackVaryings(mGLName,
mTransformFeedbackVaryings,
mTransformFeedbackBufferMode,
&mTempMappedVaryings);
// Storage for transform feedback varyings before link.
// (Work around for bug seen on nVidia drivers.)
std::vector<std::string> scopedMappedTFVaryings;
if (mContext->IsWebGL2()) {
mVertShader->MapTransformFeedbackVaryings(mNextLink_TransformFeedbackVaryings,
&scopedMappedTFVaryings);
std::vector<const char*> driverVaryings;
driverVaryings.reserve(scopedMappedTFVaryings.size());
for (const auto& cur : scopedMappedTFVaryings) {
driverVaryings.push_back(cur.c_str());
}
mContext->gl->fTransformFeedbackVaryings(mGLName, driverVaryings.size(),
driverVaryings.data(),
mNextLink_TransformFeedbackBufferMode);
}
LinkAndUpdate();
@ -1080,10 +1129,63 @@ NumUsedLocationsByElemType(GLenum elemType)
}
}
static uint8_t
NumComponents(GLenum elemType)
{
switch (elemType) {
case LOCAL_GL_FLOAT:
case LOCAL_GL_INT:
case LOCAL_GL_UNSIGNED_INT:
case LOCAL_GL_BOOL:
return 1;
case LOCAL_GL_FLOAT_VEC2:
case LOCAL_GL_INT_VEC2:
case LOCAL_GL_UNSIGNED_INT_VEC2:
case LOCAL_GL_BOOL_VEC2:
return 2;
case LOCAL_GL_FLOAT_VEC3:
case LOCAL_GL_INT_VEC3:
case LOCAL_GL_UNSIGNED_INT_VEC3:
case LOCAL_GL_BOOL_VEC3:
return 3;
case LOCAL_GL_FLOAT_VEC4:
case LOCAL_GL_INT_VEC4:
case LOCAL_GL_UNSIGNED_INT_VEC4:
case LOCAL_GL_BOOL_VEC4:
case LOCAL_GL_FLOAT_MAT2:
return 4;
case LOCAL_GL_FLOAT_MAT2x3:
case LOCAL_GL_FLOAT_MAT3x2:
return 6;
case LOCAL_GL_FLOAT_MAT2x4:
case LOCAL_GL_FLOAT_MAT4x2:
return 8;
case LOCAL_GL_FLOAT_MAT3:
return 9;
case LOCAL_GL_FLOAT_MAT3x4:
case LOCAL_GL_FLOAT_MAT4x3:
return 12;
case LOCAL_GL_FLOAT_MAT4:
return 16;
default:
MOZ_CRASH("`elemType`");
}
}
bool
WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const
{
const auto& linkInfo = mMostRecentLinkInfo;
const auto& gl = mContext->gl;
// Check if the attrib name conflicting to uniform name
for (const auto& attrib : linkInfo->attribs) {
@ -1123,15 +1225,107 @@ WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const
}
}
// Forbid:
// * Unrecognized varying name
// * Duplicate varying name
// * Too many components for specified buffer mode
if (mNextLink_TransformFeedbackVaryings.size()) {
GLuint maxComponentsPerIndex = 0;
switch (mNextLink_TransformFeedbackBufferMode) {
case LOCAL_GL_INTERLEAVED_ATTRIBS:
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
&maxComponentsPerIndex);
break;
case LOCAL_GL_SEPARATE_ATTRIBS:
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,
&maxComponentsPerIndex);
break;
default:
MOZ_CRASH("`bufferMode`");
}
std::vector<size_t> componentsPerVert;
std::set<const WebGLActiveInfo*> alreadyUsed;
for (const auto& wideUserName : mNextLink_TransformFeedbackVaryings) {
if (!componentsPerVert.size() ||
mNextLink_TransformFeedbackBufferMode == LOCAL_GL_SEPARATE_ATTRIBS)
{
componentsPerVert.push_back(0);
}
////
const WebGLActiveInfo* curInfo = nullptr;
for (const auto& info : linkInfo->transformFeedbackVaryings) {
const NS_ConvertASCIItoUTF16 info_wideUserName(info->mBaseUserName);
if (info_wideUserName == wideUserName) {
curInfo = info.get();
break;
}
}
if (!curInfo) {
const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
*out_linkLog = nsPrintfCString("Transform feedback varying \"%s\" not"
" found.",
asciiUserName.BeginReading());
return false;
}
const auto insertResPair = alreadyUsed.insert(curInfo);
const auto& didInsert = insertResPair.second;
if (!didInsert) {
const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
*out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
" specified twice.",
asciiUserName.BeginReading());
return false;
}
////
size_t varyingComponents = NumComponents(curInfo->mElemType);
varyingComponents *= curInfo->mElemCount;
auto& totalComponentsForIndex = *(componentsPerVert.rbegin());
totalComponentsForIndex += varyingComponents;
if (totalComponentsForIndex > maxComponentsPerIndex) {
const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
*out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
" pushed `componentsForIndex` over the"
" limit of %u.",
asciiUserName.BeginReading(),
maxComponentsPerIndex);
return false;
}
}
linkInfo->componentsPerTFVert.swap(componentsPerVert);
}
return true;
}
bool
WebGLProgram::UseProgram() const
{
const char funcName[] = "useProgram";
if (!mMostRecentLinkInfo) {
mContext->ErrorInvalidOperation("useProgram: Program has not been successfully"
" linked.");
mContext->ErrorInvalidOperation("%s: Program has not been successfully linked.",
funcName);
return false;
}
if (mContext->mBoundTransformFeedback &&
mContext->mBoundTransformFeedback->mIsActive &&
!mContext->mBoundTransformFeedback->mIsPaused)
{
mContext->ErrorInvalidOperation("%s: Transform feedback active and not paused.",
funcName);
return false;
}
@ -1183,11 +1377,6 @@ WebGLProgram::LinkAndUpdate()
mLinkLog.SetLength(0);
}
// Post link, temporary mapped varying names for transform feedback can be discarded.
// The memory can only be deleted after log is queried or the link status will fail.
std::vector<std::string> empty;
empty.swap(mTempMappedVaryings);
GLint ok = 0;
gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
if (!ok)
@ -1237,42 +1426,43 @@ void
WebGLProgram::TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
GLenum bufferMode)
{
if (bufferMode != LOCAL_GL_INTERLEAVED_ATTRIBS &&
bufferMode != LOCAL_GL_SEPARATE_ATTRIBS)
{
mContext->ErrorInvalidEnum("transformFeedbackVaryings: `bufferMode` %s is "
"invalid. Must be one of gl.INTERLEAVED_ATTRIBS or "
"gl.SEPARATE_ATTRIBS.",
mContext->EnumName(bufferMode));
const char funcName[] = "transformFeedbackVaryings";
const auto& gl = mContext->gl;
gl->MakeCurrent();
switch (bufferMode) {
case LOCAL_GL_INTERLEAVED_ATTRIBS:
break;
case LOCAL_GL_SEPARATE_ATTRIBS:
{
GLuint maxAttribs = 0;
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
&maxAttribs);
if (varyings.Length() >= maxAttribs) {
mContext->ErrorInvalidValue("%s: Length of `varyings` exceeds %s.",
funcName,
"TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
return;
}
}
break;
default:
mContext->ErrorInvalidEnum("%s: Bad `bufferMode`: 0x%04x.", funcName, bufferMode);
return;
}
size_t varyingsCount = varyings.Length();
if (bufferMode == LOCAL_GL_SEPARATE_ATTRIBS &&
varyingsCount >= mContext->mGLMaxTransformFeedbackSeparateAttribs)
{
mContext->ErrorInvalidValue("transformFeedbackVaryings: Number of `varyings` exc"
"eeds gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS.");
return;
}
////
std::vector<nsCString> asciiVaryings;
for (size_t i = 0; i < varyingsCount; i++) {
if (!ValidateGLSLVariableName(varyings[i], mContext, "transformFeedbackVaryings"))
return;
NS_LossyConvertUTF16toASCII asciiName(varyings[i]);
asciiVaryings.push_back(asciiName);
}
// All validated. Translate the strings and store them until
// program linking.
mTransformFeedbackBufferMode = bufferMode;
mTransformFeedbackVaryings.swap(asciiVaryings);
mNextLink_TransformFeedbackVaryings.assign(varyings.Elements(),
varyings.Elements() + varyings.Length());
mNextLink_TransformFeedbackBufferMode = bufferMode;
}
already_AddRefed<WebGLActiveInfo>
WebGLProgram::GetTransformFeedbackVarying(GLuint index)
WebGLProgram::GetTransformFeedbackVarying(GLuint index) const
{
// No docs in the WebGL 2 spec for this function. Taking the language for
// getActiveAttrib, which states that the function returns null on any error.

View File

@ -61,18 +61,25 @@ struct UniformBlockInfo final
{
const nsCString mBaseUserName;
const nsCString mBaseMappedName;
const uint32_t mDataSize;
UniformBlockInfo(const nsACString& baseUserName,
const nsACString& baseMappedName)
const IndexedBufferBinding* mBinding;
UniformBlockInfo(WebGLContext* webgl, const nsACString& baseUserName,
const nsACString& baseMappedName, uint32_t dataSize)
: mBaseUserName(baseUserName)
, mBaseMappedName(baseMappedName)
{}
, mDataSize(dataSize)
, mBinding(&webgl->mIndexedUniformBufferBindings[0])
{ }
};
struct LinkedProgramInfo final
: public RefCounted<LinkedProgramInfo>
, public SupportsWeakPtr<LinkedProgramInfo>
{
friend class WebGLProgram;
MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(LinkedProgramInfo)
@ -82,12 +89,14 @@ struct LinkedProgramInfo final
std::vector<AttribInfo> attribs;
std::vector<UniformInfo*> uniforms; // Owns its contents.
std::vector<const UniformBlockInfo*> uniformBlocks; // Owns its contents.
std::vector<UniformBlockInfo*> uniformBlocks; // Owns its contents.
std::vector<RefPtr<WebGLActiveInfo>> transformFeedbackVaryings;
// Needed for draw call validation.
std::vector<UniformInfo*> uniformSamplers;
mutable std::vector<size_t> componentsPerTFVert;
//////
// The maps for the frag data names to the translated names.
@ -123,6 +132,8 @@ class WebGLProgram final
, public LinkedListElement<WebGLProgram>
, public WebGLContextBoundObject
{
friend class WebGLTransformFeedback;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
@ -174,7 +185,7 @@ public:
void TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
GLenum bufferMode);
already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(GLuint index);
already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(GLuint index) const;
void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
@ -194,6 +205,7 @@ private:
~WebGLProgram();
void LinkAndUpdate();
bool ValidateForLink();
bool ValidateAfterTentativeLink(nsCString* const out_linkLog) const;
public:
@ -202,14 +214,15 @@ public:
private:
WebGLRefPtr<WebGLShader> mVertShader;
WebGLRefPtr<WebGLShader> mFragShader;
std::map<nsCString, GLuint> mBoundAttribLocs;
std::vector<nsCString> mTransformFeedbackVaryings;
GLenum mTransformFeedbackBufferMode;
size_t mNumActiveTFOs;
std::map<nsCString, GLuint> mNextLink_BoundAttribLocs;
std::vector<nsString> mNextLink_TransformFeedbackVaryings;
GLenum mNextLink_TransformFeedbackBufferMode;
nsCString mLinkLog;
RefPtr<const webgl::LinkedProgramInfo> mMostRecentLinkInfo;
// Storage for transform feedback varyings before link.
// (Work around for bug seen on nVidia drivers.)
std::vector<std::string> mTempMappedVaryings;
};
} // namespace mozilla

View File

@ -228,22 +228,20 @@ WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
}
void
WebGLRenderbuffer::DoFramebufferRenderbuffer(GLenum attachment) const
WebGLRenderbuffer::DoFramebufferRenderbuffer(FBTarget target, GLenum attachment) const
{
gl::GLContext* gl = mContext->gl;
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
const GLuint stencilRB = (mSecondaryRB ? mSecondaryRB : mPrimaryRB);
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_DEPTH_ATTACHMENT,
gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_DEPTH_ATTACHMENT,
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_STENCIL_ATTACHMENT,
gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_STENCIL_ATTACHMENT,
LOCAL_GL_RENDERBUFFER, stencilRB);
return;
}
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
gl->fFramebufferRenderbuffer(target.get(), attachment,
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
}

View File

@ -85,7 +85,7 @@ protected:
DeleteOnce();
}
void DoFramebufferRenderbuffer(GLenum attachment) const;
void DoFramebufferRenderbuffer(FBTarget target, GLenum attachment) const;
GLenum DoRenderbufferStorage(uint32_t samples, const webgl::FormatUsageInfo* format,
uint32_t width, uint32_t height);
};

View File

@ -408,40 +408,24 @@ WebGLShader::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_Frag
}
void
WebGLShader::ApplyTransformFeedbackVaryings(GLuint prog,
const std::vector<nsCString>& varyings,
GLenum bufferMode,
std::vector<std::string>* out_mappedVaryings) const
WebGLShader::MapTransformFeedbackVaryings(const std::vector<nsString>& varyings,
std::vector<std::string>* out_mappedVaryings) const
{
MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER);
MOZ_ASSERT(!varyings.empty());
MOZ_ASSERT(out_mappedVaryings);
const size_t varyingsCount = varyings.size();
std::vector<std::string> mappedVaryings;
out_mappedVaryings->clear();
out_mappedVaryings->reserve(varyings.size());
for (size_t i = 0; i < varyingsCount; i++) {
const nsCString& userName = varyings[i];
std::string userNameStr(userName.BeginReading());
const std::string* mappedNameStr = &userNameStr;
if (mValidator)
mValidator->FindVaryingMappedNameByUserName(userNameStr, &mappedNameStr);
mappedVaryings.push_back(*mappedNameStr);
for (const auto& wideUserName : varyings) {
const NS_LossyConvertUTF16toASCII mozUserName(wideUserName); // Don't validate here.
const std::string userName(mozUserName.BeginReading(), mozUserName.Length());
const std::string* pMappedName = &userName;
if (mValidator) {
mValidator->FindVaryingMappedNameByUserName(userName, &pMappedName);
}
out_mappedVaryings->push_back(*pMappedName);
}
// Temporary, tight packed array of string pointers into mappedVaryings.
std::vector<const GLchar*> strings;
strings.resize(varyingsCount);
for (size_t i = 0; i < varyingsCount; i++) {
strings[i] = mappedVaryings[i].c_str();
}
mContext->MakeContextCurrent();
mContext->gl->fTransformFeedbackVaryings(prog, varyingsCount, &strings[0], bufferMode);
out_mappedVaryings->swap(mappedVaryings);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -52,7 +52,6 @@ public:
bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const;
size_t CalcNumSamplerUniforms() const;
size_t NumAttributes() const;
void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
bool FindAttribUserNameByMappedName(const nsACString& mappedName,
nsDependentCString* const out_userName) const;
bool FindVaryingByMappedName(const nsACString& mappedName,
@ -71,11 +70,12 @@ public:
return mTranslationSuccessful && mCompilationSuccessful;
}
void ApplyTransformFeedbackVaryings(GLuint prog,
const std::vector<nsCString>& varyings,
GLenum bufferMode,
std::vector<std::string>* out_mappedVaryings) const;
private:
void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
void MapTransformFeedbackVaryings(const std::vector<nsString>& varyings,
std::vector<std::string>* out_mappedVaryings) const;
public:
// Other funcs
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
void Delete();

View File

@ -64,6 +64,10 @@ public:
std::string* const out_userName) const;
void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
bool ValidateTransformFeedback(const std::vector<nsString>& userNames,
uint32_t maxComponents, nsCString* const out_errorText,
std::vector<std::string>* const out_mappedNames);
};
} // namespace webgl

View File

@ -19,6 +19,7 @@
#include "mozilla/Unused.h"
#include "ScopedGLHelpers.h"
#include "TexUnpackBlob.h"
#include "WebGLBuffer.h"
#include "WebGLContext.h"
#include "WebGLContextUtils.h"
#include "WebGLFramebuffer.h"
@ -213,6 +214,15 @@ WebGLContext::ValidateUnpackInfo(const char* funcName, bool usePBOs, GLenum form
return false;
}
if (mBoundPixelUnpackBuffer &&
mBoundPixelUnpackBuffer->mNumActiveTFOs)
{
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
" object.",
funcName);
return false;
}
if (!mFormatUsage->AreUnpackEnumsValid(format, type)) {
ErrorInvalidEnum("%s: Invalid unpack format/type: 0x%04x/0x%04x", funcName,
format, type);
@ -315,7 +325,7 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
const auto bufferByteCount = packBuffer->ByteLength();
uint32_t byteCount = 0;
if (bufferByteCount >= offset) {
if (bufferByteCount >= uint64_t(offset)) {
byteCount = bufferByteCount - offset;
}
@ -1969,20 +1979,18 @@ WebGLTexture::ValidateCopyTexImageForFeedback(const char* funcName, uint32_t lev
{
const auto& fb = mContext->mBoundReadFramebuffer;
if (fb) {
const auto readBuffer = fb->ReadBufferMode();
MOZ_ASSERT(readBuffer != LOCAL_GL_NONE);
const uint32_t colorAttachment = readBuffer - LOCAL_GL_COLOR_ATTACHMENT0;
const auto& attach = fb->ColorAttachment(colorAttachment);
const auto& attach = fb->ColorReadBuffer();
MOZ_ASSERT(attach);
if (attach.Texture() == this &&
uint32_t(attach.MipLevel()) == level)
if (attach->Texture() == this &&
uint32_t(attach->MipLevel()) == level)
{
// Note that the TexImageTargets *don't* have to match for this to be
// undefined per GLES 3.0.4 p211, thus an INVALID_OP in WebGL.
mContext->ErrorInvalidOperation("%s: Feedback loop detected, as this texture"
" is already attached to READ_FRAMEBUFFER's"
" READ_BUFFER-selected COLOR_ATTACHMENT%u.",
funcName, colorAttachment);
funcName, attach->mAttachmentPoint);
return false;
}
}

View File

@ -11,48 +11,206 @@
namespace mozilla {
WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl,
GLuint tf)
WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf)
: WebGLContextBoundObject(webgl)
, mGLName(tf)
, mMode(LOCAL_GL_NONE)
, mIsActive(false)
, mIndexedBindings(webgl->mGLMaxTransformFeedbackSeparateAttribs)
, mIsPaused(false)
, mIsActive(false)
{
mContext->mTransformFeedbacks.insertBack(this);
}
WebGLTransformFeedback::~WebGLTransformFeedback()
{
mMode = LOCAL_GL_NONE;
mIsActive = false;
mIsPaused = false;
DeleteOnce();
}
void
WebGLTransformFeedback::Delete()
{
mContext->MakeContextCurrent();
mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
if (mGLName) {
mContext->MakeContextCurrent();
mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
}
removeFrom(mContext->mTransformFeedbacks);
}
WebGLContext*
WebGLTransformFeedback::GetParentObject() const
////////////////////////////////////////
void
WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode)
{
return mContext;
const char funcName[] = "beginTransformFeedback";
if (mIsActive)
return mContext->ErrorInvalidOperation("%s: Already active.", funcName);
switch (primMode) {
case LOCAL_GL_POINTS:
case LOCAL_GL_LINES:
case LOCAL_GL_TRIANGLES:
break;
default:
mContext->ErrorInvalidEnum("%s: `primitiveMode` must be one of POINTS, LINES, or"
" TRIANGLES.",
funcName);
return;
}
const auto& prog = mContext->mCurrentProgram;
if (!prog ||
!prog->IsLinked() ||
!prog->LinkInfo()->componentsPerTFVert.size())
{
mContext->ErrorInvalidOperation("%s: Current program not valid for transform"
" feedback.",
funcName);
return;
}
const auto& linkInfo = prog->LinkInfo();
const auto& componentsPerTFVert = linkInfo->componentsPerTFVert;
size_t minVertCapacity = SIZE_MAX;
for (size_t i = 0; i < componentsPerTFVert.size(); i++) {
const auto& indexedBinding = mIndexedBindings[i];
const auto& componentsPerVert = componentsPerTFVert[i];
const auto& buffer = indexedBinding.mBufferBinding;
if (!buffer) {
mContext->ErrorInvalidOperation("%s: No buffer attached to required transform"
" feedback index %u.",
funcName, (uint32_t)i);
return;
}
const size_t vertCapacity = buffer->ByteLength() / 4 / componentsPerVert;
minVertCapacity = std::min(minVertCapacity, vertCapacity);
}
////
const auto& gl = mContext->gl;
gl->MakeCurrent();
gl->fBeginTransformFeedback(primMode);
////
mIsActive = true;
MOZ_ASSERT(!mIsPaused);
mActive_Program = prog;
mActive_PrimMode = primMode;
mActive_VertPosition = 0;
mActive_VertCapacity = minVertCapacity;
////
for (const auto& cur : mIndexedBindings) {
const auto& buffer = cur.mBufferBinding;
if (buffer) {
buffer->mNumActiveTFOs++;
}
}
mActive_Program->mNumActiveTFOs++;
}
void
WebGLTransformFeedback::EndTransformFeedback()
{
const char funcName[] = "endTransformFeedback";
if (!mIsActive)
return mContext->ErrorInvalidOperation("%s: Not active.", funcName);
////
const auto& gl = mContext->gl;
gl->MakeCurrent();
gl->fEndTransformFeedback();
////
mIsActive = false;
mIsPaused = false;
////
for (const auto& cur : mIndexedBindings) {
const auto& buffer = cur.mBufferBinding;
if (buffer) {
buffer->mNumActiveTFOs--;
}
}
mActive_Program->mNumActiveTFOs--;
}
void
WebGLTransformFeedback::PauseTransformFeedback()
{
const char funcName[] = "pauseTransformFeedback";
if (!mIsActive ||
mIsPaused)
{
mContext->ErrorInvalidOperation("%s: Not active or is paused.", funcName);
return;
}
////
const auto& gl = mContext->gl;
gl->MakeCurrent();
gl->fPauseTransformFeedback();
////
mIsPaused = true;
}
void
WebGLTransformFeedback::ResumeTransformFeedback()
{
const char funcName[] = "resumeTransformFeedback";
if (!mIsPaused)
return mContext->ErrorInvalidOperation("%s: Not paused.", funcName);
if (mContext->mCurrentProgram != mActive_Program) {
mContext->ErrorInvalidOperation("%s: Active program differs from original.",
funcName);
return;
}
////
const auto& gl = mContext->gl;
gl->MakeCurrent();
gl->fResumeTransformFeedback();
////
MOZ_ASSERT(mIsActive);
mIsPaused = false;
}
////////////////////////////////////////
JSObject*
WebGLTransformFeedback::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLTransformFeedbackBinding::Wrap(cx, this, givenProto);
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTransformFeedback)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTransformFeedback, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTransformFeedback, Release)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLTransformFeedback,
mGenericBufferBinding,
mIndexedBindings,
mActive_Program)
} // namespace mozilla

View File

@ -18,27 +18,43 @@ class WebGLTransformFeedback final
, public LinkedListElement<WebGLTransformFeedback>
, public WebGLContextBoundObject
{
friend class ScopedDrawWithTransformFeedback;
friend class WebGLContext;
friend class WebGL2Context;
friend class WebGLProgram;
public:
const GLuint mGLName;
private:
// GLES 3.0.4 p267, Table 6.24 "Transform Feedback State"
WebGLRefPtr<WebGLBuffer> mGenericBufferBinding;
std::vector<IndexedBufferBinding> mIndexedBindings;
bool mIsPaused;
bool mIsActive;
// Not in state tables:
WebGLRefPtr<WebGLProgram> mActive_Program;
GLenum mActive_PrimMode;
size_t mActive_VertPosition;
size_t mActive_VertCapacity;
public:
WebGLTransformFeedback(WebGLContext* webgl, GLuint tf);
void Delete();
WebGLContext* GetParentObject() const;
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) 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;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTransformFeedback)
void Delete();
WebGLContext* GetParentObject() const { return mContext; }
virtual JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
// GL Funcs
void BeginTransformFeedback(GLenum primMode);
void EndTransformFeedback();
void PauseTransformFeedback();
void ResumeTransformFeedback();
};
} // namespace mozilla

View File

@ -41,26 +41,19 @@ struct WebGLVertexAttribData
GLuint componentSize() const {
switch(type) {
case LOCAL_GL_BYTE:
return sizeof(GLbyte);
case LOCAL_GL_UNSIGNED_BYTE:
return sizeof(GLubyte);
return 1;
case LOCAL_GL_SHORT:
return sizeof(GLshort);
case LOCAL_GL_UNSIGNED_SHORT:
return sizeof(GLushort);
case LOCAL_GL_HALF_FLOAT:
case LOCAL_GL_HALF_FLOAT_OES:
return 2;
case LOCAL_GL_INT:
return sizeof(GLint);
case LOCAL_GL_UNSIGNED_INT:
return sizeof(GLuint);
// case LOCAL_GL_FIXED:
case LOCAL_GL_FLOAT:
return sizeof(GLfloat);
return 4;
default:
MOZ_ASSERT(false, "Should never get here!");

View File

@ -66,14 +66,8 @@ void
CheckValidate(bool expectSuccess, mozilla::WebGLElementArrayCache& c, GLenum type,
uint32_t maxAllowed, size_t first, size_t count)
{
uint32_t out_upperBound = 0;
const bool success = c.Validate(type, maxAllowed, first, count, &out_upperBound);
const bool success = c.Validate(type, maxAllowed, first, count);
VERIFY(success == expectSuccess);
if (success) {
VERIFY(out_upperBound <= maxAllowed);
} else {
VERIFY(out_upperBound > maxAllowed);
}
}
template<typename T>

View File

@ -71,7 +71,6 @@ SOURCES += [
UNIFIED_SOURCES += [
'TexUnpackBlob.cpp',
'WebGL1Context.cpp',
'WebGL1ContextBuffers.cpp',
'WebGL1ContextUniforms.cpp',
'WebGL2Context.cpp',
'WebGL2ContextBuffers.cpp',

View File

@ -4593,7 +4593,6 @@ skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.
[generated/test_2_conformance2__state__gl-object-get-calls.html]
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
[generated/test_2_conformance2__transform_feedback__transform_feedback.html]
fail-if = (os == 'win' && (os_version == '6.1' || os_version == '6.2' || os_version == '10.0'))
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
[generated/test_2_conformance2__vertex_arrays__vertex-array-object.html]
fail-if = (os == 'mac') || (os == 'win')
@ -6044,7 +6043,6 @@ skip-if = (os == 'win')
[generated/test_conformance__extensions__webgl-draw-buffers-max-draw-buffers.html]
[generated/test_conformance__extensions__webgl-draw-buffers.html]
skip-if = (os == 'linux')
fail-if = (os == 'mac')
[generated/test_conformance__extensions__webgl-shared-resources.html]
[generated/test_conformance__glsl__bugs__angle-ambiguous-function-call.html]
[generated/test_conformance__glsl__bugs__angle-constructor-invalid-parameters.html]

View File

@ -90,7 +90,6 @@ fail-if = (os == 'mac' && os_version == '10.6')
skip-if = (os == 'b2g') || (os == 'linux') || (os == 'android')
[generated/test_conformance__extensions__webgl-draw-buffers.html]
fail-if = (os == 'mac')
# Crashes
skip-if = (os == 'linux')
@ -658,8 +657,6 @@ skip-if = (os == 'win' && os_version == '6.1')
[generated/test_2_conformance__textures__misc__tex-image-and-sub-image-2d-with-array-buffer-view.html]
# Failure on win7 but got passed on win7 vm
skip-if = (os == 'win' && os_version == '6.1')
[generated/test_2_conformance2__transform_feedback__transform_feedback.html]
fail-if = (os == 'win' && (os_version == '6.1' || os_version == '6.2' || os_version == '10.0'))
####################
# failure on Windows

View File

@ -278,7 +278,14 @@ GetFilesHelper::RunIO()
}
nsAutoString path;
path.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
mErrorResult = file->GetLeafName(path);
if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
return;
}
if (path.IsEmpty()) {
path.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
}
mErrorResult = ExploreDirectory(path, file);
}

View File

@ -111,7 +111,8 @@ addMessageListener("dir.open", function (e) {
}
sendAsyncMessage("dir.opened", {
dir: testFile.path
dir: testFile.path,
name: testFile.leafName
});
});

View File

@ -23,6 +23,7 @@ function create_fileList(aPath) {
function onOpened(message) {
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
fileList.setAttribute('data-name', message.name);
fileList.getFilesAndDirectories().then(function(array) {
is(array.length, 1, "We want just 1 directory.");
@ -84,6 +85,7 @@ function test_inputGetFiles() {
function onOpened(message) {
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
fileList.setAttribute('data-name', message.name);
fileList.getFilesAndDirectories()
.then(function(result) {
@ -96,7 +98,7 @@ function test_inputGetFiles() {
is(result.length, 1, "getFiles should return 1 element");
ok(result[0] instanceof File, "getFile should return 1 file");
is(result[0].name, 'foo.txt', "getFiles()[0].name should be 'foo.txt'");
is(result[0].webkitRelativePath, '/foo.txt', "getFiles()[0].webkitRelativePath should be '/foo.txt'");
is(result[0].webkitRelativePath, fileList.dataset.name + '/foo.txt', "getFiles()[0].webkitRelativePath should be '/foo.txt'");
return fileList.getFiles(true);
})
@ -106,10 +108,10 @@ function test_inputGetFiles() {
function checkFile(file) {
ok(file instanceof File, "getFile[x] should return a file");
if (file.name == 'foo.txt') {
is(file.webkitRelativePath, '/foo.txt', "getFiles()[x].webkitRelativePath should be '/foo.txt'");
is(file.webkitRelativePath, fileList.dataset.name + '/foo.txt', "getFiles()[x].webkitRelativePath should be '/foo.txt'");
} else {
is(file.name, 'bar.txt', "getFiles()[x].name should be 'bar.txt'");
is(file.webkitRelativePath, '/subdir/bar.txt', "getFiles()[x].webkitRelativePath should be '/subdir/bar.txt'");
is(file.webkitRelativePath, fileList.dataset.name + '/subdir/bar.txt', "getFiles()[x].webkitRelativePath should be '/subdir/bar.txt'");
}
}

View File

@ -25,6 +25,7 @@ function populateInputFile(aInputFile) {
MockFilePicker.useDirectory(message.dir);
var input = document.getElementById(aInputFile);
input.setAttribute('data-name', message.name);
input.addEventListener('change', function change() {
input.removeEventListener('change', change);
MockFilePicker.cleanup();
@ -39,11 +40,11 @@ function populateInputFile(aInputFile) {
script.sendAsyncMessage("dir.open", { path: 'test' });
}
function checkFile(file, fileList) {
function checkFile(file, fileList, dirName) {
for (var i = 0; i < fileList.length; ++i) {
ok(fileList[i] instanceof File, "We want just files.");
if (fileList[i].name == file.name) {
is(fileList[i].webkitRelativePath, file.path, "Path matches");
is(fileList[i].webkitRelativePath, dirName + file.path, "Path matches");
return;
}
}
@ -63,7 +64,7 @@ function test_fileList(aInputFile, aWhat) {
is(fileList.length, aWhat.length, "We want just " + aWhat.length + " elements for " + aInputFile);
for (var i = 0; i < aWhat.length; ++i) {
checkFile(aWhat[i], fileList);
checkFile(aWhat[i], fileList, input.dataset.name);
}
next();

View File

@ -5635,7 +5635,7 @@ HTMLInputElement::GetFiles(bool aRecursiveFlag, ErrorResult& aRv)
GetFilesHelper* helper = GetOrCreateGetFilesHelper(aRecursiveFlag, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
}
MOZ_ASSERT(helper);
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();

View File

@ -6214,18 +6214,25 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
EventHandlerNonNull*
HTMLMediaElement::GetOnencrypted()
{
EventListenerManager *elm = GetExistingListenerManager();
return elm ? elm->GetEventHandler(nsGkAtoms::onencrypted, EmptyString())
: nullptr;
return EventTarget::GetEventHandler(nsGkAtoms::onencrypted, EmptyString());
}
void
HTMLMediaElement::SetOnencrypted(EventHandlerNonNull* handler)
HTMLMediaElement::SetOnencrypted(EventHandlerNonNull* aCallback)
{
EventListenerManager *elm = GetOrCreateListenerManager();
if (elm) {
elm->SetEventHandler(nsGkAtoms::onencrypted, EmptyString(), handler);
}
EventTarget::SetEventHandler(nsGkAtoms::onencrypted, EmptyString(), aCallback);
}
EventHandlerNonNull*
HTMLMediaElement::GetOnwaitingforkey()
{
return EventTarget::GetEventHandler(nsGkAtoms::onwaitingforkey, EmptyString());
}
void
HTMLMediaElement::SetOnwaitingforkey(EventHandlerNonNull* aCallback)
{
EventTarget::SetEventHandler(nsGkAtoms::onwaitingforkey, EmptyString(), aCallback);
}
void

View File

@ -633,7 +633,10 @@ public:
ErrorResult& aRv);
mozilla::dom::EventHandlerNonNull* GetOnencrypted();
void SetOnencrypted(mozilla::dom::EventHandlerNonNull* listener);
void SetOnencrypted(mozilla::dom::EventHandlerNonNull* aCallback);
mozilla::dom::EventHandlerNonNull* GetOnwaitingforkey();
void SetOnwaitingforkey(mozilla::dom::EventHandlerNonNull* aCallback);
void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
const nsAString& aInitDataType) override;

View File

@ -483,5 +483,29 @@ MediaKeySession::SetExpiration(double aExpiration)
mExpiration = aExpiration;
}
EventHandlerNonNull*
MediaKeySession::GetOnkeystatuseschange()
{
return GetEventHandler(nsGkAtoms::onkeystatuseschange, EmptyString());
}
void
MediaKeySession::SetOnkeystatuseschange(EventHandlerNonNull* aCallback)
{
SetEventHandler(nsGkAtoms::onkeystatuseschange, EmptyString(), aCallback);
}
EventHandlerNonNull*
MediaKeySession::GetOnmessage()
{
return GetEventHandler(nsGkAtoms::onmessage, EmptyString());
}
void
MediaKeySession::SetOnmessage(EventHandlerNonNull* aCallback)
{
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
}
} // namespace dom
} // namespace mozilla

View File

@ -94,6 +94,12 @@ public:
void SetExpiration(double aExpiry);
mozilla::dom::EventHandlerNonNull* GetOnkeystatuseschange();
void SetOnkeystatuseschange(mozilla::dom::EventHandlerNonNull* aCallback);
mozilla::dom::EventHandlerNonNull* GetOnmessage();
void SetOnmessage(mozilla::dom::EventHandlerNonNull* aCallback);
// Process-unique identifier.
uint32_t Token() const;

View File

@ -6,7 +6,6 @@
#include "VideoDecoderManagerParent.h"
#include "VideoDecoderParent.h"
#include "base/thread.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Services.h"
#include "mozilla/Observer.h"
@ -15,6 +14,7 @@
#include "nsIEventTarget.h"
#include "nsThreadUtils.h"
#include "ImageContainer.h"
#include "mozilla/layers/VideoBridgeChild.h"
#if XP_WIN
#include <objbase.h>
@ -28,53 +28,11 @@ using namespace ipc;
using namespace layers;
using namespace gfx;
struct ImageMapEntry {
ImageMapEntry()
: mOwner(nullptr)
{}
ImageMapEntry(layers::Image* aImage, VideoDecoderManagerParent* aOwner)
: mImage(aImage)
, mOwner(aOwner)
{}
~ImageMapEntry() {}
RefPtr<layers::Image> mImage;
VideoDecoderManagerParent* mOwner;
};
std::map<uint64_t, ImageMapEntry> sImageMap;
StaticMutex sImageMutex;
/* static */ layers::Image*
VideoDecoderManagerParent::LookupImage(const SurfaceDescriptorGPUVideo& aSD)
{
StaticMutexAutoLock lock(sImageMutex);
return sImageMap[aSD.handle()].mImage;
}
SurfaceDescriptorGPUVideo
VideoDecoderManagerParent::StoreImage(Image* aImage)
VideoDecoderManagerParent::StoreImage(TextureClient* aTexture)
{
StaticMutexAutoLock lock(sImageMutex);
static uint64_t sImageCount = 0;
sImageMap[++sImageCount] = ImageMapEntry(aImage, this);
return SurfaceDescriptorGPUVideo(sImageCount);
}
void
VideoDecoderManagerParent::ClearAllOwnedImages()
{
StaticMutexAutoLock lock(sImageMutex);
for (auto it = sImageMap.begin(); it != sImageMap.end();)
{
if ((*it).second.mOwner == this) {
it = sImageMap.erase(it);
} else {
++it;
}
}
mTextureMap[aTexture->GetSerial()] = aTexture;
return SurfaceDescriptorGPUVideo(aTexture->GetSerial());
}
StaticRefPtr<nsIThread> sVideoDecoderManagerThread;
@ -126,6 +84,9 @@ VideoDecoderManagerParent::StartupThreads()
MOZ_ASSERT(hr == S_OK);
}), NS_DISPATCH_NORMAL);
#endif
sVideoDecoderManagerThread->Dispatch(NS_NewRunnableFunction([]() {
layers::VideoBridgeChild::Startup();
}), NS_DISPATCH_NORMAL);
sManagerTaskQueue = new TaskQueue(managerThread.forget());
@ -156,6 +117,10 @@ VideoDecoderManagerParent::ShutdownThreads()
sManagerTaskQueue->AwaitShutdownAndIdle();
sVideoDecoderTaskThread->Shutdown();
sVideoDecoderTaskThread = nullptr;
sVideoDecoderManagerThread->Dispatch(NS_NewRunnableFunction([]() {
layers::VideoBridgeChild::Shutdown();
}), NS_DISPATCH_SYNC);
sVideoDecoderManagerThread->Shutdown();
sVideoDecoderManagerThread = nullptr;
}
@ -193,8 +158,6 @@ VideoDecoderManagerParent::VideoDecoderManagerParent()
VideoDecoderManagerParent::~VideoDecoderManagerParent()
{
MOZ_COUNT_DTOR(VideoDecoderManagerParent);
ClearAllOwnedImages();
}
PVideoDecoderParent*
@ -231,8 +194,7 @@ VideoDecoderManagerParent::DeallocPVideoDecoderManagerParent()
bool
VideoDecoderManagerParent::RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD)
{
StaticMutexAutoLock lock(sImageMutex);
sImageMap.erase(aSD.handle());
mTextureMap.erase(aSD.handle());
return true;
}

View File

@ -19,8 +19,7 @@ public:
static bool CreateForContent(Endpoint<PVideoDecoderManagerParent>&& aEndpoint);
// Can be called from any thread
static layers::Image* LookupImage(const SurfaceDescriptorGPUVideo& aSD);
SurfaceDescriptorGPUVideo StoreImage(layers::Image* aImage);
SurfaceDescriptorGPUVideo StoreImage(layers::TextureClient* aImage);
static void StartupThreads();
static void ShutdownThreads();
@ -41,9 +40,9 @@ protected:
VideoDecoderManagerParent();
~VideoDecoderManagerParent();
void ClearAllOwnedImages();
void Open(Endpoint<PVideoDecoderManagerParent>&& aEndpoint);
std::map<uint64_t, RefPtr<layers::TextureClient>> mTextureMap;
};
} // namespace dom

View File

@ -7,8 +7,8 @@
#include "mozilla/Unused.h"
#include "mozilla/layers/CompositorThread.h"
#include "base/thread.h"
#include "mozilla/layers/TextureHost.h"
#include "mozilla/layers/PTextureParent.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/layers/VideoBridgeChild.h"
#include "MediaInfo.h"
#include "VideoDecoderManagerParent.h"
#ifdef XP_WIN
@ -164,6 +164,13 @@ VideoDecoderParent::Output(MediaData* aData)
MOZ_ASSERT(video->mImage, "Decoded video must output a layer::Image to be used with VideoDecoderParent");
RefPtr<TextureClient> texture = video->mImage->GetTextureClient(VideoBridgeChild::GetSingleton());
if (texture && !texture->IsAddedToCompositableClient()) {
texture->InitIPDLActor(VideoBridgeChild::GetSingleton());
texture->SetAddedToCompositableClient();
}
VideoDataIPDL output(MediaDataIPDL(data->mOffset,
data->mTime,
data->mTimecode,
@ -171,7 +178,7 @@ VideoDecoderParent::Output(MediaData* aData)
data->mFrames,
data->mKeyframe),
video->mDisplay,
self->GetManager()->StoreImage(video->mImage),
texture ? self->mParent->StoreImage(texture) : SurfaceDescriptorGPUVideo(0),
video->mFrameID);
Unused << self->SendOutput(output);
}));

View File

@ -48,8 +48,6 @@ public:
private:
~VideoDecoderParent();
VideoDecoderManagerParent* GetManager() { return static_cast<VideoDecoderManagerParent*>(Manager()); }
RefPtr<VideoDecoderManagerParent> mParent;
RefPtr<VideoDecoderParent> mIPDLSelfRef;
RefPtr<TaskQueue> mManagerTaskQueue;

View File

@ -13,6 +13,7 @@
#include "mozilla/gfx/DeviceManagerDx.h"
#include "mozilla/layers/D3D11ShareHandleImage.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/VideoBridgeChild.h"
#include "mozilla/Telemetry.h"
#include "MediaTelemetryConstants.h"
#include "mfapi.h"
@ -431,8 +432,11 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason)
if (layers::ImageBridgeChild::GetSingleton()) {
mTextureClientAllocator = new D3D9RecycleAllocator(layers::ImageBridgeChild::GetSingleton().get(),
mDevice);
mTextureClientAllocator->SetMaxPoolSize(5);
} else {
mTextureClientAllocator = new D3D9RecycleAllocator(layers::VideoBridgeChild::GetSingleton(),
mDevice);
}
mTextureClientAllocator->SetMaxPoolSize(5);
Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED,
uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D9));
@ -762,8 +766,11 @@ D3D11DXVA2Manager::Init(nsACString& aFailureReason)
if (layers::ImageBridgeChild::GetSingleton()) {
mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton().get(),
mDevice);
mTextureClientAllocator->SetMaxPoolSize(5);
} else {
mTextureClientAllocator = new D3D11RecycleAllocator(layers::VideoBridgeChild::GetSingleton(),
mDevice);
}
mTextureClientAllocator->SetMaxPoolSize(5);
Telemetry::Accumulate(Telemetry::MEDIA_DECODER_BACKEND_USED,
uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D11));

View File

@ -83,6 +83,25 @@ function startTest(test, token)
onsessioncreated: function(session) {
sessions.push(session);
session.addEventListener("keystatuseschange", KeysChangeFunc(session, test.keys, token), false);
session.numKeystatuseschangeEvents = 0;
session.numOnkeystatuseschangeEvents = 0;
session.addEventListener("keystatuseschange", function() {
session.numKeystatuseschangeEvents += 1;
});
session.onkeystatuseschange = function() {
session.numOnkeystatuseschangeEvents += 1;
};
session.numMessageEvents = 0;
session.numOnMessageEvents = 0;
session.addEventListener("message", function() {
session.numMessageEvents += 1;
});
session.onmessage = function() {
session.numOnMessageEvents += 1;
};
}
}
);
@ -129,6 +148,13 @@ function startTest(test, token)
Log(token, "session[" + session.sessionId + "] key " + kid + " = " + (session.keyIdsReceived[kid] ? "true" : "false"));
if (session.keyIdsReceived[kid]) { keyIdsReceived[kid] = true; }
}
ok(session.numKeystatuseschangeEvents > 0, TimeStamp(token) + " should get key status changes");
is(session.numKeystatuseschangeEvents, session.numOnkeystatuseschangeEvents,
TimeStamp(token) + " should have as many keystatuseschange event listener calls as event handler calls.");
ok(session.numMessageEvents > 0, TimeStamp(token) + " should get message events");
is(session.numMessageEvents, session.numOnMessageEvents,
TimeStamp(token) + " should have as many message event listener calls as event handler calls.");
}
for (var kid in keyIdsReceived) {
ok(keyIdsReceived[kid], TimeStamp(token) + " key with id " + kid + " was usable as expected");

View File

@ -58,6 +58,7 @@ function startTest(test, token)
var gotEncrypted = 0;
var gotWaitingForKey = 0;
var gotOnwaitingforkey = 0;
v.addEventListener("encrypted", function() {
gotEncrypted += 1;
@ -69,6 +70,10 @@ function startTest(test, token)
TestIfDoneDelaying()
});
v.onwaitingforkey = function() {
gotOnwaitingforkey += 1;
};
v.addEventListener("loadedmetadata", function() {
ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v),
TimeStamp(token) + " isEncrypted should be true");
@ -81,6 +86,7 @@ function startTest(test, token)
// I.e. one waitingForKey should be fired, after which, we process all sessions,
// so it should not be possible to be blocked by a key after that point.
ok(gotWaitingForKey == 1, "Expected number 1 wait, got: " + gotWaitingForKey);
ok(gotOnwaitingforkey == gotWaitingForKey, "Should have as many event listener calls as event handler calls, got: " + gotOnwaitingforkey);
v.closeSessions().then(() => manager.finished(token));
});

View File

@ -207,6 +207,10 @@ MediaEngineRemoteVideoSource::Stop(mozilla::SourceMediaStream* aSource,
{
MonitorAutoLock lock(mMonitor);
// Drop any cached image so we don't start with a stale image on next
// usage
mImage = nullptr;
size_t i = mSources.IndexOf(aSource);
if (i == mSources.NoIndex) {
// Already stopped - this is allowed
@ -227,9 +231,6 @@ MediaEngineRemoteVideoSource::Stop(mozilla::SourceMediaStream* aSource,
}
mState = kStopped;
// Drop any cached image so we don't start with a stale image on next
// usage
mImage = nullptr;
}
mozilla::camera::GetChildAndCall(

View File

@ -248,6 +248,7 @@ nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo,
aPluginInfo->fMimeDescriptionArray,
aPluginInfo->fExtensionArray,
aPluginInfo->fVariantCount);
InitSandboxLevel();
EnsureMembersAreUTF8();
FixupVersion();
}

View File

@ -120,8 +120,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
Services.ppmm.addMessageListener("Test:content-ready", function contentReadyListener() {
Services.ppmm.removeMessageListener("Test:content-ready", contentReadyListener);
sendAsyncMessage("Test:content-ready-forward");
Services.ppmm.removeDelayedProcessScript(pScript);
})
Services.ppmm.loadProcessScript("data:,new " + function () {
var pScript = "data:,new " + function () {
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
var observer = {
@ -133,7 +135,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=803225
}
};
os.addObserver(observer, "content-document-global-created", false);
}, false);
}
Services.ppmm.loadProcessScript(pScript, true);
var uri = ioService.newURI("mailto:foo@bar.com", null, null);
webHandler.launchWithURI(uri);

View File

@ -31,7 +31,7 @@ nsSVGElement::StringInfo SVGMPathElement::sStringInfo[2] =
{ &nsGkAtoms::href, kNameSpaceID_XLink, false }
};
// Cycle collection magic -- based on nsSVGUseElement
// Cycle collection magic -- based on SVGUseElement
NS_IMPL_CYCLE_COLLECTION_CLASS(SVGMPathElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGMPathElement,

View File

@ -18,7 +18,7 @@ interface FileSystemDirectoryEntry : FileSystemEntry {
optional ErrorCallback errorCallback);
// This method is not implemented. ErrorCallback will be called
// with NS_ERROR_DOM_NOT_SUPPORTED_ERR.
// with SecurityError
void removeRecursively(VoidCallback successCallback,
optional ErrorCallback errorCallback);
};

View File

@ -10,8 +10,7 @@ callback interface BlobCallback {
interface FileSystemFileEntry : FileSystemEntry {
// the successCallback should be a FileWriteCallback but this method is not
// implemented. ErrorCallback will be called with
// NS_ERROR_DOM_NOT_SUPPORTED_ERR.
// implemented. ErrorCallback will be called with SecurityError.
void createWriter (VoidCallback successCallback,
optional ErrorCallback errorCallback);

Some files were not shown because too many files have changed in this diff Show More