зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to fx-team
This commit is contained in:
Коммит
8a347d8479
|
@ -102,6 +102,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "SelfSupportBackend",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
|
||||
"resource:///modules/sessionstore/SessionStore.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUsageTelemetry",
|
||||
"resource:///modules/BrowserUsageTelemetry.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
|
||||
"resource:///modules/BrowserUITelemetry.jsm");
|
||||
|
||||
|
@ -781,6 +784,7 @@ BrowserGlue.prototype = {
|
|||
NewTabMessages.init();
|
||||
|
||||
SessionStore.init();
|
||||
BrowserUsageTelemetry.init();
|
||||
BrowserUITelemetry.init();
|
||||
ContentSearch.init();
|
||||
FormValidationHandler.init();
|
||||
|
@ -1174,6 +1178,7 @@ BrowserGlue.prototype = {
|
|||
Cu.reportError("Could not end startup crash tracking in quit-application-granted: " + e);
|
||||
}
|
||||
|
||||
BrowserUsageTelemetry.uninit();
|
||||
SelfSupportBackend.uninit();
|
||||
NewTabMessages.uninit();
|
||||
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["BrowserUsageTelemetry"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Observed topic names.
|
||||
const WINDOWS_RESTORED_TOPIC = "sessionstore-windows-restored";
|
||||
const TELEMETRY_SUBSESSIONSPLIT_TOPIC = "internal-telemetry-after-subsession-split";
|
||||
const DOMWINDOW_OPENED_TOPIC = "domwindowopened";
|
||||
const DOMWINDOW_CLOSED_TOPIC = "domwindowclosed";
|
||||
|
||||
// Probe names.
|
||||
const MAX_TAB_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_tab_count";
|
||||
const MAX_WINDOW_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_window_count";
|
||||
const TAB_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.tab_open_event_count";
|
||||
const WINDOW_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.window_open_event_count";
|
||||
|
||||
function getOpenTabsAndWinsCounts() {
|
||||
let tabCount = 0;
|
||||
let winCount = 0;
|
||||
|
||||
let browserEnum = Services.wm.getEnumerator("navigator:browser");
|
||||
while (browserEnum.hasMoreElements()) {
|
||||
let win = browserEnum.getNext();
|
||||
winCount++;
|
||||
tabCount += win.gBrowser.tabs.length;
|
||||
}
|
||||
|
||||
return { tabCount, winCount };
|
||||
}
|
||||
|
||||
let BrowserUsageTelemetry = {
|
||||
init() {
|
||||
Services.obs.addObserver(this, WINDOWS_RESTORED_TOPIC, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle subsession splits in the parent process.
|
||||
*/
|
||||
afterSubsessionSplit() {
|
||||
// Scalars just got cleared due to a subsession split. We need to set the maximum
|
||||
// concurrent tab and window counts so that they reflect the correct value for the
|
||||
// new subsession.
|
||||
const counts = getOpenTabsAndWinsCounts();
|
||||
Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, counts.tabCount);
|
||||
Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(this, DOMWINDOW_OPENED_TOPIC, false);
|
||||
Services.obs.removeObserver(this, DOMWINDOW_CLOSED_TOPIC, false);
|
||||
Services.obs.removeObserver(this, TELEMETRY_SUBSESSIONSPLIT_TOPIC, false);
|
||||
Services.obs.removeObserver(this, WINDOWS_RESTORED_TOPIC, false);
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
switch(topic) {
|
||||
case WINDOWS_RESTORED_TOPIC:
|
||||
this._setupAfterRestore();
|
||||
break;
|
||||
case DOMWINDOW_OPENED_TOPIC:
|
||||
this._onWindowOpen(subject);
|
||||
break;
|
||||
case DOMWINDOW_CLOSED_TOPIC:
|
||||
this._unregisterWindow(subject);
|
||||
break;
|
||||
case TELEMETRY_SUBSESSIONSPLIT_TOPIC:
|
||||
this.afterSubsessionSplit();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
switch(event.type) {
|
||||
case "TabOpen":
|
||||
this._onTabOpen();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This gets called shortly after the SessionStore has finished restoring
|
||||
* windows and tabs. It counts the open tabs and adds listeners to all the
|
||||
* windows.
|
||||
*/
|
||||
_setupAfterRestore() {
|
||||
// Make sure to catch new chrome windows and subsession splits.
|
||||
Services.obs.addObserver(this, DOMWINDOW_OPENED_TOPIC, false);
|
||||
Services.obs.addObserver(this, DOMWINDOW_CLOSED_TOPIC, false);
|
||||
Services.obs.addObserver(this, TELEMETRY_SUBSESSIONSPLIT_TOPIC, false);
|
||||
|
||||
// Attach the tabopen handlers to the existing Windows.
|
||||
let browserEnum = Services.wm.getEnumerator("navigator:browser");
|
||||
while (browserEnum.hasMoreElements()) {
|
||||
this._registerWindow(browserEnum.getNext());
|
||||
}
|
||||
|
||||
// Get the initial tab and windows max counts.
|
||||
const counts = getOpenTabsAndWinsCounts();
|
||||
Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, counts.tabCount);
|
||||
Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds listeners to a single chrome window.
|
||||
*/
|
||||
_registerWindow(win) {
|
||||
win.addEventListener("TabOpen", this, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes listeners from a single chrome window.
|
||||
*/
|
||||
_unregisterWindow(win) {
|
||||
// Ignore non-browser windows.
|
||||
if (!(win instanceof Ci.nsIDOMWindow) ||
|
||||
win.document.documentElement.getAttribute("windowtype") != "navigator:browser") {
|
||||
return;
|
||||
}
|
||||
|
||||
win.removeEventListener("TabOpen", this, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the tab counts.
|
||||
* @param {Number} [newTabCount=0] The count of the opened tabs across all windows. This
|
||||
* is computed manually if not provided.
|
||||
*/
|
||||
_onTabOpen(tabCount = 0) {
|
||||
// Use the provided tab count if available. Otherwise, go on and compute it.
|
||||
tabCount = tabCount || getOpenTabsAndWinsCounts().tabCount;
|
||||
// Update the "tab opened" count and its maximum.
|
||||
Services.telemetry.scalarAdd(TAB_OPEN_EVENT_COUNT_SCALAR_NAME, 1);
|
||||
Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, tabCount);
|
||||
},
|
||||
|
||||
/**
|
||||
* Tracks the window count and registers the listeners for the tab count.
|
||||
* @param{Object} win The window object.
|
||||
*/
|
||||
_onWindowOpen(win) {
|
||||
// Make sure to have a |nsIDOMWindow|.
|
||||
if (!(win instanceof Ci.nsIDOMWindow)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let onLoad = () => {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
|
||||
// Ignore non browser windows.
|
||||
if (win.document.documentElement.getAttribute("windowtype") != "navigator:browser") {
|
||||
return;
|
||||
}
|
||||
|
||||
this._registerWindow(win);
|
||||
// Track the window open event and check the maximum.
|
||||
const counts = getOpenTabsAndWinsCounts();
|
||||
Services.telemetry.scalarAdd(WINDOW_OPEN_EVENT_COUNT_SCALAR_NAME, 1);
|
||||
Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount);
|
||||
|
||||
// We won't receive the "TabOpen" event for the first tab within a new window.
|
||||
// Account for that.
|
||||
this._onTabOpen(counts.tabCount);
|
||||
};
|
||||
win.addEventListener("load", onLoad, false);
|
||||
},
|
||||
};
|
|
@ -14,6 +14,7 @@ EXTRA_JS_MODULES += [
|
|||
'AboutHome.jsm',
|
||||
'AboutNewTab.jsm',
|
||||
'BrowserUITelemetry.jsm',
|
||||
'BrowserUsageTelemetry.jsm',
|
||||
'CaptivePortalWatcher.jsm',
|
||||
'CastingApps.jsm',
|
||||
'Chat.jsm',
|
||||
|
|
|
@ -23,3 +23,4 @@ support-files =
|
|||
../../components/uitour/UITour-lib.js
|
||||
[browser_taskbar_preview.js]
|
||||
skip-if = os != "win"
|
||||
[browser_UsageTelemetry.js]
|
||||
|
|
|
@ -20,6 +20,12 @@ const TEST_WAIT_RETRIES = 60;
|
|||
const TEST_PAGE_URL = getRootDirectory(gTestPath) + "uitour.html";
|
||||
const TEST_PAGE_URL_HTTPS = TEST_PAGE_URL.replace("chrome://mochitests/content/", "https://example.com/");
|
||||
|
||||
function sendSessionRestoredNotification() {
|
||||
let selfSupportBackendImpl =
|
||||
Cu.import("resource:///modules/SelfSupportBackend.jsm", {}).SelfSupportBackendInternal;
|
||||
selfSupportBackendImpl.observe(null, "sessionstore-windows-restored", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a browser, with an IFRAME as parent, who has aURL as the source attribute.
|
||||
*
|
||||
|
@ -128,7 +134,7 @@ add_task(function* test_selfSupport() {
|
|||
|
||||
// SelfSupportBackend waits for "sessionstore-windows-restored" to start loading. Send it.
|
||||
info("Sending sessionstore-windows-restored");
|
||||
Services.obs.notifyObservers(null, "sessionstore-windows-restored", null);
|
||||
sendSessionRestoredNotification();
|
||||
|
||||
// Wait for the SelfSupport page to load.
|
||||
info("Waiting for the SelfSupport local page to load.");
|
||||
|
@ -196,7 +202,7 @@ add_task(function* test_selfSupport_noHTTPS() {
|
|||
|
||||
// SelfSupportBackend waits for "sessionstore-windows-restored" to start loading. Send it.
|
||||
info("Sending sessionstore-windows-restored");
|
||||
Services.obs.notifyObservers(null, "sessionstore-windows-restored", null);
|
||||
sendSessionRestoredNotification();
|
||||
|
||||
// Find the SelfSupport browser. We don't expect to find it since we are not using https.
|
||||
let selfSupportBrowser = findSelfSupportBrowser(TEST_PAGE_URL);
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
"use strict";
|
||||
|
||||
const MAX_CONCURRENT_TABS = "browser.engagement.max_concurrent_tab_count";
|
||||
const TAB_EVENT_COUNT = "browser.engagement.tab_open_event_count";
|
||||
const MAX_CONCURRENT_WINDOWS = "browser.engagement.max_concurrent_window_count";
|
||||
const WINDOW_OPEN_COUNT = "browser.engagement.window_open_event_count";
|
||||
|
||||
const TELEMETRY_SUBSESSION_TOPIC = "internal-telemetry-after-subsession-split";
|
||||
|
||||
/**
|
||||
* An helper that checks the value of a scalar if it's expected to be > 0,
|
||||
* otherwise makes sure that the scalar it's not reported.
|
||||
*/
|
||||
let checkScalar = (scalars, scalarName, value, msg) => {
|
||||
if (value > 0) {
|
||||
is(scalars[scalarName], value, msg);
|
||||
return;
|
||||
}
|
||||
ok(!(scalarName in scalars), scalarName + " must not be reported.");
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a snapshot of the scalars and check them against the provided values.
|
||||
*/
|
||||
let checkScalars = (maxTabs, tabOpenCount, maxWindows, windowsOpenCount) => {
|
||||
const scalars =
|
||||
Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
|
||||
|
||||
// Check the expected values. Scalars that are never set must not be reported.
|
||||
checkScalar(scalars, MAX_CONCURRENT_TABS, maxTabs,
|
||||
"The maximum tab count must match the expected value.");
|
||||
checkScalar(scalars, TAB_EVENT_COUNT, tabOpenCount,
|
||||
"The number of open tab event count must match the expected value.");
|
||||
checkScalar(scalars, MAX_CONCURRENT_WINDOWS, maxWindows,
|
||||
"The maximum window count must match the expected value.");
|
||||
checkScalar(scalars, WINDOW_OPEN_COUNT, windowsOpenCount,
|
||||
"The number of window open event count must match the expected value.");
|
||||
};
|
||||
|
||||
add_task(function* test_tabsAndWindows() {
|
||||
// Let's reset the counts.
|
||||
Services.telemetry.clearScalars();
|
||||
|
||||
let openedTabs = [];
|
||||
let expectedTabOpenCount = 0;
|
||||
let expectedWinOpenCount = 0;
|
||||
let expectedMaxTabs = 0;
|
||||
let expectedMaxWins = 0;
|
||||
|
||||
// Add a new tab and check that the count is right.
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
|
||||
expectedTabOpenCount = 1;
|
||||
expectedMaxTabs = 2;
|
||||
checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount);
|
||||
|
||||
// Add two new tabs in the same window.
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
|
||||
expectedTabOpenCount += 2;
|
||||
expectedMaxTabs += 2;
|
||||
checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount);
|
||||
|
||||
// Add a new window and then some tabs in it. An empty new windows counts as a tab.
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"));
|
||||
// The new window started with a new tab, so account for it.
|
||||
expectedTabOpenCount += 4;
|
||||
expectedWinOpenCount += 1;
|
||||
expectedMaxWins = 2;
|
||||
expectedMaxTabs += 4;
|
||||
|
||||
// Remove a tab from the first window, the max shouldn't change.
|
||||
yield BrowserTestUtils.removeTab(openedTabs.pop());
|
||||
checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount);
|
||||
|
||||
// Remove all the extra windows and tabs.
|
||||
for (let tab of openedTabs) {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
|
||||
// Make sure all the scalars still have the expected values.
|
||||
checkScalars(expectedMaxTabs, expectedTabOpenCount, expectedMaxWins, expectedWinOpenCount);
|
||||
});
|
||||
|
||||
add_task(function* test_subsessionSplit() {
|
||||
// Let's reset the counts.
|
||||
Services.telemetry.clearScalars();
|
||||
|
||||
// Add a new window (that will have 4 tabs).
|
||||
let win = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
let openedTabs = [];
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
openedTabs.push(yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, "about:blank"));
|
||||
|
||||
// Check that the scalars have the right values.
|
||||
checkScalars(5 /*maxTabs*/, 4 /*tabOpen*/, 2 /*maxWins*/, 1 /*winOpen*/);
|
||||
|
||||
// Remove a tab.
|
||||
yield BrowserTestUtils.removeTab(openedTabs.pop());
|
||||
|
||||
// Simulate a subsession split by clearing the scalars (via |snapshotScalars|) and
|
||||
// notifying the subsession split topic.
|
||||
Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
|
||||
true /* clearScalars*/);
|
||||
Services.obs.notifyObservers(null, TELEMETRY_SUBSESSION_TOPIC, "");
|
||||
|
||||
// After a subsession split, only the MAX_CONCURRENT_* scalars must be available
|
||||
// and have the correct value. No tabs or windows were opened so other scalars
|
||||
// must not be reported.
|
||||
checkScalars(4 /*maxTabs*/, 0 /*tabOpen*/, 2 /*maxWins*/, 0 /*winOpen*/);
|
||||
|
||||
// Remove all the extra windows and tabs.
|
||||
for (let tab of openedTabs) {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
add_task(function* test_privateMode() {
|
||||
// Let's reset the counts.
|
||||
Services.telemetry.clearScalars();
|
||||
|
||||
// Open a private window and load a website in it.
|
||||
let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private: true});
|
||||
yield BrowserTestUtils.loadURI(privateWin.gBrowser.selectedBrowser, "http://example.com/");
|
||||
yield BrowserTestUtils.browserLoaded(privateWin.gBrowser.selectedBrowser);
|
||||
|
||||
// Check that tab and window count is recorded.
|
||||
const scalars =
|
||||
Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN);
|
||||
|
||||
is(scalars[TAB_EVENT_COUNT], 1, "The number of open tab event count must match the expected value.");
|
||||
is(scalars[MAX_CONCURRENT_TABS], 2, "The maximum tab count must match the expected value.");
|
||||
is(scalars[WINDOW_OPEN_COUNT], 1, "The number of window open event count must match the expected value.");
|
||||
is(scalars[MAX_CONCURRENT_WINDOWS], 2, "The maximum window count must match the expected value.");
|
||||
|
||||
// Clean up.
|
||||
yield BrowserTestUtils.closeWindow(privateWin);
|
||||
});
|
|
@ -72,6 +72,7 @@ support-files =
|
|||
[browser_styleeditor_init.js]
|
||||
[browser_styleeditor_inline_friendly_names.js]
|
||||
[browser_styleeditor_loading.js]
|
||||
[browser_styleeditor_loading_with_containers.js]
|
||||
[browser_styleeditor_media_sidebar.js]
|
||||
[browser_styleeditor_media_sidebar_links.js]
|
||||
skip-if = e10s && debug # Bug 1252201 - Docshell leak on debug e10s
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that the stylesheets can be loaded correctly with containers
|
||||
// (bug 1282660).
|
||||
|
||||
const TESTCASE_URI = TEST_BASE_HTTP + "simple.html";
|
||||
const EXPECTED_SHEETS = [
|
||||
{
|
||||
sheetIndex: 0,
|
||||
name: /^simple.css$/,
|
||||
rules: 1,
|
||||
active: true
|
||||
}, {
|
||||
sheetIndex: 1,
|
||||
name: /^<.*>$/,
|
||||
rules: 3,
|
||||
active: false
|
||||
}
|
||||
];
|
||||
|
||||
add_task(function* () {
|
||||
// Using the personal container.
|
||||
let userContextId = 1;
|
||||
let { tab } = yield* openTabInUserContext(TESTCASE_URI, userContextId);
|
||||
let { ui } = yield openStyleEditor(tab);
|
||||
|
||||
is(ui.editors.length, 2, "The UI contains two style sheets.");
|
||||
checkSheet(ui.editors[0], EXPECTED_SHEETS[0]);
|
||||
checkSheet(ui.editors[1], EXPECTED_SHEETS[1]);
|
||||
});
|
||||
|
||||
function* openTabInUserContext(uri, userContextId) {
|
||||
// Open the tab in the correct userContextId.
|
||||
let tab = gBrowser.addTab(uri, {userContextId});
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerDocument.defaultView.focus();
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
}
|
||||
|
||||
function checkSheet(editor, expected) {
|
||||
is(editor.styleSheet.styleSheetIndex, expected.sheetIndex,
|
||||
"Style sheet has correct index.");
|
||||
|
||||
let summary = editor.summary;
|
||||
let name = summary.querySelector(".stylesheet-name > label")
|
||||
.getAttribute("value");
|
||||
ok(expected.name.test(name), "The name '" + name + "' is correct.");
|
||||
|
||||
let ruleCount = summary.querySelector(".stylesheet-rule-count").textContent;
|
||||
is(parseInt(ruleCount, 10), expected.rules, "the rule count is correct");
|
||||
|
||||
is(summary.classList.contains("splitview-active"), expected.active,
|
||||
"The active status for this sheet is correct.");
|
||||
}
|
|
@ -19,6 +19,7 @@ const { ActorClassWithSpec } = require("devtools/shared/protocol");
|
|||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const { assert, dumpn, update, fetch } = DevToolsUtils;
|
||||
const promise = require("promise");
|
||||
const PromiseDebugging = require("PromiseDebugging");
|
||||
const xpcInspector = require("xpcInspector");
|
||||
const ScriptStore = require("./utils/ScriptStore");
|
||||
const { DevToolsWorker } = require("devtools/shared/worker/worker");
|
||||
|
|
|
@ -452,10 +452,19 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
|
|||
let options = {
|
||||
loadFromCache: true,
|
||||
policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
|
||||
window: this.window,
|
||||
charset: this._getCSSCharset()
|
||||
};
|
||||
|
||||
// Bug 1282660 - We use the system principal to load the default internal
|
||||
// stylesheets instead of the content principal since such stylesheets
|
||||
// require system principal to load. At meanwhile, we strip the loadGroup
|
||||
// for preventing the assertion of the userContextId mismatching.
|
||||
// The default internal stylesheets load from the 'resource:' URL.
|
||||
if (!/^resource:\/\//.test(this.href)) {
|
||||
options.window = this.window;
|
||||
options.principal = this.document.nodePrincipal;
|
||||
}
|
||||
|
||||
return fetch(this.href, options).then(({ content }) => {
|
||||
this.text = content;
|
||||
return content;
|
||||
|
|
|
@ -317,6 +317,12 @@ this.WorkerDebuggerLoader = WorkerDebuggerLoader;
|
|||
// does not provide alternative definitions for them. Consequently, they are
|
||||
// stubbed out both on the main thread and worker threads.
|
||||
|
||||
var PromiseDebugging = {
|
||||
getState: function () {
|
||||
throw new Error("PromiseDebugging is not available in workers!");
|
||||
}
|
||||
};
|
||||
|
||||
var chrome = {
|
||||
CC: undefined,
|
||||
Cc: undefined,
|
||||
|
@ -490,6 +496,7 @@ this.worker = new WorkerDebuggerLoader({
|
|||
loadSubScript: loadSubScript,
|
||||
modules: {
|
||||
"Debugger": Debugger,
|
||||
"PromiseDebugging": PromiseDebugging,
|
||||
"Services": Object.create(null),
|
||||
"chrome": chrome,
|
||||
"xpcInspector": xpcInspector
|
||||
|
|
|
@ -14236,7 +14236,10 @@ nsDocShell::SetOriginAttributesBeforeLoading(JS::Handle<JS::Value> aOriginAttrib
|
|||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(&aOriginAttributes.toObject());
|
||||
if (!jsapi.Init(&aOriginAttributes.toObject())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
if (NS_WARN_IF(!cx)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -50,11 +50,7 @@ if (Services.prefs.getBoolPref("javascript.options.asyncstack")) {
|
|||
ok(frame.asyncParent !== null, "Parent frame has async parent");
|
||||
is(frame.asyncParent.asyncCause, "promise callback",
|
||||
"Async parent has correct cause");
|
||||
let asyncFrame = frame.asyncParent;
|
||||
// Skip over self-hosted parts of our Promise implementation.
|
||||
while (asyncFrame.source === 'self-hosted')
|
||||
asyncFrame = asyncFrame.parent;
|
||||
is(asyncFrame.functionDisplayName, "do_promise",
|
||||
is(frame.asyncParent.functionDisplayName, "do_promise",
|
||||
"Async parent has correct function name");
|
||||
}
|
||||
}, {
|
||||
|
@ -75,11 +71,7 @@ if (Services.prefs.getBoolPref("javascript.options.asyncstack")) {
|
|||
ok(frame.asyncParent !== null, "Parent frame has async parent");
|
||||
is(frame.asyncParent.asyncCause, "promise callback",
|
||||
"Async parent has correct cause");
|
||||
let asyncFrame = frame.asyncParent;
|
||||
// Skip over self-hosted parts of our Promise implementation.
|
||||
while (asyncFrame.source === 'self-hosted')
|
||||
asyncFrame = asyncFrame.parent;
|
||||
is(asyncFrame.functionDisplayName, "do_promise_script",
|
||||
is(frame.asyncParent.functionDisplayName, "do_promise_script",
|
||||
"Async parent has correct function name");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -91,24 +91,12 @@ if (Services.prefs.getBoolPref("javascript.options.asyncstack")) {
|
|||
check: function(markers) {
|
||||
markers = markers.filter(m => m.name == "ConsoleTime");
|
||||
ok(markers.length > 0, "Promise marker includes stack");
|
||||
ok(markers[0].stack.functionDisplayName == "testConsoleTime",
|
||||
"testConsoleTime is on the stack");
|
||||
let frame = markers[0].endStack;
|
||||
ok(frame.functionDisplayName == "testConsoleTimeEnd",
|
||||
"testConsoleTimeEnd is on the stack");
|
||||
|
||||
frame = frame.parent;
|
||||
ok(frame.functionDisplayName == "makePromise/<",
|
||||
"makePromise/< is on the stack");
|
||||
let asyncFrame = frame.asyncParent;
|
||||
ok(asyncFrame !== null, "Frame has async parent");
|
||||
is(asyncFrame.asyncCause, "promise callback",
|
||||
let frame = markers[0].endStack;
|
||||
ok(frame.parent.asyncParent !== null, "Parent frame has async parent");
|
||||
is(frame.parent.asyncParent.asyncCause, "promise callback",
|
||||
"Async parent has correct cause");
|
||||
// Skip over self-hosted parts of our Promise implementation.
|
||||
while (asyncFrame.source === 'self-hosted') {
|
||||
asyncFrame = asyncFrame.parent;
|
||||
}
|
||||
is(asyncFrame.functionDisplayName, "makePromise",
|
||||
is(frame.parent.asyncParent.functionDisplayName, "makePromise",
|
||||
"Async parent has correct function name");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1531,9 +1531,9 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
// Unset this flag since we now really are in a document.
|
||||
UnsetFlags(NODE_FORCE_XBL_BINDINGS |
|
||||
// And clear the lazy frame construction bits.
|
||||
NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
|
||||
// And the restyle bits
|
||||
ELEMENT_ALL_RESTYLE_FLAGS);
|
||||
NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
|
||||
// And the restyle bits
|
||||
UnsetRestyleFlagsIfGecko();
|
||||
} else if (IsInShadowTree()) {
|
||||
// We're not in a document, but we did get inserted into a shadow tree.
|
||||
// Since we won't have any restyle data in the document's restyle trackers,
|
||||
|
@ -1542,8 +1542,8 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
// Also clear all the other flags that are cleared above when we do get
|
||||
// inserted into a document.
|
||||
UnsetFlags(NODE_FORCE_XBL_BINDINGS |
|
||||
NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES |
|
||||
ELEMENT_ALL_RESTYLE_FLAGS);
|
||||
NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
|
||||
UnsetRestyleFlagsIfGecko();
|
||||
} else {
|
||||
// If we're not in the doc and not in a shadow tree,
|
||||
// update our subtree pointer.
|
||||
|
|
|
@ -225,11 +225,11 @@ public:
|
|||
// If aGlobalObject represents a web-visible global, errors reported by this
|
||||
// AutoJSAPI as it comes off the stack will fire the relevant error events and
|
||||
// show up in the corresponding web console.
|
||||
bool Init(nsIGlobalObject* aGlobalObject);
|
||||
MOZ_MUST_USE bool Init(nsIGlobalObject* aGlobalObject);
|
||||
|
||||
// This is a helper that grabs the native global associated with aObject and
|
||||
// invokes the above Init() with that.
|
||||
bool Init(JSObject* aObject);
|
||||
MOZ_MUST_USE bool Init(JSObject* aObject);
|
||||
|
||||
// Unsurprisingly, this uses aCx and enters the compartment of aGlobalObject.
|
||||
// If aGlobalObject or its associated JS global are null then it returns
|
||||
|
@ -239,15 +239,15 @@ public:
|
|||
// If aGlobalObject represents a web-visible global, errors reported by this
|
||||
// AutoJSAPI as it comes off the stack will fire the relevant error events and
|
||||
// show up in the corresponding web console.
|
||||
bool Init(nsIGlobalObject* aGlobalObject, JSContext* aCx);
|
||||
MOZ_MUST_USE bool Init(nsIGlobalObject* aGlobalObject, JSContext* aCx);
|
||||
|
||||
// Convenience functions to take an nsPIDOMWindow* or nsGlobalWindow*,
|
||||
// when it is more easily available than an nsIGlobalObject.
|
||||
bool Init(nsPIDOMWindowInner* aWindow);
|
||||
bool Init(nsPIDOMWindowInner* aWindow, JSContext* aCx);
|
||||
MOZ_MUST_USE bool Init(nsPIDOMWindowInner* aWindow);
|
||||
MOZ_MUST_USE bool Init(nsPIDOMWindowInner* aWindow, JSContext* aCx);
|
||||
|
||||
bool Init(nsGlobalWindow* aWindow);
|
||||
bool Init(nsGlobalWindow* aWindow, JSContext* aCx);
|
||||
MOZ_MUST_USE bool Init(nsGlobalWindow* aWindow);
|
||||
MOZ_MUST_USE bool Init(nsGlobalWindow* aWindow, JSContext* aCx);
|
||||
|
||||
JSContext* cx() const {
|
||||
MOZ_ASSERT(mCx, "Must call Init before using an AutoJSAPI");
|
||||
|
@ -273,7 +273,7 @@ public:
|
|||
//
|
||||
// Note that this fails if and only if we OOM while wrapping the exception
|
||||
// into the current compartment.
|
||||
bool StealException(JS::MutableHandle<JS::Value> aVal);
|
||||
MOZ_MUST_USE bool StealException(JS::MutableHandle<JS::Value> aVal);
|
||||
|
||||
// Peek the current exception from the JS engine, without stealing it.
|
||||
// Callers must ensure that HasException() is true, and that cx() is in a
|
||||
|
@ -281,7 +281,7 @@ public:
|
|||
//
|
||||
// Note that this fails if and only if we OOM while wrapping the exception
|
||||
// into the current compartment.
|
||||
bool PeekException(JS::MutableHandle<JS::Value> aVal);
|
||||
MOZ_MUST_USE bool PeekException(JS::MutableHandle<JS::Value> aVal);
|
||||
|
||||
void ClearException() {
|
||||
MOZ_ASSERT(IsStackTop());
|
||||
|
|
|
@ -327,7 +327,9 @@ nsresult
|
|||
nsDOMClassInfo::DefineStaticJSVals()
|
||||
{
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init(xpc::UnprivilegedJunkScope());
|
||||
if (!jsapi.Init(xpc::UnprivilegedJunkScope())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
#define SET_JSID_TO_STRING(_id, _cx, _str) \
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
#include "nsHostObjectProtocolHandler.h"
|
||||
|
||||
#include "DOMMediaStream.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/dom/MediaSource.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
|
@ -38,9 +41,79 @@ struct DataInfo
|
|||
|
||||
static nsClassHashtable<nsCStringHashKey, DataInfo>* gDataTable;
|
||||
|
||||
static DataInfo*
|
||||
GetDataInfo(const nsACString& aUri)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataInfo* res;
|
||||
|
||||
// Let's remove any fragment and query from this URI.
|
||||
int32_t hasFragmentPos = aUri.FindChar('#');
|
||||
int32_t hasQueryPos = aUri.FindChar('?');
|
||||
|
||||
int32_t pos = -1;
|
||||
if (hasFragmentPos >= 0 && hasQueryPos >= 0) {
|
||||
pos = std::min(hasFragmentPos, hasQueryPos);
|
||||
} else if (hasFragmentPos >= 0) {
|
||||
pos = hasFragmentPos;
|
||||
} else {
|
||||
pos = hasQueryPos;
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
gDataTable->Get(aUri, &res);
|
||||
} else {
|
||||
gDataTable->Get(StringHead(aUri, pos), &res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Memory reporting for the hash table.
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
BroadcastBlobURLRegistration(const nsACString& aURI,
|
||||
BlobImpl* aBlobImpl,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aBlobImpl);
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
ContentParent::BroadcastBlobURLRegistration(aURI, aBlobImpl,
|
||||
aPrincipal);
|
||||
return;
|
||||
}
|
||||
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
BlobChild* actor = cc->GetOrCreateActorForBlobImpl(aBlobImpl);
|
||||
if (NS_WARN_IF(!actor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NS_WARN_IF(!cc->SendStoreAndBroadcastBlobURLRegistration(nsCString(aURI), actor,
|
||||
IPC::Principal(aPrincipal)));
|
||||
}
|
||||
|
||||
void
|
||||
BroadcastBlobURLUnregistration(const nsACString& aURI, DataInfo* aInfo)
|
||||
{
|
||||
MOZ_ASSERT(aInfo);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
ContentParent::BroadcastBlobURLUnregistration(aURI);
|
||||
return;
|
||||
}
|
||||
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration(nsCString(aURI)));
|
||||
}
|
||||
|
||||
class HostObjectURLsReporter final : public nsIMemoryReporter
|
||||
{
|
||||
~HostObjectURLsReporter() {}
|
||||
|
@ -321,12 +394,14 @@ nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aScheme,
|
|||
nsACString& aUri)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<BlobImpl> blobImpl(do_QueryInterface(aObject));
|
||||
nsCOMPtr<MediaSource> mediaSource(do_QueryInterface(aObject));
|
||||
nsCOMPtr<DOMMediaStream> mediaStream(do_QueryInterface(aObject));
|
||||
{
|
||||
nsCOMPtr<BlobImpl> blobImpl(do_QueryInterface(aObject));
|
||||
nsCOMPtr<MediaSource> mediaSource(do_QueryInterface(aObject));
|
||||
nsCOMPtr<DOMMediaStream> mediaStream(do_QueryInterface(aObject));
|
||||
|
||||
// We support only these types.
|
||||
MOZ_ASSERT(blobImpl || mediaSource || mediaStream);
|
||||
// We support only these types.
|
||||
MOZ_ASSERT(blobImpl || mediaSource || mediaStream);
|
||||
}
|
||||
#endif
|
||||
|
||||
Init();
|
||||
|
@ -334,6 +409,22 @@ nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aScheme,
|
|||
nsresult rv = GenerateURIString(aScheme, aPrincipal, aUri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = AddDataEntry(aUri, aObject, aPrincipal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(aObject);
|
||||
if (blobImpl) {
|
||||
BroadcastBlobURLRegistration(aUri, blobImpl, aPrincipal);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aURI,
|
||||
nsISupports* aObject,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
gDataTable = new nsClassHashtable<nsCStringHashKey, DataInfo>;
|
||||
}
|
||||
|
@ -344,17 +435,62 @@ nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aScheme,
|
|||
info->mPrincipal = aPrincipal;
|
||||
mozilla::BlobURLsReporter::GetJSStackForBlob(info);
|
||||
|
||||
gDataTable->Put(aUri, info);
|
||||
gDataTable->Put(aURI, info);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsHostObjectProtocolHandler::GetAllBlobURLEntries(nsTArray<BlobURLRegistrationData>& aRegistrations,
|
||||
ContentParent* aCP)
|
||||
{
|
||||
MOZ_ASSERT(aCP);
|
||||
|
||||
if (!gDataTable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto iter = gDataTable->ConstIter(); !iter.Done(); iter.Next()) {
|
||||
DataInfo* info = iter.UserData();
|
||||
MOZ_ASSERT(info);
|
||||
|
||||
nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(info->mObject);
|
||||
if (!blobImpl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PBlobParent* blobParent = aCP->GetOrCreateActorForBlobImpl(blobImpl);
|
||||
if (!blobParent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aRegistrations.AppendElement(
|
||||
BlobURLRegistrationData(nsCString(iter.Key()), blobParent, nullptr,
|
||||
IPC::Principal(info->mPrincipal)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri)
|
||||
nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri,
|
||||
bool aBroadcastToOtherProcesses)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataInfo* info = GetDataInfo(aUri);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aBroadcastToOtherProcesses) {
|
||||
nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(info->mObject);
|
||||
if (blobImpl) {
|
||||
BroadcastBlobURLUnregistration(aUri, info);
|
||||
}
|
||||
}
|
||||
|
||||
gDataTable->Remove(aUri);
|
||||
if (gDataTable->Count() == 0) {
|
||||
delete gDataTable;
|
||||
|
@ -362,6 +498,20 @@ nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHostObjectProtocolHandler::RemoveDataEntries()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
|
||||
if (!gDataTable) {
|
||||
return;
|
||||
}
|
||||
|
||||
gDataTable->Clear();
|
||||
delete gDataTable;
|
||||
gDataTable = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHostObjectProtocolHandler::GenerateURIString(const nsACString &aScheme,
|
||||
nsIPrincipal* aPrincipal,
|
||||
|
@ -398,37 +548,6 @@ nsHostObjectProtocolHandler::GenerateURIString(const nsACString &aScheme,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static DataInfo*
|
||||
GetDataInfo(const nsACString& aUri)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataInfo* res;
|
||||
|
||||
// Let's remove any fragment and query from this URI.
|
||||
int32_t hasFragmentPos = aUri.FindChar('#');
|
||||
int32_t hasQueryPos = aUri.FindChar('?');
|
||||
|
||||
int32_t pos = -1;
|
||||
if (hasFragmentPos >= 0 && hasQueryPos >= 0) {
|
||||
pos = std::min(hasFragmentPos, hasQueryPos);
|
||||
} else if (hasFragmentPos >= 0) {
|
||||
pos = hasFragmentPos;
|
||||
} else {
|
||||
pos = hasQueryPos;
|
||||
}
|
||||
|
||||
if (pos < 0) {
|
||||
gDataTable->Get(aUri, &res);
|
||||
} else {
|
||||
gDataTable->Get(StringHead(aUri, pos), &res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
nsHostObjectProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri)
|
||||
{
|
||||
|
@ -509,8 +628,13 @@ nsHostObjectProtocolHandler::NewURI(const nsACString& aSpec,
|
|||
|
||||
DataInfo* info = GetDataInfo(aSpec);
|
||||
|
||||
RefPtr<nsHostObjectURI> uri =
|
||||
new nsHostObjectURI(info ? info->mPrincipal.get() : nullptr);
|
||||
RefPtr<nsHostObjectURI> uri;
|
||||
if (info) {
|
||||
nsCOMPtr<BlobImpl> blob = do_QueryInterface(info->mObject);
|
||||
uri = new nsHostObjectURI(info->mPrincipal, blob);
|
||||
} else {
|
||||
uri = new nsHostObjectURI(nullptr, nullptr);
|
||||
}
|
||||
|
||||
rv = uri->SetSpec(aSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -528,22 +652,26 @@ nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri,
|
|||
{
|
||||
*result = nullptr;
|
||||
|
||||
nsCOMPtr<nsIURIWithBlobImpl> uriBlobImpl = do_QueryInterface(uri);
|
||||
if (!uriBlobImpl) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> tmp;
|
||||
MOZ_ALWAYS_SUCCEEDS(uriBlobImpl->GetBlobImpl(getter_AddRefs(tmp)));
|
||||
nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(tmp);
|
||||
if (!blobImpl) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCString spec;
|
||||
uri->GetSpec(spec);
|
||||
|
||||
DataInfo* info = GetDataInfo(spec);
|
||||
|
||||
if (!info) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
nsCOMPtr<BlobImpl> blob = do_QueryInterface(info->mObject);
|
||||
if (!blob) {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Info can be null, in case this blob URL has been revoked already.
|
||||
if (info) {
|
||||
nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(uri);
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
uriPrinc->GetPrincipal(getter_AddRefs(principal));
|
||||
|
@ -553,13 +681,13 @@ nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri,
|
|||
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
blob->GetInternalStream(getter_AddRefs(stream), rv);
|
||||
blobImpl->GetInternalStream(getter_AddRefs(stream), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
nsAutoString contentType;
|
||||
blob->GetType(contentType);
|
||||
blobImpl->GetType(contentType);
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
|
||||
|
@ -572,13 +700,13 @@ nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri,
|
|||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
if (blob->IsFile()) {
|
||||
if (blobImpl->IsFile()) {
|
||||
nsString filename;
|
||||
blob->GetName(filename);
|
||||
blobImpl->GetName(filename);
|
||||
channel->SetContentDispositionFilename(filename);
|
||||
}
|
||||
|
||||
uint64_t size = blob->GetSize(rv);
|
||||
uint64_t size = blobImpl->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
@ -795,3 +923,4 @@ static const mozilla::Module kHostObjectProtocolHandlerModule = {
|
|||
};
|
||||
|
||||
NSMODULE_DEFN(HostObjectProtocolHandler) = &kHostObjectProtocolHandlerModule;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define BLOBURI_SCHEME "blob"
|
||||
#define MEDIASTREAMURI_SCHEME "mediastream"
|
||||
|
@ -25,6 +26,8 @@ namespace mozilla {
|
|||
class DOMMediaStream;
|
||||
namespace dom {
|
||||
class BlobImpl;
|
||||
class BlobURLRegistrationData;
|
||||
class ContentParent;
|
||||
class MediaSource;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -55,10 +58,23 @@ public:
|
|||
nsISupports* aObject,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsACString& aUri);
|
||||
static void RemoveDataEntry(const nsACString& aUri);
|
||||
static void RemoveDataEntry(const nsACString& aUri,
|
||||
bool aBroadcastToOTherProcesses = true);
|
||||
|
||||
// This is for IPC only.
|
||||
static void RemoveDataEntries();
|
||||
|
||||
static nsIPrincipal* GetDataEntryPrincipal(const nsACString& aUri);
|
||||
static void Traverse(const nsACString& aUri, nsCycleCollectionTraversalCallback& aCallback);
|
||||
|
||||
// IPC or internal use only
|
||||
static nsresult AddDataEntry(const nsACString& aURI,
|
||||
nsISupports* aObject,
|
||||
nsIPrincipal* aPrincipal);
|
||||
static bool
|
||||
GetAllBlobURLEntries(nsTArray<mozilla::dom::BlobURLRegistrationData>& aRegistrations,
|
||||
mozilla::dom::ContentParent* aCP);
|
||||
|
||||
protected:
|
||||
virtual ~nsHostObjectProtocolHandler() {}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ NS_IMPL_ADDREF_INHERITED(nsHostObjectURI, mozilla::net::nsSimpleURI)
|
|||
NS_IMPL_RELEASE_INHERITED(nsHostObjectURI, mozilla::net::nsSimpleURI)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsHostObjectURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURIWithBlobImpl)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal)
|
||||
if (aIID.Equals(kHOSTOBJECTURICID))
|
||||
foundInterface = static_cast<nsIURI*>(this);
|
||||
|
@ -34,6 +35,16 @@ NS_INTERFACE_MAP_BEGIN(nsHostObjectURI)
|
|||
else
|
||||
NS_INTERFACE_MAP_END_INHERITING(mozilla::net::nsSimpleURI)
|
||||
|
||||
// nsIURIWithBlobImpl methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHostObjectURI::GetBlobImpl(nsISupports** aBlobImpl)
|
||||
{
|
||||
RefPtr<BlobImpl> blobImpl(mBlobImpl);
|
||||
blobImpl.forget(aBlobImpl);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIURIWithPrincipal methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -126,6 +137,10 @@ nsHostObjectURI::Deserialize(const mozilla::ipc::URIParams& aParams)
|
|||
if (!mozilla::net::nsSimpleURI::Deserialize(hostParams.simpleParams())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXXbaku: when we will have shared blobURL maps, we can populate mBlobImpl
|
||||
// here asll well.
|
||||
|
||||
if (hostParams.principal().type() == OptionalPrincipalInfo::Tvoid_t) {
|
||||
return true;
|
||||
}
|
||||
|
@ -162,6 +177,7 @@ nsHostObjectURI::CloneInternal(mozilla::net::nsSimpleURI::RefHandlingEnum aRefHa
|
|||
nsHostObjectURI* u = static_cast<nsHostObjectURI*>(simpleClone.get());
|
||||
|
||||
u->mPrincipal = mPrincipal;
|
||||
u->mBlobImpl = mBlobImpl;
|
||||
|
||||
simpleClone.forget(aClone);
|
||||
return NS_OK;
|
||||
|
@ -190,7 +206,10 @@ nsHostObjectURI::EqualsInternal(nsIURI* aOther,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compare the piece of additional member data that we add to base class.
|
||||
// Compare the piece of additional member data that we add to base class,
|
||||
// but we cannot compare BlobImpl. This should not be a problem, because we
|
||||
// don't support changing the underlying mBlobImpl.
|
||||
|
||||
if (mPrincipal && otherUri->mPrincipal) {
|
||||
// Both of us have mPrincipals. Compare them.
|
||||
return mPrincipal->Equals(otherUri->mPrincipal, aResult);
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
#define nsHostObjectURI_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsISerializable.h"
|
||||
#include "nsIURIWithBlobImpl.h"
|
||||
#include "nsIURIWithPrincipal.h"
|
||||
#include "nsSimpleURI.h"
|
||||
#include "nsIIPCSerializableURI.h"
|
||||
|
@ -21,18 +23,23 @@
|
|||
* MediaStreams, with scheme "mediastream", and MediaSources, with scheme
|
||||
* "mediasource".
|
||||
*/
|
||||
class nsHostObjectURI : public mozilla::net::nsSimpleURI,
|
||||
public nsIURIWithPrincipal
|
||||
class nsHostObjectURI : public mozilla::net::nsSimpleURI
|
||||
, public nsIURIWithPrincipal
|
||||
, public nsIURIWithBlobImpl
|
||||
{
|
||||
public:
|
||||
explicit nsHostObjectURI(nsIPrincipal* aPrincipal) :
|
||||
mozilla::net::nsSimpleURI(), mPrincipal(aPrincipal)
|
||||
nsHostObjectURI(nsIPrincipal* aPrincipal,
|
||||
mozilla::dom::BlobImpl* aBlobImpl)
|
||||
: mozilla::net::nsSimpleURI()
|
||||
, mPrincipal(aPrincipal)
|
||||
, mBlobImpl(aBlobImpl)
|
||||
{}
|
||||
|
||||
// For use only from deserialization
|
||||
nsHostObjectURI() : mozilla::net::nsSimpleURI() {}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIURIWITHBLOBIMPL
|
||||
NS_DECL_NSIURIWITHPRINCIPAL
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
@ -52,6 +59,7 @@ public:
|
|||
{ return new nsHostObjectURI(); }
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
RefPtr<mozilla::dom::BlobImpl> mBlobImpl;
|
||||
|
||||
protected:
|
||||
virtual ~nsHostObjectURI() {}
|
||||
|
|
|
@ -1295,7 +1295,9 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
|
||||
# Conditional exposure makes no sense for interfaces with no
|
||||
# interface object, unless they're navigator properties.
|
||||
if (self.isExposedConditionally() and
|
||||
# And SecureContext makes sense for interfaces with no interface object,
|
||||
# since it is also propagated to interface members.
|
||||
if (self.isExposedConditionally(exclusions=["SecureContext"]) and
|
||||
not self.hasInterfaceObject() and
|
||||
not self.isNavigatorProperty()):
|
||||
raise WebIDLError("Interface with no interface object is "
|
||||
|
@ -1533,8 +1535,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
"SecureContext",
|
||||
"CheckAnyPermissions",
|
||||
"CheckAllPermissions" ]
|
||||
def isExposedConditionally(self):
|
||||
return any(self.getExtendedAttribute(a) for a in self.conditionExtendedAttributes)
|
||||
def isExposedConditionally(self, exclusions=[]):
|
||||
return any(((not a in exclusions) and self.getExtendedAttribute(a)) for a in self.conditionExtendedAttributes)
|
||||
|
||||
class IDLInterface(IDLInterfaceOrNamespace):
|
||||
def __init__(self, location, parentScope, name, parent, members,
|
||||
|
|
|
@ -316,3 +316,17 @@ def WebIDLTest(parser, harness):
|
|||
harness.ok(results[0].members[3].getExtendedAttribute("SecureContext") is None,
|
||||
"Methods copied from non-[SecureContext] interface should not be [SecureContext]")
|
||||
|
||||
# Test SecureContext and NoInterfaceObject
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
[NoInterfaceObject, SecureContext]
|
||||
interface TestSecureContextNoInterfaceObject {
|
||||
void testSecureMethod(byte foo);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
harness.check(len(results[0].members), 1, "TestSecureContextNoInterfaceObject should have only one member")
|
||||
harness.ok(results[0].getExtendedAttribute("SecureContext"),
|
||||
"Interface should have [SecureContext] extended attribute")
|
||||
harness.ok(results[0].members[0].getExtendedAttribute("SecureContext"),
|
||||
"Interface member should have [SecureContext] extended attribute")
|
||||
|
|
|
@ -25,7 +25,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
|
|||
"Should have the right message in test " + testNumber);
|
||||
is(exn.code, code, "Should have the right .code in test " + testNumber);
|
||||
if (message === "") {
|
||||
is(exn.name, "InternalError",
|
||||
is(exn.name, "NS_ERROR_UNEXPECTED",
|
||||
"Should have one of our synthetic exceptions in test " + testNumber);
|
||||
}
|
||||
is(exn.stack, stack, "Should have the right stack in test " + testNumber);
|
||||
|
@ -41,88 +41,79 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
|
|||
var isE10S = !SpecialPowers.isMainProcess();
|
||||
var asyncStack = SpecialPowers.getBoolPref("javascript.options.asyncstack");
|
||||
var ourFile = location.href;
|
||||
var unwrapError = "Promise rejection value is a non-unwrappable cross-compartment wrapper.";
|
||||
var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:130:3
|
||||
var parentFrame = (asyncStack && !isE10S) ? `Async*@${ourFile}:121:3
|
||||
` : "";
|
||||
|
||||
Promise.all([
|
||||
t.testPromiseWithThrowingChromePromiseInit().then(
|
||||
ensurePromiseFail.bind(null, 1),
|
||||
checkExn.bind(null, 49, "InternalError", unwrapError,
|
||||
undefined, ourFile, 1,
|
||||
`doTest@${ourFile}:49:7
|
||||
checkExn.bind(null, 48, "NS_ERROR_UNEXPECTED", "", undefined,
|
||||
ourFile, 1,
|
||||
`doTest@${ourFile}:48:7
|
||||
` +
|
||||
parentFrame)),
|
||||
t.testPromiseWithThrowingContentPromiseInit(function() {
|
||||
thereIsNoSuchContentFunction1();
|
||||
}).then(
|
||||
ensurePromiseFail.bind(null, 2),
|
||||
checkExn.bind(null, 57, "ReferenceError",
|
||||
checkExn.bind(null, 56, "ReferenceError",
|
||||
"thereIsNoSuchContentFunction1 is not defined",
|
||||
undefined, ourFile, 2,
|
||||
`doTest/<@${ourFile}:57:11
|
||||
doTest@${ourFile}:56:7
|
||||
`doTest/<@${ourFile}:56:11
|
||||
doTest@${ourFile}:55:7
|
||||
` +
|
||||
parentFrame)),
|
||||
t.testPromiseWithThrowingChromeThenFunction().then(
|
||||
ensurePromiseFail.bind(null, 3),
|
||||
checkExn.bind(null, 0, "InternalError", unwrapError, undefined, "", 3, asyncStack ? (`Async*doTest@${ourFile}:67:7
|
||||
` +
|
||||
parentFrame) : "")),
|
||||
checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 3, "")),
|
||||
t.testPromiseWithThrowingContentThenFunction(function() {
|
||||
thereIsNoSuchContentFunction2();
|
||||
}).then(
|
||||
ensurePromiseFail.bind(null, 4),
|
||||
checkExn.bind(null, 73, "ReferenceError",
|
||||
checkExn.bind(null, 70, "ReferenceError",
|
||||
"thereIsNoSuchContentFunction2 is not defined",
|
||||
undefined, ourFile, 4,
|
||||
`doTest/<@${ourFile}:73:11
|
||||
`doTest/<@${ourFile}:70:11
|
||||
` +
|
||||
(asyncStack ? `Async*doTest@${ourFile}:72:7
|
||||
(asyncStack ? `Async*doTest@${ourFile}:69:7
|
||||
` : "") +
|
||||
parentFrame)),
|
||||
t.testPromiseWithThrowingChromeThenable().then(
|
||||
ensurePromiseFail.bind(null, 5),
|
||||
checkExn.bind(null, 0, "InternalError", unwrapError, undefined, "", 5, asyncStack ? (`Async*doTest@${ourFile}:84:7
|
||||
` +
|
||||
parentFrame) : "")),
|
||||
checkExn.bind(null, 0, "NS_ERROR_UNEXPECTED", "", undefined, "", 5, "")),
|
||||
t.testPromiseWithThrowingContentThenable({
|
||||
then: function() { thereIsNoSuchContentFunction3(); }
|
||||
}).then(
|
||||
ensurePromiseFail.bind(null, 6),
|
||||
checkExn.bind(null, 90, "ReferenceError",
|
||||
checkExn.bind(null, 85, "ReferenceError",
|
||||
"thereIsNoSuchContentFunction3 is not defined",
|
||||
undefined, ourFile, 6,
|
||||
`doTest/<.then@${ourFile}:90:32
|
||||
` + (asyncStack ? `Async*doTest@${ourFile}:89:7\n` + parentFrame : ""))),
|
||||
`doTest/<.then@${ourFile}:85:32
|
||||
`)),
|
||||
t.testPromiseWithDOMExceptionThrowingPromiseInit().then(
|
||||
ensurePromiseFail.bind(null, 7),
|
||||
checkExn.bind(null, 98, "NotFoundError",
|
||||
checkExn.bind(null, 93, "NotFoundError",
|
||||
"We are a second DOMException",
|
||||
DOMException.NOT_FOUND_ERR, ourFile, 7,
|
||||
`doTest@${ourFile}:98:7
|
||||
`doTest@${ourFile}:93:7
|
||||
` +
|
||||
parentFrame)),
|
||||
t.testPromiseWithDOMExceptionThrowingThenFunction().then(
|
||||
ensurePromiseFail.bind(null, 8),
|
||||
checkExn.bind(null, asyncStack ? 106 : 0, "NetworkError",
|
||||
checkExn.bind(null, asyncStack ? 101 : 0, "NetworkError",
|
||||
"We are a third DOMException",
|
||||
DOMException.NETWORK_ERR, asyncStack ? ourFile : "", 8,
|
||||
(asyncStack ? `Async*doTest@${ourFile}:106:7
|
||||
(asyncStack ? `Async*doTest@${ourFile}:101:7
|
||||
` +
|
||||
parentFrame : ""))),
|
||||
t.testPromiseWithDOMExceptionThrowingThenable().then(
|
||||
ensurePromiseFail.bind(null, 9),
|
||||
checkExn.bind(null, asyncStack ? 114 : 0, "TypeMismatchError",
|
||||
checkExn.bind(null, 0, "TypeMismatchError",
|
||||
"We are a fourth DOMException",
|
||||
DOMException.TYPE_MISMATCH_ERR,
|
||||
asyncStack ? ourFile : "", 9,
|
||||
(asyncStack ? `Async*doTest@${ourFile}:114:7
|
||||
` +
|
||||
parentFrame : ""))),
|
||||
DOMException.TYPE_MISMATCH_ERR, "", 9, "")),
|
||||
]).then(SimpleTest.finish,
|
||||
function(err) {
|
||||
ok(false, "One of our catch statements totally failed with err" + err + ', stack: ' + (err ? err.stack : ''));
|
||||
function() {
|
||||
ok(false, "One of our catch statements totally failed");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -191,7 +191,6 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
|
|||
const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha;
|
||||
|
||||
const auto pi = dstDUI->ToPacking();
|
||||
const auto dstFormat = FormatForPackingInfo(pi);
|
||||
|
||||
const auto dstBPP = webgl::BytesPerPixel(pi);
|
||||
const auto dstWidthBytes = CheckedUint32(dstBPP) * mWidth;
|
||||
|
@ -203,8 +202,9 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
|
|||
//////
|
||||
|
||||
const auto dstTotalRows = CheckedUint32(mDepth - 1) * mImageHeight + mHeight;
|
||||
const auto dstUsedSizeExceptLastRow = (dstTotalRows - 1) * dstStride;
|
||||
|
||||
const auto dstSize = skipBytes + (dstTotalRows - 1) * dstStride + dstWidthBytes;
|
||||
const auto dstSize = skipBytes + dstUsedSizeExceptLastRow + dstWidthBytes;
|
||||
if (!dstSize.isValid()) {
|
||||
webgl->ErrorOutOfMemory("%s: Invalid dstSize calculation during conversion.",
|
||||
funcName);
|
||||
|
@ -213,32 +213,71 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
|
|||
|
||||
//////
|
||||
|
||||
bool needsConvert = (srcOrigin != dstOrigin ||
|
||||
srcFormat != dstFormat ||
|
||||
srcStride != dstStride.value());
|
||||
const auto dstFormat = FormatForPackingInfo(pi);
|
||||
|
||||
if (UnpackFormatHasAlpha(dstDUI->unpackFormat)) {
|
||||
needsConvert |= (mIsSrcPremult != isDstPremult);
|
||||
bool premultMatches = (mIsSrcPremult == isDstPremult);
|
||||
if (!UnpackFormatHasAlpha(dstDUI->unpackFormat)) {
|
||||
premultMatches = true;
|
||||
}
|
||||
|
||||
if (!needsConvert)
|
||||
const bool needsPixelConversion = (srcFormat != dstFormat || !premultMatches);
|
||||
const bool originsMatch = (srcOrigin == dstOrigin);
|
||||
|
||||
MOZ_ASSERT_IF(!needsPixelConversion, srcBPP == dstBPP);
|
||||
|
||||
if (!needsPixelConversion &&
|
||||
originsMatch &&
|
||||
srcStride == dstStride.value())
|
||||
{
|
||||
// No conversion needed!
|
||||
return true;
|
||||
|
||||
////////////
|
||||
// Ugh, ok, fine!
|
||||
|
||||
webgl->GenerateWarning("%s: Incurred CPU data conversion, which is slow.",
|
||||
funcName);
|
||||
}
|
||||
|
||||
//////
|
||||
// We need some sort of conversion, so create the dest buffer.
|
||||
|
||||
*out_anchoredBuffer = calloc(1, dstSize.value());
|
||||
if (!out_anchoredBuffer->get()) {
|
||||
*out_bytes = out_anchoredBuffer->get();
|
||||
if (!*out_bytes) {
|
||||
webgl->ErrorOutOfMemory("%s: Unable to allocate buffer during conversion.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
const auto dstBegin = (uint8_t*)out_anchoredBuffer->get() + skipBytes;
|
||||
const auto dstBegin = (uint8_t*)(*out_bytes) + skipBytes;
|
||||
|
||||
//////
|
||||
// Row conversion
|
||||
|
||||
if (!needsPixelConversion) {
|
||||
webgl->GenerateWarning("%s: Incurred CPU row conversion, which is slow.",
|
||||
funcName);
|
||||
|
||||
const uint8_t* srcRow = srcBegin;
|
||||
uint8_t* dstRow = dstBegin;
|
||||
const auto widthBytes = dstWidthBytes.value();
|
||||
ptrdiff_t dstCopyStride = dstStride.value();
|
||||
|
||||
if (!originsMatch) {
|
||||
dstRow += dstUsedSizeExceptLastRow.value();
|
||||
dstCopyStride = -dstCopyStride;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < dstTotalRows.value(); i++) {
|
||||
memcpy(dstRow, srcRow, widthBytes);
|
||||
srcRow += srcStride;
|
||||
dstRow += dstCopyStride;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////
|
||||
// Pixel conversion.
|
||||
|
||||
MOZ_ASSERT(srcFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
|
||||
MOZ_ASSERT(dstFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
|
||||
|
||||
webgl->GenerateWarning("%s: Incurred CPU pixel conversion, which is very slow.",
|
||||
funcName);
|
||||
|
||||
//////
|
||||
|
||||
|
@ -259,7 +298,6 @@ TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
|
|||
funcName, dstDUI->unpackFormat, dstDUI->unpackType);
|
||||
}
|
||||
|
||||
*out_bytes = out_anchoredBuffer->get();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -297,7 +335,6 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
WebGLContext* webgl = tex->mContext;
|
||||
|
||||
const auto pi = dui->ToPacking();
|
||||
const auto format = FormatForPackingInfo(pi);
|
||||
|
||||
const auto bytesPerPixel = webgl::BytesPerPixel(pi);
|
||||
const auto bytesPerRow = CheckedUint32(mRowLength) * bytesPerPixel;
|
||||
|
@ -306,6 +343,8 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
MOZ_CRASH("Should be checked earlier.");
|
||||
}
|
||||
|
||||
const auto format = FormatForPackingInfo(pi);
|
||||
|
||||
const void* uploadBytes;
|
||||
UniqueBuffer tempBuffer;
|
||||
if (!ConvertIfNeeded(webgl, funcName, mBytes, rowStride.value(), bytesPerPixel,
|
||||
|
|
|
@ -55,7 +55,16 @@ public:
|
|||
const dom::Nullable<dom::ArrayBuffer>& maybeData);
|
||||
void GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::SharedArrayBuffer& data);
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, WebGLsizeiptr offset, ErrorResult& out_error);
|
||||
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
const dom::Nullable<dom::ArrayBufferView>& pixels,
|
||||
ErrorResult& out_error)
|
||||
{
|
||||
WebGLContext::ReadPixels(x, y, width, height, format, type, pixels, out_error);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Framebuffer objects - WebGL2ContextFramebuffers.cpp
|
||||
|
@ -142,111 +151,68 @@ public:
|
|||
void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
|
||||
|
||||
// GL 3.0 & ES 3.0
|
||||
void Uniform1ui(WebGLUniformLocation* location, GLuint v0);
|
||||
void Uniform2ui(WebGLUniformLocation* location, GLuint v0, GLuint v1);
|
||||
void Uniform3ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, GLuint v2);
|
||||
void Uniform4ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
|
||||
void Uniform1ui(WebGLUniformLocation* loc, GLuint v0);
|
||||
void Uniform2ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1);
|
||||
void Uniform3ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2);
|
||||
void Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2,
|
||||
GLuint v3);
|
||||
|
||||
private:
|
||||
void Uniform1uiv_base(WebGLUniformLocation* loc, size_t arrayLength, const GLuint* data);
|
||||
void Uniform2uiv_base(WebGLUniformLocation* loc, size_t arrayLength, const GLuint* data);
|
||||
void Uniform3uiv_base(WebGLUniformLocation* loc, size_t arrayLength, const GLuint* data);
|
||||
void Uniform4uiv_base(WebGLUniformLocation* loc, size_t arrayLength, const GLuint* data);
|
||||
////////////////
|
||||
|
||||
protected:
|
||||
typedef Arr<GLuint, dom::Uint32Array> UintArr;
|
||||
|
||||
void UniformNuiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
|
||||
const UintArr& arr);
|
||||
|
||||
//////
|
||||
|
||||
public:
|
||||
void Uniform1uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform1uiv_base(loc, arr.Length(), arr.Elements());
|
||||
template<typename T>
|
||||
void Uniform1uiv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNuiv("uniform1uiv", 1, loc, UintArr(arr));
|
||||
}
|
||||
void Uniform2uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform2uiv_base(loc, arr.Length(), arr.Elements());
|
||||
template<typename T>
|
||||
void Uniform2uiv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNuiv("uniform2uiv", 2, loc, UintArr(arr));
|
||||
}
|
||||
void Uniform3uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform3uiv_base(loc, arr.Length(), arr.Elements());
|
||||
template<typename T>
|
||||
void Uniform3uiv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNuiv("uniform3uiv", 3, loc, UintArr(arr));
|
||||
}
|
||||
void Uniform4uiv(WebGLUniformLocation* loc, const dom::Sequence<GLuint>& arr) {
|
||||
Uniform4uiv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform1uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3uiv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4uiv(WebGLUniformLocation* loc, const dom::Uint32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4uiv_base(loc, arr.Length(), arr.Data());
|
||||
template<typename T>
|
||||
void Uniform4uiv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNuiv("uniform4uiv", 4, loc, UintArr(arr));
|
||||
}
|
||||
|
||||
private:
|
||||
void UniformMatrix2x3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix3x2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix2x4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix4x2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix3x4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
void UniformMatrix4x3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data);
|
||||
//////
|
||||
|
||||
public:
|
||||
// GL 2.1 & ES 3.0
|
||||
void UniformMatrix2x3fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix2x3fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix2x3fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix2x3fv", 2, 3, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix2x4fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix2x4fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix2x4fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix2x4fv", 2, 4, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix3x2fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix3x2fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix3x2fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix3x2fv", 3, 2, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix3x4fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix3x4fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix3x4fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix3x4fv", 3, 4, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix4x2fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix4x2fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix4x2fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix4x2fv", 4, 2, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
void UniformMatrix4x3fv(WebGLUniformLocation* loc, bool transpose, const dom::Sequence<GLfloat>& value){
|
||||
UniformMatrix4x3fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
template<typename T>
|
||||
void UniformMatrix4x3fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix4x3fv", 4, 3, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
|
||||
void UniformMatrix2x3fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix2x3fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix2x4fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix2x4fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix3x2fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix3x2fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix3x4fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix3x4fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix4x2fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix4x2fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
|
||||
void UniformMatrix4x3fv(WebGLUniformLocation* loc, bool transpose, const dom::Float32Array& value){
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix4x3fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
////////////////
|
||||
|
||||
private:
|
||||
void VertexAttribI4iv(GLuint index, size_t length, const GLint* v);
|
||||
|
|
|
@ -12,26 +12,26 @@
|
|||
namespace mozilla {
|
||||
|
||||
bool
|
||||
WebGL2Context::ValidateBufferTarget(GLenum target, const char* info)
|
||||
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_TRANSFORM_FEEDBACK_BUFFER:
|
||||
case LOCAL_GL_UNIFORM_BUFFER:
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_PIXEL_PACK_BUFFER:
|
||||
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
|
||||
ErrorInvalidOperation("%s: PBOs are still under development, and are currently"
|
||||
" disabled.",
|
||||
info);
|
||||
funcName);
|
||||
return false;
|
||||
|
||||
default:
|
||||
ErrorInvalidEnumInfo(info, target);
|
||||
ErrorInvalidEnumInfo(funcName, target);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -80,11 +80,12 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
|||
GLintptr readOffset, GLintptr writeOffset,
|
||||
GLsizeiptr size)
|
||||
{
|
||||
const char funcName[] = "copyBufferSubData";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateBufferTarget(readTarget, "copyBufferSubData") ||
|
||||
!ValidateBufferTarget(writeTarget, "copyBufferSubData"))
|
||||
if (!ValidateBufferTarget(readTarget, funcName) ||
|
||||
!ValidateBufferTarget(writeTarget, funcName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -95,27 +96,25 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
|||
return;
|
||||
|
||||
const WebGLBuffer* readBuffer = readBufferSlot.get();
|
||||
if (!readBuffer)
|
||||
return ErrorInvalidOperation("copyBufferSubData: No buffer bound to readTarget");
|
||||
if (!readBuffer) {
|
||||
ErrorInvalidOperation("%s: No buffer bound to readTarget.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLBuffer* writeBuffer = writeBufferSlot.get();
|
||||
if (!writeBuffer)
|
||||
return ErrorInvalidOperation("copyBufferSubData: No buffer bound to writeTarget");
|
||||
|
||||
if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(),
|
||||
"copyBufferSubData"))
|
||||
{
|
||||
if (!writeBuffer) {
|
||||
ErrorInvalidOperation("%s: No buffer bound to writeTarget.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(),
|
||||
"copyBufferSubData"))
|
||||
{
|
||||
if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(), funcName))
|
||||
return;
|
||||
|
||||
if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(), funcName))
|
||||
return;
|
||||
}
|
||||
|
||||
if (readTarget == writeTarget &&
|
||||
!ValidateDataRanges(readOffset, writeOffset, size, "copyBufferSubData"))
|
||||
!ValidateDataRanges(readOffset, writeOffset, size, funcName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -127,9 +126,12 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
|||
writeType != WebGLBuffer::Kind::Undefined &&
|
||||
writeType != readType)
|
||||
{
|
||||
ErrorInvalidOperation("copyBufferSubData: Can't copy %s data to %s data",
|
||||
(readType == WebGLBuffer::Kind::OtherData) ? "other" : "element",
|
||||
(writeType == WebGLBuffer::Kind::OtherData) ? "other" : "element");
|
||||
ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
|
||||
funcName,
|
||||
(readType == WebGLBuffer::Kind::OtherData) ? "other"
|
||||
: "element",
|
||||
(writeType == WebGLBuffer::Kind::OtherData) ? "other"
|
||||
: "element");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -150,6 +152,7 @@ template<typename BufferT>
|
|||
void
|
||||
WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT& data)
|
||||
{
|
||||
const char funcName[] = "getBufferSubData";
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
|
@ -159,18 +162,22 @@ WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT&
|
|||
|
||||
// If zero is bound to target, an INVALID_OPERATION error is
|
||||
// generated.
|
||||
if (!ValidateBufferTarget(target, "getBufferSubData"))
|
||||
if (!ValidateBufferTarget(target, funcName))
|
||||
return;
|
||||
|
||||
// If offset is less than zero, an INVALID_VALUE error is
|
||||
// generated.
|
||||
if (offset < 0)
|
||||
return ErrorInvalidValue("getBufferSubData: negative offset");
|
||||
if (offset < 0) {
|
||||
ErrorInvalidValue("%s: Offset must be non-negative.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("getBufferSubData: no buffer bound");
|
||||
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.
|
||||
|
@ -178,15 +185,15 @@ WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT&
|
|||
|
||||
CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.LengthAllowShared();
|
||||
if (!neededByteLength.isValid()) {
|
||||
ErrorInvalidValue("getBufferSubData: Integer overflow computing the needed"
|
||||
" byte length.");
|
||||
ErrorInvalidValue("%s: Integer overflow computing the needed byte length.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (neededByteLength.value() > boundBuffer->ByteLength()) {
|
||||
ErrorInvalidValue("getBufferSubData: Not enough data. Operation requires"
|
||||
" %d bytes, but buffer only has %d bytes.",
|
||||
neededByteLength.value(), boundBuffer->ByteLength());
|
||||
ErrorInvalidValue("%s: Not enough data. Operation requires %d bytes, but buffer"
|
||||
" only has %d bytes.",
|
||||
funcName, neededByteLength.value(), boundBuffer->ByteLength());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -195,9 +202,11 @@ WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT&
|
|||
// is generated.
|
||||
WebGLTransformFeedback* currentTF = mBoundTransformFeedback;
|
||||
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
|
||||
if (currentTF->mIsActive)
|
||||
return ErrorInvalidOperation("getBufferSubData: Currently bound transform"
|
||||
" feedback is active");
|
||||
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
|
||||
|
@ -218,30 +227,37 @@ WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT&
|
|||
* bound to a transform feedback binding point.
|
||||
*/
|
||||
|
||||
void* ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(), LOCAL_GL_MAP_READ_BIT);
|
||||
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 && currentTF) {
|
||||
BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF);
|
||||
}
|
||||
}
|
||||
|
||||
void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData)
|
||||
void
|
||||
WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData)
|
||||
{
|
||||
// If returnedData is null then an INVALID_VALUE error is
|
||||
// generated.
|
||||
if (maybeData.IsNull())
|
||||
return ErrorInvalidValue("getBufferSubData: returnedData is null");
|
||||
if (maybeData.IsNull()) {
|
||||
ErrorInvalidValue("getBufferSubData: returnedData is null");
|
||||
return;
|
||||
}
|
||||
|
||||
const dom::ArrayBuffer& data = maybeData.Value();
|
||||
GetBufferSubDataT(target, offset, data);
|
||||
}
|
||||
|
||||
void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::SharedArrayBuffer& data)
|
||||
void
|
||||
WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::SharedArrayBuffer& data)
|
||||
{
|
||||
GetBufferSubDataT(target, offset, data);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "WebGLBuffer.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLProgram.h"
|
||||
#include "WebGLUniformLocation.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
|
||||
|
@ -28,220 +29,42 @@ WebGL2Context::ValidateUniformMatrixTranspose(bool /*transpose*/, const char* /*
|
|||
void
|
||||
WebGL2Context::Uniform1ui(WebGLUniformLocation* loc, GLuint v0)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 1, LOCAL_GL_UNSIGNED_INT, "uniform1ui", &rawLoc))
|
||||
if (!ValidateUniformSetter(loc, 1, LOCAL_GL_UNSIGNED_INT, "uniform1ui"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1ui(rawLoc, v0);
|
||||
gl->fUniform1ui(loc->mLoc, v0);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform2ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 2, LOCAL_GL_UNSIGNED_INT, "uniform2ui", &rawLoc))
|
||||
if (!ValidateUniformSetter(loc, 2, LOCAL_GL_UNSIGNED_INT, "uniform2ui"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform2ui(rawLoc, v0, v1);
|
||||
gl->fUniform2ui(loc->mLoc, v0, v1);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform3ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 3, LOCAL_GL_UNSIGNED_INT, "uniform3ui", &rawLoc))
|
||||
if (!ValidateUniformSetter(loc, 3, LOCAL_GL_UNSIGNED_INT, "uniform3ui"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform3ui(rawLoc, v0, v1, v2);
|
||||
gl->fUniform3ui(loc->mLoc, v0, v1, v2);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
|
||||
WebGL2Context::Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2,
|
||||
GLuint v3)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
if (!ValidateUniformSetter(loc, 4, LOCAL_GL_UNSIGNED_INT, "uniform4ui", &rawLoc))
|
||||
if (!ValidateUniformSetter(loc, 4, LOCAL_GL_UNSIGNED_INT, "uniform4ui"))
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform4ui(rawLoc, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform1uiv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLuint* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformArraySetter(loc, 1, LOCAL_GL_UNSIGNED_INT, arrayLength,
|
||||
"uniform1uiv", &rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1uiv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform2uiv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLuint* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformArraySetter(loc, 2, LOCAL_GL_UNSIGNED_INT, arrayLength,
|
||||
"uniform2uiv", &rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform2uiv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform3uiv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLuint* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformArraySetter(loc, 3, LOCAL_GL_UNSIGNED_INT, arrayLength,
|
||||
"uniform3uiv", &rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform1uiv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::Uniform4uiv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLuint* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformArraySetter(loc, 4, LOCAL_GL_UNSIGNED_INT, arrayLength,
|
||||
"uniform4uiv", &rawLoc, &numElementsToUpload)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniform4uiv(rawLoc, numElementsToUpload, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix2x3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 2, 3, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix2x3fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix2x3fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix2x4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 2, 4, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix2x4fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix2x4fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix3x2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 3, 2, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix3x2fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix3x2fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix3x4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 3, 4, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix3x4fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix3x4fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix4x2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 4, 2, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix4x2fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix4x2fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::UniformMatrix4x3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const GLfloat* data)
|
||||
{
|
||||
GLuint rawLoc;
|
||||
GLsizei numElementsToUpload;
|
||||
|
||||
if (!ValidateUniformMatrixArraySetter(loc, 4, 3, LOCAL_GL_FLOAT, arrayLength,
|
||||
transpose, "uniformMatrix4x3fv",
|
||||
&rawLoc, &numElementsToUpload))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fUniformMatrix4x3fv(rawLoc, numElementsToUpload, transpose, data);
|
||||
gl->fUniform4ui(loc->mLoc, v0, v1, v2, v3);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
uint8_t
|
||||
static uint8_t
|
||||
ElemSizeFromType(GLenum elemType)
|
||||
{
|
||||
switch (elemType) {
|
||||
|
@ -76,6 +76,8 @@ ElemSizeFromType(GLenum elemType)
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
|
||||
WebGLActiveInfo::WebGLActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum elemType,
|
||||
bool isArray, const nsACString& baseUserName,
|
||||
const nsACString& baseMappedName)
|
||||
|
@ -88,6 +90,32 @@ WebGLActiveInfo::WebGLActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum el
|
|||
, mBaseMappedName(baseMappedName)
|
||||
{ }
|
||||
|
||||
bool
|
||||
WebGLActiveInfo::IsSampler() const
|
||||
{
|
||||
switch (mElemType) {
|
||||
case LOCAL_GL_SAMPLER_2D:
|
||||
case LOCAL_GL_SAMPLER_3D:
|
||||
case LOCAL_GL_SAMPLER_CUBE:
|
||||
case LOCAL_GL_SAMPLER_2D_SHADOW:
|
||||
case LOCAL_GL_SAMPLER_2D_ARRAY:
|
||||
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
|
||||
case LOCAL_GL_INT_SAMPLER_2D:
|
||||
case LOCAL_GL_INT_SAMPLER_3D:
|
||||
case LOCAL_GL_INT_SAMPLER_CUBE:
|
||||
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JSObject*
|
||||
|
|
|
@ -30,11 +30,10 @@ public:
|
|||
return mWebGL;
|
||||
}
|
||||
|
||||
|
||||
WebGLContext* const mWebGL;
|
||||
|
||||
// ActiveInfo state:
|
||||
const GLint mElemCount; // `size`
|
||||
const uint32_t mElemCount; // `size`
|
||||
const GLenum mElemType; // `type`
|
||||
const nsCString mBaseUserName; // `name`, but ASCII, and without any final "[0]".
|
||||
|
||||
|
@ -43,6 +42,8 @@ public:
|
|||
const uint8_t mElemSize;
|
||||
const nsCString mBaseMappedName; // Without any final "[0]".
|
||||
|
||||
bool IsSampler() const;
|
||||
|
||||
WebGLActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum elemType, bool isArray,
|
||||
const nsACString& baseUserName, const nsACString& baseMappedName);
|
||||
|
||||
|
@ -90,7 +91,7 @@ private:
|
|||
|
||||
//////////
|
||||
|
||||
uint8_t ElemSizeFromType(GLenum elemType);
|
||||
bool IsElemTypeSampler(GLenum elemType);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ namespace webgl {
|
|||
struct LinkedProgramInfo;
|
||||
class ShaderValidator;
|
||||
class TexUnpackBlob;
|
||||
struct UniformInfo;
|
||||
} // namespace webgl
|
||||
|
||||
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
|
||||
|
@ -539,9 +540,13 @@ public:
|
|||
void PixelStorei(GLenum pname, GLint param);
|
||||
void PolygonOffset(GLfloat factor, GLfloat units);
|
||||
protected:
|
||||
bool DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum destFormat, GLenum destType, void* destBytes,
|
||||
GLenum auxReadFormat, GLenum auxReadType);
|
||||
bool ReadPixels_SharedPrecheck(ErrorResult* const out_error);
|
||||
void ReadPixelsImpl(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum type, void* data, uint32_t dataLen);
|
||||
bool DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat, GLint x, GLint y,
|
||||
GLsizei width, GLsizei height, GLenum format,
|
||||
GLenum destType, void* dest, uint32_t dataLen,
|
||||
uint32_t rowStride);
|
||||
public:
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
|
@ -565,160 +570,108 @@ public:
|
|||
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail,
|
||||
GLenum dppass);
|
||||
|
||||
//////
|
||||
|
||||
void Uniform1i(WebGLUniformLocation* loc, GLint x);
|
||||
void Uniform2i(WebGLUniformLocation* loc, GLint x, GLint y);
|
||||
void Uniform3i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z);
|
||||
void Uniform4i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z,
|
||||
GLint w);
|
||||
void Uniform4i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z, GLint w);
|
||||
|
||||
void Uniform1f(WebGLUniformLocation* loc, GLfloat x);
|
||||
void Uniform2f(WebGLUniformLocation* loc, GLfloat x, GLfloat y);
|
||||
void Uniform3f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z);
|
||||
void Uniform4f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z,
|
||||
GLfloat w);
|
||||
void Uniform4f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
|
||||
|
||||
// Int array
|
||||
void Uniform1iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform1iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform1iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform1iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
//////////////////////////
|
||||
|
||||
void Uniform2iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform2iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform2iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
protected:
|
||||
template<typename elemT, typename arrT>
|
||||
struct Arr {
|
||||
size_t dataCount;
|
||||
const elemT* data;
|
||||
|
||||
void Uniform3iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform3iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform3iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
explicit Arr(const arrT& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
dataCount = arr.Length();
|
||||
data = arr.Data();
|
||||
}
|
||||
|
||||
void Uniform4iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4iv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4iv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLint>& arr)
|
||||
{
|
||||
Uniform4iv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform4iv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLint* data);
|
||||
explicit Arr(const dom::Sequence<elemT>& arr) {
|
||||
dataCount = arr.Length();
|
||||
data = arr.Elements();
|
||||
}
|
||||
};
|
||||
|
||||
// Float array
|
||||
void Uniform1fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform1fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform1fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform1fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform1fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
typedef Arr<GLint, dom::Int32Array> IntArr;
|
||||
typedef Arr<GLfloat, dom::Float32Array> FloatArr;
|
||||
|
||||
void Uniform2fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform2fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform2fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform2fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform2fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
////////////////
|
||||
|
||||
void Uniform3fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform3fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform3fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform3fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform3fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
void UniformNiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
|
||||
const IntArr& arr);
|
||||
|
||||
void Uniform4fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
|
||||
arr.ComputeLengthAndData();
|
||||
Uniform4fv_base(loc, arr.Length(), arr.Data());
|
||||
}
|
||||
void Uniform4fv(WebGLUniformLocation* loc,
|
||||
const dom::Sequence<GLfloat>& arr)
|
||||
{
|
||||
Uniform4fv_base(loc, arr.Length(), arr.Elements());
|
||||
}
|
||||
void Uniform4fv_base(WebGLUniformLocation* loc, size_t arrayLength,
|
||||
const GLfloat* data);
|
||||
void UniformNfv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
|
||||
const FloatArr& arr);
|
||||
|
||||
// Matrix
|
||||
void UniformMatrix2fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Float32Array& value)
|
||||
{
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix2fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix2fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Sequence<float>& value)
|
||||
{
|
||||
UniformMatrix2fv_base(loc, transpose, value.Length(),
|
||||
value.Elements());
|
||||
}
|
||||
void UniformMatrix2fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const float* data);
|
||||
void UniformMatrixAxBfv(const char* funcName, uint8_t A, uint8_t B,
|
||||
WebGLUniformLocation* loc, bool transpose,
|
||||
const FloatArr& arr);
|
||||
|
||||
void UniformMatrix3fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Float32Array& value)
|
||||
{
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix3fv_base(loc, transpose, value.Length(), value.Data());
|
||||
}
|
||||
void UniformMatrix3fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Sequence<float>& value)
|
||||
{
|
||||
UniformMatrix3fv_base(loc, transpose, value.Length(), value.Elements());
|
||||
}
|
||||
void UniformMatrix3fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const float* data);
|
||||
////////////////
|
||||
|
||||
void UniformMatrix4fv(WebGLUniformLocation* loc, WebGLboolean transpose,
|
||||
const dom::Float32Array& value)
|
||||
{
|
||||
value.ComputeLengthAndData();
|
||||
UniformMatrix4fv_base(loc, transpose, value.Length(), value.Data());
|
||||
public:
|
||||
template<typename T>
|
||||
void Uniform1iv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNiv("uniform1iv", 1, loc, IntArr(arr));
|
||||
}
|
||||
void UniformMatrix4fv(WebGLUniformLocation* loc, bool transpose,
|
||||
const dom::Sequence<float>& value)
|
||||
{
|
||||
UniformMatrix4fv_base(loc, transpose, value.Length(),
|
||||
value.Elements());
|
||||
template<typename T>
|
||||
void Uniform2iv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNiv("uniform2iv", 2, loc, IntArr(arr));
|
||||
}
|
||||
void UniformMatrix4fv_base(WebGLUniformLocation* loc, bool transpose,
|
||||
size_t arrayLength, const float* data);
|
||||
template<typename T>
|
||||
void Uniform3iv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNiv("uniform3iv", 3, loc, IntArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void Uniform4iv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNiv("uniform4iv", 4, loc, IntArr(arr));
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
template<typename T>
|
||||
void Uniform1fv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNfv("uniform1fv", 1, loc, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void Uniform2fv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNfv("uniform2fv", 2, loc, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void Uniform3fv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNfv("uniform3fv", 3, loc, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void Uniform4fv(WebGLUniformLocation* loc, const T& arr) {
|
||||
UniformNfv("uniform4fv", 4, loc, FloatArr(arr));
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
template<typename T>
|
||||
void UniformMatrix2fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix2fv", 2, 2, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void UniformMatrix3fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix3fv", 3, 3, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
template<typename T>
|
||||
void UniformMatrix4fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
|
||||
UniformMatrixAxBfv("uniformMatrix4fv", 4, 4, loc, transpose, FloatArr(arr));
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
|
||||
void UseProgram(WebGLProgram* prog);
|
||||
|
||||
|
@ -726,22 +679,19 @@ public:
|
|||
uint32_t arrayLength);
|
||||
bool ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName);
|
||||
bool ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterSize,
|
||||
GLenum setterType, const char* info,
|
||||
GLuint* out_rawLoc);
|
||||
GLenum setterType, const char* funcName);
|
||||
bool ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, GLenum setterType,
|
||||
size_t setterArraySize, const char* info,
|
||||
GLuint* out_rawLoc,
|
||||
GLsizei* out_numElementsToUpload);
|
||||
uint32_t setterArraySize, const char* funcName,
|
||||
uint32_t* out_numElementsToUpload);
|
||||
bool ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterCols,
|
||||
uint8_t setterRows,
|
||||
GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
uint32_t setterArraySize,
|
||||
bool setterTranspose,
|
||||
const char* info,
|
||||
GLuint* out_rawLoc,
|
||||
GLsizei* out_numElementsToUpload);
|
||||
const char* funcName,
|
||||
uint32_t* out_numElementsToUpload);
|
||||
void ValidateProgram(WebGLProgram* prog);
|
||||
bool ValidateUniformLocation(const char* info, WebGLUniformLocation* loc);
|
||||
bool ValidateSamplerUniformSetter(const char* info,
|
||||
|
@ -1603,6 +1553,9 @@ public:
|
|||
virtual UniquePtr<webgl::FormatUsageAuthority>
|
||||
CreateFormatUsage(gl::GLContext* gl) const = 0;
|
||||
|
||||
|
||||
const decltype(mBound2DTextures)* TexListForElemType(GLenum elemType) const;
|
||||
|
||||
// Friend list
|
||||
friend class ScopedCopyTexImageSource;
|
||||
friend class ScopedResolveTexturesForDraw;
|
||||
|
@ -1611,6 +1564,7 @@ public:
|
|||
friend class webgl::TexUnpackBytes;
|
||||
friend class webgl::TexUnpackImage;
|
||||
friend class webgl::TexUnpackSurface;
|
||||
friend struct webgl::UniformInfo;
|
||||
friend class WebGLTexture;
|
||||
friend class WebGLFBAttachPoint;
|
||||
friend class WebGLFramebuffer;
|
||||
|
|
|
@ -42,26 +42,95 @@ public:
|
|||
~ScopedResolveTexturesForDraw();
|
||||
};
|
||||
|
||||
bool
|
||||
WebGLTexture::IsFeedback(WebGLContext* webgl, const char* funcName, uint32_t texUnit,
|
||||
const std::vector<const WebGLFBAttachPoint*>& fbAttachments) const
|
||||
{
|
||||
auto itr = fbAttachments.cbegin();
|
||||
for (; itr != fbAttachments.cend(); ++itr) {
|
||||
const auto& attach = *itr;
|
||||
if (attach->Texture() == this)
|
||||
break;
|
||||
}
|
||||
|
||||
if (itr == fbAttachments.cend())
|
||||
return false;
|
||||
|
||||
////
|
||||
|
||||
const auto minLevel = mBaseMipmapLevel;
|
||||
uint32_t maxLevel;
|
||||
if (!MaxEffectiveMipmapLevel(texUnit, &maxLevel)) {
|
||||
// No valid mips. Will need fake-black.
|
||||
return false;
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
for (; itr != fbAttachments.cend(); ++itr) {
|
||||
const auto& attach = *itr;
|
||||
if (attach->Texture() != this)
|
||||
continue;
|
||||
|
||||
const auto dstLevel = attach->MipLevel();
|
||||
|
||||
if (minLevel <= dstLevel && dstLevel <= maxLevel) {
|
||||
webgl->ErrorInvalidOperation("%s: Feedback loop detected between tex target"
|
||||
" 0x%04x, tex unit %u, levels %u-%u; and"
|
||||
" framebuffer attachment 0x%04x, level %u.",
|
||||
funcName, mTarget.get(), texUnit, minLevel,
|
||||
maxLevel, attach->mAttachmentPoint, dstLevel);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
||||
const char* funcName,
|
||||
bool* const out_error)
|
||||
: mWebGL(webgl)
|
||||
{
|
||||
MOZ_ASSERT(webgl->gl->IsCurrent());
|
||||
MOZ_ASSERT(mWebGL->gl->IsCurrent());
|
||||
|
||||
typedef decltype(WebGLContext::mBound2DTextures) TexturesT;
|
||||
if (!mWebGL->mActiveProgramLinkInfo) {
|
||||
mWebGL->ErrorInvalidOperation("%s: The current program is not linked.", funcName);
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto fnResolveAll = [this, funcName](const TexturesT& textures)
|
||||
{
|
||||
const auto len = textures.Length();
|
||||
for (uint32_t texUnit = 0; texUnit < len; ++texUnit) {
|
||||
WebGLTexture* tex = textures[texUnit];
|
||||
std::vector<const WebGLFBAttachPoint*> fbAttachments;
|
||||
if (mWebGL->mBoundDrawFramebuffer) {
|
||||
const auto& fb = mWebGL->mBoundDrawFramebuffer;
|
||||
fb->GatherAttachments(&fbAttachments);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWebGL->mActiveProgramLinkInfo);
|
||||
const auto& uniformSamplers = mWebGL->mActiveProgramLinkInfo->uniformSamplers;
|
||||
for (const auto& uniform : uniformSamplers) {
|
||||
const auto& texList = *(uniform->mSamplerTexList);
|
||||
|
||||
for (const auto& texUnit : uniform->mSamplerValues) {
|
||||
if (texUnit >= texList.Length())
|
||||
continue;
|
||||
|
||||
const auto& tex = texList[texUnit];
|
||||
if (!tex)
|
||||
continue;
|
||||
|
||||
if (tex->IsFeedback(mWebGL, funcName, texUnit, fbAttachments)) {
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
FakeBlackType fakeBlack;
|
||||
if (!tex->ResolveForDraw(funcName, texUnit, &fakeBlack))
|
||||
return false;
|
||||
if (!tex->ResolveForDraw(funcName, texUnit, &fakeBlack)) {
|
||||
mWebGL->ErrorOutOfMemory("%s: Failed to resolve textures for draw.",
|
||||
funcName);
|
||||
*out_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fakeBlack == FakeBlackType::None)
|
||||
continue;
|
||||
|
@ -69,21 +138,9 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
|
|||
mWebGL->BindFakeBlack(texUnit, tex->Target(), fakeBlack);
|
||||
mRebindRequests.push_back({texUnit, tex});
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool ok = true;
|
||||
ok &= fnResolveAll(mWebGL->mBound2DTextures);
|
||||
ok &= fnResolveAll(mWebGL->mBoundCubeMapTextures);
|
||||
ok &= fnResolveAll(mWebGL->mBound3DTextures);
|
||||
ok &= fnResolveAll(mWebGL->mBound2DArrayTextures);
|
||||
|
||||
if (!ok) {
|
||||
mWebGL->ErrorOutOfMemory("%s: Failed to resolve textures for draw.", funcName);
|
||||
}
|
||||
|
||||
*out_error = !ok;
|
||||
*out_error = false;
|
||||
}
|
||||
|
||||
ScopedResolveTexturesForDraw::~ScopedResolveTexturesForDraw()
|
||||
|
@ -195,12 +252,6 @@ WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Any checks below this depend on a program being available.
|
||||
if (!mCurrentProgram) {
|
||||
ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateBufferFetching(info)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -360,14 +411,6 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Any checks below this depend on mActiveProgramLinkInfo being available.
|
||||
if (!mActiveProgramLinkInfo) {
|
||||
// Technically, this will only be null iff CURRENT_PROGRAM is null.
|
||||
// But it's better to branch on what we actually care about.
|
||||
ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mBoundVertexArray->mElementArrayBuffer) {
|
||||
ErrorInvalidOperation("%s: must have element array buffer binding", info);
|
||||
return false;
|
||||
|
@ -603,8 +646,8 @@ WebGLContext::ValidateBufferFetching(const char* info)
|
|||
|
||||
mBufferFetch_IsAttrib0Active = false;
|
||||
|
||||
for (const auto& pair : mActiveProgramLinkInfo->activeAttribLocs) {
|
||||
const uint32_t attribLoc = pair.second;
|
||||
for (const auto& attrib : mActiveProgramLinkInfo->attribs) {
|
||||
const auto& attribLoc = attrib.mLoc;
|
||||
|
||||
if (attribLoc >= attribCount)
|
||||
continue;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -437,7 +437,7 @@ WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* fun
|
|||
return false;
|
||||
}
|
||||
|
||||
return loc->ValidateForProgram(mCurrentProgram, this, funcName);
|
||||
return loc->ValidateForProgram(mCurrentProgram, funcName);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -459,7 +459,7 @@ WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSiz
|
|||
bool
|
||||
WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize, GLenum setterType,
|
||||
const char* funcName, GLuint* out_rawLoc)
|
||||
const char* funcName)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
@ -467,10 +467,9 @@ WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
|
|||
if (!ValidateUniformLocation(loc, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName))
|
||||
return false;
|
||||
|
||||
*out_rawLoc = loc->mLoc;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -478,10 +477,9 @@ bool
|
|||
WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
||||
uint8_t setterElemSize,
|
||||
GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
uint32_t setterArraySize,
|
||||
const char* funcName,
|
||||
GLuint* const out_rawLoc,
|
||||
GLsizei* const out_numElementsToUpload)
|
||||
uint32_t* const out_numElementsToUpload)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
@ -489,16 +487,18 @@ WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
|||
if (!ValidateUniformLocation(loc, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, funcName))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT((size_t)loc->mActiveInfo->mElemCount > loc->mArrayIndex);
|
||||
size_t uniformElemCount = loc->mActiveInfo->mElemCount - loc->mArrayIndex;
|
||||
*out_rawLoc = loc->mLoc;
|
||||
*out_numElementsToUpload = std::min(uniformElemCount, setterArraySize / setterElemSize);
|
||||
const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount;
|
||||
MOZ_ASSERT(elemCount > loc->mArrayIndex);
|
||||
const uint32_t uniformElemCount = elemCount - loc->mArrayIndex;
|
||||
|
||||
*out_numElementsToUpload = std::min(uniformElemCount,
|
||||
setterArraySize / setterElemSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -507,13 +507,12 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
|||
uint8_t setterCols,
|
||||
uint8_t setterRows,
|
||||
GLenum setterType,
|
||||
size_t setterArraySize,
|
||||
uint32_t setterArraySize,
|
||||
bool setterTranspose,
|
||||
const char* funcName,
|
||||
GLuint* const out_rawLoc,
|
||||
GLsizei* const out_numElementsToUpload)
|
||||
uint32_t* const out_numElementsToUpload)
|
||||
{
|
||||
uint8_t setterElemSize = setterCols * setterRows;
|
||||
const uint8_t setterElemSize = setterCols * setterRows;
|
||||
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
@ -521,20 +520,21 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
|||
if (!ValidateUniformLocation(loc, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
|
||||
if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName))
|
||||
return false;
|
||||
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
|
||||
if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, funcName))
|
||||
return false;
|
||||
|
||||
if (!ValidateUniformMatrixTranspose(setterTranspose, funcName))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT((size_t)loc->mActiveInfo->mElemCount > loc->mArrayIndex);
|
||||
size_t uniformElemCount = loc->mActiveInfo->mElemCount - loc->mArrayIndex;
|
||||
*out_rawLoc = loc->mLoc;
|
||||
*out_numElementsToUpload = std::min(uniformElemCount, setterArraySize / setterElemSize);
|
||||
const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount;
|
||||
MOZ_ASSERT(elemCount > loc->mArrayIndex);
|
||||
const uint32_t uniformElemCount = elemCount - loc->mArrayIndex;
|
||||
|
||||
*out_numElementsToUpload = std::min(uniformElemCount,
|
||||
setterArraySize / setterElemSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -440,24 +440,28 @@ FormatInfo::GetCopyDecayFormat(UnsizedFormat uf) const
|
|||
return FindOrNull(this->copyDecayFormats, uf);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
BytesPerPixel(const PackingInfo& packing)
|
||||
bool
|
||||
GetBytesPerPixel(const PackingInfo& packing, uint8_t* const out_bytes)
|
||||
{
|
||||
uint8_t bytesPerChannel;
|
||||
|
||||
switch (packing.type) {
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
return 2;
|
||||
*out_bytes = 2;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
|
||||
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
|
||||
case LOCAL_GL_UNSIGNED_INT_24_8:
|
||||
case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
|
||||
return 4;
|
||||
*out_bytes = 4;
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
|
||||
return 8;
|
||||
*out_bytes = 8;
|
||||
return true;
|
||||
|
||||
// Alright, that's all the fixed-size unpackTypes.
|
||||
|
||||
|
@ -480,11 +484,20 @@ BytesPerPixel(const PackingInfo& packing)
|
|||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("GFX: invalid PackingInfo");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t channels;
|
||||
|
||||
switch (packing.format) {
|
||||
case LOCAL_GL_RED:
|
||||
case LOCAL_GL_RED_INTEGER:
|
||||
case LOCAL_GL_LUMINANCE:
|
||||
case LOCAL_GL_ALPHA:
|
||||
case LOCAL_GL_DEPTH_COMPONENT:
|
||||
channels = 1;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_RG:
|
||||
case LOCAL_GL_RG_INTEGER:
|
||||
case LOCAL_GL_LUMINANCE_ALPHA:
|
||||
|
@ -493,23 +506,36 @@ BytesPerPixel(const PackingInfo& packing)
|
|||
|
||||
case LOCAL_GL_RGB:
|
||||
case LOCAL_GL_RGB_INTEGER:
|
||||
case LOCAL_GL_SRGB:
|
||||
channels = 3;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_BGRA:
|
||||
case LOCAL_GL_RGBA:
|
||||
case LOCAL_GL_RGBA_INTEGER:
|
||||
case LOCAL_GL_SRGB_ALPHA:
|
||||
channels = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
channels = 1;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
return bytesPerChannel * channels;
|
||||
*out_bytes = bytesPerChannel * channels;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
BytesPerPixel(const PackingInfo& packing)
|
||||
{
|
||||
uint8_t ret;
|
||||
if (MOZ_LIKELY(GetBytesPerPixel(packing, &ret)))
|
||||
return ret;
|
||||
|
||||
gfxCriticalError() << "Bad `packing`: " << gfx::hexa(packing.format) << ", "
|
||||
<< gfx::hexa(packing.type);
|
||||
MOZ_CRASH("Bad `packing`.");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -254,6 +254,7 @@ struct DriverUnpackInfo
|
|||
|
||||
const FormatInfo* GetFormat(EffectiveFormat format);
|
||||
uint8_t BytesPerPixel(const PackingInfo& packing);
|
||||
bool GetBytesPerPixel(const PackingInfo& packing, uint8_t* const out_bytes);
|
||||
/*
|
||||
GLint ComponentSize(const FormatInfo* format, GLenum component);
|
||||
GLenum ComponentType(const FormatInfo* format);
|
||||
|
|
|
@ -1281,6 +1281,34 @@ WebGLFramebuffer::GetAttachmentParameter(const char* funcName, JSContext* cx,
|
|||
out_error);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WebGLFramebuffer::GatherAttachments(std::vector<const WebGLFBAttachPoint*>* const out) const
|
||||
{
|
||||
auto itr = mDrawBuffers.cbegin();
|
||||
if (itr != mDrawBuffers.cend() &&
|
||||
*itr != LOCAL_GL_NONE)
|
||||
{
|
||||
out->push_back(&mColorAttachment0);
|
||||
++itr;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (; itr != mDrawBuffers.cend(); ++itr) {
|
||||
if (i >= mMoreColorAttachments.Size())
|
||||
break;
|
||||
|
||||
if (*itr != LOCAL_GL_NONE) {
|
||||
out->push_back(&mMoreColorAttachments[i]);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
out->push_back(&mDepthAttachment);
|
||||
out->push_back(&mStencilAttachment);
|
||||
out->push_back(&mDepthStencilAttachment);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Goop.
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ private:
|
|||
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
|
||||
TexImageTarget mTexImageTarget;
|
||||
GLint mTexImageLayer;
|
||||
GLint mTexImageLevel;
|
||||
uint32_t mTexImageLevel;
|
||||
|
||||
// PlacementArray needs a default constructor.
|
||||
template<typename T>
|
||||
|
@ -89,7 +89,7 @@ public:
|
|||
GLint Layer() const {
|
||||
return mTexImageLayer;
|
||||
}
|
||||
GLint MipLevel() const {
|
||||
uint32_t MipLevel() const {
|
||||
return mTexImageLevel;
|
||||
}
|
||||
void AttachmentName(nsCString* out) const;
|
||||
|
@ -259,6 +259,8 @@ public:
|
|||
|
||||
GLenum ReadBufferMode() const { return mReadBufferMode; }
|
||||
|
||||
void GatherAttachments(std::vector<const WebGLFBAttachPoint*>* const out) const;
|
||||
|
||||
protected:
|
||||
WebGLFBAttachPoint* GetAttachPoint(GLenum attachment); // Fallible
|
||||
|
||||
|
|
|
@ -69,36 +69,60 @@ ParseName(const nsCString& name, nsCString* const out_baseName,
|
|||
return true;
|
||||
}
|
||||
|
||||
static WebGLActiveInfo*
|
||||
AddActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum elemType, bool isArray,
|
||||
const nsACString& baseUserName, const nsACString& baseMappedName,
|
||||
std::vector<RefPtr<WebGLActiveInfo>>* activeInfoList,
|
||||
std::map<nsCString, const WebGLActiveInfo*>* infoLocMap)
|
||||
{
|
||||
RefPtr<WebGLActiveInfo> info = new WebGLActiveInfo(webgl, elemCount, elemType,
|
||||
isArray, baseUserName,
|
||||
baseMappedName);
|
||||
activeInfoList->push_back(info);
|
||||
//////////
|
||||
|
||||
infoLocMap->insert(std::make_pair(info->mBaseUserName, info.get()));
|
||||
return info.get();
|
||||
/*static*/ const webgl::UniformInfo::TexListT*
|
||||
webgl::UniformInfo::GetTexList(WebGLActiveInfo* activeInfo)
|
||||
{
|
||||
const auto& webgl = activeInfo->mWebGL;
|
||||
|
||||
switch (activeInfo->mElemType) {
|
||||
case LOCAL_GL_SAMPLER_2D:
|
||||
case LOCAL_GL_SAMPLER_2D_SHADOW:
|
||||
case LOCAL_GL_INT_SAMPLER_2D:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
|
||||
return &webgl->mBound2DTextures;
|
||||
|
||||
case LOCAL_GL_SAMPLER_CUBE:
|
||||
case LOCAL_GL_SAMPLER_CUBE_SHADOW:
|
||||
case LOCAL_GL_INT_SAMPLER_CUBE:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||
return &webgl->mBoundCubeMapTextures;
|
||||
|
||||
case LOCAL_GL_SAMPLER_3D:
|
||||
case LOCAL_GL_INT_SAMPLER_3D:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
|
||||
return &webgl->mBound3DTextures;
|
||||
|
||||
case LOCAL_GL_SAMPLER_2D_ARRAY:
|
||||
case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
|
||||
case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||
return &webgl->mBound2DArrayTextures;
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AddActiveBlockInfo(const nsACString& baseUserName,
|
||||
const nsACString& baseMappedName,
|
||||
std::vector<RefPtr<webgl::UniformBlockInfo>>* activeInfoList)
|
||||
webgl::UniformInfo::UniformInfo(WebGLActiveInfo* activeInfo)
|
||||
: mActiveInfo(activeInfo)
|
||||
, mSamplerTexList(GetTexList(activeInfo))
|
||||
{
|
||||
RefPtr<webgl::UniformBlockInfo> info = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
|
||||
|
||||
activeInfoList->push_back(info);
|
||||
if (mSamplerTexList) {
|
||||
mSamplerValues.assign(mActiveInfo->mElemCount, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//////////
|
||||
|
||||
//#define DUMP_SHADERVAR_MAPPINGS
|
||||
|
||||
static already_AddRefed<const webgl::LinkedProgramInfo>
|
||||
QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
||||
{
|
||||
WebGLContext* const webgl = prog->mContext;
|
||||
|
||||
RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
|
||||
|
||||
GLuint maxAttribLenWithNull = 0;
|
||||
|
@ -154,33 +178,37 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
|
||||
mappedName.SetLength(lengthWithoutNull);
|
||||
|
||||
// Collect ActiveInfos:
|
||||
|
||||
// Attribs can't be arrays, so we can skip some of the mess we have in the Uniform
|
||||
// path.
|
||||
nsDependentCString userName;
|
||||
if (!prog->FindAttribUserNameByMappedName(mappedName, &userName))
|
||||
userName.Rebind(mappedName, 0);
|
||||
|
||||
///////
|
||||
|
||||
const GLint loc = gl->fGetAttribLocation(prog->mGLName,
|
||||
mappedName.BeginReading());
|
||||
if (loc == -1) {
|
||||
MOZ_ASSERT(mappedName == "gl_InstanceID",
|
||||
"Active attrib should have a location.");
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
||||
printf_stderr("[attrib %i] %s/%s\n", i, mappedName.BeginReading(),
|
||||
printf_stderr("[attrib %i: %i] %s/%s\n", i, loc, mappedName.BeginReading(),
|
||||
userName.BeginReading());
|
||||
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
|
||||
#endif
|
||||
|
||||
const bool isArray = false;
|
||||
const auto attrib = AddActiveInfo(prog->mContext, elemCount, elemType, isArray,
|
||||
userName, mappedName, &info->activeAttribs,
|
||||
&info->attribMap);
|
||||
///////
|
||||
|
||||
// Collect active locations:
|
||||
GLint loc = gl->fGetAttribLocation(prog->mGLName, mappedName.BeginReading());
|
||||
if (loc == -1) {
|
||||
if (mappedName != "gl_InstanceID")
|
||||
MOZ_CRASH("GFX: Active attrib has no location.");
|
||||
} else {
|
||||
info->activeAttribLocs.insert({attrib, (GLuint)loc});
|
||||
}
|
||||
const bool isArray = false;
|
||||
const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
|
||||
elemType, isArray,
|
||||
userName,
|
||||
mappedName);
|
||||
const webgl::AttribInfo attrib = {activeInfo, uint32_t(loc)};
|
||||
info->attribs.push_back(attrib);
|
||||
}
|
||||
|
||||
// Uniforms
|
||||
|
@ -203,6 +231,8 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
|
||||
mappedName.SetLength(lengthWithoutNull);
|
||||
|
||||
///////
|
||||
|
||||
nsAutoCString baseMappedName;
|
||||
bool isArray;
|
||||
size_t arrayIndex;
|
||||
|
@ -212,8 +242,11 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
// Note that for good drivers, `isArray` should already be correct.
|
||||
// However, if FindUniform succeeds, it will be validator-guaranteed correct.
|
||||
|
||||
///////
|
||||
|
||||
nsAutoCString baseUserName;
|
||||
if (!prog->FindUniformByMappedName(baseMappedName, &baseUserName, &isArray)) {
|
||||
// Validator likely missing.
|
||||
baseUserName = baseMappedName;
|
||||
|
||||
if (needsCheckForArrays && !isArray) {
|
||||
|
@ -229,6 +262,8 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
}
|
||||
}
|
||||
|
||||
///////
|
||||
|
||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
||||
printf_stderr("[uniform %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
|
||||
(int)isArray, baseMappedName.BeginReading(),
|
||||
|
@ -237,11 +272,23 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
printf_stderr(" isArray: %d\n", (int)isArray);
|
||||
#endif
|
||||
|
||||
AddActiveInfo(prog->mContext, elemCount, elemType, isArray, baseUserName,
|
||||
baseMappedName, &info->activeUniforms, &info->uniformMap);
|
||||
///////
|
||||
|
||||
const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
|
||||
elemType, isArray,
|
||||
baseUserName,
|
||||
baseMappedName);
|
||||
|
||||
auto* uniform = new webgl::UniformInfo(activeInfo);
|
||||
info->uniforms.push_back(uniform);
|
||||
|
||||
if (uniform->mSamplerTexList) {
|
||||
info->uniformSamplers.push_back(uniform);
|
||||
}
|
||||
}
|
||||
|
||||
// Uniform Blocks
|
||||
// (no sampler types allowed!)
|
||||
|
||||
if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
|
||||
GLuint numActiveUniformBlocks = 0;
|
||||
|
@ -281,14 +328,15 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
}
|
||||
|
||||
#ifdef DUMP_SHADERVAR_MAPPINGS
|
||||
printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
|
||||
(int)isArray, baseMappedName.BeginReading(),
|
||||
baseUserName.BeginReading());
|
||||
printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i,
|
||||
mappedName.BeginReading(), (int)isArray,
|
||||
baseMappedName.BeginReading(), baseUserName.BeginReading());
|
||||
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
|
||||
printf_stderr(" isArray: %d\n", (int)isArray);
|
||||
#endif
|
||||
|
||||
AddActiveBlockInfo(baseUserName, baseMappedName, &info->uniformBlocks);
|
||||
const auto* block = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
|
||||
info->uniformBlocks.push_back(block);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,19 +352,23 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
mappedName.SetLength(maxTransformFeedbackVaryingLenWithNull - 1);
|
||||
|
||||
GLint lengthWithoutNull;
|
||||
GLsizei size;
|
||||
GLenum type;
|
||||
gl->fGetTransformFeedbackVarying(prog->mGLName, i, maxTransformFeedbackVaryingLenWithNull,
|
||||
&lengthWithoutNull, &size, &type,
|
||||
GLsizei elemCount;
|
||||
GLenum elemType;
|
||||
gl->fGetTransformFeedbackVarying(prog->mGLName, i,
|
||||
maxTransformFeedbackVaryingLenWithNull,
|
||||
&lengthWithoutNull, &elemCount, &elemType,
|
||||
mappedName.BeginWriting());
|
||||
mappedName.SetLength(lengthWithoutNull);
|
||||
|
||||
////
|
||||
|
||||
nsAutoCString baseMappedName;
|
||||
bool isArray;
|
||||
size_t arrayIndex;
|
||||
if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
|
||||
MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
|
||||
|
||||
|
||||
nsAutoCString baseUserName;
|
||||
if (!prog->FindVaryingByMappedName(mappedName, &baseUserName, &isArray)) {
|
||||
baseUserName = baseMappedName;
|
||||
|
@ -332,9 +384,15 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
|
|||
}
|
||||
}
|
||||
|
||||
AddActiveInfo(prog->mContext, size, type, isArray, baseUserName, mappedName,
|
||||
&info->transformFeedbackVaryings,
|
||||
&info->transformFeedbackVaryingsMap);
|
||||
////
|
||||
|
||||
const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl,
|
||||
elemCount,
|
||||
elemType,
|
||||
isArray,
|
||||
baseUserName,
|
||||
mappedName);
|
||||
info->transformFeedbackVaryings.push_back(activeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,6 +405,16 @@ webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
|
|||
: prog(prog)
|
||||
{ }
|
||||
|
||||
webgl::LinkedProgramInfo::~LinkedProgramInfo()
|
||||
{
|
||||
for (auto& cur : uniforms) {
|
||||
delete cur;
|
||||
}
|
||||
for (auto& cur : uniformBlocks) {
|
||||
delete cur;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebGLProgram
|
||||
|
||||
|
@ -487,15 +555,15 @@ WebGLProgram::GetActiveAttrib(GLuint index) const
|
|||
return ret.forget();
|
||||
}
|
||||
|
||||
const auto& activeList = mMostRecentLinkInfo->activeAttribs;
|
||||
const auto& attribs = mMostRecentLinkInfo->attribs;
|
||||
|
||||
if (index >= activeList.size()) {
|
||||
if (index >= attribs.size()) {
|
||||
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
|
||||
index, "ACTIVE_ATTRIBS", activeList.size());
|
||||
index, "ACTIVE_ATTRIBS", attribs.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<WebGLActiveInfo> ret = activeList[index];
|
||||
RefPtr<WebGLActiveInfo> ret = attribs[index].mActiveInfo;
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
|
@ -508,15 +576,15 @@ WebGLProgram::GetActiveUniform(GLuint index) const
|
|||
return ret.forget();
|
||||
}
|
||||
|
||||
const auto& activeList = mMostRecentLinkInfo->activeUniforms;
|
||||
const auto& uniforms = mMostRecentLinkInfo->uniforms;
|
||||
|
||||
if (index >= activeList.size()) {
|
||||
if (index >= uniforms.size()) {
|
||||
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
|
||||
index, "ACTIVE_UNIFORMS", activeList.size());
|
||||
index, "ACTIVE_UNIFORMS", uniforms.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<WebGLActiveInfo> ret = activeList[index];
|
||||
RefPtr<WebGLActiveInfo> ret = uniforms[index]->mActiveInfo;
|
||||
return ret.forget();
|
||||
}
|
||||
|
||||
|
@ -545,16 +613,11 @@ WebGLProgram::GetAttribLocation(const nsAString& userName_wide) const
|
|||
|
||||
const NS_LossyConvertUTF16toASCII userName(userName_wide);
|
||||
|
||||
const WebGLActiveInfo* info;
|
||||
const webgl::AttribInfo* info;
|
||||
if (!LinkInfo()->FindAttrib(userName, &info))
|
||||
return -1;
|
||||
|
||||
const nsCString& mappedName = info->mBaseMappedName;
|
||||
|
||||
gl::GLContext* gl = mContext->GL();
|
||||
gl->MakeCurrent();
|
||||
|
||||
return gl->fGetAttribLocation(mGLName, mappedName.BeginReading());
|
||||
return GLint(info->mLoc);
|
||||
}
|
||||
|
||||
GLint
|
||||
|
@ -658,13 +721,12 @@ WebGLProgram::GetUniformBlockIndex(const nsAString& userName_wide) const
|
|||
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
|
||||
return LOCAL_GL_INVALID_INDEX;
|
||||
|
||||
RefPtr<const webgl::UniformBlockInfo> info;
|
||||
const webgl::UniformBlockInfo* info;
|
||||
if (!LinkInfo()->FindUniformBlock(baseUserName, &info)) {
|
||||
return LOCAL_GL_INVALID_INDEX;
|
||||
}
|
||||
|
||||
const nsCString& baseMappedName = info->mBaseMappedName;
|
||||
nsAutoCString mappedName(baseMappedName);
|
||||
nsAutoCString mappedName(info->mBaseMappedName);
|
||||
if (isArray) {
|
||||
mappedName.AppendLiteral("[");
|
||||
mappedName.AppendInt(uint32_t(arrayIndex));
|
||||
|
@ -799,13 +861,11 @@ WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
|
|||
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
|
||||
return nullptr;
|
||||
|
||||
const WebGLActiveInfo* activeInfo;
|
||||
if (!LinkInfo()->FindUniform(baseUserName, &activeInfo))
|
||||
webgl::UniformInfo* info;
|
||||
if (!LinkInfo()->FindUniform(baseUserName, &info))
|
||||
return nullptr;
|
||||
|
||||
const nsCString& baseMappedName = activeInfo->mBaseMappedName;
|
||||
|
||||
nsAutoCString mappedName(baseMappedName);
|
||||
nsAutoCString mappedName(info->mActiveInfo->mBaseMappedName);
|
||||
if (isArray) {
|
||||
mappedName.AppendLiteral("[");
|
||||
mappedName.AppendInt(uint32_t(arrayIndex));
|
||||
|
@ -820,8 +880,7 @@ WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
|
|||
return nullptr;
|
||||
|
||||
RefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
|
||||
loc, arrayIndex,
|
||||
activeInfo);
|
||||
info, loc, arrayIndex);
|
||||
return locObj.forget();
|
||||
}
|
||||
|
||||
|
@ -846,15 +905,13 @@ WebGLProgram::GetUniformIndices(const dom::Sequence<nsString>& uniformNames,
|
|||
continue;
|
||||
}
|
||||
|
||||
const WebGLActiveInfo* activeInfo;
|
||||
if (!LinkInfo()->FindUniform(baseUserName, &activeInfo)) {
|
||||
webgl::UniformInfo* info;
|
||||
if (!LinkInfo()->FindUniform(baseUserName, &info)) {
|
||||
arr.AppendElement(LOCAL_GL_INVALID_INDEX);
|
||||
continue;
|
||||
}
|
||||
|
||||
const nsCString& baseMappedName = activeInfo->mBaseMappedName;
|
||||
|
||||
nsAutoCString mappedName(baseMappedName);
|
||||
nsAutoCString mappedName(info->mActiveInfo->mBaseMappedName);
|
||||
if (isArray) {
|
||||
mappedName.AppendLiteral("[");
|
||||
mappedName.AppendInt(uint32_t(arrayIndex));
|
||||
|
@ -879,8 +936,7 @@ WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockB
|
|||
}
|
||||
|
||||
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
|
||||
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
|
||||
if (uniformBlockIndex >= uniformBlockCount) {
|
||||
if (uniformBlockIndex >= linkInfo->uniformBlocks.size()) {
|
||||
mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
|
||||
return;
|
||||
}
|
||||
|
@ -990,49 +1046,70 @@ WebGLProgram::LinkProgram()
|
|||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
NumUsedLocationsByElemType(GLenum elemType)
|
||||
{
|
||||
// GLES 3.0.4 p55
|
||||
|
||||
switch (elemType) {
|
||||
case LOCAL_GL_FLOAT_MAT2:
|
||||
case LOCAL_GL_FLOAT_MAT2x3:
|
||||
case LOCAL_GL_FLOAT_MAT2x4:
|
||||
return 2;
|
||||
|
||||
case LOCAL_GL_FLOAT_MAT3x2:
|
||||
case LOCAL_GL_FLOAT_MAT3:
|
||||
case LOCAL_GL_FLOAT_MAT3x4:
|
||||
return 3;
|
||||
|
||||
case LOCAL_GL_FLOAT_MAT4x2:
|
||||
case LOCAL_GL_FLOAT_MAT4x3:
|
||||
case LOCAL_GL_FLOAT_MAT4:
|
||||
return 4;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const
|
||||
{
|
||||
const auto& linkInfo = mMostRecentLinkInfo;
|
||||
|
||||
// Check if the attrib name conflicting to uniform name
|
||||
for (const auto& uniform : linkInfo->uniformMap) {
|
||||
if (linkInfo->attribMap.find(uniform.first) != linkInfo->attribMap.end()) {
|
||||
*out_linkLog = nsPrintfCString("The uniform name (%s) conflicts with"
|
||||
" attribute name.",
|
||||
uniform.first.get());
|
||||
return false;
|
||||
for (const auto& attrib : linkInfo->attribs) {
|
||||
const auto& attribName = attrib.mActiveInfo->mBaseUserName;
|
||||
|
||||
for (const auto& uniform : linkInfo->uniforms) {
|
||||
const auto& uniformName = uniform->mActiveInfo->mBaseUserName;
|
||||
if (attribName == uniformName) {
|
||||
*out_linkLog = nsPrintfCString("Attrib name conflicts with uniform name:"
|
||||
" %s",
|
||||
attribName.BeginReading());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<GLuint, const WebGLActiveInfo*> attribsByLoc;
|
||||
for (const auto& pair : linkInfo->activeAttribLocs) {
|
||||
const auto dupe = attribsByLoc.find(pair.second);
|
||||
if (dupe != attribsByLoc.end()) {
|
||||
*out_linkLog = nsPrintfCString("Aliased location between active attribs"
|
||||
" \"%s\" and \"%s\".",
|
||||
dupe->second->mBaseUserName.BeginReading(),
|
||||
pair.first->mBaseUserName.BeginReading());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::map<uint32_t, const webgl::AttribInfo*> attribsByLoc;
|
||||
for (const auto& attrib : linkInfo->attribs) {
|
||||
const auto& elemType = attrib.mActiveInfo->mElemType;
|
||||
const auto numUsedLocs = NumUsedLocationsByElemType(elemType);
|
||||
for (uint32_t i = 0; i < numUsedLocs; i++) {
|
||||
const uint32_t usedLoc = attrib.mLoc + i;
|
||||
|
||||
for (const auto& pair : attribsByLoc) {
|
||||
const GLuint attribLoc = pair.first;
|
||||
const auto attrib = pair.second;
|
||||
|
||||
const auto elemSize = ElemSizeFromType(attrib->mElemType);
|
||||
const GLuint locationsUsed = (elemSize + 3) / 4;
|
||||
for (GLuint i = 1; i < locationsUsed; i++) {
|
||||
const GLuint usedLoc = attribLoc + i;
|
||||
|
||||
const auto dupe = attribsByLoc.find(usedLoc);
|
||||
if (dupe != attribsByLoc.end()) {
|
||||
*out_linkLog = nsPrintfCString("Attrib \"%s\" of type \"0x%04x\" aliases"
|
||||
" \"%s\" by overhanging its location.",
|
||||
attrib->mBaseUserName.BeginReading(),
|
||||
attrib->mElemType,
|
||||
dupe->second->mBaseUserName.BeginReading());
|
||||
const auto res = attribsByLoc.insert({usedLoc, &attrib});
|
||||
const bool& didInsert = res.second;
|
||||
if (!didInsert) {
|
||||
const auto& aliasingName = attrib.mActiveInfo->mBaseUserName;
|
||||
const auto& itrExisting = res.first;
|
||||
const auto& existingInfo = itrExisting->second;
|
||||
const auto& existingName = existingInfo->mActiveInfo->mBaseUserName;
|
||||
*out_linkLog = nsPrintfCString("Attrib \"%s\" aliases locations used by"
|
||||
" attrib \"%s\".",
|
||||
aliasingName.BeginReading(),
|
||||
existingName.BeginReading());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1234,6 +1311,50 @@ WebGLProgram::FindUniformBlockByMappedName(const nsACString& mappedName,
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool
|
||||
webgl::LinkedProgramInfo::FindAttrib(const nsCString& baseUserName,
|
||||
const webgl::AttribInfo** const out) const
|
||||
{
|
||||
for (const auto& attrib : attribs) {
|
||||
if (attrib.mActiveInfo->mBaseUserName == baseUserName) {
|
||||
*out = &attrib;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
webgl::LinkedProgramInfo::FindUniform(const nsCString& baseUserName,
|
||||
webgl::UniformInfo** const out) const
|
||||
{
|
||||
for (const auto& uniform : uniforms) {
|
||||
if (uniform->mActiveInfo->mBaseUserName == baseUserName) {
|
||||
*out = uniform;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
webgl::LinkedProgramInfo::FindUniformBlock(const nsCString& baseUserName,
|
||||
const webgl::UniformBlockInfo** const out) const
|
||||
{
|
||||
for (const auto& block : uniformBlocks) {
|
||||
if (block->mBaseUserName == baseUserName) {
|
||||
*out = block;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JSObject*
|
||||
WebGLProgram::WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto)
|
||||
{
|
||||
|
|
|
@ -35,11 +35,30 @@ template<typename> class Sequence;
|
|||
|
||||
namespace webgl {
|
||||
|
||||
struct UniformBlockInfo final
|
||||
: public RefCounted<UniformBlockInfo>
|
||||
struct AttribInfo final
|
||||
{
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(UniformBlockInfo);
|
||||
const RefPtr<WebGLActiveInfo> mActiveInfo;
|
||||
uint32_t mLoc;
|
||||
};
|
||||
|
||||
struct UniformInfo final
|
||||
{
|
||||
typedef decltype(WebGLContext::mBound2DTextures) TexListT;
|
||||
|
||||
const RefPtr<WebGLActiveInfo> mActiveInfo;
|
||||
const TexListT* const mSamplerTexList;
|
||||
std::vector<uint32_t> mSamplerValues;
|
||||
|
||||
protected:
|
||||
static const TexListT*
|
||||
GetTexList(WebGLActiveInfo* activeInfo);
|
||||
|
||||
public:
|
||||
explicit UniformInfo(WebGLActiveInfo* activeInfo);
|
||||
};
|
||||
|
||||
struct UniformBlockInfo final
|
||||
{
|
||||
const nsCString mBaseUserName;
|
||||
const nsCString mBaseMappedName;
|
||||
|
||||
|
@ -57,61 +76,27 @@ struct LinkedProgramInfo final
|
|||
MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(LinkedProgramInfo)
|
||||
|
||||
//////
|
||||
|
||||
WebGLProgram* const prog;
|
||||
std::vector<RefPtr<WebGLActiveInfo>> activeAttribs;
|
||||
std::vector<RefPtr<WebGLActiveInfo>> activeUniforms;
|
||||
|
||||
std::vector<AttribInfo> attribs;
|
||||
std::vector<UniformInfo*> uniforms; // Owns its contents.
|
||||
std::vector<const UniformBlockInfo*> uniformBlocks; // Owns its contents.
|
||||
std::vector<RefPtr<WebGLActiveInfo>> transformFeedbackVaryings;
|
||||
|
||||
// Needed for Get{Attrib,Uniform}Location. The keys for these are non-mapped
|
||||
// user-facing `GLActiveInfo::name`s, without any final "[0]".
|
||||
std::map<nsCString, const WebGLActiveInfo*> attribMap;
|
||||
std::map<nsCString, const WebGLActiveInfo*> uniformMap;
|
||||
std::map<nsCString, const WebGLActiveInfo*> transformFeedbackVaryingsMap;
|
||||
|
||||
std::vector<RefPtr<UniformBlockInfo>> uniformBlocks;
|
||||
|
||||
// Needed for draw call validation.
|
||||
std::map<const WebGLActiveInfo*, GLuint> activeAttribLocs;
|
||||
std::vector<UniformInfo*> uniformSamplers;
|
||||
|
||||
//////
|
||||
|
||||
explicit LinkedProgramInfo(WebGLProgram* prog);
|
||||
~LinkedProgramInfo();
|
||||
|
||||
bool FindAttrib(const nsCString& baseUserName,
|
||||
const WebGLActiveInfo** const out_activeInfo) const
|
||||
{
|
||||
auto itr = attribMap.find(baseUserName);
|
||||
if (itr == attribMap.end())
|
||||
return false;
|
||||
|
||||
*out_activeInfo = itr->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FindUniform(const nsCString& baseUserName,
|
||||
const WebGLActiveInfo** const out_activeInfo) const
|
||||
{
|
||||
auto itr = uniformMap.find(baseUserName);
|
||||
if (itr == uniformMap.end())
|
||||
return false;
|
||||
|
||||
*out_activeInfo = itr->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FindAttrib(const nsCString& baseUserName, const AttribInfo** const out) const;
|
||||
bool FindUniform(const nsCString& baseUserName, UniformInfo** const out) const;
|
||||
bool FindUniformBlock(const nsCString& baseUserName,
|
||||
RefPtr<const UniformBlockInfo>* const out_info) const
|
||||
{
|
||||
const size_t count = uniformBlocks.size();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (baseUserName == uniformBlocks[i]->mBaseUserName) {
|
||||
*out_info = uniformBlocks[i].get();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
const UniformBlockInfo** const out) const;
|
||||
};
|
||||
|
||||
} // namespace webgl
|
||||
|
|
|
@ -195,7 +195,9 @@ WebGLTexture::IsMipmapComplete(uint32_t texUnit) const
|
|||
MOZ_ASSERT(DoesMinFilterRequireMipmap());
|
||||
// GLES 3.0.4, p161
|
||||
|
||||
const uint32_t maxLevel = MaxEffectiveMipmapLevel(texUnit);
|
||||
uint32_t maxLevel;
|
||||
if (!MaxEffectiveMipmapLevel(texUnit, &maxLevel))
|
||||
return false;
|
||||
|
||||
// "* `level_base <= level_max`"
|
||||
if (mBaseMipmapLevel > maxLevel)
|
||||
|
@ -203,8 +205,6 @@ WebGLTexture::IsMipmapComplete(uint32_t texUnit) const
|
|||
|
||||
// Make a copy so we can modify it.
|
||||
const ImageInfo& baseImageInfo = BaseImageInfo();
|
||||
if (!baseImageInfo.IsDefined())
|
||||
return false;
|
||||
|
||||
// Reference dimensions based on the current level.
|
||||
uint32_t refWidth = baseImageInfo.mWidth;
|
||||
|
@ -425,24 +425,26 @@ WebGLTexture::IsComplete(uint32_t texUnit, const char** const out_reason) const
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
WebGLTexture::MaxEffectiveMipmapLevel(uint32_t texUnit) const
|
||||
bool
|
||||
WebGLTexture::MaxEffectiveMipmapLevel(uint32_t texUnit, uint32_t* const out) const
|
||||
{
|
||||
WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
|
||||
TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
|
||||
if (minFilter == LOCAL_GL_NEAREST ||
|
||||
minFilter == LOCAL_GL_LINEAR)
|
||||
{
|
||||
// No mips used.
|
||||
return mBaseMipmapLevel;
|
||||
// No extra mips used.
|
||||
*out = mBaseMipmapLevel;
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& imageInfo = BaseImageInfo();
|
||||
MOZ_ASSERT(imageInfo.IsDefined());
|
||||
if (!imageInfo.IsDefined())
|
||||
return false;
|
||||
|
||||
uint32_t maxLevelBySize = mBaseMipmapLevel + imageInfo.MaxMipmapLevels() - 1;
|
||||
return std::min<uint32_t>(maxLevelBySize, mMaxMipmapLevel);
|
||||
uint32_t maxLevelBySize = mBaseMipmapLevel + imageInfo.PossibleMipmapLevels() - 1;
|
||||
*out = std::min<uint32_t>(maxLevelBySize, mMaxMipmapLevel);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -466,7 +468,9 @@ WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit,
|
|||
bool hasUninitializedData = false;
|
||||
bool hasInitializedData = false;
|
||||
|
||||
const auto maxLevel = MaxEffectiveMipmapLevel(texUnit);
|
||||
uint32_t maxLevel;
|
||||
MOZ_ALWAYS_TRUE( MaxEffectiveMipmapLevel(texUnit, &maxLevel) );
|
||||
|
||||
MOZ_ASSERT(mBaseMipmapLevel <= maxLevel);
|
||||
for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
|
||||
for (uint8_t face = 0; face < mFaceCount; face++) {
|
||||
|
@ -790,8 +794,8 @@ WebGLTexture::GenerateMipmap(TexTarget texTarget)
|
|||
// Record the results.
|
||||
// Note that we don't use MaxEffectiveMipmapLevel() here, since that returns
|
||||
// mBaseMipmapLevel if the min filter doesn't require mipmaps.
|
||||
const uint32_t lastLevel = mBaseMipmapLevel + baseImageInfo.MaxMipmapLevels() - 1;
|
||||
PopulateMipChain(mBaseMipmapLevel, lastLevel);
|
||||
const uint32_t maxLevel = mBaseMipmapLevel + baseImageInfo.PossibleMipmapLevels() - 1;
|
||||
PopulateMipChain(mBaseMipmapLevel, maxLevel);
|
||||
}
|
||||
|
||||
JS::Value
|
||||
|
|
|
@ -154,9 +154,10 @@ public:
|
|||
ImageInfo& operator =(const ImageInfo& a);
|
||||
|
||||
public:
|
||||
uint32_t MaxMipmapLevels() const {
|
||||
uint32_t PossibleMipmapLevels() const {
|
||||
// GLES 3.0.4, 3.8 - Mipmapping: `floor(log2(largest_of_dims)) + 1`
|
||||
uint32_t largest = std::max(std::max(mWidth, mHeight), mDepth);
|
||||
const uint32_t largest = std::max(std::max(mWidth, mHeight), mDepth);
|
||||
MOZ_ASSERT(largest != 0);
|
||||
return FloorLog2Size(largest) + 1;
|
||||
}
|
||||
|
||||
|
@ -288,7 +289,7 @@ protected:
|
|||
|
||||
void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel);
|
||||
|
||||
uint32_t MaxEffectiveMipmapLevel(uint32_t texUnit) const;
|
||||
bool MaxEffectiveMipmapLevel(uint32_t texUnit, uint32_t* const out) const;
|
||||
|
||||
static uint8_t FaceForTarget(TexImageTarget texImageTarget) {
|
||||
GLenum rawTexImageTarget = texImageTarget.get();
|
||||
|
@ -388,6 +389,9 @@ protected:
|
|||
bool GetFakeBlackType(const char* funcName, uint32_t texUnit,
|
||||
FakeBlackType* const out_fakeBlack);
|
||||
public:
|
||||
bool IsFeedback(WebGLContext* webgl, const char* funcName, uint32_t texUnit,
|
||||
const std::vector<const WebGLFBAttachPoint*>& fbAttachments) const;
|
||||
|
||||
bool ResolveForDraw(const char* funcName, uint32_t texUnit,
|
||||
FakeBlackType* const out_fakeBlack);
|
||||
|
||||
|
|
|
@ -16,34 +16,32 @@ namespace mozilla {
|
|||
|
||||
WebGLUniformLocation::WebGLUniformLocation(WebGLContext* webgl,
|
||||
const webgl::LinkedProgramInfo* linkInfo,
|
||||
GLuint loc,
|
||||
size_t arrayIndex,
|
||||
const WebGLActiveInfo* activeInfo)
|
||||
webgl::UniformInfo* info, GLuint loc,
|
||||
size_t arrayIndex)
|
||||
: WebGLContextBoundObject(webgl)
|
||||
, mLinkInfo(linkInfo)
|
||||
, mInfo(info)
|
||||
, mLoc(loc)
|
||||
, mArrayIndex(arrayIndex)
|
||||
, mActiveInfo(activeInfo)
|
||||
{ }
|
||||
|
||||
WebGLUniformLocation::~WebGLUniformLocation()
|
||||
{ }
|
||||
|
||||
bool
|
||||
WebGLUniformLocation::ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
|
||||
const char* funcName) const
|
||||
WebGLUniformLocation::ValidateForProgram(WebGLProgram* prog, const char* funcName) const
|
||||
{
|
||||
// Check the weak-pointer.
|
||||
if (!mLinkInfo) {
|
||||
webgl->ErrorInvalidOperation("%s: This uniform location is obsolete because its"
|
||||
" program has been successfully relinked.",
|
||||
funcName);
|
||||
mContext->ErrorInvalidOperation("%s: This uniform location is obsolete because"
|
||||
" its program has been successfully relinked.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mLinkInfo->prog != prog) {
|
||||
webgl->ErrorInvalidOperation("%s: This uniform location corresponds to a"
|
||||
" different program.", funcName);
|
||||
mContext->ErrorInvalidOperation("%s: This uniform location corresponds to a"
|
||||
" different program.", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -121,19 +119,22 @@ IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
|
|||
|
||||
bool
|
||||
WebGLUniformLocation::ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
|
||||
WebGLContext* webgl, const char* funcName) const
|
||||
const char* funcName) const
|
||||
{
|
||||
MOZ_ASSERT(mLinkInfo);
|
||||
|
||||
if (setterElemSize != mActiveInfo->mElemSize) {
|
||||
webgl->ErrorInvalidOperation("%s: Bad uniform size: %i", funcName,
|
||||
mActiveInfo->mElemSize);
|
||||
const auto& uniformElemSize = mInfo->mActiveInfo->mElemSize;
|
||||
if (setterElemSize != uniformElemSize) {
|
||||
mContext->ErrorInvalidOperation("%s: Function used differs from uniform size: %i",
|
||||
funcName, uniformElemSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsUniformSetterTypeValid(setterType, mActiveInfo->mElemType)) {
|
||||
webgl->ErrorInvalidOperation("%s: Bad uniform type: %i", funcName,
|
||||
mActiveInfo->mElemSize);
|
||||
const auto& uniformElemType = mInfo->mActiveInfo->mElemType;
|
||||
if (!IsUniformSetterTypeValid(setterType, uniformElemType)) {
|
||||
mContext->ErrorInvalidOperation("%s: Function used is incompatible with uniform"
|
||||
" type: %i",
|
||||
funcName, uniformElemType);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -142,16 +143,16 @@ WebGLUniformLocation::ValidateSizeAndType(uint8_t setterElemSize, GLenum setterT
|
|||
|
||||
bool
|
||||
WebGLUniformLocation::ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
|
||||
WebGLContext* webgl, const char* funcName) const
|
||||
const char* funcName) const
|
||||
{
|
||||
MOZ_ASSERT(mLinkInfo);
|
||||
|
||||
if (setterArraySize == 0 ||
|
||||
setterArraySize % setterElemSize)
|
||||
{
|
||||
webgl->ErrorInvalidValue("%s: expected an array of length a multiple of"
|
||||
" %d, got an array of length %d.",
|
||||
funcName, setterElemSize, setterArraySize);
|
||||
mContext->ErrorInvalidValue("%s: Expected an array of length a multiple of %d,"
|
||||
" got an array of length %d.",
|
||||
funcName, setterElemSize, setterArraySize);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -162,55 +163,34 @@ WebGLUniformLocation::ValidateArrayLength(uint8_t setterElemSize, size_t setterA
|
|||
* highest array element index used, as reported by `GetActiveUniform`, will be
|
||||
* ignored by GL.
|
||||
*/
|
||||
if (!mActiveInfo->mIsArray &&
|
||||
if (!mInfo->mActiveInfo->mIsArray &&
|
||||
setterArraySize != setterElemSize)
|
||||
{
|
||||
webgl->ErrorInvalidOperation("%s: expected an array of length exactly %d"
|
||||
" (since this uniform is not an array"
|
||||
" uniform), got an array of length %d.",
|
||||
funcName, setterElemSize, setterArraySize);
|
||||
mContext->ErrorInvalidOperation("%s: Expected an array of length exactly %d"
|
||||
" (since this uniform is not an array uniform),"
|
||||
" got an array of length %d.",
|
||||
funcName, setterElemSize, setterArraySize);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLUniformLocation::ValidateSamplerSetter(GLint value, WebGLContext* webgl,
|
||||
const char* funcName) const
|
||||
{
|
||||
MOZ_ASSERT(mLinkInfo);
|
||||
|
||||
if (mActiveInfo->mElemType != LOCAL_GL_SAMPLER_2D &&
|
||||
mActiveInfo->mElemType != LOCAL_GL_SAMPLER_CUBE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value >= 0 && value < (GLint)webgl->GLMaxTextureUnits())
|
||||
return true;
|
||||
|
||||
webgl->ErrorInvalidValue("%s: This uniform location is a sampler, but %d is not a"
|
||||
" valid texture unit.",
|
||||
funcName, value);
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Value
|
||||
WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
||||
WebGLUniformLocation::GetUniform(JSContext* js) const
|
||||
{
|
||||
MOZ_ASSERT(mLinkInfo);
|
||||
|
||||
uint8_t elemSize = mActiveInfo->mElemSize;
|
||||
const uint8_t elemSize = mInfo->mActiveInfo->mElemSize;
|
||||
static const uint8_t kMaxElemSize = 16;
|
||||
MOZ_ASSERT(elemSize <= kMaxElemSize);
|
||||
|
||||
GLuint prog = mLinkInfo->prog->mGLName;
|
||||
|
||||
gl::GLContext* gl = webgl->GL();
|
||||
gl::GLContext* gl = mContext->GL();
|
||||
gl->MakeCurrent();
|
||||
|
||||
switch (mActiveInfo->mElemType) {
|
||||
switch (mInfo->mActiveInfo->mElemType) {
|
||||
case LOCAL_GL_INT:
|
||||
case LOCAL_GL_INT_VEC2:
|
||||
case LOCAL_GL_INT_VEC3:
|
||||
|
@ -237,9 +217,9 @@ WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
|||
if (elemSize == 1)
|
||||
return JS::Int32Value(buffer[0]);
|
||||
|
||||
JSObject* obj = dom::Int32Array::Create(js, webgl, elemSize, buffer);
|
||||
JSObject* obj = dom::Int32Array::Create(js, mContext, elemSize, buffer);
|
||||
if (!obj) {
|
||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
||||
mContext->ErrorOutOfMemory("getUniform: Out of memory.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
|
@ -263,7 +243,7 @@ WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
|||
JS::RootedValue val(js);
|
||||
// Be careful: we don't want to convert all of |uv|!
|
||||
if (!dom::ToJSValue(js, boolBuffer, elemSize, &val)) {
|
||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
||||
mContext->ErrorOutOfMemory("getUniform: Out of memory.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
return val;
|
||||
|
@ -289,9 +269,9 @@ WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
|||
if (elemSize == 1)
|
||||
return JS::DoubleValue(buffer[0]);
|
||||
|
||||
JSObject* obj = dom::Float32Array::Create(js, webgl, elemSize, buffer);
|
||||
JSObject* obj = dom::Float32Array::Create(js, mContext, elemSize, buffer);
|
||||
if (!obj) {
|
||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
||||
mContext->ErrorOutOfMemory("getUniform: Out of memory.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
|
@ -308,9 +288,9 @@ WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
|
|||
if (elemSize == 1)
|
||||
return JS::DoubleValue(buffer[0]); // This is Double because only Int32 is special cased.
|
||||
|
||||
JSObject* obj = dom::Uint32Array::Create(js, webgl, elemSize, buffer);
|
||||
JSObject* obj = dom::Uint32Array::Create(js, mContext, elemSize, buffer);
|
||||
if (!obj) {
|
||||
webgl->ErrorOutOfMemory("getUniform: out of memory");
|
||||
mContext->ErrorOutOfMemory("getUniform: Out of memory.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
|
|
|
@ -39,24 +39,25 @@ public:
|
|||
return mContext;
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
const WeakPtr<const webgl::LinkedProgramInfo> mLinkInfo;
|
||||
webgl::UniformInfo* const mInfo;
|
||||
const GLuint mLoc;
|
||||
const size_t mArrayIndex;
|
||||
const WebGLActiveInfo* const mActiveInfo;
|
||||
|
||||
//////
|
||||
|
||||
WebGLUniformLocation(WebGLContext* webgl, const webgl::LinkedProgramInfo* linkInfo,
|
||||
GLuint loc, size_t arrayIndex, const WebGLActiveInfo* activeInfo);
|
||||
webgl::UniformInfo* info, GLuint loc, size_t arrayIndex);
|
||||
|
||||
bool ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
|
||||
const char* funcName) const;
|
||||
bool ValidateSamplerSetter(GLint value, WebGLContext* webgl,
|
||||
const char* funcName) const;
|
||||
bool ValidateForProgram(WebGLProgram* prog, const char* funcName) const;
|
||||
bool ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
|
||||
WebGLContext* webgl, const char* funcName) const;
|
||||
const char* funcName) const;
|
||||
bool ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
|
||||
WebGLContext* webgl, const char* funcName) const;
|
||||
const char* funcName) const;
|
||||
|
||||
JS::Value GetUniform(JSContext* js, WebGLContext* webgl) const;
|
||||
JS::Value GetUniform(JSContext* js) const;
|
||||
|
||||
// Needed for certain helper functions like ValidateObject.
|
||||
// `WebGLUniformLocation`s can't be 'Deleted' in the WebGL sense.
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += [
|
||||
'compiledtest',
|
||||
'compiledtest',
|
||||
'gtest'
|
||||
]
|
||||
|
||||
# Change the following line(s) to avoid bug 1081323 (clobber after changing a manifest):
|
||||
# * Add a regression test for triangle-then-point rendering.
|
||||
# * Implement ReadPixel with PBOs.
|
||||
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'test/crash/mochitest.ini',
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<link rel='stylesheet' href='checkout/resources/js-test-style.css'/>
|
||||
<script src='checkout/resources/js-test-pre.js'></script>
|
||||
<script src='checkout/js/js-test-pre.js'></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id='description'></div>
|
||||
|
|
|
@ -3,4 +3,6 @@
|
|||
|
||||
conformance/00_test_list.txt
|
||||
conformance/more/00_test_list.txt
|
||||
|
||||
// Disable deqp tests temporarily
|
||||
//deqp/00_test_list.txt
|
||||
--min-version 2.0.0 conformance2/00_test_list.txt
|
||||
|
|
|
@ -63,10 +63,8 @@ OSs on which the WebGL implementation is intended to be supported.
|
|||
3. Conformance as the web browser is upgraded
|
||||
|
||||
WebGL conformance results submitted for an earlier version of the
|
||||
browser carry forward to later versions of the browser, unless the
|
||||
WebGL implementation changes substantially enough that it is expected
|
||||
that conformance may have been affected. In that case, the browser
|
||||
implementer should submit new conformance results.
|
||||
browser carry forward to later versions of the browser that do not
|
||||
cause any previously passing test to fail.
|
||||
|
||||
4. Conformance as the operating system is upgraded
|
||||
|
||||
|
@ -88,15 +86,12 @@ built-in web browser. In this case the following rules apply:
|
|||
1. Conformance results must be submitted for each GPU and operating
|
||||
system combination to be certified. It is not required to submit
|
||||
results for different devices containing the same GPU and running the
|
||||
same operating system.
|
||||
same operating system that do not cause any previously passing test to
|
||||
fail.
|
||||
|
||||
2. Conformance results may be submitted up to three months in advance
|
||||
of the product reaching initial shipment.
|
||||
|
||||
3. Conformance results carry forward for a given GPU as the operating
|
||||
system and graphics driver are upgraded, unless there is an
|
||||
expectation that conformance may have been affected. In that case, the
|
||||
GPU vendor should submit new conformance results.
|
||||
2. Conformance results carry forward for a given GPU as the operating
|
||||
system and graphics driver are upgraded but do not cause any previously
|
||||
passing test to fail.
|
||||
|
||||
Discussion
|
||||
==========
|
||||
|
|
|
@ -69,9 +69,11 @@ There are various URL options you can pass in.
|
|||
History
|
||||
-------
|
||||
|
||||
The dates below are when work on the conformance suite version was started.
|
||||
|
||||
- 2011/02/24: Version 1.0.0
|
||||
- 2012/02/23: Version 1.0.1
|
||||
- 2012/03/20: Version 1.0.2
|
||||
- 2013/02/14: Version 1.0.3
|
||||
- 2013/10/11: Version 2.0.0 (beta)
|
||||
|
||||
- 2014/11/14: Version 1.0.4
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# This is a list of contributors to the Closure Library.
|
||||
|
||||
# Names should be added to this file like so:
|
||||
# Name or Organization <email address>
|
||||
|
||||
Google Inc.
|
||||
Stellar Science Ltd.
|
||||
Mohamed Mansour <hello@mohamedmansour.com>
|
||||
Bjorn Tipling <bjorn.tipling@gmail.com>
|
||||
SameGoal LLC <help@samegoal.com>
|
||||
Guido Tapia <guido.tapia@gmail.com>
|
||||
Andrew Mattie <amattie@gmail.com>
|
||||
Ilia Mirkin <ibmirkin@gmail.com>
|
||||
Ivan Kozik <ivan.kozik@gmail.com>
|
||||
Rich Dougherty <rich@rd.gen.nz>
|
||||
Chad Killingsworth <chadkillingsworth@missouristate.edu>
|
||||
Dan Pupius <dan.pupius@gmail.com>
|
||||
Mike Dunn <dunn74@gmail.com>
|
||||
Kengo Toda <skypencil@gmail.com>
|
|
@ -0,0 +1,48 @@
|
|||
Closure Library welcomes patches/pulls for features and bugfixes.
|
||||
|
||||
For contributors inside Google, follow the instructions given here:
|
||||
http://go/closure-contributors
|
||||
|
||||
For contributors external to Google, follow the instructions given here:
|
||||
|
||||
Notes on Contributions to Closure Library
|
||||
|
||||
Google Individual Contributor License
|
||||
|
||||
In all cases, contributors must sign a contributor license agreement,
|
||||
either for an individual or corporation, before a patch can be
|
||||
accepted. Please fill out the agreement for an individual or a
|
||||
corporation, as appropriate.
|
||||
|
||||
https://developers.google.com/open-source/cla/individual
|
||||
https://developers.google.com/open-source/cla/corporate
|
||||
|
||||
If you or your organization is not listed there already, you should
|
||||
add an entry to the AUTHORS file as part of your patch.
|
||||
|
||||
If you plan to add a significant component or large chunk of code, it
|
||||
is recommended to bring it up on the discussion list for a design
|
||||
discussion before writing code.
|
||||
|
||||
If appropriate, write a unit test that demonstrates your patch. Tests are the
|
||||
best way to ensure that future contributors do not break your code
|
||||
accidentally.
|
||||
|
||||
To change the Closure Library source, you must submit a pull request
|
||||
in GitHub. See the GitHub documentation here:
|
||||
|
||||
https://help.github.com/categories/63/articles
|
||||
|
||||
Closure Library developers monitor outstanding pull requests. They may
|
||||
request changes on the pull request before accepting. They will also
|
||||
verify that the CLA has been signed.
|
||||
|
||||
Oftentimes, the pull request will not be directly merged, but patched to
|
||||
the internal Google codebase to verify that unit and integration tests
|
||||
will Closure pass before submitting (and optionally make changes to
|
||||
the patch to match style, fix text, or to make the code or comments
|
||||
clearer). In this case, the issue associated with the pull request
|
||||
will be closed when the patch pushed to the repository via the MOE
|
||||
(Make Open Easy) system.
|
||||
|
||||
https://code.google.com/p/moe-java/
|
|
@ -0,0 +1,176 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
|
@ -0,0 +1,20 @@
|
|||
This is a partial snapshot of the Closure library workspace from:
|
||||
|
||||
https://github.com/google/closure-library
|
||||
|
||||
It contains only the portions needed to type check the ported dEQP
|
||||
tests, namely:
|
||||
|
||||
closure/goog/base.js
|
||||
closure/goog/deps.js
|
||||
|
||||
and supporting scripts in closure/bin/ .
|
||||
|
||||
The current version snapshotted here is:
|
||||
|
||||
-----
|
||||
commit 57bdfe0093cc158fb3a58d2c5f7d75ece8c4b45b
|
||||
Author: Nathan Naze <nanaze@gmail.com>
|
||||
Date: Fri Apr 24 18:38:26 2015 -0400
|
||||
|
||||
fix bad merge
|
|
@ -0,0 +1,9 @@
|
|||
# Closure Library
|
||||
|
||||
Closure Library is a powerful, low-level JavaScript library designed
|
||||
for building complex and scalable web applications. It is used by many
|
||||
Google web applications, such as Gmail and Google Docs.
|
||||
|
||||
For more information, visit the
|
||||
[Google Developers](https://developers.google.com/closure/library) or
|
||||
[GitHub](https://github.com/google/closure-library) sites.
|
|
@ -0,0 +1,287 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Utility for Closure Library dependency calculation.
|
||||
|
||||
ClosureBuilder scans source files to build dependency info. From the
|
||||
dependencies, the script can produce a manifest in dependency order,
|
||||
a concatenated script, or compiled output from the Closure Compiler.
|
||||
|
||||
Paths to files can be expressed as individual arguments to the tool (intended
|
||||
for use with find and xargs). As a convenience, --root can be used to specify
|
||||
all JS files below a directory.
|
||||
|
||||
usage: %prog [options] [file1.js file2.js ...]
|
||||
"""
|
||||
|
||||
__author__ = 'nnaze@google.com (Nathan Naze)'
|
||||
|
||||
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
import depstree
|
||||
import jscompiler
|
||||
import source
|
||||
import treescan
|
||||
|
||||
|
||||
def _GetOptionsParser():
|
||||
"""Get the options parser."""
|
||||
|
||||
parser = optparse.OptionParser(__doc__)
|
||||
parser.add_option('-i',
|
||||
'--input',
|
||||
dest='inputs',
|
||||
action='append',
|
||||
default=[],
|
||||
help='One or more input files to calculate dependencies '
|
||||
'for. The namespaces in this file will be combined with '
|
||||
'those given with the -n flag to form the set of '
|
||||
'namespaces to find dependencies for.')
|
||||
parser.add_option('-n',
|
||||
'--namespace',
|
||||
dest='namespaces',
|
||||
action='append',
|
||||
default=[],
|
||||
help='One or more namespaces to calculate dependencies '
|
||||
'for. These namespaces will be combined with those given '
|
||||
'with the -i flag to form the set of namespaces to find '
|
||||
'dependencies for. A Closure namespace is a '
|
||||
'dot-delimited path expression declared with a call to '
|
||||
'goog.provide() (e.g. "goog.array" or "foo.bar").')
|
||||
parser.add_option('--root',
|
||||
dest='roots',
|
||||
action='append',
|
||||
default=[],
|
||||
help='The paths that should be traversed to build the '
|
||||
'dependencies.')
|
||||
parser.add_option('-o',
|
||||
'--output_mode',
|
||||
dest='output_mode',
|
||||
type='choice',
|
||||
action='store',
|
||||
choices=['list', 'script', 'compiled'],
|
||||
default='list',
|
||||
help='The type of output to generate from this script. '
|
||||
'Options are "list" for a list of filenames, "script" '
|
||||
'for a single script containing the contents of all the '
|
||||
'files, or "compiled" to produce compiled output with '
|
||||
'the Closure Compiler. Default is "list".')
|
||||
parser.add_option('-c',
|
||||
'--compiler_jar',
|
||||
dest='compiler_jar',
|
||||
action='store',
|
||||
help='The location of the Closure compiler .jar file.')
|
||||
parser.add_option('-f',
|
||||
'--compiler_flags',
|
||||
dest='compiler_flags',
|
||||
default=[],
|
||||
action='append',
|
||||
help='Additional flags to pass to the Closure compiler. '
|
||||
'To pass multiple flags, --compiler_flags has to be '
|
||||
'specified multiple times.')
|
||||
parser.add_option('-j',
|
||||
'--jvm_flags',
|
||||
dest='jvm_flags',
|
||||
default=[],
|
||||
action='append',
|
||||
help='Additional flags to pass to the JVM compiler. '
|
||||
'To pass multiple flags, --jvm_flags has to be '
|
||||
'specified multiple times.')
|
||||
parser.add_option('--output_file',
|
||||
dest='output_file',
|
||||
action='store',
|
||||
help=('If specified, write output to this path instead of '
|
||||
'writing to standard output.'))
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def _GetInputByPath(path, sources):
|
||||
"""Get the source identified by a path.
|
||||
|
||||
Args:
|
||||
path: str, A path to a file that identifies a source.
|
||||
sources: An iterable collection of source objects.
|
||||
|
||||
Returns:
|
||||
The source from sources identified by path, if found. Converts to
|
||||
real paths for comparison.
|
||||
"""
|
||||
for js_source in sources:
|
||||
# Convert both to real paths for comparison.
|
||||
if os.path.realpath(path) == os.path.realpath(js_source.GetPath()):
|
||||
return js_source
|
||||
|
||||
|
||||
def _GetClosureBaseFile(sources):
|
||||
"""Given a set of sources, returns the one base.js file.
|
||||
|
||||
Note that if zero or two or more base.js files are found, an error message
|
||||
will be written and the program will be exited.
|
||||
|
||||
Args:
|
||||
sources: An iterable of _PathSource objects.
|
||||
|
||||
Returns:
|
||||
The _PathSource representing the base Closure file.
|
||||
"""
|
||||
base_files = [
|
||||
js_source for js_source in sources if _IsClosureBaseFile(js_source)]
|
||||
|
||||
if not base_files:
|
||||
logging.error('No Closure base.js file found.')
|
||||
sys.exit(1)
|
||||
if len(base_files) > 1:
|
||||
logging.error('More than one Closure base.js files found at these paths:')
|
||||
for base_file in base_files:
|
||||
logging.error(base_file.GetPath())
|
||||
sys.exit(1)
|
||||
return base_files[0]
|
||||
|
||||
|
||||
def _IsClosureBaseFile(js_source):
|
||||
"""Returns true if the given _PathSource is the Closure base.js source."""
|
||||
return (os.path.basename(js_source.GetPath()) == 'base.js' and
|
||||
js_source.provides == set(['goog']))
|
||||
|
||||
|
||||
class _PathSource(source.Source):
|
||||
"""Source file subclass that remembers its file path."""
|
||||
|
||||
def __init__(self, path):
|
||||
"""Initialize a source.
|
||||
|
||||
Args:
|
||||
path: str, Path to a JavaScript file. The source string will be read
|
||||
from this file.
|
||||
"""
|
||||
super(_PathSource, self).__init__(source.GetFileContents(path))
|
||||
|
||||
self._path = path
|
||||
|
||||
def __str__(self):
|
||||
return 'PathSource %s' % self._path
|
||||
|
||||
def GetPath(self):
|
||||
"""Returns the path."""
|
||||
return self._path
|
||||
|
||||
|
||||
def _WrapGoogModuleSource(src):
|
||||
return ('goog.loadModule(function(exports) {{'
|
||||
'"use strict";'
|
||||
'{0}'
|
||||
'\n' # terminate any trailing single line comment.
|
||||
';return exports'
|
||||
'}});\n').format(src)
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig(format=(sys.argv[0] + ': %(message)s'),
|
||||
level=logging.INFO)
|
||||
options, args = _GetOptionsParser().parse_args()
|
||||
|
||||
# Make our output pipe.
|
||||
if options.output_file:
|
||||
out = open(options.output_file, 'w')
|
||||
else:
|
||||
out = sys.stdout
|
||||
|
||||
sources = set()
|
||||
|
||||
logging.info('Scanning paths...')
|
||||
for path in options.roots:
|
||||
for js_path in treescan.ScanTreeForJsFiles(path):
|
||||
sources.add(_PathSource(js_path))
|
||||
|
||||
# Add scripts specified on the command line.
|
||||
for js_path in args:
|
||||
sources.add(_PathSource(js_path))
|
||||
|
||||
logging.info('%s sources scanned.', len(sources))
|
||||
|
||||
# Though deps output doesn't need to query the tree, we still build it
|
||||
# to validate dependencies.
|
||||
logging.info('Building dependency tree..')
|
||||
tree = depstree.DepsTree(sources)
|
||||
|
||||
input_namespaces = set()
|
||||
inputs = options.inputs or []
|
||||
for input_path in inputs:
|
||||
js_input = _GetInputByPath(input_path, sources)
|
||||
if not js_input:
|
||||
logging.error('No source matched input %s', input_path)
|
||||
sys.exit(1)
|
||||
input_namespaces.update(js_input.provides)
|
||||
|
||||
input_namespaces.update(options.namespaces)
|
||||
|
||||
if not input_namespaces:
|
||||
logging.error('No namespaces found. At least one namespace must be '
|
||||
'specified with the --namespace or --input flags.')
|
||||
sys.exit(2)
|
||||
|
||||
# The Closure Library base file must go first.
|
||||
base = _GetClosureBaseFile(sources)
|
||||
deps = [base] + tree.GetDependencies(input_namespaces)
|
||||
|
||||
output_mode = options.output_mode
|
||||
if output_mode == 'list':
|
||||
out.writelines([js_source.GetPath() + '\n' for js_source in deps])
|
||||
elif output_mode == 'script':
|
||||
for js_source in deps:
|
||||
src = js_source.GetSource()
|
||||
if js_source.is_goog_module:
|
||||
src = _WrapGoogModuleSource(src)
|
||||
out.write(src + '\n')
|
||||
elif output_mode == 'compiled':
|
||||
logging.warning("""\
|
||||
Closure Compiler now natively understands and orders Closure dependencies and
|
||||
is prefererred over using this script for performing JavaScript compilation.
|
||||
|
||||
Please migrate your codebase.
|
||||
|
||||
See:
|
||||
https://github.com/google/closure-compiler/wiki/Manage-Closure-Dependencies
|
||||
""")
|
||||
|
||||
# Make sure a .jar is specified.
|
||||
if not options.compiler_jar:
|
||||
logging.error('--compiler_jar flag must be specified if --output is '
|
||||
'"compiled"')
|
||||
sys.exit(2)
|
||||
|
||||
# Will throw an error if the compilation fails.
|
||||
compiled_source = jscompiler.Compile(
|
||||
options.compiler_jar,
|
||||
[js_source.GetPath() for js_source in deps],
|
||||
jvm_flags=options.jvm_flags,
|
||||
compiler_flags=options.compiler_flags)
|
||||
|
||||
logging.info('JavaScript compilation succeeded.')
|
||||
out.write(compiled_source)
|
||||
|
||||
else:
|
||||
logging.error('Invalid value for --output flag.')
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,189 @@
|
|||
# Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
"""Class to represent a full Closure Library dependency tree.
|
||||
|
||||
Offers a queryable tree of dependencies of a given set of sources. The tree
|
||||
will also do logical validation to prevent duplicate provides and circular
|
||||
dependencies.
|
||||
"""
|
||||
|
||||
__author__ = 'nnaze@google.com (Nathan Naze)'
|
||||
|
||||
|
||||
class DepsTree(object):
|
||||
"""Represents the set of dependencies between source files."""
|
||||
|
||||
def __init__(self, sources):
|
||||
"""Initializes the tree with a set of sources.
|
||||
|
||||
Args:
|
||||
sources: A set of JavaScript sources.
|
||||
|
||||
Raises:
|
||||
MultipleProvideError: A namespace is provided by muplitple sources.
|
||||
NamespaceNotFoundError: A namespace is required but never provided.
|
||||
"""
|
||||
|
||||
self._sources = sources
|
||||
self._provides_map = dict()
|
||||
|
||||
# Ensure nothing was provided twice.
|
||||
for source in sources:
|
||||
for provide in source.provides:
|
||||
if provide in self._provides_map:
|
||||
raise MultipleProvideError(
|
||||
provide, [self._provides_map[provide], source])
|
||||
|
||||
self._provides_map[provide] = source
|
||||
|
||||
# Check that all required namespaces are provided.
|
||||
for source in sources:
|
||||
for require in source.requires:
|
||||
if require not in self._provides_map:
|
||||
raise NamespaceNotFoundError(require, source)
|
||||
|
||||
def GetDependencies(self, required_namespaces):
|
||||
"""Get source dependencies, in order, for the given namespaces.
|
||||
|
||||
Args:
|
||||
required_namespaces: A string (for one) or list (for one or more) of
|
||||
namespaces.
|
||||
|
||||
Returns:
|
||||
A list of source objects that provide those namespaces and all
|
||||
requirements, in dependency order.
|
||||
|
||||
Raises:
|
||||
NamespaceNotFoundError: A namespace is requested but doesn't exist.
|
||||
CircularDependencyError: A cycle is detected in the dependency tree.
|
||||
"""
|
||||
if isinstance(required_namespaces, str):
|
||||
required_namespaces = [required_namespaces]
|
||||
|
||||
deps_sources = []
|
||||
|
||||
for namespace in required_namespaces:
|
||||
for source in DepsTree._ResolveDependencies(
|
||||
namespace, [], self._provides_map, []):
|
||||
if source not in deps_sources:
|
||||
deps_sources.append(source)
|
||||
|
||||
return deps_sources
|
||||
|
||||
@staticmethod
|
||||
def _ResolveDependencies(required_namespace, deps_list, provides_map,
|
||||
traversal_path):
|
||||
"""Resolve dependencies for Closure source files.
|
||||
|
||||
Follows the dependency tree down and builds a list of sources in dependency
|
||||
order. This function will recursively call itself to fill all dependencies
|
||||
below the requested namespaces, and then append its sources at the end of
|
||||
the list.
|
||||
|
||||
Args:
|
||||
required_namespace: String of required namespace.
|
||||
deps_list: List of sources in dependency order. This function will append
|
||||
the required source once all of its dependencies are satisfied.
|
||||
provides_map: Map from namespace to source that provides it.
|
||||
traversal_path: List of namespaces of our path from the root down the
|
||||
dependency/recursion tree. Used to identify cyclical dependencies.
|
||||
This is a list used as a stack -- when the function is entered, the
|
||||
current namespace is pushed and popped right before returning.
|
||||
Each recursive call will check that the current namespace does not
|
||||
appear in the list, throwing a CircularDependencyError if it does.
|
||||
|
||||
Returns:
|
||||
The given deps_list object filled with sources in dependency order.
|
||||
|
||||
Raises:
|
||||
NamespaceNotFoundError: A namespace is requested but doesn't exist.
|
||||
CircularDependencyError: A cycle is detected in the dependency tree.
|
||||
"""
|
||||
|
||||
source = provides_map.get(required_namespace)
|
||||
if not source:
|
||||
raise NamespaceNotFoundError(required_namespace)
|
||||
|
||||
if required_namespace in traversal_path:
|
||||
traversal_path.append(required_namespace) # do this *after* the test
|
||||
|
||||
# This must be a cycle.
|
||||
raise CircularDependencyError(traversal_path)
|
||||
|
||||
# If we don't have the source yet, we'll have to visit this namespace and
|
||||
# add the required dependencies to deps_list.
|
||||
if source not in deps_list:
|
||||
traversal_path.append(required_namespace)
|
||||
|
||||
for require in source.requires:
|
||||
|
||||
# Append all other dependencies before we append our own.
|
||||
DepsTree._ResolveDependencies(require, deps_list, provides_map,
|
||||
traversal_path)
|
||||
deps_list.append(source)
|
||||
|
||||
traversal_path.pop()
|
||||
|
||||
return deps_list
|
||||
|
||||
|
||||
class BaseDepsTreeError(Exception):
|
||||
"""Base DepsTree error."""
|
||||
|
||||
def __init__(self):
|
||||
Exception.__init__(self)
|
||||
|
||||
|
||||
class CircularDependencyError(BaseDepsTreeError):
|
||||
"""Raised when a dependency cycle is encountered."""
|
||||
|
||||
def __init__(self, dependency_list):
|
||||
BaseDepsTreeError.__init__(self)
|
||||
self._dependency_list = dependency_list
|
||||
|
||||
def __str__(self):
|
||||
return ('Encountered circular dependency:\n%s\n' %
|
||||
'\n'.join(self._dependency_list))
|
||||
|
||||
|
||||
class MultipleProvideError(BaseDepsTreeError):
|
||||
"""Raised when a namespace is provided more than once."""
|
||||
|
||||
def __init__(self, namespace, sources):
|
||||
BaseDepsTreeError.__init__(self)
|
||||
self._namespace = namespace
|
||||
self._sources = sources
|
||||
|
||||
def __str__(self):
|
||||
source_strs = map(str, self._sources)
|
||||
|
||||
return ('Namespace "%s" provided more than once in sources:\n%s\n' %
|
||||
(self._namespace, '\n'.join(source_strs)))
|
||||
|
||||
|
||||
class NamespaceNotFoundError(BaseDepsTreeError):
|
||||
"""Raised when a namespace is requested but not provided."""
|
||||
|
||||
def __init__(self, namespace, source=None):
|
||||
BaseDepsTreeError.__init__(self)
|
||||
self._namespace = namespace
|
||||
self._source = source
|
||||
|
||||
def __str__(self):
|
||||
msg = 'Namespace "%s" never provided.' % self._namespace
|
||||
if self._source:
|
||||
msg += ' Required in %s' % self._source
|
||||
return msg
|
|
@ -0,0 +1,204 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
"""Generates out a Closure deps.js file given a list of JavaScript sources.
|
||||
|
||||
Paths can be specified as arguments or (more commonly) specifying trees
|
||||
with the flags (call with --help for descriptions).
|
||||
|
||||
Usage: depswriter.py [path/to/js1.js [path/to/js2.js] ...]
|
||||
"""
|
||||
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import posixpath
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
import source
|
||||
import treescan
|
||||
|
||||
|
||||
__author__ = 'nnaze@google.com (Nathan Naze)'
|
||||
|
||||
|
||||
def MakeDepsFile(source_map):
|
||||
"""Make a generated deps file.
|
||||
|
||||
Args:
|
||||
source_map: A dict map of the source path to source.Source object.
|
||||
|
||||
Returns:
|
||||
str, A generated deps file source.
|
||||
"""
|
||||
|
||||
# Write in path alphabetical order
|
||||
paths = sorted(source_map.keys())
|
||||
|
||||
lines = []
|
||||
|
||||
for path in paths:
|
||||
js_source = source_map[path]
|
||||
|
||||
# We don't need to add entries that don't provide anything.
|
||||
if js_source.provides:
|
||||
lines.append(_GetDepsLine(path, js_source))
|
||||
|
||||
return ''.join(lines)
|
||||
|
||||
|
||||
def _GetDepsLine(path, js_source):
|
||||
"""Get a deps.js file string for a source."""
|
||||
|
||||
provides = sorted(js_source.provides)
|
||||
requires = sorted(js_source.requires)
|
||||
module = 'true' if js_source.is_goog_module else 'false'
|
||||
|
||||
return 'goog.addDependency(\'%s\', %s, %s, %s);\n' % (
|
||||
path, provides, requires, module)
|
||||
|
||||
|
||||
def _GetOptionsParser():
|
||||
"""Get the options parser."""
|
||||
|
||||
parser = optparse.OptionParser(__doc__)
|
||||
|
||||
parser.add_option('--output_file',
|
||||
dest='output_file',
|
||||
action='store',
|
||||
help=('If specified, write output to this path instead of '
|
||||
'writing to standard output.'))
|
||||
parser.add_option('--root',
|
||||
dest='roots',
|
||||
default=[],
|
||||
action='append',
|
||||
help='A root directory to scan for JS source files. '
|
||||
'Paths of JS files in generated deps file will be '
|
||||
'relative to this path. This flag may be specified '
|
||||
'multiple times.')
|
||||
parser.add_option('--root_with_prefix',
|
||||
dest='roots_with_prefix',
|
||||
default=[],
|
||||
action='append',
|
||||
help='A root directory to scan for JS source files, plus '
|
||||
'a prefix (if either contains a space, surround with '
|
||||
'quotes). Paths in generated deps file will be relative '
|
||||
'to the root, but preceded by the prefix. This flag '
|
||||
'may be specified multiple times.')
|
||||
parser.add_option('--path_with_depspath',
|
||||
dest='paths_with_depspath',
|
||||
default=[],
|
||||
action='append',
|
||||
help='A path to a source file and an alternate path to '
|
||||
'the file in the generated deps file (if either contains '
|
||||
'a space, surround with whitespace). This flag may be '
|
||||
'specified multiple times.')
|
||||
return parser
|
||||
|
||||
|
||||
def _NormalizePathSeparators(path):
|
||||
"""Replaces OS-specific path separators with POSIX-style slashes.
|
||||
|
||||
Args:
|
||||
path: str, A file path.
|
||||
|
||||
Returns:
|
||||
str, The path with any OS-specific path separators (such as backslash on
|
||||
Windows) replaced with URL-compatible forward slashes. A no-op on systems
|
||||
that use POSIX paths.
|
||||
"""
|
||||
return path.replace(os.sep, posixpath.sep)
|
||||
|
||||
|
||||
def _GetRelativePathToSourceDict(root, prefix=''):
|
||||
"""Scans a top root directory for .js sources.
|
||||
|
||||
Args:
|
||||
root: str, Root directory.
|
||||
prefix: str, Prefix for returned paths.
|
||||
|
||||
Returns:
|
||||
dict, A map of relative paths (with prefix, if given), to source.Source
|
||||
objects.
|
||||
"""
|
||||
# Remember and restore the cwd when we're done. We work from the root so
|
||||
# that paths are relative from the root.
|
||||
start_wd = os.getcwd()
|
||||
os.chdir(root)
|
||||
|
||||
path_to_source = {}
|
||||
for path in treescan.ScanTreeForJsFiles('.'):
|
||||
prefixed_path = _NormalizePathSeparators(os.path.join(prefix, path))
|
||||
path_to_source[prefixed_path] = source.Source(source.GetFileContents(path))
|
||||
|
||||
os.chdir(start_wd)
|
||||
|
||||
return path_to_source
|
||||
|
||||
|
||||
def _GetPair(s):
|
||||
"""Return a string as a shell-parsed tuple. Two values expected."""
|
||||
try:
|
||||
# shlex uses '\' as an escape character, so they must be escaped.
|
||||
s = s.replace('\\', '\\\\')
|
||||
first, second = shlex.split(s)
|
||||
return (first, second)
|
||||
except:
|
||||
raise Exception('Unable to parse input line as a pair: %s' % s)
|
||||
|
||||
|
||||
def main():
|
||||
"""CLI frontend to MakeDepsFile."""
|
||||
logging.basicConfig(format=(sys.argv[0] + ': %(message)s'),
|
||||
level=logging.INFO)
|
||||
options, args = _GetOptionsParser().parse_args()
|
||||
|
||||
path_to_source = {}
|
||||
|
||||
# Roots without prefixes
|
||||
for root in options.roots:
|
||||
path_to_source.update(_GetRelativePathToSourceDict(root))
|
||||
|
||||
# Roots with prefixes
|
||||
for root_and_prefix in options.roots_with_prefix:
|
||||
root, prefix = _GetPair(root_and_prefix)
|
||||
path_to_source.update(_GetRelativePathToSourceDict(root, prefix=prefix))
|
||||
|
||||
# Source paths
|
||||
for path in args:
|
||||
path_to_source[path] = source.Source(source.GetFileContents(path))
|
||||
|
||||
# Source paths with alternate deps paths
|
||||
for path_with_depspath in options.paths_with_depspath:
|
||||
srcpath, depspath = _GetPair(path_with_depspath)
|
||||
path_to_source[depspath] = source.Source(source.GetFileContents(srcpath))
|
||||
|
||||
# Make our output pipe.
|
||||
if options.output_file:
|
||||
out = open(options.output_file, 'w')
|
||||
else:
|
||||
out = sys.stdout
|
||||
|
||||
out.write('// This file was autogenerated by %s.\n' % sys.argv[0])
|
||||
out.write('// Please do not edit.\n')
|
||||
|
||||
out.write(MakeDepsFile(path_to_source))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,135 @@
|
|||
# Copyright 2010 The Closure Library Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Utility to use the Closure Compiler CLI from Python."""
|
||||
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
|
||||
# Pulls just the major and minor version numbers from the first line of
|
||||
# 'java -version'. Versions are in the format of [0-9]+\.[0-9]+\..* See:
|
||||
# http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html
|
||||
_VERSION_REGEX = re.compile(r'"([0-9]+)\.([0-9]+)')
|
||||
|
||||
|
||||
class JsCompilerError(Exception):
|
||||
"""Raised if there's an error in calling the compiler."""
|
||||
pass
|
||||
|
||||
|
||||
def _GetJavaVersionString():
|
||||
"""Get the version string from the Java VM."""
|
||||
return subprocess.check_output(['java', '-version'], stderr=subprocess.STDOUT)
|
||||
|
||||
|
||||
def _ParseJavaVersion(version_string):
|
||||
"""Returns a 2-tuple for the current version of Java installed.
|
||||
|
||||
Args:
|
||||
version_string: String of the Java version (e.g. '1.7.2-ea').
|
||||
|
||||
Returns:
|
||||
The major and minor versions, as a 2-tuple (e.g. (1, 7)).
|
||||
"""
|
||||
match = _VERSION_REGEX.search(version_string)
|
||||
if match:
|
||||
version = tuple(int(x, 10) for x in match.groups())
|
||||
assert len(version) == 2
|
||||
return version
|
||||
|
||||
|
||||
def _JavaSupports32BitMode():
|
||||
"""Determines whether the JVM supports 32-bit mode on the platform."""
|
||||
# Suppresses process output to stderr and stdout from showing up in the
|
||||
# console as we're only trying to determine 32-bit JVM support.
|
||||
supported = False
|
||||
try:
|
||||
devnull = open(os.devnull, 'wb')
|
||||
return subprocess.call(
|
||||
['java', '-d32', '-version'], stdout=devnull, stderr=devnull) == 0
|
||||
except IOError:
|
||||
pass
|
||||
else:
|
||||
devnull.close()
|
||||
return supported
|
||||
|
||||
|
||||
def _GetJsCompilerArgs(compiler_jar_path, java_version, source_paths,
|
||||
jvm_flags, compiler_flags):
|
||||
"""Assembles arguments for call to JsCompiler."""
|
||||
|
||||
if java_version < (1, 7):
|
||||
raise JsCompilerError('Closure Compiler requires Java 1.7 or higher. '
|
||||
'Please visit http://www.java.com/getjava')
|
||||
|
||||
args = ['java']
|
||||
|
||||
# Add JVM flags we believe will produce the best performance. See
|
||||
# https://groups.google.com/forum/#!topic/closure-library-discuss/7w_O9-vzlj4
|
||||
|
||||
# Attempt 32-bit mode if available (Java 7 on Mac OS X does not support 32-bit
|
||||
# mode, for example).
|
||||
if _JavaSupports32BitMode():
|
||||
args += ['-d32']
|
||||
|
||||
# Prefer the "client" VM.
|
||||
args += ['-client']
|
||||
|
||||
# Add JVM flags, if any
|
||||
if jvm_flags:
|
||||
args += jvm_flags
|
||||
|
||||
# Add the application JAR.
|
||||
args += ['-jar', compiler_jar_path]
|
||||
|
||||
for path in source_paths:
|
||||
args += ['--js', path]
|
||||
|
||||
# Add compiler flags, if any.
|
||||
if compiler_flags:
|
||||
args += compiler_flags
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def Compile(compiler_jar_path, source_paths,
|
||||
jvm_flags=None,
|
||||
compiler_flags=None):
|
||||
"""Prepares command-line call to Closure Compiler.
|
||||
|
||||
Args:
|
||||
compiler_jar_path: Path to the Closure compiler .jar file.
|
||||
source_paths: Source paths to build, in order.
|
||||
jvm_flags: A list of additional flags to pass on to JVM.
|
||||
compiler_flags: A list of additional flags to pass on to Closure Compiler.
|
||||
|
||||
Returns:
|
||||
The compiled source, as a string, or None if compilation failed.
|
||||
"""
|
||||
|
||||
java_version = _ParseJavaVersion(_GetJavaVersionString())
|
||||
|
||||
args = _GetJsCompilerArgs(
|
||||
compiler_jar_path, java_version, source_paths, jvm_flags, compiler_flags)
|
||||
|
||||
logging.info('Compiling with the following command: %s', ' '.join(args))
|
||||
|
||||
try:
|
||||
return subprocess.check_output(args)
|
||||
except subprocess.CalledProcessError:
|
||||
raise JsCompilerError('JavaScript compilation failed.')
|
|
@ -0,0 +1,127 @@
|
|||
# Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
"""Scans a source JS file for its provided and required namespaces.
|
||||
|
||||
Simple class to scan a JavaScript file and express its dependencies.
|
||||
"""
|
||||
|
||||
__author__ = 'nnaze@google.com'
|
||||
|
||||
|
||||
import re
|
||||
|
||||
_BASE_REGEX_STRING = r'^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)'
|
||||
_MODULE_REGEX = re.compile(_BASE_REGEX_STRING % 'module')
|
||||
_PROVIDE_REGEX = re.compile(_BASE_REGEX_STRING % 'provide')
|
||||
|
||||
_REQUIRE_REGEX_STRING = (r'^\s*(?:(?:var|let|const)\s+[a-zA-Z_$][a-zA-Z0-9$_]*'
|
||||
r'\s*=\s*)?goog\.require\(\s*[\'"](.+)[\'"]\s*\)')
|
||||
_REQUIRES_REGEX = re.compile(_REQUIRE_REGEX_STRING)
|
||||
|
||||
|
||||
class Source(object):
|
||||
"""Scans a JavaScript source for its provided and required namespaces."""
|
||||
|
||||
# Matches a "/* ... */" comment.
|
||||
# Note: We can't definitively distinguish a "/*" in a string literal without a
|
||||
# state machine tokenizer. We'll assume that a line starting with whitespace
|
||||
# and "/*" is a comment.
|
||||
_COMMENT_REGEX = re.compile(
|
||||
r"""
|
||||
^\s* # Start of a new line and whitespace
|
||||
/\* # Opening "/*"
|
||||
.*? # Non greedy match of any characters (including newlines)
|
||||
\*/ # Closing "*/""",
|
||||
re.MULTILINE | re.DOTALL | re.VERBOSE)
|
||||
|
||||
def __init__(self, source):
|
||||
"""Initialize a source.
|
||||
|
||||
Args:
|
||||
source: str, The JavaScript source.
|
||||
"""
|
||||
|
||||
self.provides = set()
|
||||
self.requires = set()
|
||||
self.is_goog_module = False
|
||||
|
||||
self._source = source
|
||||
self._ScanSource()
|
||||
|
||||
def GetSource(self):
|
||||
"""Get the source as a string."""
|
||||
return self._source
|
||||
|
||||
@classmethod
|
||||
def _StripComments(cls, source):
|
||||
return cls._COMMENT_REGEX.sub('', source)
|
||||
|
||||
@classmethod
|
||||
def _HasProvideGoogFlag(cls, source):
|
||||
"""Determines whether the @provideGoog flag is in a comment."""
|
||||
for comment_content in cls._COMMENT_REGEX.findall(source):
|
||||
if '@provideGoog' in comment_content:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _ScanSource(self):
|
||||
"""Fill in provides and requires by scanning the source."""
|
||||
|
||||
stripped_source = self._StripComments(self.GetSource())
|
||||
|
||||
source_lines = stripped_source.splitlines()
|
||||
for line in source_lines:
|
||||
match = _PROVIDE_REGEX.match(line)
|
||||
if match:
|
||||
self.provides.add(match.group(1))
|
||||
match = _MODULE_REGEX.match(line)
|
||||
if match:
|
||||
self.provides.add(match.group(1))
|
||||
self.is_goog_module = True
|
||||
match = _REQUIRES_REGEX.match(line)
|
||||
if match:
|
||||
self.requires.add(match.group(1))
|
||||
|
||||
# Closure's base file implicitly provides 'goog'.
|
||||
# This is indicated with the @provideGoog flag.
|
||||
if self._HasProvideGoogFlag(self.GetSource()):
|
||||
|
||||
if len(self.provides) or len(self.requires):
|
||||
raise Exception(
|
||||
'Base file should not provide or require namespaces.')
|
||||
|
||||
self.provides.add('goog')
|
||||
|
||||
|
||||
def GetFileContents(path):
|
||||
"""Get a file's contents as a string.
|
||||
|
||||
Args:
|
||||
path: str, Path to file.
|
||||
|
||||
Returns:
|
||||
str, Contents of file.
|
||||
|
||||
Raises:
|
||||
IOError: An error occurred opening or reading the file.
|
||||
|
||||
"""
|
||||
fileobj = open(path)
|
||||
try:
|
||||
return fileobj.read()
|
||||
finally:
|
||||
fileobj.close()
|
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2010 The Closure Library Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
"""Shared utility functions for scanning directory trees."""
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
__author__ = 'nnaze@google.com (Nathan Naze)'
|
||||
|
||||
|
||||
# Matches a .js file path.
|
||||
_JS_FILE_REGEX = re.compile(r'^.+\.js$')
|
||||
|
||||
|
||||
def ScanTreeForJsFiles(root):
|
||||
"""Scans a directory tree for JavaScript files.
|
||||
|
||||
Args:
|
||||
root: str, Path to a root directory.
|
||||
|
||||
Returns:
|
||||
An iterable of paths to JS files, relative to cwd.
|
||||
"""
|
||||
return ScanTree(root, path_filter=_JS_FILE_REGEX)
|
||||
|
||||
|
||||
def ScanTree(root, path_filter=None, ignore_hidden=True):
|
||||
"""Scans a directory tree for files.
|
||||
|
||||
Args:
|
||||
root: str, Path to a root directory.
|
||||
path_filter: A regular expression filter. If set, only paths matching
|
||||
the path_filter are returned.
|
||||
ignore_hidden: If True, do not follow or return hidden directories or files
|
||||
(those starting with a '.' character).
|
||||
|
||||
Yields:
|
||||
A string path to files, relative to cwd.
|
||||
"""
|
||||
|
||||
def OnError(os_error):
|
||||
raise os_error
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(root, onerror=OnError):
|
||||
# os.walk allows us to modify dirnames to prevent decent into particular
|
||||
# directories. Avoid hidden directories.
|
||||
for dirname in dirnames:
|
||||
if ignore_hidden and dirname.startswith('.'):
|
||||
dirnames.remove(dirname)
|
||||
|
||||
for filename in filenames:
|
||||
|
||||
# nothing that starts with '.'
|
||||
if ignore_hidden and filename.startswith('.'):
|
||||
continue
|
||||
|
||||
fullpath = os.path.join(dirpath, filename)
|
||||
|
||||
if path_filter and not path_filter.match(fullpath):
|
||||
continue
|
||||
|
||||
yield os.path.normpath(fullpath)
|
|
@ -0,0 +1,590 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2006 The Closure Library Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
"""Calculates JavaScript dependencies without requiring Google's build system.
|
||||
|
||||
This tool is deprecated and is provided for legacy users.
|
||||
See build/closurebuilder.py and build/depswriter.py for the current tools.
|
||||
|
||||
It iterates over a number of search paths and builds a dependency tree. With
|
||||
the inputs provided, it walks the dependency tree and outputs all the files
|
||||
required for compilation.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
import distutils.version
|
||||
except ImportError:
|
||||
# distutils is not available in all environments
|
||||
distutils = None
|
||||
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
_BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)'
|
||||
req_regex = re.compile(_BASE_REGEX_STRING % 'require')
|
||||
prov_regex = re.compile(_BASE_REGEX_STRING % 'provide')
|
||||
ns_regex = re.compile('^ns:((\w+\.)*(\w+))$')
|
||||
version_regex = re.compile('[\.0-9]+')
|
||||
|
||||
|
||||
def IsValidFile(ref):
|
||||
"""Returns true if the provided reference is a file and exists."""
|
||||
return os.path.isfile(ref)
|
||||
|
||||
|
||||
def IsJsFile(ref):
|
||||
"""Returns true if the provided reference is a Javascript file."""
|
||||
return ref.endswith('.js')
|
||||
|
||||
|
||||
def IsNamespace(ref):
|
||||
"""Returns true if the provided reference is a namespace."""
|
||||
return re.match(ns_regex, ref) is not None
|
||||
|
||||
|
||||
def IsDirectory(ref):
|
||||
"""Returns true if the provided reference is a directory."""
|
||||
return os.path.isdir(ref)
|
||||
|
||||
|
||||
def ExpandDirectories(refs):
|
||||
"""Expands any directory references into inputs.
|
||||
|
||||
Description:
|
||||
Looks for any directories in the provided references. Found directories
|
||||
are recursively searched for .js files, which are then added to the result
|
||||
list.
|
||||
|
||||
Args:
|
||||
refs: a list of references such as files, directories, and namespaces
|
||||
|
||||
Returns:
|
||||
A list of references with directories removed and replaced by any
|
||||
.js files that are found in them. Also, the paths will be normalized.
|
||||
"""
|
||||
result = []
|
||||
for ref in refs:
|
||||
if IsDirectory(ref):
|
||||
# Disable 'Unused variable' for subdirs
|
||||
# pylint: disable=unused-variable
|
||||
for (directory, subdirs, filenames) in os.walk(ref):
|
||||
for filename in filenames:
|
||||
if IsJsFile(filename):
|
||||
result.append(os.path.join(directory, filename))
|
||||
else:
|
||||
result.append(ref)
|
||||
return map(os.path.normpath, result)
|
||||
|
||||
|
||||
class DependencyInfo(object):
|
||||
"""Represents a dependency that is used to build and walk a tree."""
|
||||
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.provides = []
|
||||
self.requires = []
|
||||
|
||||
def __str__(self):
|
||||
return '%s Provides: %s Requires: %s' % (self.filename,
|
||||
repr(self.provides),
|
||||
repr(self.requires))
|
||||
|
||||
|
||||
def BuildDependenciesFromFiles(files):
|
||||
"""Build a list of dependencies from a list of files.
|
||||
|
||||
Description:
|
||||
Takes a list of files, extracts their provides and requires, and builds
|
||||
out a list of dependency objects.
|
||||
|
||||
Args:
|
||||
files: a list of files to be parsed for goog.provides and goog.requires.
|
||||
|
||||
Returns:
|
||||
A list of dependency objects, one for each file in the files argument.
|
||||
"""
|
||||
result = []
|
||||
filenames = set()
|
||||
for filename in files:
|
||||
if filename in filenames:
|
||||
continue
|
||||
|
||||
# Python 3 requires the file encoding to be specified
|
||||
if (sys.version_info[0] < 3):
|
||||
file_handle = open(filename, 'r')
|
||||
else:
|
||||
file_handle = open(filename, 'r', encoding='utf8')
|
||||
|
||||
try:
|
||||
dep = CreateDependencyInfo(filename, file_handle)
|
||||
result.append(dep)
|
||||
finally:
|
||||
file_handle.close()
|
||||
|
||||
filenames.add(filename)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def CreateDependencyInfo(filename, source):
|
||||
"""Create dependency info.
|
||||
|
||||
Args:
|
||||
filename: Filename for source.
|
||||
source: File-like object containing source.
|
||||
|
||||
Returns:
|
||||
A DependencyInfo object with provides and requires filled.
|
||||
"""
|
||||
dep = DependencyInfo(filename)
|
||||
for line in source:
|
||||
if re.match(req_regex, line):
|
||||
dep.requires.append(re.search(req_regex, line).group(1))
|
||||
if re.match(prov_regex, line):
|
||||
dep.provides.append(re.search(prov_regex, line).group(1))
|
||||
return dep
|
||||
|
||||
|
||||
def BuildDependencyHashFromDependencies(deps):
|
||||
"""Builds a hash for searching dependencies by the namespaces they provide.
|
||||
|
||||
Description:
|
||||
Dependency objects can provide multiple namespaces. This method enumerates
|
||||
the provides of each dependency and adds them to a hash that can be used
|
||||
to easily resolve a given dependency by a namespace it provides.
|
||||
|
||||
Args:
|
||||
deps: a list of dependency objects used to build the hash.
|
||||
|
||||
Raises:
|
||||
Exception: If a multiple files try to provide the same namepace.
|
||||
|
||||
Returns:
|
||||
A hash table { namespace: dependency } that can be used to resolve a
|
||||
dependency by a namespace it provides.
|
||||
"""
|
||||
dep_hash = {}
|
||||
for dep in deps:
|
||||
for provide in dep.provides:
|
||||
if provide in dep_hash:
|
||||
raise Exception('Duplicate provide (%s) in (%s, %s)' % (
|
||||
provide,
|
||||
dep_hash[provide].filename,
|
||||
dep.filename))
|
||||
dep_hash[provide] = dep
|
||||
return dep_hash
|
||||
|
||||
|
||||
def CalculateDependencies(paths, inputs):
|
||||
"""Calculates the dependencies for given inputs.
|
||||
|
||||
Description:
|
||||
This method takes a list of paths (files, directories) and builds a
|
||||
searchable data structure based on the namespaces that each .js file
|
||||
provides. It then parses through each input, resolving dependencies
|
||||
against this data structure. The final output is a list of files,
|
||||
including the inputs, that represent all of the code that is needed to
|
||||
compile the given inputs.
|
||||
|
||||
Args:
|
||||
paths: the references (files, directories) that are used to build the
|
||||
dependency hash.
|
||||
inputs: the inputs (files, directories, namespaces) that have dependencies
|
||||
that need to be calculated.
|
||||
|
||||
Raises:
|
||||
Exception: if a provided input is invalid.
|
||||
|
||||
Returns:
|
||||
A list of all files, including inputs, that are needed to compile the given
|
||||
inputs.
|
||||
"""
|
||||
deps = BuildDependenciesFromFiles(paths + inputs)
|
||||
search_hash = BuildDependencyHashFromDependencies(deps)
|
||||
result_list = []
|
||||
seen_list = []
|
||||
for input_file in inputs:
|
||||
if IsNamespace(input_file):
|
||||
namespace = re.search(ns_regex, input_file).group(1)
|
||||
if namespace not in search_hash:
|
||||
raise Exception('Invalid namespace (%s)' % namespace)
|
||||
input_file = search_hash[namespace].filename
|
||||
if not IsValidFile(input_file) or not IsJsFile(input_file):
|
||||
raise Exception('Invalid file (%s)' % input_file)
|
||||
seen_list.append(input_file)
|
||||
file_handle = open(input_file, 'r')
|
||||
try:
|
||||
for line in file_handle:
|
||||
if re.match(req_regex, line):
|
||||
require = re.search(req_regex, line).group(1)
|
||||
ResolveDependencies(require, search_hash, result_list, seen_list)
|
||||
finally:
|
||||
file_handle.close()
|
||||
result_list.append(input_file)
|
||||
|
||||
# All files depend on base.js, so put it first.
|
||||
base_js_path = FindClosureBasePath(paths)
|
||||
if base_js_path:
|
||||
result_list.insert(0, base_js_path)
|
||||
else:
|
||||
logging.warning('Closure Library base.js not found.')
|
||||
|
||||
return result_list
|
||||
|
||||
|
||||
def FindClosureBasePath(paths):
|
||||
"""Given a list of file paths, return Closure base.js path, if any.
|
||||
|
||||
Args:
|
||||
paths: A list of paths.
|
||||
|
||||
Returns:
|
||||
The path to Closure's base.js file including filename, if found.
|
||||
"""
|
||||
|
||||
for path in paths:
|
||||
pathname, filename = os.path.split(path)
|
||||
|
||||
if filename == 'base.js':
|
||||
f = open(path)
|
||||
|
||||
is_base = False
|
||||
|
||||
# Sanity check that this is the Closure base file. Check that this
|
||||
# is where goog is defined. This is determined by the @provideGoog
|
||||
# flag.
|
||||
for line in f:
|
||||
if '@provideGoog' in line:
|
||||
is_base = True
|
||||
break
|
||||
|
||||
f.close()
|
||||
|
||||
if is_base:
|
||||
return path
|
||||
|
||||
def ResolveDependencies(require, search_hash, result_list, seen_list):
|
||||
"""Takes a given requirement and resolves all of the dependencies for it.
|
||||
|
||||
Description:
|
||||
A given requirement may require other dependencies. This method
|
||||
recursively resolves all dependencies for the given requirement.
|
||||
|
||||
Raises:
|
||||
Exception: when require does not exist in the search_hash.
|
||||
|
||||
Args:
|
||||
require: the namespace to resolve dependencies for.
|
||||
search_hash: the data structure used for resolving dependencies.
|
||||
result_list: a list of filenames that have been calculated as dependencies.
|
||||
This variable is the output for this function.
|
||||
seen_list: a list of filenames that have been 'seen'. This is required
|
||||
for the dependency->dependant ordering.
|
||||
"""
|
||||
if require not in search_hash:
|
||||
raise Exception('Missing provider for (%s)' % require)
|
||||
|
||||
dep = search_hash[require]
|
||||
if not dep.filename in seen_list:
|
||||
seen_list.append(dep.filename)
|
||||
for sub_require in dep.requires:
|
||||
ResolveDependencies(sub_require, search_hash, result_list, seen_list)
|
||||
result_list.append(dep.filename)
|
||||
|
||||
|
||||
def GetDepsLine(dep, base_path):
|
||||
"""Returns a JS string for a dependency statement in the deps.js file.
|
||||
|
||||
Args:
|
||||
dep: The dependency that we're printing.
|
||||
base_path: The path to Closure's base.js including filename.
|
||||
"""
|
||||
return 'goog.addDependency("%s", %s, %s);' % (
|
||||
GetRelpath(dep.filename, base_path), dep.provides, dep.requires)
|
||||
|
||||
|
||||
def GetRelpath(path, start):
|
||||
"""Return a relative path to |path| from |start|."""
|
||||
# NOTE: Python 2.6 provides os.path.relpath, which has almost the same
|
||||
# functionality as this function. Since we want to support 2.4, we have
|
||||
# to implement it manually. :(
|
||||
path_list = os.path.abspath(os.path.normpath(path)).split(os.sep)
|
||||
start_list = os.path.abspath(
|
||||
os.path.normpath(os.path.dirname(start))).split(os.sep)
|
||||
|
||||
common_prefix_count = 0
|
||||
for i in range(0, min(len(path_list), len(start_list))):
|
||||
if path_list[i] != start_list[i]:
|
||||
break
|
||||
common_prefix_count += 1
|
||||
|
||||
# Always use forward slashes, because this will get expanded to a url,
|
||||
# not a file path.
|
||||
return '/'.join(['..'] * (len(start_list) - common_prefix_count) +
|
||||
path_list[common_prefix_count:])
|
||||
|
||||
|
||||
def PrintLine(msg, out):
|
||||
out.write(msg)
|
||||
out.write('\n')
|
||||
|
||||
|
||||
def PrintDeps(source_paths, deps, out):
|
||||
"""Print out a deps.js file from a list of source paths.
|
||||
|
||||
Args:
|
||||
source_paths: Paths that we should generate dependency info for.
|
||||
deps: Paths that provide dependency info. Their dependency info should
|
||||
not appear in the deps file.
|
||||
out: The output file.
|
||||
|
||||
Returns:
|
||||
True on success, false if it was unable to find the base path
|
||||
to generate deps relative to.
|
||||
"""
|
||||
base_path = FindClosureBasePath(source_paths + deps)
|
||||
if not base_path:
|
||||
return False
|
||||
|
||||
PrintLine('// This file was autogenerated by calcdeps.py', out)
|
||||
excludesSet = set(deps)
|
||||
|
||||
for dep in BuildDependenciesFromFiles(source_paths + deps):
|
||||
if not dep.filename in excludesSet:
|
||||
PrintLine(GetDepsLine(dep, base_path), out)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def PrintScript(source_paths, out):
|
||||
for index, dep in enumerate(source_paths):
|
||||
PrintLine('// Input %d' % index, out)
|
||||
f = open(dep, 'r')
|
||||
PrintLine(f.read(), out)
|
||||
f.close()
|
||||
|
||||
|
||||
def GetJavaVersion():
|
||||
"""Returns the string for the current version of Java installed."""
|
||||
proc = subprocess.Popen(['java', '-version'], stderr=subprocess.PIPE)
|
||||
proc.wait()
|
||||
version_line = proc.stderr.read().splitlines()[0]
|
||||
return version_regex.search(version_line).group()
|
||||
|
||||
|
||||
def FilterByExcludes(options, files):
|
||||
"""Filters the given files by the exlusions specified at the command line.
|
||||
|
||||
Args:
|
||||
options: The flags to calcdeps.
|
||||
files: The files to filter.
|
||||
Returns:
|
||||
A list of files.
|
||||
"""
|
||||
excludes = []
|
||||
if options.excludes:
|
||||
excludes = ExpandDirectories(options.excludes)
|
||||
|
||||
excludesSet = set(excludes)
|
||||
return [i for i in files if not i in excludesSet]
|
||||
|
||||
|
||||
def GetPathsFromOptions(options):
|
||||
"""Generates the path files from flag options.
|
||||
|
||||
Args:
|
||||
options: The flags to calcdeps.
|
||||
Returns:
|
||||
A list of files in the specified paths. (strings).
|
||||
"""
|
||||
|
||||
search_paths = options.paths
|
||||
if not search_paths:
|
||||
search_paths = ['.'] # Add default folder if no path is specified.
|
||||
|
||||
search_paths = ExpandDirectories(search_paths)
|
||||
return FilterByExcludes(options, search_paths)
|
||||
|
||||
|
||||
def GetInputsFromOptions(options):
|
||||
"""Generates the inputs from flag options.
|
||||
|
||||
Args:
|
||||
options: The flags to calcdeps.
|
||||
Returns:
|
||||
A list of inputs (strings).
|
||||
"""
|
||||
inputs = options.inputs
|
||||
if not inputs: # Parse stdin
|
||||
logging.info('No inputs specified. Reading from stdin...')
|
||||
inputs = filter(None, [line.strip('\n') for line in sys.stdin.readlines()])
|
||||
|
||||
logging.info('Scanning files...')
|
||||
inputs = ExpandDirectories(inputs)
|
||||
|
||||
return FilterByExcludes(options, inputs)
|
||||
|
||||
|
||||
def Compile(compiler_jar_path, source_paths, out, flags=None):
|
||||
"""Prepares command-line call to Closure compiler.
|
||||
|
||||
Args:
|
||||
compiler_jar_path: Path to the Closure compiler .jar file.
|
||||
source_paths: Source paths to build, in order.
|
||||
flags: A list of additional flags to pass on to Closure compiler.
|
||||
"""
|
||||
args = ['java', '-jar', compiler_jar_path]
|
||||
for path in source_paths:
|
||||
args += ['--js', path]
|
||||
|
||||
if flags:
|
||||
args += flags
|
||||
|
||||
logging.info('Compiling with the following command: %s', ' '.join(args))
|
||||
proc = subprocess.Popen(args, stdout=subprocess.PIPE)
|
||||
(stdoutdata, stderrdata) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
logging.error('JavaScript compilation failed.')
|
||||
sys.exit(1)
|
||||
else:
|
||||
out.write(stdoutdata)
|
||||
|
||||
|
||||
def main():
|
||||
"""The entrypoint for this script."""
|
||||
|
||||
logging.basicConfig(format='calcdeps.py: %(message)s', level=logging.INFO)
|
||||
|
||||
usage = 'usage: %prog [options] arg'
|
||||
parser = optparse.OptionParser(usage)
|
||||
parser.add_option('-i',
|
||||
'--input',
|
||||
dest='inputs',
|
||||
action='append',
|
||||
help='The inputs to calculate dependencies for. Valid '
|
||||
'values can be files, directories, or namespaces '
|
||||
'(ns:goog.net.XhrIo). Only relevant to "list" and '
|
||||
'"script" output.')
|
||||
parser.add_option('-p',
|
||||
'--path',
|
||||
dest='paths',
|
||||
action='append',
|
||||
help='The paths that should be traversed to build the '
|
||||
'dependencies.')
|
||||
parser.add_option('-d',
|
||||
'--dep',
|
||||
dest='deps',
|
||||
action='append',
|
||||
help='Directories or files that should be traversed to '
|
||||
'find required dependencies for the deps file. '
|
||||
'Does not generate dependency information for names '
|
||||
'provided by these files. Only useful in "deps" mode.')
|
||||
parser.add_option('-e',
|
||||
'--exclude',
|
||||
dest='excludes',
|
||||
action='append',
|
||||
help='Files or directories to exclude from the --path '
|
||||
'and --input flags')
|
||||
parser.add_option('-o',
|
||||
'--output_mode',
|
||||
dest='output_mode',
|
||||
action='store',
|
||||
default='list',
|
||||
help='The type of output to generate from this script. '
|
||||
'Options are "list" for a list of filenames, "script" '
|
||||
'for a single script containing the contents of all the '
|
||||
'file, "deps" to generate a deps.js file for all '
|
||||
'paths, or "compiled" to produce compiled output with '
|
||||
'the Closure compiler.')
|
||||
parser.add_option('-c',
|
||||
'--compiler_jar',
|
||||
dest='compiler_jar',
|
||||
action='store',
|
||||
help='The location of the Closure compiler .jar file.')
|
||||
parser.add_option('-f',
|
||||
'--compiler_flag',
|
||||
'--compiler_flags', # for backwards compatability
|
||||
dest='compiler_flags',
|
||||
action='append',
|
||||
help='Additional flag to pass to the Closure compiler. '
|
||||
'May be specified multiple times to pass multiple flags.')
|
||||
parser.add_option('--output_file',
|
||||
dest='output_file',
|
||||
action='store',
|
||||
help=('If specified, write output to this path instead of '
|
||||
'writing to standard output.'))
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
search_paths = GetPathsFromOptions(options)
|
||||
|
||||
if options.output_file:
|
||||
out = open(options.output_file, 'w')
|
||||
else:
|
||||
out = sys.stdout
|
||||
|
||||
if options.output_mode == 'deps':
|
||||
result = PrintDeps(search_paths, ExpandDirectories(options.deps or []), out)
|
||||
if not result:
|
||||
logging.error('Could not find Closure Library in the specified paths')
|
||||
sys.exit(1)
|
||||
|
||||
return
|
||||
|
||||
inputs = GetInputsFromOptions(options)
|
||||
|
||||
logging.info('Finding Closure dependencies...')
|
||||
deps = CalculateDependencies(search_paths, inputs)
|
||||
output_mode = options.output_mode
|
||||
|
||||
if output_mode == 'script':
|
||||
PrintScript(deps, out)
|
||||
elif output_mode == 'list':
|
||||
# Just print out a dep per line
|
||||
for dep in deps:
|
||||
PrintLine(dep, out)
|
||||
elif output_mode == 'compiled':
|
||||
# Make sure a .jar is specified.
|
||||
if not options.compiler_jar:
|
||||
logging.error('--compiler_jar flag must be specified if --output is '
|
||||
'"compiled"')
|
||||
sys.exit(1)
|
||||
|
||||
# User friendly version check.
|
||||
if distutils and not (distutils.version.LooseVersion(GetJavaVersion()) >
|
||||
distutils.version.LooseVersion('1.6')):
|
||||
logging.error('Closure Compiler requires Java 1.6 or higher.')
|
||||
logging.error('Please visit http://www.java.com/getjava')
|
||||
sys.exit(1)
|
||||
|
||||
Compile(options.compiler_jar, deps, out, options.compiler_flags)
|
||||
|
||||
else:
|
||||
logging.error('Invalid value for --output flag.')
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,221 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Copyright 2010 The Closure Library Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
"""Automatically converts codebases over to goog.scope.
|
||||
|
||||
Usage:
|
||||
cd path/to/my/dir;
|
||||
../../../../javascript/closure/bin/scopify.py
|
||||
|
||||
Scans every file in this directory, recursively. Looks for existing
|
||||
goog.scope calls, and goog.require'd symbols. If it makes sense to
|
||||
generate a goog.scope call for the file, then we will do so, and
|
||||
try to auto-generate some aliases based on the goog.require'd symbols.
|
||||
|
||||
Known Issues:
|
||||
|
||||
When a file is goog.scope'd, the file contents will be indented +2.
|
||||
This may put some lines over 80 chars. These will need to be fixed manually.
|
||||
|
||||
We will only try to create aliases for capitalized names. We do not check
|
||||
to see if those names will conflict with any existing locals.
|
||||
|
||||
This creates merge conflicts for every line of every outstanding change.
|
||||
If you intend to run this on your codebase, make sure your team members
|
||||
know. Better yet, send them this script so that they can scopify their
|
||||
outstanding changes and "accept theirs".
|
||||
|
||||
When an alias is "captured", it can no longer be stubbed out for testing.
|
||||
Run your tests.
|
||||
|
||||
"""
|
||||
|
||||
__author__ = 'nicksantos@google.com (Nick Santos)'
|
||||
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
|
||||
REQUIRES_RE = re.compile(r"goog.require\('([^']*)'\)")
|
||||
|
||||
# Edit this manually if you want something to "always" be aliased.
|
||||
# TODO(nicksantos): Add a flag for this.
|
||||
DEFAULT_ALIASES = {}
|
||||
|
||||
def Transform(lines):
|
||||
"""Converts the contents of a file into javascript that uses goog.scope.
|
||||
|
||||
Arguments:
|
||||
lines: A list of strings, corresponding to each line of the file.
|
||||
Returns:
|
||||
A new list of strings, or None if the file was not modified.
|
||||
"""
|
||||
requires = []
|
||||
|
||||
# Do an initial scan to be sure that this file can be processed.
|
||||
for line in lines:
|
||||
# Skip this file if it has already been scopified.
|
||||
if line.find('goog.scope') != -1:
|
||||
return None
|
||||
|
||||
# If there are any global vars or functions, then we also have
|
||||
# to skip the whole file. We might be able to deal with this
|
||||
# more elegantly.
|
||||
if line.find('var ') == 0 or line.find('function ') == 0:
|
||||
return None
|
||||
|
||||
for match in REQUIRES_RE.finditer(line):
|
||||
requires.append(match.group(1))
|
||||
|
||||
if len(requires) == 0:
|
||||
return None
|
||||
|
||||
# Backwards-sort the requires, so that when one is a substring of another,
|
||||
# we match the longer one first.
|
||||
for val in DEFAULT_ALIASES.values():
|
||||
if requires.count(val) == 0:
|
||||
requires.append(val)
|
||||
|
||||
requires.sort()
|
||||
requires.reverse()
|
||||
|
||||
# Generate a map of requires to their aliases
|
||||
aliases_to_globals = DEFAULT_ALIASES.copy()
|
||||
for req in requires:
|
||||
index = req.rfind('.')
|
||||
if index == -1:
|
||||
alias = req
|
||||
else:
|
||||
alias = req[(index + 1):]
|
||||
|
||||
# Don't scopify lowercase namespaces, because they may conflict with
|
||||
# local variables.
|
||||
if alias[0].isupper():
|
||||
aliases_to_globals[alias] = req
|
||||
|
||||
aliases_to_matchers = {}
|
||||
globals_to_aliases = {}
|
||||
for alias, symbol in aliases_to_globals.items():
|
||||
globals_to_aliases[symbol] = alias
|
||||
aliases_to_matchers[alias] = re.compile('\\b%s\\b' % symbol)
|
||||
|
||||
# Insert a goog.scope that aliases all required symbols.
|
||||
result = []
|
||||
|
||||
START = 0
|
||||
SEEN_REQUIRES = 1
|
||||
IN_SCOPE = 2
|
||||
|
||||
mode = START
|
||||
aliases_used = set()
|
||||
insertion_index = None
|
||||
num_blank_lines = 0
|
||||
for line in lines:
|
||||
if mode == START:
|
||||
result.append(line)
|
||||
|
||||
if re.search(REQUIRES_RE, line):
|
||||
mode = SEEN_REQUIRES
|
||||
|
||||
elif mode == SEEN_REQUIRES:
|
||||
if (line and
|
||||
not re.search(REQUIRES_RE, line) and
|
||||
not line.isspace()):
|
||||
# There should be two blank lines before goog.scope
|
||||
result += ['\n'] * 2
|
||||
result.append('goog.scope(function() {\n')
|
||||
insertion_index = len(result)
|
||||
result += ['\n'] * num_blank_lines
|
||||
mode = IN_SCOPE
|
||||
elif line.isspace():
|
||||
# Keep track of the number of blank lines before each block of code so
|
||||
# that we can move them after the goog.scope line if necessary.
|
||||
num_blank_lines += 1
|
||||
else:
|
||||
# Print the blank lines we saw before this code block
|
||||
result += ['\n'] * num_blank_lines
|
||||
num_blank_lines = 0
|
||||
result.append(line)
|
||||
|
||||
if mode == IN_SCOPE:
|
||||
for symbol in requires:
|
||||
if not symbol in globals_to_aliases:
|
||||
continue
|
||||
|
||||
alias = globals_to_aliases[symbol]
|
||||
matcher = aliases_to_matchers[alias]
|
||||
for match in matcher.finditer(line):
|
||||
# Check to make sure we're not in a string.
|
||||
# We do this by being as conservative as possible:
|
||||
# if there are any quote or double quote characters
|
||||
# before the symbol on this line, then bail out.
|
||||
before_symbol = line[:match.start(0)]
|
||||
if before_symbol.count('"') > 0 or before_symbol.count("'") > 0:
|
||||
continue
|
||||
|
||||
line = line.replace(match.group(0), alias)
|
||||
aliases_used.add(alias)
|
||||
|
||||
if line.isspace():
|
||||
# Truncate all-whitespace lines
|
||||
result.append('\n')
|
||||
else:
|
||||
result.append(line)
|
||||
|
||||
if len(aliases_used):
|
||||
aliases_used = [alias for alias in aliases_used]
|
||||
aliases_used.sort()
|
||||
aliases_used.reverse()
|
||||
for alias in aliases_used:
|
||||
symbol = aliases_to_globals[alias]
|
||||
result.insert(insertion_index,
|
||||
'var %s = %s;\n' % (alias, symbol))
|
||||
result.append('}); // goog.scope\n')
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
def TransformFileAt(path):
|
||||
"""Converts a file into javascript that uses goog.scope.
|
||||
|
||||
Arguments:
|
||||
path: A path to a file.
|
||||
"""
|
||||
f = open(path)
|
||||
lines = Transform(f.readlines())
|
||||
if lines:
|
||||
f = open(path, 'w')
|
||||
for l in lines:
|
||||
f.write(l)
|
||||
f.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = sys.argv[1:]
|
||||
if not len(args):
|
||||
args = '.'
|
||||
|
||||
for file_name in args:
|
||||
if os.path.isdir(file_name):
|
||||
for root, dirs, files in os.walk(file_name):
|
||||
for name in files:
|
||||
if name.endswith('.js') and \
|
||||
not os.path.islink(os.path.join(root, name)):
|
||||
TransformFileAt(os.path.join(root, name))
|
||||
else:
|
||||
if file_name.endswith('.js') and \
|
||||
not os.path.islink(file_name):
|
||||
TransformFileAt(file_name)
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,9 +1,10 @@
|
|||
--min-version 1.0.3 gl-bindAttribLocation-aliasing.html
|
||||
--min-version 1.0.3 gl-bindAttribLocation-matrix.html
|
||||
--min-version 1.0.4 gl-bindAttribLocation-repeated.html
|
||||
--min-version 1.0.2 gl-disabled-vertex-attrib.html
|
||||
gl-enable-vertex-attrib.html
|
||||
--min-version 1.0.3 gl-matrix-attributes.html
|
||||
gl-vertex-attrib.html
|
||||
--max-version 1.9.9 gl-vertex-attrib.html
|
||||
gl-vertexattribpointer.html
|
||||
gl-vertexattribpointer-offsets.html
|
||||
--min-version 1.0.2 gl-vertex-attrib-render.html
|
||||
|
|
|
@ -1,90 +1,90 @@
|
|||
<!--
|
||||
/*
|
||||
** Copyright (c) 2014 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<title>bindAttribLocation with aliasing</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
|
||||
<script id="vertexShader" type="text/something-not-javascript">
|
||||
precision mediump float;
|
||||
attribute $(type_1) a_1;
|
||||
attribute $(type_2) a_2;
|
||||
void main() {
|
||||
gl_Position = $(gl_Position_1) + $(gl_Position_2);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
"use strict";
|
||||
description("This test verifies combinations of valid, active attribute types cannot be bound to the same location with bindAttribLocation.");
|
||||
var wtu = WebGLTestUtils;
|
||||
var canvas = document.getElementById("canvas");
|
||||
var gl = wtu.create3DContext(canvas, {antialias: false});
|
||||
var glFragmentShader = wtu.setupSimpleColorFragmentShader(gl);
|
||||
var typeInfo = [
|
||||
{ type: 'float', asVec4: 'vec4(0.0, $(var), 0.0, 1.0)' },
|
||||
{ type: 'vec2', asVec4: 'vec4($(var), 0.0, 1.0)' },
|
||||
{ type: 'vec3', asVec4: 'vec4($(var), 1.0)' },
|
||||
{ type: 'vec4', asVec4: '$(var)' },
|
||||
];
|
||||
var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
|
||||
// Test all type combinations of a_1 and a_2.
|
||||
typeInfo.forEach(function(typeInfo1) {
|
||||
typeInfo.forEach(function(typeInfo2) {
|
||||
debug('attribute_1: ' + typeInfo1.type + ' attribute_2: ' + typeInfo2.type);
|
||||
var replaceParams = {
|
||||
type_1: typeInfo1.type,
|
||||
type_2: typeInfo2.type,
|
||||
gl_Position_1: wtu.replaceParams(typeInfo1.asVec4, {var: 'a_1'}),
|
||||
gl_Position_2: wtu.replaceParams(typeInfo2.asVec4, {var: 'a_2'})
|
||||
};
|
||||
var strVertexShader = wtu.replaceParams(wtu.getScript('vertexShader'), replaceParams);
|
||||
var glVertexShader = wtu.loadShader(gl, strVertexShader, gl.VERTEX_SHADER);
|
||||
assertMsg(glVertexShader != null, "Vertex shader compiled successfully.");
|
||||
// Bind both a_1 and a_2 to the same position and verify the link fails.
|
||||
// Do so for all valid positions available.
|
||||
for (var l = 0; l < maxAttributes; l++) {
|
||||
var glProgram = gl.createProgram();
|
||||
gl.bindAttribLocation(glProgram, l, 'a_1');
|
||||
gl.bindAttribLocation(glProgram, l, 'a_2');
|
||||
gl.attachShader(glProgram, glVertexShader);
|
||||
gl.attachShader(glProgram, glFragmentShader);
|
||||
gl.linkProgram(glProgram);
|
||||
assertMsg(!gl.getProgramParameter(glProgram, gl.LINK_STATUS), "Link should fail when both types are aliased to location " + l);
|
||||
}
|
||||
});
|
||||
});
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
<!--
|
||||
/*
|
||||
** Copyright (c) 2014 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
<title>bindAttribLocation with aliasing</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
|
||||
<script id="vertexShader" type="text/something-not-javascript">
|
||||
precision mediump float;
|
||||
attribute $(type_1) a_1;
|
||||
attribute $(type_2) a_2;
|
||||
void main() {
|
||||
gl_Position = $(gl_Position_1) + $(gl_Position_2);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
"use strict";
|
||||
description("This test verifies combinations of valid, active attribute types cannot be bound to the same location with bindAttribLocation.");
|
||||
var wtu = WebGLTestUtils;
|
||||
var canvas = document.getElementById("canvas");
|
||||
var gl = wtu.create3DContext(canvas, {antialias: false});
|
||||
var glFragmentShader = wtu.loadShader(gl, wtu.simpleColorFragmentShader, gl.FRAGMENT_SHADER);
|
||||
var typeInfo = [
|
||||
{ type: 'float', asVec4: 'vec4(0.0, $(var), 0.0, 1.0)' },
|
||||
{ type: 'vec2', asVec4: 'vec4($(var), 0.0, 1.0)' },
|
||||
{ type: 'vec3', asVec4: 'vec4($(var), 1.0)' },
|
||||
{ type: 'vec4', asVec4: '$(var)' },
|
||||
];
|
||||
var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
|
||||
// Test all type combinations of a_1 and a_2.
|
||||
typeInfo.forEach(function(typeInfo1) {
|
||||
typeInfo.forEach(function(typeInfo2) {
|
||||
debug('attribute_1: ' + typeInfo1.type + ' attribute_2: ' + typeInfo2.type);
|
||||
var replaceParams = {
|
||||
type_1: typeInfo1.type,
|
||||
type_2: typeInfo2.type,
|
||||
gl_Position_1: wtu.replaceParams(typeInfo1.asVec4, {var: 'a_1'}),
|
||||
gl_Position_2: wtu.replaceParams(typeInfo2.asVec4, {var: 'a_2'})
|
||||
};
|
||||
var strVertexShader = wtu.replaceParams(wtu.getScript('vertexShader'), replaceParams);
|
||||
var glVertexShader = wtu.loadShader(gl, strVertexShader, gl.VERTEX_SHADER);
|
||||
assertMsg(glVertexShader != null, "Vertex shader compiled successfully.");
|
||||
// Bind both a_1 and a_2 to the same position and verify the link fails.
|
||||
// Do so for all valid positions available.
|
||||
for (var l = 0; l < maxAttributes; l++) {
|
||||
var glProgram = gl.createProgram();
|
||||
gl.bindAttribLocation(glProgram, l, 'a_1');
|
||||
gl.bindAttribLocation(glProgram, l, 'a_2');
|
||||
gl.attachShader(glProgram, glVertexShader);
|
||||
gl.attachShader(glProgram, glFragmentShader);
|
||||
gl.linkProgram(glProgram);
|
||||
assertMsg(!gl.getProgramParameter(glProgram, gl.LINK_STATUS), "Link should fail when both types are aliased to location " + l);
|
||||
}
|
||||
});
|
||||
});
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<!--
|
||||
<!--
|
||||
|
||||
/*
|
||||
** Copyright (c) 2014 The Khronos Group Inc.
|
||||
|
@ -29,8 +29,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
<title>WebGL bindAttribLocation with Matrix Attributes Conformance Test</title>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -50,7 +50,7 @@ var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
|
|||
debug('MAX_VERTEX_ATTRIBUTES is ' + maxAttributes);
|
||||
shouldBeGreaterThanOrEqual('maxAttributes', '4');
|
||||
|
||||
var glFragmentShader = wtu.setupSimpleColorFragmentShader(gl);
|
||||
var glFragmentShader = wtu.loadShader(gl, wtu.simpleColorFragmentShader, gl.FRAGMENT_SHADER);
|
||||
|
||||
// Given a matrix dimension, load a vertex shader with a matrix of that dimension
|
||||
// and a vector. Ensure that both the vector and matrix are active attributes.
|
||||
|
@ -114,6 +114,6 @@ for (var mm = 2; mm <= 4; ++mm) {
|
|||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<!--
|
||||
|
||||
/*
|
||||
** Copyright (c) 2012 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>WebGL Repeated BindAttribLocation Test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="50" height="50">
|
||||
</canvas>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<script id="vshader" type="x-shader/x-vertex">
|
||||
attribute vec4 vPosition;
|
||||
void main()
|
||||
{
|
||||
gl_Position = vPosition;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="fshader" type="x-shader/x-fragment">
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = vec4(0.0,1.0,0.0,1.0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
description("Test repeated loading of programs involving bindAttribLocation calls");
|
||||
debug("Regression test for <a href='https://code.google.com/p/chromium/issues/detail?id=510637'>crbug.com/510637</a>");
|
||||
var wtu = WebGLTestUtils;
|
||||
var gl = wtu.create3DContext("example");
|
||||
var g_program;
|
||||
var g_attribLocation;
|
||||
function setup(attribIndex) {
|
||||
var program = wtu.setupProgram(
|
||||
gl, ['vshader', 'fshader'], ['vPosition'], [attribIndex]);
|
||||
g_program = program;
|
||||
g_attribLocation = attribIndex;
|
||||
shouldBe("gl.getAttribLocation(g_program, 'vPosition')", "g_attribLocation");
|
||||
return program;
|
||||
}
|
||||
|
||||
var p0 = setup(0);
|
||||
var p3 = setup(3);
|
||||
var p1 = setup(1);
|
||||
// This call fails the getAttribLocation check on some drivers when
|
||||
// Chrome's program binary cache is enabled. On the affected drivers,
|
||||
// it returns the bound attribute location from the first binary
|
||||
// created. Swapping 0 and 1 above will cause it to return 1 rather
|
||||
// than 0.
|
||||
p3 = setup(3);
|
||||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL Disabled Vertex Attrib Test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"> </script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="50" height="50">
|
||||
|
@ -93,7 +93,7 @@ wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors");
|
|||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL Enable Vertex Attrib Test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"> </script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="50" height="50">
|
||||
|
@ -75,7 +75,7 @@ wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
|
|||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
<title>WebGL Matrix Attribute Conformance Test</title>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -50,7 +50,7 @@ var maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
|
|||
debug('MAX_VERTEX_ATTRIBUTES is ' + maxAttributes);
|
||||
shouldBeGreaterThanOrEqual('maxAttributes', '4');
|
||||
|
||||
var glFragmentShader = wtu.setupSimpleColorFragmentShader(gl);
|
||||
var glFragmentShader = wtu.loadShader(gl, wtu.simpleColorFragmentShader, gl.FRAGMENT_SHADER);
|
||||
|
||||
// prepareMatrixProgram creates a program with glFragmentShader as the fragment shader.
|
||||
// The vertex shader has numVector number of vectors and a matrix with numMatrixDimensions
|
||||
|
@ -152,6 +152,6 @@ for (var mm = 2; mm <= 4; ++mm) {
|
|||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -27,84 +27,84 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script id='vshader' type='x-shader'>
|
||||
attribute vec4 a;
|
||||
attribute vec2 p;
|
||||
void main() {
|
||||
gl_Position = vec4(p.x + a.x + a.y + a.z + a.w, p.y, 0.0, 1.0);
|
||||
}
|
||||
</script>
|
||||
<script id='fshader' type='x-shader'>
|
||||
precision mediump float;
|
||||
void main() {
|
||||
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
"use strict";
|
||||
function checkRedPortion(gl, w, low, high) {
|
||||
var buf = new Uint8Array(w * w * 4);
|
||||
gl.readPixels(0, 0, w, w, gl.RGBA, gl.UNSIGNED_BYTE, buf);
|
||||
var i = 0;
|
||||
for (; i < w; ++i) {
|
||||
if (buf[i * 4 + 0] == 255 && buf[i * 4 + 1] == 0 && buf[i * 4 + 2] == 0 && buf[i * 4 + 3] == 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return low <= i && i <= high;
|
||||
}
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
<script id='vshader' type='x-shader'>
|
||||
attribute vec4 a;
|
||||
attribute vec2 p;
|
||||
void main() {
|
||||
gl_Position = vec4(p.x + a.x + a.y + a.z + a.w, p.y, 0.0, 1.0);
|
||||
}
|
||||
</script>
|
||||
<script id='fshader' type='x-shader'>
|
||||
precision mediump float;
|
||||
void main() {
|
||||
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
"use strict";
|
||||
function checkRedPortion(gl, w, low, high) {
|
||||
var buf = new Uint8Array(w * w * 4);
|
||||
gl.readPixels(0, 0, w, w, gl.RGBA, gl.UNSIGNED_BYTE, buf);
|
||||
var i = 0;
|
||||
for (; i < w; ++i) {
|
||||
if (buf[i * 4 + 0] == 255 && buf[i * 4 + 1] == 0 && buf[i * 4 + 2] == 0 && buf[i * 4 + 3] == 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return low <= i && i <= high;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var wtu = WebGLTestUtils;
|
||||
var gl = wtu.create3DContext('testbed', { preserveDrawingBuffer : true });
|
||||
if (!gl) {
|
||||
testFailed('could not create context');
|
||||
return;
|
||||
}
|
||||
var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['p', 'a'])
|
||||
function runTest() {
|
||||
var wtu = WebGLTestUtils;
|
||||
var gl = wtu.create3DContext('testbed', { preserveDrawingBuffer : true });
|
||||
if (!gl) {
|
||||
testFailed('could not create context');
|
||||
return;
|
||||
}
|
||||
var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['p', 'a'])
|
||||
|
||||
gl.enableVertexAttribArray(gl.p);
|
||||
var pos = gl.createBuffer();
|
||||
pos.type = gl.FLOAT;
|
||||
pos.size = 2;
|
||||
pos.num = 4;
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, pos);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(gl.p);
|
||||
var pos = gl.createBuffer();
|
||||
pos.type = gl.FLOAT;
|
||||
pos.size = 2;
|
||||
pos.num = 4;
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, pos);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
|
||||
|
||||
gl.vertexAttribPointer(0, pos.size, pos.type, false, 0, 0);
|
||||
gl.vertexAttribPointer(0, pos.size, pos.type, false, 0, 0);
|
||||
|
||||
debug('Test vertexAttrib[1..4]fv by setting different combinations that add up to 1.5 and use that when rendering.');
|
||||
var vals = [[0.5], [0.1,0.4], [0.2,-0.2,0.5], [-1.0,0.3,0.2,2.0]];
|
||||
debug('Test vertexAttrib[1..4]fv by setting different combinations that add up to 1.5 and use that when rendering.');
|
||||
var vals = [[0.5], [0.1,0.4], [0.2,-0.2,0.5], [-1.0,0.3,0.2,2.0]];
|
||||
|
||||
for (var j = 0; j < 4; ++j) {
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
gl['vertexAttrib' + (j+1) + 'fv'](1, vals[j]);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, pos.num);
|
||||
for (var j = 0; j < 4; ++j) {
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
gl['vertexAttrib' + (j+1) + 'fv'](1, vals[j]);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, pos.num);
|
||||
|
||||
if (checkRedPortion(gl, 50, 50 * 0.7, 50 * 0.8)) {
|
||||
testPassed('Attribute of size ' + (j+1) + ' was set correctly');
|
||||
} else {
|
||||
testFailed('Attribute of size ' + (j+1) + ' was not set correctly');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="testbed" width="50" height="50"></canvas>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<script>
|
||||
"use strict";
|
||||
description('Verify that using constant attributes works.');
|
||||
runTest();
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
</body>
|
||||
if (checkRedPortion(gl, 50, 50 * 0.7, 50 * 0.8)) {
|
||||
testPassed('Attribute of size ' + (j+1) + ' was set correctly');
|
||||
} else {
|
||||
testFailed('Attribute of size ' + (j+1) + ' was not set correctly');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="testbed" width="50" height="50"></canvas>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<script>
|
||||
"use strict";
|
||||
description('Verify that using constant attributes works.');
|
||||
runTest();
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL Enable Vertex Attrib Zero Test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"> </script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="50" height="50">
|
||||
|
@ -145,7 +145,7 @@ for (var ii = 0; ii < 5; ++ii) {
|
|||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -31,88 +31,19 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL vertexAttrib Conformance Tests</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<canvas id="canvas" width="2" height="2"> </canvas>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
description("This test ensures WebGL implementations vertexAttrib can be set and read.");
|
||||
|
||||
debug("");
|
||||
debug("Canvas.getContext");
|
||||
|
||||
var wtu = WebGLTestUtils;
|
||||
var gl = wtu.create3DContext("canvas");
|
||||
if (!gl) {
|
||||
testFailed("context does not exist");
|
||||
} else {
|
||||
testPassed("context exists");
|
||||
|
||||
debug("");
|
||||
debug("Checking gl.vertexAttrib.");
|
||||
|
||||
var numVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
|
||||
for (var ii = 0; ii < numVertexAttribs; ++ii) {
|
||||
gl.vertexAttrib1fv(ii, [1]);
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
|
||||
|
||||
gl.vertexAttrib2fv(ii, [1, 2]);
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
|
||||
|
||||
gl.vertexAttrib3fv(ii, [1, 2, 3]);
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '3');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
|
||||
|
||||
gl.vertexAttrib4fv(ii, [1, 2, 3, 4]);
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '1');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '2');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '3');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '4');
|
||||
|
||||
gl.vertexAttrib1f(ii, 5);
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '5');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '0');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
|
||||
|
||||
gl.vertexAttrib2f(ii, 6, 7);
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '6');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '7');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '0');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
|
||||
|
||||
gl.vertexAttrib3f(ii, 7, 8, 9);
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '7');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '8');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '9');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '1');
|
||||
|
||||
gl.vertexAttrib4f(ii, 6, 7, 8, 9);
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[0]', '6');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[1]', '7');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[2]', '8');
|
||||
shouldBe('gl.getVertexAttrib(' + ii + ', gl.CURRENT_VERTEX_ATTRIB)[3]', '9');
|
||||
}
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
|
||||
}
|
||||
|
||||
debug("");
|
||||
var successfullyParsed = true;
|
||||
|
||||
var contextVersion = 1;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/tests/gl-vertex-attrib.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>vertexattribpointer offsets test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"> </script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="50" height="50">
|
||||
|
@ -175,7 +175,7 @@ There is supposed to be an example drawing here, but it's not important.
|
|||
init();
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL vertexAttribPointer Conformance Tests</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -66,16 +66,18 @@ if (!gl) {
|
|||
var vertexObject = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(0), gl.STATIC_DRAW);
|
||||
|
||||
gl.vertexAttribPointer(0, 1, gl.INT, 0, 0, 0);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
|
||||
"vertexAttribPointer should not support INT");
|
||||
gl.vertexAttribPointer(0, 1, gl.UNSIGNED_INT, 0, 0, 0);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
|
||||
"vertexAttribPointer should not support UNSIGNED_INT");
|
||||
gl.vertexAttribPointer(0, 1, gl.FIXED, 0, 0, 0);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
|
||||
"vertexAttribPointer should not support FIXED");
|
||||
|
||||
if (wtu.getDefault3DContextVersion() < 2) {
|
||||
gl.vertexAttribPointer(0, 1, gl.INT, 0, 0, 0);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
|
||||
"vertexAttribPointer should not support INT");
|
||||
gl.vertexAttribPointer(0, 1, gl.UNSIGNED_INT, 0, 0, 0);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
|
||||
"vertexAttribPointer should not support UNSIGNED_INT");
|
||||
gl.vertexAttribPointer(0, 1, gl.FIXED, 0, 0, 0);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM,
|
||||
"vertexAttribPointer should not support FIXED");
|
||||
}
|
||||
|
||||
var checkVertexAttribPointer = function(
|
||||
gl, err, reason, size, type, normalize, stride, offset) {
|
||||
|
@ -87,6 +89,11 @@ if (!gl) {
|
|||
", " + stride +
|
||||
", " + offset +
|
||||
") should " + (err == gl.NO_ERROR ? "succeed " : "fail ") + reason);
|
||||
shouldBe('gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_SIZE)', size.toString());
|
||||
shouldBe('gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_TYPE)', 'gl.' + wtu.glEnumToString(gl, type));
|
||||
shouldBe('gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED)', normalize.toString());
|
||||
shouldBe('gl.getVertexAttrib(0, gl.VERTEX_ATTRIB_ARRAY_STRIDE)', stride.toString());
|
||||
shouldBe('gl.getVertexAttribOffset(0, gl.VERTEX_ATTRIB_ARRAY_POINTER)', offset.toString());
|
||||
}
|
||||
|
||||
var types = [
|
||||
|
@ -148,7 +155,7 @@ debug("");
|
|||
var successfullyParsed = true;
|
||||
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
buffer-bind-test.html
|
||||
buffer-data-array-buffer.html
|
||||
buffer-data-and-buffer-sub-data.html
|
||||
--min-version 1.0.3 buffer-data-array-buffer-delete.html
|
||||
--min-version 1.0.2 element-array-buffer-delete-recreate.html
|
||||
index-validation-copies-indices.html
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL BindBuffer conformance test.</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"> </script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="40" height="40" style="width: 40px; height: 40px;"></canvas>
|
||||
|
@ -80,7 +80,7 @@ if (!gl) {
|
|||
debug("");
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
<!--
|
||||
|
||||
/*
|
||||
** Copyright (c) 2012 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
description("Test bufferData/bufferSubData with or without ArrayBuffer input");
|
||||
|
||||
debug('Regression test for <a href="https://bugs.webkit.org/show_bug.cgi?id=41884">https://bugs.webkit.org/show_bug.cgi?id=41884</a> : <code>Implement bufferData and bufferSubData with ArrayBuffer as input</code>');
|
||||
|
||||
var wtu = WebGLTestUtils;
|
||||
var gl = wtu.create3DContext();
|
||||
if (!gl) {
|
||||
testFailed("WebGL context does not exist");
|
||||
} else {
|
||||
testPassed("WebGL context exists");
|
||||
|
||||
bufferDataTest();
|
||||
bufferDataSizesTest();
|
||||
|
||||
bufferSubDataTest();
|
||||
}
|
||||
|
||||
function bufferDataTest() {
|
||||
debug("");
|
||||
debug("Test bufferData without ArrayBuffer input");
|
||||
|
||||
var buf = gl.createBuffer();
|
||||
shouldBeNonNull(buf);
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, 4, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "no buffer bound");
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, -4, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
|
||||
"calling bufferData when buffer size is negative should generate INVALID_VALUE");
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, null, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
|
||||
"calling bufferData when BufferDataSource is null should generate INVALID_VALUE");
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, undefined, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
|
||||
"calling bufferData when BufferDataSource is undefined should generate INVALID_VALUE");
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
}
|
||||
|
||||
function bufferDataSizesTest() {
|
||||
debug("");
|
||||
debug("Test bufferData overloads");
|
||||
|
||||
// bufferData has an integer overload and an ArrayBuffer overload.
|
||||
// Per the WebIDL spec, the overload resolution algorithm should resolve types as follows:
|
||||
// - If the argument is null or undefined, pick the nullable type, which is ArrayBuffer.
|
||||
// Per the WebGL spec, null should flag INVALID_VALUE.
|
||||
// - If the argument is an ArrayBuffer, then pick the ArrayBuffer overload
|
||||
// - Everything else should pick the numeric overload. This means things like objects, strings,
|
||||
// floating point numbers, arrays of numbers and strings, etc should convert themselves to a number.
|
||||
var bufferDataParams = [
|
||||
{ parameter: 0, expectedBufferSize: 0 },
|
||||
{ parameter: 4, expectedBufferSize: 4 },
|
||||
{ parameter: 5.1, expectedBufferSize: 5 },
|
||||
{ parameter: 5.8, expectedBufferSize: 5 },
|
||||
{ parameter: 5.5, expectedBufferSize: 5 },
|
||||
|
||||
{ parameter: "4", expectedBufferSize: 4 },
|
||||
{ parameter: "5.1", expectedBufferSize: 5 },
|
||||
{ parameter: "5.8", expectedBufferSize: 5 },
|
||||
{ parameter: "5.5", expectedBufferSize: 5 },
|
||||
{ parameter: "0", expectedBufferSize: 0 },
|
||||
|
||||
{ parameter: [42, 64], expectedBufferSize: 0 },
|
||||
{ parameter: [42], expectedBufferSize: 42 },
|
||||
{ parameter: ["42"], expectedBufferSize: 42 },
|
||||
{ parameter: ["42", "64"], expectedBufferSize: 0 },
|
||||
|
||||
{ parameter: new ArrayBuffer(0), expectedBufferSize: 0 },
|
||||
{ parameter: new ArrayBuffer(4), expectedBufferSize: 4 },
|
||||
|
||||
{ parameter: "WebGL Rocks!", expectedBufferSize: 0 },
|
||||
{ parameter: { mystring: "WebGL Rocks!" }, expectedBufferSize: 0 },
|
||||
];
|
||||
|
||||
bufferDataParams.forEach(function (bufferDataParam) {
|
||||
var buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, bufferDataParam.parameter, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Passing " + bufferDataParam.parameter + " to bufferData");
|
||||
|
||||
shouldEvaluateTo("gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE)", bufferDataParam.expectedBufferSize);
|
||||
});
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
}
|
||||
|
||||
function bufferSubDataTest() {
|
||||
debug("");
|
||||
debug("Test bufferSubData");
|
||||
|
||||
var buf = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 0, new ArrayBuffer(1));
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "Calling bufferSubData before bufferData should fail");
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, 128, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
|
||||
|
||||
var array = new ArrayBuffer(64);
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, -10, array);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
|
||||
"calling bufferSubData with ArrayBuffer when offset is negative should INVALID_VALUE");
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 65, array);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "buffer overflow");
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, -10, new Float32Array(8));
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
|
||||
"calling bufferSubData with ArrayBufferView when offset is negative should generate INVALID_VALUE");
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 10, array);
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
|
||||
"calling bufferSubData with ArrayBuffer should succeed");
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 10, null);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE,
|
||||
"calling bufferSubData when BufferDataSource is null should generate INVALID_VALUE");
|
||||
|
||||
wtu.shouldGenerateGLError(gl, gl.INVALID_VALUE, "gl.bufferSubData(gl.ARRAY_BUFFER, 10, undefined)");
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 10, new Float32Array(0));
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR,
|
||||
"calling bufferSubData with zero-sized ArrayBufferView should succeed");
|
||||
|
||||
// Arguments that are not ArrayBuffers, null or undefined should throw a TypeError exception
|
||||
shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, 42);");
|
||||
shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, 5.5);");
|
||||
shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, \"5.5\");");
|
||||
shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, [4]);");
|
||||
shouldThrow("gl.bufferSubData(gl.ARRAY_BUFFER, 0, { mynumber: 42});");
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
}
|
||||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -30,8 +30,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
<!--
|
||||
|
||||
/*
|
||||
** Copyright (c) 2012 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
description("Test bufferData/bufferSubData with ArrayBuffer input");
|
||||
|
||||
debug('Regression test for <a href="https://bugs.webkit.org/show_bug.cgi?id=41884">https://bugs.webkit.org/show_bug.cgi?id=41884</a> : <code>Implement bufferData and bufferSubData with ArrayBuffer as input</code>');
|
||||
|
||||
var wtu = WebGLTestUtils;
|
||||
var gl = wtu.create3DContext();
|
||||
shouldBeNonNull("gl");
|
||||
|
||||
var array = new ArrayBuffer(128);
|
||||
shouldBeNonNull("array");
|
||||
|
||||
var buf = gl.createBuffer();
|
||||
shouldBeNonNull("buf");
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, -10, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, null, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
|
||||
|
||||
// This should not crash, but the selection of the overload is ambiguous per Web IDL.
|
||||
gl.bufferData(gl.ARRAY_BUFFER, null, gl.STATIC_DRAW);
|
||||
gl.getError();
|
||||
|
||||
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
|
||||
|
||||
array = new ArrayBuffer(64);
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, -10, array);
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, -10, new Float32Array(8));
|
||||
wtu.glErrorShouldBe(gl, gl.INVALID_VALUE);
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 10, array);
|
||||
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
|
||||
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 10, null);
|
||||
wtu.glErrorShouldBe(gl, [gl.NO_ERROR, gl.INVALID_VALUE]);
|
||||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -30,8 +30,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>Element Array Buffer Deletion and Recreation Test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"> </script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="32" height="32"></canvas>
|
||||
|
@ -85,6 +85,6 @@ function init()
|
|||
init();
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -68,6 +68,6 @@ debug("")
|
|||
var successfullyParsed = true;
|
||||
</script>
|
||||
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -54,6 +54,6 @@ testPassed("bufferSubData, when buffer object was initialized with null, did not
|
|||
var successfullyParsed = true;
|
||||
</script>
|
||||
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -72,6 +72,6 @@ debug("")
|
|||
var successfullyParsed = true;
|
||||
</script>
|
||||
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -66,6 +66,6 @@ debug("")
|
|||
var successfullyParsed = true;
|
||||
</script>
|
||||
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="1" height="1"></canvas>
|
||||
|
@ -123,6 +123,6 @@ debug("")
|
|||
var successfullyParsed = true;
|
||||
</script>
|
||||
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -133,6 +133,6 @@ shouldBeUndefined('gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0)');
|
|||
var successfullyParsed = true;
|
||||
</script>
|
||||
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -8,8 +8,8 @@ drawingbuffer-test.html
|
|||
--min-version 1.0.3 draw-webgl-to-canvas-test.html
|
||||
--min-version 1.0.3 draw-static-webgl-to-multiple-canvas-test.html
|
||||
--min-version 1.0.2 framebuffer-bindings-unaffected-on-resize.html
|
||||
--min-version 1.0.4 framebuffer-bindings-affected-by-to-data-url.html
|
||||
--min-version 1.0.3 rapid-resizing.html
|
||||
--min-version 1.0.2 texture-bindings-unaffected-on-resize.html
|
||||
--min-version 1.0.2 to-data-url-test.html
|
||||
viewport-unchanged-upon-resize.html
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL required buffer clear behaviour test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"> </script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
height: 3000px;
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL required buffer clear behaviour test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"> </script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
height: 3000px;
|
||||
|
@ -44,7 +44,7 @@ body {
|
|||
<canvas width="20" height="20" style="border: 1px solid blue;" id="c"></canvas>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<script type="text/javascript">
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
|
||||
description("This test ensures WebGL implementations correctly clear the drawing buffer " +
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL Canvas Conformance Tests</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>Zero Size Canvas Test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"> </script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"> </script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -58,7 +58,7 @@ wtu.clearAndDrawUnitQuad(gl);
|
|||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors from setup.");
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL Canvas Conformance Tests</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL Canvas Conformance Tests</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL DrawingBuffer dimensions on HD-DPI machines test</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -220,6 +220,6 @@ test(256, 512);
|
|||
debug("")
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL Canvas Conformance Tests</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -132,6 +132,6 @@ if (!gl) {
|
|||
debug("")
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>WebGL Canvas.drawingBufferWidth,drawingBufferHeight Conformance Tests</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
|
@ -133,6 +133,6 @@ test(maxSize[0] + 32, 8);
|
|||
debug("")
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
<!--
|
||||
/*
|
||||
** Copyright (c) 2015 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Verifies than GL framebuffer bindings do not change by toDataURL()</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="50" height="50"></canvas>
|
||||
<div id="description"></div>
|
||||
<div id="console"></div>
|
||||
<script>
|
||||
"use strict";
|
||||
description("Verifies than GL framebuffer bindings do not change by toDataURL()");
|
||||
|
||||
var wtu = WebGLTestUtils;
|
||||
function test() {
|
||||
var glCanvas = document.getElementById("example");
|
||||
var gl = wtu.create3DContext(glCanvas, {preserveDrawingBuffer: true, premultipliedAlpha: true});
|
||||
|
||||
var program = wtu.setupColorQuad(gl);
|
||||
|
||||
// Clear backbuffer in red.
|
||||
gl.clearColor(1.0, 0.0, 0.0, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
|
||||
|
||||
var fbo = gl.createFramebuffer();
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 50, 50, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
|
||||
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the FBO in green.
|
||||
gl.clearColor(0.0, 1.0, 0.0, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
// backbuffer is still in red.
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
|
||||
// toDataURL() calls must not bind backbuffer.
|
||||
glCanvas.toDataURL();
|
||||
// Calling twice caused a bug due to wrong cache impl; crbug.com/445848
|
||||
glCanvas.toDataURL();
|
||||
// It must applies to the FBO, not backbuffer.
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
// backbuffer must be in red, not green.
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
wtu.checkCanvas(gl, [255, 0, 0, 255], "should be red");
|
||||
}
|
||||
test();
|
||||
|
||||
var successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../js/js-test-post.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -31,8 +31,8 @@
|
|||
<meta charset="utf-8">
|
||||
<title>Verifies that GL framebuffer bindings do not change when canvas is resized</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
<script src="../../js/js-test-pre.js"></script>
|
||||
<script src="../../js/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="example" width="4" height="4"></canvas>
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче