mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
0903b3fd7b
2
CLOBBER
2
CLOBBER
@ -22,4 +22,4 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1190180 - need clobber for backouts
|
||||
Bug 1186748 needed a CLOBBER again
|
||||
|
@ -692,7 +692,8 @@ void
|
||||
DocAccessible::AttributeWillChange(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute, int32_t aModType)
|
||||
nsIAtom* aAttribute, int32_t aModType,
|
||||
const nsAttrValue* aNewValue)
|
||||
{
|
||||
Accessible* accessible = GetAccessible(aElement);
|
||||
if (!accessible) {
|
||||
@ -733,7 +734,8 @@ void
|
||||
DocAccessible::AttributeChanged(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
NS_ASSERTION(!IsDefunct(),
|
||||
"Attribute changed called on defunct document accessible!");
|
||||
|
@ -9,6 +9,7 @@ let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/ExtensionContent.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
|
||||
"resource:///modules/E10SUtils.jsm");
|
||||
@ -656,3 +657,8 @@ let DOMFullscreenHandler = {
|
||||
}
|
||||
};
|
||||
DOMFullscreenHandler.init();
|
||||
|
||||
ExtensionContent.init(this);
|
||||
addEventListener("unload", () => {
|
||||
ExtensionContent.uninit(this);
|
||||
});
|
||||
|
20
browser/components/extensions/bootstrap.js
vendored
Normal file
20
browser/components/extensions/bootstrap.js
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Extension.jsm");
|
||||
|
||||
let extension;
|
||||
|
||||
function startup(data, reason)
|
||||
{
|
||||
extension = new Extension(data);
|
||||
extension.startup();
|
||||
}
|
||||
|
||||
function shutdown(data, reason)
|
||||
{
|
||||
extension.shutdown();
|
||||
}
|
326
browser/components/extensions/ext-browserAction.js
Normal file
326
browser/components/extensions/ext-browserAction.js
Normal file
@ -0,0 +1,326 @@
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm");
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
let {
|
||||
EventManager,
|
||||
DefaultWeakMap,
|
||||
ignoreEvent,
|
||||
runSafe,
|
||||
} = ExtensionUtils;
|
||||
|
||||
// WeakMap[Extension -> BrowserAction]
|
||||
let browserActionMap = new WeakMap();
|
||||
|
||||
function browserActionOf(extension)
|
||||
{
|
||||
return browserActionMap.get(extension);
|
||||
}
|
||||
|
||||
function makeWidgetId(id)
|
||||
{
|
||||
id = id.toLowerCase();
|
||||
return id.replace(/[^a-z0-9_-]/g, "_");
|
||||
}
|
||||
|
||||
let nextActionId = 0;
|
||||
|
||||
// Responsible for the browser_action section of the manifest as well
|
||||
// as the associated popup.
|
||||
function BrowserAction(options, extension)
|
||||
{
|
||||
this.extension = extension;
|
||||
this.id = makeWidgetId(extension.id) + "-browser-action";
|
||||
this.widget = null;
|
||||
|
||||
this.title = new DefaultWeakMap(extension.localize(options.default_title));
|
||||
this.badgeText = new DefaultWeakMap();
|
||||
this.badgeBackgroundColor = new DefaultWeakMap();
|
||||
this.icon = new DefaultWeakMap(options.default_icon);
|
||||
this.popup = new DefaultWeakMap(options.default_popup);
|
||||
|
||||
// Make the default something that won't compare equal to anything.
|
||||
this.prevPopups = new DefaultWeakMap({});
|
||||
|
||||
this.context = null;
|
||||
}
|
||||
|
||||
BrowserAction.prototype = {
|
||||
build() {
|
||||
let widget = CustomizableUI.createWidget({
|
||||
id: this.id,
|
||||
type: "custom",
|
||||
removable: true,
|
||||
defaultArea: CustomizableUI.AREA_NAVBAR,
|
||||
onBuild: document => {
|
||||
let node = document.createElement("toolbarbutton");
|
||||
node.id = this.id;
|
||||
node.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional badged-button");
|
||||
node.setAttribute("constrain-size", "true");
|
||||
|
||||
this.updateTab(null, node);
|
||||
|
||||
let tabbrowser = document.defaultView.gBrowser;
|
||||
tabbrowser.ownerDocument.addEventListener("TabSelect", () => {
|
||||
this.updateTab(tabbrowser.selectedTab, node);
|
||||
});
|
||||
|
||||
node.addEventListener("command", event => {
|
||||
if (node.getAttribute("type") != "panel") {
|
||||
this.emit("click");
|
||||
}
|
||||
});
|
||||
|
||||
return node;
|
||||
},
|
||||
});
|
||||
this.widget = widget;
|
||||
},
|
||||
|
||||
// Initialize the toolbar icon and popup given that |tab| is the
|
||||
// current tab and |node| is the CustomizableUI node. Note: |tab|
|
||||
// will be null if we don't know the current tab yet (during
|
||||
// initialization).
|
||||
updateTab(tab, node) {
|
||||
let window = node.ownerDocument.defaultView;
|
||||
|
||||
let title = this.getProperty(tab, "title");
|
||||
if (title) {
|
||||
node.setAttribute("tooltiptext", title);
|
||||
node.setAttribute("label", title);
|
||||
} else {
|
||||
node.removeAttribute("tooltiptext");
|
||||
node.removeAttribute("label");
|
||||
}
|
||||
|
||||
let badgeText = this.badgeText.get(tab);
|
||||
if (badgeText) {
|
||||
node.setAttribute("badge", badgeText);
|
||||
} else {
|
||||
node.removeAttribute("badge");
|
||||
}
|
||||
|
||||
function toHex(n) {
|
||||
return Math.floor(n / 16).toString(16) + (n % 16).toString(16);
|
||||
}
|
||||
|
||||
let badgeNode = node.ownerDocument.getAnonymousElementByAttribute(node,
|
||||
'class', 'toolbarbutton-badge');
|
||||
if (badgeNode) {
|
||||
let color = this.badgeBackgroundColor.get(tab);
|
||||
if (Array.isArray(color)) {
|
||||
color = `rgb(${color[0]}, ${color[1]}, ${color[2]})`;
|
||||
}
|
||||
badgeNode.style.backgroundColor = color;
|
||||
}
|
||||
|
||||
let iconURL = this.getIcon(tab, node);
|
||||
node.setAttribute("image", iconURL);
|
||||
|
||||
let popup = this.getProperty(tab, "popup");
|
||||
|
||||
if (popup != this.prevPopups.get(window)) {
|
||||
this.prevPopups.set(window, popup);
|
||||
|
||||
let panel = node.querySelector("panel");
|
||||
if (panel) {
|
||||
panel.remove();
|
||||
}
|
||||
|
||||
if (popup) {
|
||||
let popupURL = this.extension.baseURI.resolve(popup);
|
||||
node.setAttribute("type", "panel");
|
||||
|
||||
let document = node.ownerDocument;
|
||||
let panel = document.createElement("panel");
|
||||
panel.setAttribute("class", "browser-action-panel");
|
||||
panel.setAttribute("type", "arrow");
|
||||
panel.setAttribute("flip", "slide");
|
||||
node.appendChild(panel);
|
||||
|
||||
let browser = document.createElementNS(XUL_NS, "browser");
|
||||
browser.setAttribute("type", "content");
|
||||
browser.setAttribute("disableglobalhistory", "true");
|
||||
browser.setAttribute("width", "500");
|
||||
browser.setAttribute("height", "500");
|
||||
panel.appendChild(browser);
|
||||
|
||||
let loadListener = () => {
|
||||
panel.removeEventListener("load", loadListener);
|
||||
|
||||
if (this.context) {
|
||||
this.context.unload();
|
||||
}
|
||||
|
||||
this.context = new ExtensionPage(this.extension, {
|
||||
type: "popup",
|
||||
contentWindow: browser.contentWindow,
|
||||
uri: Services.io.newURI(popupURL, null, null),
|
||||
docShell: browser.docShell,
|
||||
});
|
||||
GlobalManager.injectInDocShell(browser.docShell, this.extension, this.context);
|
||||
browser.setAttribute("src", popupURL);
|
||||
};
|
||||
panel.addEventListener("load", loadListener);
|
||||
} else {
|
||||
node.removeAttribute("type");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Note: tab is allowed to be null here.
|
||||
getIcon(tab, node) {
|
||||
let icon = this.icon.get(tab);
|
||||
|
||||
let url;
|
||||
if (typeof(icon) != "object") {
|
||||
url = icon;
|
||||
} else {
|
||||
let window = node.ownerDocument.defaultView;
|
||||
let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
let res = {value: 1}
|
||||
utils.getResolution(res);
|
||||
|
||||
let size = res.value == 1 ? 19 : 38;
|
||||
url = icon[size];
|
||||
}
|
||||
|
||||
if (url) {
|
||||
return this.extension.baseURI.resolve(url);
|
||||
} else {
|
||||
return "chrome://browser/content/extension.svg";
|
||||
}
|
||||
},
|
||||
|
||||
// Update the toolbar button for a given window.
|
||||
updateWindow(window) {
|
||||
let tab = window.gBrowser ? window.gBrowser.selectedTab : null;
|
||||
let node = CustomizableUI.getWidget(this.id).forWindow(window).node;
|
||||
this.updateTab(tab, node);
|
||||
},
|
||||
|
||||
// Update the toolbar button when the extension changes the icon,
|
||||
// title, badge, etc. If it only changes a parameter for a single
|
||||
// tab, |tab| will be that tab. Otherwise it will be null.
|
||||
updateOnChange(tab) {
|
||||
if (tab) {
|
||||
if (tab.selected) {
|
||||
this.updateWindow(tab.ownerDocument.defaultView);
|
||||
}
|
||||
} else {
|
||||
let e = Services.wm.getEnumerator("navigator:browser");
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
if (window.gBrowser) {
|
||||
this.updateWindow(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// tab is allowed to be null.
|
||||
// prop should be one of "icon", "title", "badgeText", "popup", or "badgeBackgroundColor".
|
||||
setProperty(tab, prop, value) {
|
||||
this[prop].set(tab, value);
|
||||
this.updateOnChange(tab);
|
||||
},
|
||||
|
||||
// tab is allowed to be null.
|
||||
// prop should be one of "title", "badgeText", "popup", or "badgeBackgroundColor".
|
||||
getProperty(tab, prop) {
|
||||
return this[prop].get(tab);
|
||||
},
|
||||
|
||||
shutdown() {
|
||||
CustomizableUI.destroyWidget(this.id);
|
||||
},
|
||||
};
|
||||
|
||||
EventEmitter.decorate(BrowserAction.prototype);
|
||||
|
||||
extensions.on("manifest_browser_action", (type, directive, extension, manifest) => {
|
||||
let browserAction = new BrowserAction(manifest.browser_action, extension);
|
||||
browserAction.build();
|
||||
browserActionMap.set(extension, browserAction);
|
||||
});
|
||||
|
||||
extensions.on("shutdown", (type, extension) => {
|
||||
if (browserActionMap.has(extension)) {
|
||||
browserActionMap.get(extension).shutdown();
|
||||
browserActionMap.delete(extension);
|
||||
}
|
||||
});
|
||||
|
||||
extensions.registerAPI((extension, context) => {
|
||||
return {
|
||||
browserAction: {
|
||||
onClicked: new EventManager(context, "browserAction.onClicked", fire => {
|
||||
let listener = () => {
|
||||
let tab = TabManager.activeTab;
|
||||
fire(TabManager.convert(extension, tab));
|
||||
};
|
||||
browserActionOf(extension).on("click", listener);
|
||||
return () => {
|
||||
browserActionOf(extension).off("click", listener);
|
||||
};
|
||||
}).api(),
|
||||
|
||||
setTitle: function(details) {
|
||||
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
|
||||
browserActionOf(extension).setProperty(tab, "title", details.title);
|
||||
},
|
||||
|
||||
getTitle: function(details, callback) {
|
||||
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
|
||||
let title = browserActionOf(extension).getProperty(tab, "title");
|
||||
runSafe(context, callback, title);
|
||||
},
|
||||
|
||||
setIcon: function(details, callback) {
|
||||
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
|
||||
if (details.imageData) {
|
||||
// FIXME: Support the imageData attribute.
|
||||
return;
|
||||
}
|
||||
browserActionOf(extension).setProperty(tab, "icon", details.path);
|
||||
},
|
||||
|
||||
setBadgeText: function(details) {
|
||||
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
|
||||
browserActionOf(extension).setProperty(tab, "badgeText", details.text);
|
||||
},
|
||||
|
||||
getBadgeText: function(details, callback) {
|
||||
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
|
||||
let text = browserActionOf(extension).getProperty(tab, "badgeText");
|
||||
runSafe(context, callback, text);
|
||||
},
|
||||
|
||||
setPopup: function(details) {
|
||||
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
|
||||
browserActionOf(extension).setProperty(tab, "popup", details.popup);
|
||||
},
|
||||
|
||||
getPopup: function(details, callback) {
|
||||
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
|
||||
let popup = browserActionOf(extension).getProperty(tab, "popup");
|
||||
runSafe(context, callback, popup);
|
||||
},
|
||||
|
||||
setBadgeBackgroundColor: function(details) {
|
||||
let color = details.color;
|
||||
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
|
||||
browserActionOf(extension).setProperty(tab, "badgeBackgroundColor", details.color);
|
||||
},
|
||||
|
||||
getBadgeBackgroundColor: function(details, callback) {
|
||||
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
|
||||
let color = browserActionOf(extension).getProperty(tab, "badgeBackgroundColor");
|
||||
runSafe(context, callback, color);
|
||||
},
|
||||
}
|
||||
};
|
||||
});
|
8
browser/components/extensions/ext-contextMenus.js
Normal file
8
browser/components/extensions/ext-contextMenus.js
Normal file
@ -0,0 +1,8 @@
|
||||
extensions.registerPrivilegedAPI("contextMenus", (extension, context) => {
|
||||
return {
|
||||
contextMenus: {
|
||||
create() {},
|
||||
removeAll() {},
|
||||
},
|
||||
};
|
||||
});
|
486
browser/components/extensions/ext-tabs.js
Normal file
486
browser/components/extensions/ext-tabs.js
Normal file
@ -0,0 +1,486 @@
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabURL",
|
||||
"resource:///modules/NewTabURL.jsm");
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
let {
|
||||
EventManager,
|
||||
ignoreEvent,
|
||||
runSafe,
|
||||
} = ExtensionUtils;
|
||||
|
||||
// This function is pretty tightly tied to Extension.jsm.
|
||||
// Its job is to fill in the |tab| property of the sender.
|
||||
function getSender(context, target, sender)
|
||||
{
|
||||
// The message was sent from a content script to a <browser> element.
|
||||
// We can just get the |tab| from |target|.
|
||||
if (target instanceof Ci.nsIDOMXULElement) {
|
||||
// The message came from a content script.
|
||||
let tabbrowser = target.ownerDocument.defaultView.gBrowser;
|
||||
if (!tabbrowser) {
|
||||
return;
|
||||
}
|
||||
let tab = tabbrowser.getTabForBrowser(target);
|
||||
|
||||
sender.tab = TabManager.convert(context.extension, tab);
|
||||
} else {
|
||||
// The message came from an ExtensionPage. In that case, it should
|
||||
// include a tabId property (which is filled in by the page-open
|
||||
// listener below).
|
||||
if ("tabId" in sender) {
|
||||
sender.tab = TabManager.convert(context.extension, TabManager.getTab(sender.tabId));
|
||||
delete sender.tabId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WeakMap[ExtensionPage -> {tab, parentWindow}]
|
||||
let pageDataMap = new WeakMap();
|
||||
|
||||
// This listener fires whenever an extension page opens in a tab
|
||||
// (either initiated by the extension or the user). Its job is to fill
|
||||
// in some tab-specific details and keep data around about the
|
||||
// ExtensionPage.
|
||||
extensions.on("page-load", (type, page, params, sender, delegate) => {
|
||||
if (params.type == "tab") {
|
||||
let browser = params.docShell.chromeEventHandler;
|
||||
let parentWindow = browser.ownerDocument.defaultView;
|
||||
let tab = parentWindow.gBrowser.getTabForBrowser(browser);
|
||||
sender.tabId = TabManager.getId(tab);
|
||||
|
||||
pageDataMap.set(page, {tab, parentWindow});
|
||||
}
|
||||
|
||||
delegate.getSender = getSender;
|
||||
});
|
||||
|
||||
extensions.on("page-unload", (type, page) => {
|
||||
pageDataMap.delete(page);
|
||||
});
|
||||
|
||||
extensions.on("page-shutdown", (type, page) => {
|
||||
if (pageDataMap.has(page)) {
|
||||
let {tab, parentWindow} = pageDataMap.get(page);
|
||||
pageDataMap.delete(page);
|
||||
|
||||
parentWindow.gBrowser.removeTab(tab);
|
||||
}
|
||||
});
|
||||
|
||||
extensions.on("fill-browser-data", (type, browser, data, result) => {
|
||||
let tabId = TabManager.getBrowserId(browser);
|
||||
if (tabId == -1) {
|
||||
result.cancel = true;
|
||||
return;
|
||||
}
|
||||
|
||||
data.tabId = tabId;
|
||||
});
|
||||
|
||||
// TODO: activeTab permission
|
||||
|
||||
extensions.registerAPI((extension, context) => {
|
||||
let self = {
|
||||
tabs: {
|
||||
onActivated: new WindowEventManager(context, "tabs.onActivated", "TabSelect", (fire, event) => {
|
||||
let tab = event.originalTarget;
|
||||
let tabId = TabManager.getId(tab);
|
||||
let windowId = WindowManager.getId(tab.ownerDocument.defaultView);
|
||||
fire({tabId, windowId});
|
||||
}).api(),
|
||||
|
||||
onCreated: new EventManager(context, "tabs.onCreated", fire => {
|
||||
let listener = event => {
|
||||
let tab = event.originalTarget;
|
||||
fire({tab: TabManager.convert(extension, tab)});
|
||||
};
|
||||
|
||||
let windowListener = window => {
|
||||
for (let tab of window.gBrowser.tabs) {
|
||||
fire({tab: TabManager.convert(extension, tab)});
|
||||
}
|
||||
};
|
||||
|
||||
WindowListManager.addOpenListener(windowListener, false);
|
||||
AllWindowEvents.addListener("TabOpen", listener);
|
||||
return () => {
|
||||
WindowListManager.removeOpenListener(windowListener);
|
||||
AllWindowEvents.removeListener("TabOpen", listener);
|
||||
};
|
||||
}).api(),
|
||||
|
||||
onUpdated: new EventManager(context, "tabs.onUpdated", fire => {
|
||||
function sanitize(extension, changeInfo) {
|
||||
let result = {};
|
||||
let nonempty = false;
|
||||
for (let prop in changeInfo) {
|
||||
if ((prop != "favIconUrl" && prop != "url") || extension.hasPermission("tabs")) {
|
||||
nonempty = true;
|
||||
result[prop] = changeInfo[prop];
|
||||
}
|
||||
}
|
||||
return [nonempty, result];
|
||||
}
|
||||
|
||||
let listener = event => {
|
||||
let tab = event.originalTarget;
|
||||
let window = tab.ownerDocument.defaultView;
|
||||
let tabId = TabManager.getId(tab);
|
||||
|
||||
let changeInfo = {};
|
||||
let needed = false;
|
||||
if (event.type == "TabAttrModified") {
|
||||
if (event.detail.changed.indexOf("image") != -1) {
|
||||
changeInfo.favIconUrl = window.gBrowser.getIcon(tab);
|
||||
needed = true;
|
||||
}
|
||||
} else if (event.type == "TabPinned") {
|
||||
changeInfo.pinned = true;
|
||||
needed = true;
|
||||
} else if (event.type == "TabUnpinned") {
|
||||
changeInfo.pinned = false;
|
||||
needed = true;
|
||||
}
|
||||
|
||||
[needed, changeInfo] = sanitize(extension, changeInfo);
|
||||
if (needed) {
|
||||
fire(tabId, changeInfo, TabManager.convert(extension, tab));
|
||||
}
|
||||
};
|
||||
let progressListener = {
|
||||
onStateChange(browser, webProgress, request, stateFlags, statusCode) {
|
||||
if (!webProgress.isTopLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
let status;
|
||||
if (stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
|
||||
if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
|
||||
status = "loading";
|
||||
} else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
status = "complete";
|
||||
}
|
||||
} else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
statusCode == Cr.NS_BINDING_ABORTED) {
|
||||
status = "complete";
|
||||
}
|
||||
|
||||
let gBrowser = browser.ownerDocument.defaultView.gBrowser;
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
let tabId = TabManager.getId(tab);
|
||||
let [needed, changeInfo] = sanitize(extension, {status});
|
||||
fire(tabId, changeInfo, TabManager.convert(extension, tab));
|
||||
},
|
||||
|
||||
onLocationChange(browser, webProgress, request, locationURI, flags) {
|
||||
let gBrowser = browser.ownerDocument.defaultView.gBrowser;
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
let tabId = TabManager.getId(tab);
|
||||
let [needed, changeInfo] = sanitize(extension, {url: locationURI.spec});
|
||||
if (needed) {
|
||||
fire(tabId, changeInfo, TabManager.convert(extension, tab));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
AllWindowEvents.addListener("progress", progressListener);
|
||||
AllWindowEvents.addListener("TabAttrModified", listener);
|
||||
AllWindowEvents.addListener("TabPinned", listener);
|
||||
AllWindowEvents.addListener("TabUnpinned", listener);
|
||||
return () => {
|
||||
AllWindowEvents.removeListener("progress", progressListener);
|
||||
AllWindowEvents.addListener("TabAttrModified", listener);
|
||||
AllWindowEvents.addListener("TabPinned", listener);
|
||||
AllWindowEvents.addListener("TabUnpinned", listener);
|
||||
};
|
||||
}).api(),
|
||||
|
||||
onReplaced: ignoreEvent(),
|
||||
|
||||
onRemoved: new EventManager(context, "tabs.onRemoved", fire => {
|
||||
let tabListener = event => {
|
||||
let tab = event.originalTarget;
|
||||
let tabId = TabManager.getId(tab);
|
||||
let windowId = WindowManager.getId(tab.ownerDocument.defaultView);
|
||||
let removeInfo = {windowId, isWindowClosing: false};
|
||||
fire(tabId, removeInfo);
|
||||
};
|
||||
|
||||
let windowListener = window => {
|
||||
for (let tab of window.gBrowser.tabs) {
|
||||
let tabId = TabManager.getId(tab);
|
||||
let windowId = WindowManager.getId(window);
|
||||
let removeInfo = {windowId, isWindowClosing: true};
|
||||
fire(tabId, removeInfo);
|
||||
}
|
||||
};
|
||||
|
||||
WindowListManager.addCloseListener(windowListener);
|
||||
AllWindowEvents.addListener("TabClose", tabListener);
|
||||
return () => {
|
||||
WindowListManager.removeCloseListener(windowListener);
|
||||
AllWindowEvents.removeListener("TabClose", tabListener);
|
||||
};
|
||||
}).api(),
|
||||
|
||||
create: function(createProperties, callback) {
|
||||
if (!createProperties) {
|
||||
createProperties = {};
|
||||
}
|
||||
|
||||
let url = createProperties.url || NewTabURL.get();
|
||||
url = extension.baseURI.resolve(url);
|
||||
|
||||
function createInWindow(window) {
|
||||
let tab = window.gBrowser.addTab(url);
|
||||
|
||||
let active = true;
|
||||
if ("active" in createProperties) {
|
||||
active = createProperties.active;
|
||||
} else if ("selected" in createProperties) {
|
||||
active = createProperties.selected;
|
||||
}
|
||||
if (active) {
|
||||
window.gBrowser.selectedTab = tab;
|
||||
}
|
||||
|
||||
if ("index" in createProperties) {
|
||||
window.gBrowser.moveTabTo(tab, createProperties.index);
|
||||
}
|
||||
|
||||
if (createProperties.pinned) {
|
||||
window.gBrowser.pinTab(tab);
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
runSafe(context, callback, TabManager.convert(extension, tab));
|
||||
}
|
||||
}
|
||||
|
||||
let window = createProperties.windowId ?
|
||||
WindowManager.getWindow(createProperties.windowId) :
|
||||
WindowManager.topWindow;
|
||||
if (!window.gBrowser) {
|
||||
let obs = (finishedWindow, topic, data) => {
|
||||
if (finishedWindow != window) {
|
||||
return;
|
||||
}
|
||||
Services.obs.removeObserver(obs, "browser-delayed-startup-finished");
|
||||
createInWindow(window);
|
||||
};
|
||||
Services.obs.addObserver(obs, "browser-delayed-startup-finished", false);
|
||||
} else {
|
||||
createInWindow(window);
|
||||
}
|
||||
},
|
||||
|
||||
remove: function(tabs, callback) {
|
||||
if (!Array.isArray(tabs)) {
|
||||
tabs = [tabs];
|
||||
}
|
||||
|
||||
for (let tabId of tabs) {
|
||||
let tab = TabManager.getTab(tabId);
|
||||
tab.ownerDocument.defaultView.gBrowser.removeTab(tab);
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
runSafe(context, callback);
|
||||
}
|
||||
},
|
||||
|
||||
update: function(...args) {
|
||||
let tabId, updateProperties, callback;
|
||||
if (args.length == 1) {
|
||||
updateProperties = args[0];
|
||||
} else {
|
||||
[tabId, updateProperties, callback] = args;
|
||||
}
|
||||
|
||||
let tab = tabId ? TabManager.getTab(tabId) : TabManager.activeTab;
|
||||
let tabbrowser = tab.ownerDocument.gBrowser;
|
||||
if ("url" in updateProperties) {
|
||||
tab.linkedBrowser.loadURI(updateProperties.url);
|
||||
}
|
||||
if ("active" in updateProperties) {
|
||||
if (updateProperties.active) {
|
||||
tabbrowser.selectedTab = tab;
|
||||
} else {
|
||||
// Not sure what to do here? Which tab should we select?
|
||||
}
|
||||
}
|
||||
if ("pinned" in updateProperties) {
|
||||
if (updateProperties.pinned) {
|
||||
tabbrowser.pinTab(tab);
|
||||
} else {
|
||||
tabbrowser.unpinTab(tab);
|
||||
}
|
||||
}
|
||||
// FIXME: highlighted/selected, openerTabId
|
||||
|
||||
if (callback) {
|
||||
runSafe(context, callback, TabManager.convert(extension, tab));
|
||||
}
|
||||
},
|
||||
|
||||
reload: function(tabId, reloadProperties, callback) {
|
||||
let tab = tabId ? TabManager.getTab(tabId) : TabManager.activeTab;
|
||||
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
if (reloadProperties && reloadProperties.bypassCache) {
|
||||
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
|
||||
}
|
||||
tab.linkedBrowser.reloadWithFlags(flags);
|
||||
|
||||
if (callback) {
|
||||
runSafe(context, callback);
|
||||
}
|
||||
},
|
||||
|
||||
get: function(tabId, callback) {
|
||||
let tab = TabManager.getTab(tabId);
|
||||
runSafe(context, callback, TabManager.convert(extension, tab));
|
||||
},
|
||||
|
||||
getAllInWindow: function(...args) {
|
||||
let window, callback;
|
||||
if (args.length == 1) {
|
||||
callbacks = args[0];
|
||||
} else {
|
||||
window = WindowManager.getWindow(args[0]);
|
||||
callback = args[1];
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
window = WindowManager.topWindow;
|
||||
}
|
||||
|
||||
return self.tabs.query({windowId: WindowManager.getId(window)}, callback);
|
||||
},
|
||||
|
||||
query: function(queryInfo, callback) {
|
||||
if (!queryInfo) {
|
||||
queryInfo = {};
|
||||
}
|
||||
|
||||
function matches(window, tab) {
|
||||
let props = ["active", "pinned", "highlighted", "status", "title", "url", "index"];
|
||||
for (let prop of props) {
|
||||
if (prop in queryInfo && queryInfo[prop] != tab[prop]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let lastFocused = window == WindowManager.topWindow;
|
||||
if ("lastFocusedWindow" in queryInfo && queryInfo.lastFocusedWindow != lastFocused) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let windowType = WindowManager.windowType(window);
|
||||
if ("windowType" in queryInfo && queryInfo.windowType != windowType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("windowId" in queryInfo) {
|
||||
if (queryInfo.windowId == WindowManager.WINDOW_ID_CURRENT) {
|
||||
if (context.contentWindow != window) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (queryInfo.windowId != tab.windowId) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("currentWindow" in queryInfo) {
|
||||
let eq = window == context.contentWindow;
|
||||
if (queryInfo.currentWindow != eq) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
let result = [];
|
||||
let e = Services.wm.getEnumerator("navigator:browser");
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
let tabs = TabManager.getTabs(extension, window);
|
||||
for (let tab of tabs) {
|
||||
if (matches(window, tab)) {
|
||||
result.push(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
runSafe(context, callback, result);
|
||||
},
|
||||
|
||||
_execute: function(tabId, details, kind, callback) {
|
||||
let tab = tabId ? TabManager.getTab(tabId) : TabManager.activeTab;
|
||||
let mm = tab.linkedBrowser.messageManager;
|
||||
|
||||
let options = {js: [], css: []};
|
||||
if (details.code) {
|
||||
options[kind + 'Code'] = details.code;
|
||||
}
|
||||
if (details.file) {
|
||||
options[kind].push(extension.baseURI.resolve(details.file));
|
||||
}
|
||||
if (details.allFrames) {
|
||||
options.all_frames = details.allFrames;
|
||||
}
|
||||
if (details.matchAboutBlank) {
|
||||
options.match_about_blank = details.matchAboutBlank;
|
||||
}
|
||||
if (details.runAt) {
|
||||
options.run_at = details.runAt;
|
||||
}
|
||||
mm.sendAsyncMessage("Extension:Execute",
|
||||
{extensionId: extension.id, options});
|
||||
|
||||
// TODO: Call the callback with the result (which is what???).
|
||||
},
|
||||
|
||||
executeScript: function(...args) {
|
||||
if (args.length == 1) {
|
||||
self.tabs._execute(undefined, args[0], 'js', undefined);
|
||||
} else {
|
||||
self.tabs._execute(args[0], args[1], 'js', args[2]);
|
||||
}
|
||||
},
|
||||
|
||||
insertCss: function(tabId, details, callback) {
|
||||
if (args.length == 1) {
|
||||
self.tabs._execute(undefined, args[0], 'css', undefined);
|
||||
} else {
|
||||
self.tabs._execute(args[0], args[1], 'css', args[2]);
|
||||
}
|
||||
},
|
||||
|
||||
connect: function(tabId, connectInfo) {
|
||||
let tab = TabManager.getTab(tabId);
|
||||
let mm = tab.linkedBrowser.messageManager;
|
||||
|
||||
let name = connectInfo.name || "";
|
||||
let recipient = {extensionId: extension.id};
|
||||
if ("frameId" in connectInfo) {
|
||||
recipient.frameId = connectInfo.frameId;
|
||||
}
|
||||
return context.messenger.connect(mm, name, recipient);
|
||||
},
|
||||
|
||||
sendMessage: function(tabId, message, options, responseCallback) {
|
||||
let tab = TabManager.getTab(tabId);
|
||||
let mm = tab.linkedBrowser.messageManager;
|
||||
|
||||
let recipient = {extensionId: extension.id};
|
||||
if (options && "frameId" in options) {
|
||||
recipient.frameId = options.frameId;
|
||||
}
|
||||
return context.messenger.sendMessage(mm, message, recipient, responseCallback);
|
||||
},
|
||||
},
|
||||
};
|
||||
return self;
|
||||
});
|
324
browser/components/extensions/ext-utils.js
Normal file
324
browser/components/extensions/ext-utils.js
Normal file
@ -0,0 +1,324 @@
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
let {
|
||||
EventManager,
|
||||
} = ExtensionUtils;
|
||||
|
||||
// This file provides some useful code for the |tabs| and |windows|
|
||||
// modules. All of the code is installed on |global|, which is a scope
|
||||
// shared among the different ext-*.js scripts.
|
||||
|
||||
// Manages mapping between XUL tabs and extension tab IDs.
|
||||
global.TabManager = {
|
||||
_tabs: new WeakMap(),
|
||||
_nextId: 1,
|
||||
|
||||
getId(tab) {
|
||||
if (this._tabs.has(tab)) {
|
||||
return this._tabs.get(tab);
|
||||
}
|
||||
let id = this._nextId++;
|
||||
this._tabs.set(tab, id);
|
||||
return id;
|
||||
},
|
||||
|
||||
getBrowserId(browser) {
|
||||
let gBrowser = browser.ownerDocument.defaultView.gBrowser;
|
||||
// Some non-browser windows have gBrowser but not
|
||||
// getTabForBrowser!
|
||||
if (gBrowser && gBrowser.getTabForBrowser) {
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (tab) {
|
||||
return this.getId(tab);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
getTab(tabId) {
|
||||
// FIXME: Speed this up without leaking memory somehow.
|
||||
let e = Services.wm.getEnumerator("navigator:browser");
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
if (!window.gBrowser) {
|
||||
continue;
|
||||
}
|
||||
for (let tab of window.gBrowser.tabs) {
|
||||
if (this.getId(tab) == tabId) {
|
||||
return tab;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
get activeTab() {
|
||||
let window = WindowManager.topWindow;
|
||||
if (window && window.gBrowser) {
|
||||
return window.gBrowser.selectedTab;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
getStatus(tab) {
|
||||
return tab.getAttribute("busy") == "true" ? "loading" : "complete";
|
||||
},
|
||||
|
||||
convert(extension, tab) {
|
||||
let window = tab.ownerDocument.defaultView;
|
||||
let windowActive = window == WindowManager.topWindow;
|
||||
let result = {
|
||||
id: this.getId(tab),
|
||||
index: tab._tPos,
|
||||
windowId: WindowManager.getId(window),
|
||||
selected: tab.selected,
|
||||
highlighted: tab.selected,
|
||||
active: tab.selected,
|
||||
pinned: tab.pinned,
|
||||
status: this.getStatus(tab),
|
||||
incognito: PrivateBrowsingUtils.isBrowserPrivate(tab.linkedBrowser),
|
||||
width: tab.linkedBrowser.clientWidth,
|
||||
height: tab.linkedBrowser.clientHeight,
|
||||
};
|
||||
|
||||
if (extension.hasPermission("tabs")) {
|
||||
result.url = tab.linkedBrowser.currentURI.spec;
|
||||
if (tab.linkedBrowser.contentTitle) {
|
||||
result.title = tab.linkedBrowser.contentTitle;
|
||||
}
|
||||
let icon = window.gBrowser.getIcon(tab);
|
||||
if (icon) {
|
||||
result.favIconUrl = icon;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
getTabs(extension, window) {
|
||||
if (!window.gBrowser) {
|
||||
return [];
|
||||
}
|
||||
return [ for (tab of window.gBrowser.tabs) this.convert(extension, tab) ];
|
||||
},
|
||||
};
|
||||
|
||||
// Manages mapping between XUL windows and extension window IDs.
|
||||
global.WindowManager = {
|
||||
_windows: new WeakMap(),
|
||||
_nextId: 0,
|
||||
|
||||
WINDOW_ID_NONE: -1,
|
||||
WINDOW_ID_CURRENT: -2,
|
||||
|
||||
get topWindow() {
|
||||
return Services.wm.getMostRecentWindow("navigator:browser");
|
||||
},
|
||||
|
||||
windowType(window) {
|
||||
// TODO: Make this work.
|
||||
return "normal";
|
||||
},
|
||||
|
||||
getId(window) {
|
||||
if (this._windows.has(window)) {
|
||||
return this._windows.get(window);
|
||||
}
|
||||
let id = this._nextId++;
|
||||
this._windows.set(window, id);
|
||||
return id;
|
||||
},
|
||||
|
||||
getWindow(id) {
|
||||
let e = Services.wm.getEnumerator("navigator:browser");
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
if (this.getId(window) == id) {
|
||||
return window;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
convert(extension, window, getInfo) {
|
||||
let result = {
|
||||
id: this.getId(window),
|
||||
focused: window == WindowManager.topWindow,
|
||||
top: window.screenY,
|
||||
left: window.screenX,
|
||||
width: window.outerWidth,
|
||||
height: window.outerHeight,
|
||||
incognito: PrivateBrowsingUtils.isWindowPrivate(window),
|
||||
|
||||
// We fudge on these next two.
|
||||
type: this.windowType(window),
|
||||
state: window.fullScreen ? "fullscreen" : "normal",
|
||||
};
|
||||
|
||||
if (getInfo && getInfo.populate) {
|
||||
results.tabs = TabManager.getTabs(extension, window);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
};
|
||||
|
||||
// Manages listeners for window opening and closing. A window is
|
||||
// considered open when the "load" event fires on it. A window is
|
||||
// closed when a "domwindowclosed" notification fires for it.
|
||||
global.WindowListManager = {
|
||||
_openListeners: new Set(),
|
||||
_closeListeners: new Set(),
|
||||
|
||||
addOpenListener(listener, fireOnExisting = true) {
|
||||
if (this._openListeners.length == 0 && this._closeListeners.length == 0) {
|
||||
Services.ww.registerNotification(this);
|
||||
}
|
||||
this._openListeners.add(listener);
|
||||
|
||||
let e = Services.wm.getEnumerator("navigator:browser");
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
if (window.document.readyState != "complete") {
|
||||
window.addEventListener("load", this);
|
||||
} else if (fireOnExisting) {
|
||||
listener(window);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeOpenListener(listener) {
|
||||
this._openListeners.delete(listener);
|
||||
if (this._openListeners.length == 0 && this._closeListeners.length == 0) {
|
||||
Services.ww.unregisterNotification(this);
|
||||
}
|
||||
},
|
||||
|
||||
addCloseListener(listener) {
|
||||
if (this._openListeners.length == 0 && this._closeListeners.length == 0) {
|
||||
Services.ww.registerNotification(this);
|
||||
}
|
||||
this._closeListeners.add(listener);
|
||||
},
|
||||
|
||||
removeCloseListener(listener) {
|
||||
this._closeListeners.delete(listener);
|
||||
if (this._openListeners.length == 0 && this._closeListeners.length == 0) {
|
||||
Services.ww.unregisterNotification(this);
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
let window = event.target.defaultView;
|
||||
window.removeEventListener("load", this.loadListener);
|
||||
if (window.document.documentElement.getAttribute("windowtype") != "navigator:browser") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let listener of this._openListeners) {
|
||||
listener(window);
|
||||
}
|
||||
},
|
||||
|
||||
queryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
|
||||
|
||||
observe(window, topic, data) {
|
||||
if (topic == "domwindowclosed") {
|
||||
if (window.document.documentElement.getAttribute("windowtype") != "navigator:browser") {
|
||||
return;
|
||||
}
|
||||
|
||||
window.removeEventListener("load", this);
|
||||
for (let listener of this._closeListeners) {
|
||||
listener(window);
|
||||
}
|
||||
} else {
|
||||
window.addEventListener("load", this);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Provides a facility to listen for DOM events across all XUL windows.
|
||||
global.AllWindowEvents = {
|
||||
_listeners: new Map(),
|
||||
|
||||
// If |type| is a normal event type, invoke |listener| each time
|
||||
// that event fires in any open window. If |type| is "progress", add
|
||||
// a web progress listener that covers all open windows.
|
||||
addListener(type, listener) {
|
||||
if (type == "domwindowopened") {
|
||||
return WindowListManager.addOpenListener(listener);
|
||||
} else if (type == "domwindowclosed") {
|
||||
return WindowListManager.addCloseListener(listener);
|
||||
}
|
||||
|
||||
let needOpenListener = this._listeners.size == 0;
|
||||
|
||||
if (!this._listeners.has(type)) {
|
||||
this._listeners.set(type, new Set());
|
||||
}
|
||||
let list = this._listeners.get(type);
|
||||
list.add(listener);
|
||||
|
||||
if (needOpenListener) {
|
||||
WindowListManager.addOpenListener(this.openListener);
|
||||
}
|
||||
},
|
||||
|
||||
removeListener(type, listener) {
|
||||
if (type == "domwindowopened") {
|
||||
return WindowListManager.removeOpenListener(listener);
|
||||
} else if (type == "domwindowclosed") {
|
||||
return WindowListManager.removeCloseListener(listener);
|
||||
}
|
||||
|
||||
let listeners = this._listeners.get(type);
|
||||
listeners.delete(listener);
|
||||
if (listeners.length == 0) {
|
||||
this._listeners.delete(type);
|
||||
if (this._listeners.size == 0) {
|
||||
WindowListManager.removeOpenListener(this.openListener);
|
||||
}
|
||||
}
|
||||
|
||||
let e = Services.wm.getEnumerator("navigator:browser");
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
if (type == "progress") {
|
||||
window.gBrowser.removeTabsProgressListener(listener);
|
||||
} else {
|
||||
window.removeEventListener(type, listener);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Runs whenever the "load" event fires for a new window.
|
||||
openListener(window) {
|
||||
for (let [eventType, listeners] of AllWindowEvents._listeners) {
|
||||
for (let listener of listeners) {
|
||||
if (eventType == "progress") {
|
||||
window.gBrowser.addTabsProgressListener(listener);
|
||||
} else {
|
||||
window.addEventListener(eventType, listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Subclass of EventManager where we just need to call
|
||||
// add/removeEventListener on each XUL window.
|
||||
global.WindowEventManager = function(context, name, event, listener)
|
||||
{
|
||||
EventManager.call(this, context, name, fire => {
|
||||
let listener2 = (...args) => listener(fire, ...args);
|
||||
AllWindowEvents.addListener(event, listener2);
|
||||
return () => {
|
||||
AllWindowEvents.removeListener(event, listener2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
WindowEventManager.prototype = Object.create(EventManager.prototype);
|
151
browser/components/extensions/ext-windows.js
Normal file
151
browser/components/extensions/ext-windows.js
Normal file
@ -0,0 +1,151 @@
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabURL",
|
||||
"resource:///modules/NewTabURL.jsm");
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
let {
|
||||
EventManager,
|
||||
ignoreEvent,
|
||||
runSafe,
|
||||
} = ExtensionUtils;
|
||||
|
||||
extensions.registerAPI((extension, context) => {
|
||||
return {
|
||||
windows: {
|
||||
WINDOW_ID_CURRENT: WindowManager.WINDOW_ID_CURRENT,
|
||||
WINDOW_ID_NONE: WindowManager.WINDOW_ID_NONE,
|
||||
|
||||
onCreated:
|
||||
new WindowEventManager(context, "windows.onCreated", "domwindowopened", (fire, window) => {
|
||||
fire(WindowManager.convert(extension, window));
|
||||
}).api(),
|
||||
|
||||
onRemoved:
|
||||
new WindowEventManager(context, "windows.onRemoved", "domwindowclosed", (fire, window) => {
|
||||
fire(WindowManager.getId(window));
|
||||
}).api(),
|
||||
|
||||
onFocusChanged: new EventManager(context, "windows.onFocusChanged", fire => {
|
||||
// FIXME: This will send multiple messages for a single focus change.
|
||||
let listener = event => {
|
||||
let window = WindowManager.topWindow;
|
||||
let windowId = window ? WindowManager.getId(window) : WindowManager.WINDOW_ID_NONE;
|
||||
fire(windowId);
|
||||
};
|
||||
AllWindowEvents.addListener("focus", listener);
|
||||
AllWindowEvents.addListener("blur", listener);
|
||||
return () => {
|
||||
AllWindowEvents.removeListener("focus", listener);
|
||||
AllWindowEvents.removeListener("blur", listener);
|
||||
};
|
||||
}).api(),
|
||||
|
||||
get: function(windowId, getInfo, callback) {
|
||||
let window = WindowManager.getWindow(windowId);
|
||||
runSafe(context, callback, WindowManager.convert(extension, window, getInfo));
|
||||
},
|
||||
|
||||
getCurrent: function(getInfo, callback) {
|
||||
let window = context.contentWindow;
|
||||
runSafe(context, callback, WindowManager.convert(extension, window, getInfo));
|
||||
},
|
||||
|
||||
getLastFocused: function(...args) {
|
||||
let getInfo, callback;
|
||||
if (args.length == 1) {
|
||||
callback = args[0];
|
||||
} else {
|
||||
[getInfo, callback] = args;
|
||||
}
|
||||
let window = WindowManager.topWindow;
|
||||
runSafe(context, callback, WindowManager.convert(extension, window, getInfo));
|
||||
},
|
||||
|
||||
getAll: function(getAll, callback) {
|
||||
let e = Services.wm.getEnumerator("navigator:browser");
|
||||
let windows = [];
|
||||
while (e.hasMoreElements()) {
|
||||
let window = e.getNext();
|
||||
windows.push(WindowManager.convert(extension, window, getInfo));
|
||||
}
|
||||
runSafe(context, callback, windows);
|
||||
},
|
||||
|
||||
create: function(createData, callback) {
|
||||
function mkstr(s) {
|
||||
let result = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
|
||||
result.data = s;
|
||||
return result;
|
||||
}
|
||||
|
||||
let args = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray);
|
||||
if ("url" in createData) {
|
||||
if (Array.isArray(createData.url)) {
|
||||
let array = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray);
|
||||
for (let url of createData.url) {
|
||||
array.AppendElement(mkstr(url));
|
||||
}
|
||||
args.AppendElement(array);
|
||||
} else {
|
||||
args.AppendElement(mkstr(createData.url));
|
||||
}
|
||||
} else {
|
||||
args.AppendElement(mkstr(NewTabURL.get()));
|
||||
}
|
||||
|
||||
let extraFeatures = "";
|
||||
if ("incognito" in createData) {
|
||||
if (createData.incognito) {
|
||||
extraFeatures += ",private";
|
||||
} else {
|
||||
extraFeatures += ",non-private";
|
||||
}
|
||||
}
|
||||
|
||||
let window = Services.ww.openWindow(null, "chrome://browser/content/browser.xul", "_blank",
|
||||
"chrome,dialog=no,all" + extraFeatures, args);
|
||||
|
||||
if ("left" in createData || "top" in createData) {
|
||||
let left = "left" in createData ? createData.left : window.screenX;
|
||||
let top = "top" in createData ? createData.top : window.screenY;
|
||||
window.moveTo(left, top);
|
||||
}
|
||||
if ("width" in createData || "height" in createData) {
|
||||
let width = "width" in createData ? createData.width : window.outerWidth;
|
||||
let height = "height" in createData ? createData.height : window.outerHeight;
|
||||
window.resizeTo(width, height);
|
||||
}
|
||||
|
||||
// TODO: focused, type, state
|
||||
|
||||
window.addEventListener("load", function listener() {
|
||||
window.removeEventListener("load", listener);
|
||||
if (callback) {
|
||||
runSafe(context, callback, WindowManager.convert(extension, window));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
update: function(windowId, updateInfo, callback) {
|
||||
let window = WindowManager.getWindow(windowId);
|
||||
if (updateInfo.focused) {
|
||||
Services.focus.activeWindow = window;
|
||||
}
|
||||
// TODO: All the other properties...
|
||||
runSafe(context, callback, WindowManager.convert(extension, window));
|
||||
},
|
||||
|
||||
remove: function(windowId, callback) {
|
||||
let window = WindowManager.getWindow(windowId);
|
||||
window.close();
|
||||
|
||||
let listener = () => {
|
||||
AllWindowEvents.removeListener("domwindowclosed", listener);
|
||||
if (callback) {
|
||||
runSafe(context, callback);
|
||||
}
|
||||
};
|
||||
AllWindowEvents.addListener("domwindowclosed", listener);
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
19
browser/components/extensions/extension.svg
Normal file
19
browser/components/extensions/extension.svg
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="64" height="64" viewBox="0 0 64 64">
|
||||
<defs>
|
||||
<style>
|
||||
.style-puzzle-piece {
|
||||
fill: url('#gradient-linear-puzzle-piece');
|
||||
}
|
||||
</style>
|
||||
<linearGradient id="gradient-linear-puzzle-piece" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" stop-color="#66cc52" stop-opacity="1"/>
|
||||
<stop offset="100%" stop-color="#60bf4c" stop-opacity="1"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path class="style-puzzle-piece" d="M42,62c2.2,0,4-1.8,4-4l0-14.2c0,0,0.4-3.7,2.8-3.7c2.4,0,2.2,3.9,6.7,3.9c2.3,0,6.2-1.2,6.2-8.2 c0-7-3.9-7.9-6.2-7.9c-4.5,0-4.3,3.7-6.7,3.7c-2.4,0-2.8-3.8-2.8-3.8V22c0-2.2-1.8-4-4-4H31.5c0,0-3.4-0.6-3.4-3 c0-2.4,3.8-2.6,3.8-7.1c0-2.3-1.3-5.9-8.3-5.9s-8,3.6-8,5.9c0,4.5,3.4,4.7,3.4,7.1c0,2.4-3.4,3-3.4,3H6c-2.2,0-4,1.8-4,4l0,7.8 c0,0-0.4,6,4.4,6c3.1,0,3.2-4.1,7.3-4.1c2,0,4,1.9,4,6c0,4.2-2,6.3-4,6.3c-4,0-4.2-4.1-7.3-4.1c-4.8,0-4.4,5.8-4.4,5.8L2,58 c0,2.2,1.8,4,4,4H19c0,0,6.3,0.4,6.3-4.4c0-3.1-4-3.6-4-7.7c0-2,2.2-4.5,6.4-4.5c4.2,0,6.6,2.5,6.6,4.5c0,4-3.9,4.6-3.9,7.7 c0,4.9,6.3,4.4,6.3,4.4H42z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
11
browser/components/extensions/jar.mn
Normal file
11
browser/components/extensions/jar.mn
Normal file
@ -0,0 +1,11 @@
|
||||
# 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/.
|
||||
|
||||
browser.jar:
|
||||
content/browser/extension.svg (extension.svg)
|
||||
content/browser/ext-utils.js (ext-utils.js)
|
||||
content/browser/ext-contextMenus.js (ext-contextMenus.js)
|
||||
content/browser/ext-browserAction.js (ext-browserAction.js)
|
||||
content/browser/ext-tabs.js (ext-tabs.js)
|
||||
content/browser/ext-windows.js (ext-windows.js)
|
7
browser/components/extensions/moz.build
Normal file
7
browser/components/extensions/moz.build
Normal file
@ -0,0 +1,7 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
83
browser/components/extensions/prepare.py
Normal file
83
browser/components/extensions/prepare.py
Normal file
@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python
|
||||
# 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/.
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import uuid
|
||||
import sys
|
||||
import os.path
|
||||
|
||||
parser = argparse.ArgumentParser(description='Create install.rdf from manifest.json')
|
||||
parser.add_argument('--locale')
|
||||
parser.add_argument('--profile')
|
||||
parser.add_argument('--uuid')
|
||||
parser.add_argument('dir')
|
||||
args = parser.parse_args()
|
||||
|
||||
manifestFile = os.path.join(args.dir, 'manifest.json')
|
||||
manifest = json.load(open(manifestFile))
|
||||
|
||||
locale = args.locale
|
||||
if not locale:
|
||||
locale = manifest.get('default_locale', 'en-US')
|
||||
|
||||
def process_locale(s):
|
||||
if s.startswith('__MSG_') and s.endswith('__'):
|
||||
tag = s[6:-2]
|
||||
path = os.path.join(args.dir, '_locales', locale, 'messages.json')
|
||||
data = json.load(open(path))
|
||||
return data[tag]['message']
|
||||
else:
|
||||
return s
|
||||
|
||||
id = args.uuid
|
||||
if not id:
|
||||
id = '{' + str(uuid.uuid4()) + '}'
|
||||
|
||||
name = process_locale(manifest['name'])
|
||||
desc = process_locale(manifest['description'])
|
||||
version = manifest['version']
|
||||
|
||||
installFile = open(os.path.join(args.dir, 'install.rdf'), 'w')
|
||||
print >>installFile, '<?xml version="1.0"?>'
|
||||
print >>installFile, '<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"'
|
||||
print >>installFile, ' xmlns:em="http://www.mozilla.org/2004/em-rdf#">'
|
||||
print >>installFile
|
||||
print >>installFile, ' <Description about="urn:mozilla:install-manifest">'
|
||||
print >>installFile, ' <em:id>{}</em:id>'.format(id)
|
||||
print >>installFile, ' <em:type>2</em:type>'
|
||||
print >>installFile, ' <em:name>{}</em:name>'.format(name)
|
||||
print >>installFile, ' <em:description>{}</em:description>'.format(desc)
|
||||
print >>installFile, ' <em:version>{}</em:version>'.format(version)
|
||||
print >>installFile, ' <em:bootstrap>true</em:bootstrap>'
|
||||
|
||||
print >>installFile, ' <em:targetApplication>'
|
||||
print >>installFile, ' <Description>'
|
||||
print >>installFile, ' <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>'
|
||||
print >>installFile, ' <em:minVersion>4.0</em:minVersion>'
|
||||
print >>installFile, ' <em:maxVersion>50.0</em:maxVersion>'
|
||||
print >>installFile, ' </Description>'
|
||||
print >>installFile, ' </em:targetApplication>'
|
||||
|
||||
print >>installFile, ' </Description>'
|
||||
print >>installFile, '</RDF>'
|
||||
installFile.close()
|
||||
|
||||
bootstrapPath = os.path.join(os.path.dirname(sys.argv[0]), 'bootstrap.js')
|
||||
data = open(bootstrapPath).read()
|
||||
boot = open(os.path.join(args.dir, 'bootstrap.js'), 'w')
|
||||
boot.write(data)
|
||||
boot.close()
|
||||
|
||||
if args.profile:
|
||||
os.system('mkdir -p {}/extensions'.format(args.profile))
|
||||
output = open(args.profile + '/extensions/' + id, 'w')
|
||||
print >>output, os.path.realpath(args.dir)
|
||||
output.close()
|
||||
else:
|
||||
dir = os.path.realpath(args.dir)
|
||||
if dir[-1] == os.sep:
|
||||
dir = dir[:-1]
|
||||
os.system('cd "{}"; zip ../"{}".xpi -r *'.format(args.dir, os.path.basename(dir)))
|
@ -9,6 +9,7 @@ DIRS += [
|
||||
'customizableui',
|
||||
'dirprovider',
|
||||
'downloads',
|
||||
'extensions',
|
||||
'feeds',
|
||||
'loop',
|
||||
'migration',
|
||||
|
@ -169,6 +169,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonWatcher",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
|
||||
"resource://gre/modules/LightweightThemeManager.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
|
||||
"resource://gre/modules/ExtensionManagement.jsm");
|
||||
|
||||
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
|
||||
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
|
||||
|
||||
@ -601,6 +604,12 @@ BrowserGlue.prototype = {
|
||||
os.addObserver(this, "xpi-signature-changed", false);
|
||||
os.addObserver(this, "autocomplete-did-enter-text", false);
|
||||
|
||||
ExtensionManagement.registerScript("chrome://browser/content/ext-utils.js");
|
||||
ExtensionManagement.registerScript("chrome://browser/content/ext-browserAction.js");
|
||||
ExtensionManagement.registerScript("chrome://browser/content/ext-contextMenus.js");
|
||||
ExtensionManagement.registerScript("chrome://browser/content/ext-tabs.js");
|
||||
ExtensionManagement.registerScript("chrome://browser/content/ext-windows.js");
|
||||
|
||||
this._flashHangCount = 0;
|
||||
},
|
||||
|
||||
|
@ -26,6 +26,7 @@ CFLAGS="$CFLAGS -Wno-attributes"
|
||||
CPPFLAGS="$CPPFLAGS -Wno-attributes"
|
||||
CXXFLAGS="$CXXFLAGS -Wno-attributes"
|
||||
|
||||
TOOLTOOL_DIR="$(dirname $topsrcdir)"
|
||||
export PKG_CONFIG_LIBDIR=/usr/lib64/pkgconfig:/usr/share/pkgconfig
|
||||
. $topsrcdir/build/unix/mozconfig.gtk
|
||||
|
||||
|
@ -7,10 +7,11 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 4079256,
|
||||
"digest": "bb5238558bcf6db2ca395513c8dccaa15dd61b3c375598eb6a685356b0c1a2d9840e3bf81bc00242b872fd798541f53d723777c754412abf0e772b7cc284937c",
|
||||
"size": 11179576,
|
||||
"digest": "91567ce8e2bb8ab0ebc60c31e90731d88a1ea889fb71bcf55c735746a60fa7610b7e040ea3d8f727b6f692ae3ee703d6f3b30cdbd76fdf5617f77d9c38aa20ed",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"setup": "setup.sh",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
|
@ -1,16 +0,0 @@
|
||||
[
|
||||
{
|
||||
"size": 80458572,
|
||||
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
@ -8,5 +8,13 @@
|
||||
"algorithm": "sha512",
|
||||
"filename": "clang.tar.bz2",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"setup": "setup.sh",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -7,10 +7,11 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 4431740,
|
||||
"digest": "68fc56b0fb0cdba629b95683d6649ff76b00dccf97af90960c3d7716f6108b2162ffd5ffcd5c3a60a21b28674df688fe4dabc67345e2da35ec5abeae3d48c8e3",
|
||||
"size": 12057960,
|
||||
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"setup": "setup.sh",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
|
@ -10,10 +10,11 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 4431740,
|
||||
"digest": "68fc56b0fb0cdba629b95683d6649ff76b00dccf97af90960c3d7716f6108b2162ffd5ffcd5c3a60a21b28674df688fe4dabc67345e2da35ec5abeae3d48c8e3",
|
||||
"size": 12057960,
|
||||
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"setup": "setup.sh",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -1,16 +0,0 @@
|
||||
[
|
||||
{
|
||||
"size": 80458572,
|
||||
"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
@ -59,6 +59,15 @@ this.E10SUtils = {
|
||||
mustLoadRemote = chromeReg.mustLoadURLRemotely(url);
|
||||
}
|
||||
|
||||
if (aURL.startsWith("moz-extension:")) {
|
||||
canLoadRemote = false;
|
||||
mustLoadRemote = false;
|
||||
}
|
||||
|
||||
if (aURL.startsWith("view-source:")) {
|
||||
return this.canLoadURIInProcess(aURL.substr("view-source:".length), aProcess);
|
||||
}
|
||||
|
||||
if (mustLoadRemote)
|
||||
return processIsRemote;
|
||||
|
||||
|
@ -1944,3 +1944,7 @@ chatbox {
|
||||
-moz-padding-end: 0 !important;
|
||||
-moz-margin-end: 0 !important;
|
||||
}
|
||||
|
||||
.browser-action-panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -3685,3 +3685,7 @@ window > chatbox {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.browser-action-panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -2904,3 +2904,7 @@ chatbox {
|
||||
@media not all and (-moz-os-version: windows-xp) {
|
||||
%include browser-aero.css
|
||||
}
|
||||
|
||||
.browser-action-panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -241,6 +241,7 @@ class CustomTypeAnnotation {
|
||||
RK_ArrayElement,
|
||||
RK_BaseClass,
|
||||
RK_Field,
|
||||
RK_TemplateInherited,
|
||||
};
|
||||
struct AnnotationReason {
|
||||
QualType Type;
|
||||
@ -842,6 +843,15 @@ void CustomTypeAnnotation::dumpAnnotationReason(DiagnosticsEngine &Diag, QualTyp
|
||||
Diag.Report(Reason.Field->getLocation(), MemberID)
|
||||
<< Pretty << T << Reason.Field << Reason.Type;
|
||||
break;
|
||||
case RK_TemplateInherited:
|
||||
{
|
||||
const CXXRecordDecl *Decl = T->getAsCXXRecordDecl();
|
||||
assert(Decl && "This type should be a C++ class");
|
||||
|
||||
Diag.Report(Decl->getLocation(), TemplID)
|
||||
<< Pretty << T << Reason.Type;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@ -905,6 +915,29 @@ CustomTypeAnnotation::AnnotationReason CustomTypeAnnotation::directAnnotationRea
|
||||
return Reason;
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse into template arguments if the annotation
|
||||
// MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS is present
|
||||
if (MozChecker::hasCustomAnnotation(
|
||||
Decl, "moz_inherit_type_annotations_from_template_args")) {
|
||||
const ClassTemplateSpecializationDecl *Spec =
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(Decl);
|
||||
if (Spec) {
|
||||
const TemplateArgumentList &Args = Spec->getTemplateArgs();
|
||||
|
||||
for (const TemplateArgument &Arg : Args.asArray()) {
|
||||
if (Arg.getKind() == TemplateArgument::Type) {
|
||||
QualType Type = Arg.getAsType();
|
||||
|
||||
if (hasEffectiveAnnotation(Type)) {
|
||||
AnnotationReason Reason = { Type, RK_TemplateInherited, nullptr };
|
||||
Cache[Key] = Reason;
|
||||
return Reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
#define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \
|
||||
__attribute__((annotate("moz_inherit_type_annotations_from_template_args")))
|
||||
#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
|
||||
|
||||
class Normal {};
|
||||
class MOZ_STACK_CLASS Stack {};
|
||||
class IndirectStack : Stack {}; // expected-note {{'IndirectStack' is a stack type because it inherits from a stack type 'Stack'}}
|
||||
|
||||
template<class T>
|
||||
class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Template {}; // expected-note 2 {{'Template<Stack>' is a stack type because it has a template argument stack type 'Stack'}} expected-note {{'Template<IndirectStack>' is a stack type because it has a template argument stack type 'IndirectStack'}}
|
||||
class IndirectTemplate : Template<Stack> {}; // expected-note {{'IndirectTemplate' is a stack type because it inherits from a stack type 'Template<Stack>'}}
|
||||
|
||||
static Template<Stack> a; // expected-error {{variable of type 'Template<Stack>' only valid on the stack}}
|
||||
static Template<IndirectStack> b; // expected-error {{variable of type 'Template<IndirectStack>' only valid on the stack}}
|
||||
static Template<Normal> c;
|
||||
static IndirectTemplate d; // expected-error {{variable of type 'IndirectTemplate' only valid on the stack}}
|
||||
|
@ -9,6 +9,7 @@ SOURCES += [
|
||||
'TestCustomHeap.cpp',
|
||||
'TestExplicitOperatorBool.cpp',
|
||||
'TestGlobalClass.cpp',
|
||||
'TestInheritTypeAnnotationsFromTemplateArgs.cpp',
|
||||
'TestMultipleAnnotations.cpp',
|
||||
'TestMustOverride.cpp',
|
||||
'TestMustUse.cpp',
|
||||
|
@ -47,6 +47,13 @@ leak:webrtc::DesktopApplication::
|
||||
# Bug 1187518 - SCTP leaks in child process while running WebRTC tests.
|
||||
leak:recv_function_udp
|
||||
|
||||
# Bug 1074310 - Very large e10s vp8 leaks, maybe in WebRTC tests.
|
||||
leak:set_noise_sensitivity
|
||||
leak:vp8_alloc_compressor_data
|
||||
leak:vp8_change_config
|
||||
leak:vp8_lookahead_init
|
||||
leak:vpx_codec_enc_init_ver
|
||||
|
||||
|
||||
###
|
||||
### Many leaks only affect some test suites. The suite annotations are not checked.
|
||||
@ -107,6 +114,14 @@ leak:MessageLoop::MessageLoop
|
||||
leak:base::WaitableEvent::TimedWait
|
||||
leak:MessageLoop::PostTask_Helper
|
||||
|
||||
# Bug 1189430 - DNS leaks in mochitest-chrome.
|
||||
leak:nsDNSService::AsyncResolveExtended
|
||||
leak:_GetAddrInfo_Portable
|
||||
|
||||
# Bug 1189568 - Indirect leaks of IMContextWrapper and nsIntRect.
|
||||
leak:nsWindow::Create
|
||||
leak:nsBaseWidget::StoreWindowClipRegion
|
||||
|
||||
|
||||
###
|
||||
### Leaks with system libraries in their stacks. These show up across a number of tests.
|
||||
|
@ -57,7 +57,7 @@ build() {
|
||||
cd build/$name
|
||||
eval ../../$name-$version/configure --disable-static $* $configure_args
|
||||
make $make_flags
|
||||
make install-strip DESTDIR=$root_dir/gtk3
|
||||
make install DESTDIR=$root_dir/gtk3
|
||||
find $root_dir/gtk3 -name \*.la -delete
|
||||
cd ../..
|
||||
}
|
||||
@ -103,5 +103,44 @@ build gtk+
|
||||
rm -rf $root_dir/gtk3/usr/local/share/gtk-doc
|
||||
rm -rf $root_dir/gtk3/usr/local/share/locale
|
||||
|
||||
# mock build environment doesn't have fonts in /usr/share/fonts, but
|
||||
# has some in /usr/share/X11/fonts. Add this directory to the
|
||||
# fontconfig configuration without changing the gtk3 tooltool package.
|
||||
cat << EOF > $root_dir/gtk3/usr/local/etc/fonts/local.conf
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<dir>/usr/share/X11/fonts</dir>
|
||||
</fontconfig>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $root_dir/gtk3/setup.sh
|
||||
#!/bin/sh
|
||||
|
||||
cd \$(dirname \$0)
|
||||
|
||||
# pango expects absolute paths in pango.modules, and TOOLTOOL_DIR may vary...
|
||||
LD_LIBRARY_PATH=./usr/local/lib \
|
||||
PANGO_SYSCONFDIR=./usr/local/etc \
|
||||
PANGO_LIBDIR=./usr/local/lib \
|
||||
./usr/local/bin/pango-querymodules > ./usr/local/etc/pango/pango.modules
|
||||
|
||||
# same with gdb-pixbuf and loaders.cache
|
||||
LD_LIBRARY_PATH=./usr/local/lib \
|
||||
GDK_PIXBUF_MODULE_FILE=./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache \
|
||||
GDK_PIXBUF_MODULEDIR=./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders \
|
||||
./usr/local/bin/gdk-pixbuf-query-loaders > ./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
|
||||
|
||||
# The fontconfig version in the tooltool package has known uses of
|
||||
# uninitialized memory when creating its cache, and while most users
|
||||
# will already have an existing cache, running Firefox on automation
|
||||
# will create it. Combined with valgrind, this generates irrelevant
|
||||
# errors.
|
||||
# So create the fontconfig cache beforehand.
|
||||
./usr/local/bin/fc-cache
|
||||
EOF
|
||||
|
||||
chmod +x $root_dir/gtk3/setup.sh
|
||||
|
||||
cd $cwd
|
||||
tar -C $root_dir -Jcf gtk3.tar.xz gtk3
|
||||
|
@ -1,48 +1,28 @@
|
||||
# $topsrcdir/gtk3 comes from tooltool, when the tooltool manifest contains it.
|
||||
if [ -d "$topsrcdir/gtk3" ]; then
|
||||
TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
|
||||
|
||||
# $TOOLTOOL_DIR/gtk3 comes from tooltool, when the tooltool manifest contains it.
|
||||
if [ -d "$TOOLTOOL_DIR/gtk3" ]; then
|
||||
if [ -z "$PKG_CONFIG_LIBDIR" ]; then
|
||||
echo PKG_CONFIG_LIBDIR must be set >&2
|
||||
exit 1
|
||||
fi
|
||||
export PKG_CONFIG_SYSROOT_DIR="$topsrcdir/gtk3"
|
||||
export PKG_CONFIG_PATH="$topsrcdir/gtk3/usr/local/lib/pkgconfig"
|
||||
export PATH="$topsrcdir/gtk3/usr/local/bin:${PATH}"
|
||||
export PKG_CONFIG_SYSROOT_DIR="$TOOLTOOL_DIR/gtk3"
|
||||
export PKG_CONFIG_PATH="$TOOLTOOL_DIR/gtk3/usr/local/lib/pkgconfig"
|
||||
export PATH="$TOOLTOOL_DIR/gtk3/usr/local/bin:${PATH}"
|
||||
# Ensure cairo, gdk-pixbuf, etc. are not taken from the system installed packages.
|
||||
LDFLAGS="-L$topsrcdir/gtk3/usr/local/lib ${LDFLAGS}"
|
||||
mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/gtk3/usr/local/lib"
|
||||
LDFLAGS="-L$TOOLTOOL_DIR/gtk3/usr/local/lib ${LDFLAGS}"
|
||||
ac_add_options --enable-default-toolkit=cairo-gtk3
|
||||
|
||||
# Set things up to use Gtk+3 from the tooltool package
|
||||
mk_add_options "export FONTCONFIG_PATH=$topsrcdir/gtk3/usr/local/etc/fonts"
|
||||
mk_add_options "export PANGO_SYSCONFDIR=$topsrcdir/gtk3/usr/local/etc"
|
||||
mk_add_options "export PANGO_LIBDIR=$topsrcdir/gtk3/usr/local/lib"
|
||||
mk_add_options "export GDK_PIXBUF_MODULE_FILE=$topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
|
||||
mk_add_options "export GDK_PIXBUF_MODULEDIR=$topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders"
|
||||
mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/gtk3/usr/local/lib"
|
||||
|
||||
# pango expects absolute paths in pango.modules, and topsrcdir may vary...
|
||||
LD_LIBRARY_PATH=$topsrcdir/gtk3/usr/local/lib \
|
||||
PANGO_SYSCONFDIR=$topsrcdir/gtk3/usr/local/etc \
|
||||
PANGO_LIBDIR=$topsrcdir/gtk3/usr/local/lib \
|
||||
$topsrcdir/gtk3/usr/local/bin/pango-querymodules > $topsrcdir/gtk3/usr/local/etc/pango/pango.modules
|
||||
|
||||
# same with gdb-pixbuf and loaders.cache
|
||||
LD_LIBRARY_PATH=$topsrcdir/gtk3/usr/local/lib \
|
||||
GDK_PIXBUF_MODULE_FILE=$topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache \
|
||||
GDK_PIXBUF_MODULEDIR=$topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders \
|
||||
$topsrcdir/gtk3/usr/local/bin/gdk-pixbuf-query-loaders > $topsrcdir/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
|
||||
|
||||
# mock build environment doesn't have fonts in /usr/share/fonts, but
|
||||
# has some in /usr/share/X11/fonts. Add this directory to the
|
||||
# fontconfig configuration without changing the gtk3 tooltool package.
|
||||
cat << EOF > $topsrcdir/gtk3/usr/local/etc/fonts/local.conf
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<dir>/usr/share/X11/fonts</dir>
|
||||
</fontconfig>
|
||||
EOF
|
||||
mk_add_options "export FONTCONFIG_PATH=$TOOLTOOL_DIR/gtk3/usr/local/etc/fonts"
|
||||
mk_add_options "export PANGO_SYSCONFDIR=$TOOLTOOL_DIR/gtk3/usr/local/etc"
|
||||
mk_add_options "export PANGO_LIBDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib"
|
||||
mk_add_options "export GDK_PIXBUF_MODULE_FILE=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
|
||||
mk_add_options "export GDK_PIXBUF_MODULEDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders"
|
||||
mk_add_options "export LD_LIBRARY_PATH=$TOOLTOOL_DIR/gtk3/usr/local/lib"
|
||||
|
||||
# Until a tooltool with bug 1188571 landed is available everywhere
|
||||
$TOOLTOOL_DIR/gtk3/setup.sh
|
||||
else
|
||||
ac_add_options --enable-default-toolkit=cairo-gtk2
|
||||
fi
|
||||
|
@ -111,6 +111,13 @@ class MachCommands(MachCommandBase):
|
||||
'--show-possibly-lost=no',
|
||||
'--track-origins=yes',
|
||||
'--trace-children=yes',
|
||||
# The gstreamer plugin scanner can run as part of executing
|
||||
# firefox, but is an external program. In some weird cases,
|
||||
# valgrind finds errors while executing __libc_freeres when
|
||||
# it runs, but those are not relevant, as it's related to
|
||||
# executing third party code. So don't trace
|
||||
# gst-plugin-scanner.
|
||||
'--trace-children-skip=*/gst-plugin-scanner',
|
||||
'-v', # Enable verbosity to get the list of used suppressions
|
||||
]
|
||||
|
||||
|
@ -25,7 +25,7 @@ else
|
||||
_arch=32
|
||||
fi
|
||||
|
||||
TOOLTOOL_MANIFEST=browser/config/tooltool-manifests/linux${_arch}/valgrind.manifest
|
||||
TOOLTOOL_MANIFEST=browser/config/tooltool-manifests/linux${_arch}/releng.manifest
|
||||
TOOLTOOL_SERVER=https://api.pub.build.mozilla.org/tooltool/
|
||||
(cd $srcdir; python /builds/tooltool.py --url $TOOLTOOL_SERVER --overwrite -m $TOOLTOOL_MANIFEST fetch ${TOOLTOOL_CACHE:+ -c ${TOOLTOOL_CACHE}}) || exit 2
|
||||
|
||||
|
@ -327,7 +327,8 @@ nsSHEntryShared::AttributeWillChange(nsIDocument* aDocument,
|
||||
dom::Element* aContent,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue)
|
||||
{
|
||||
}
|
||||
|
||||
@ -336,7 +337,8 @@ nsSHEntryShared::AttributeChanged(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
RemoveFromBFCacheAsync();
|
||||
}
|
||||
|
@ -2181,9 +2181,11 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAttrValue* preparsedAttrValue = value.GetStoredAttrValue();
|
||||
|
||||
if (aNotify) {
|
||||
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
|
||||
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
|
||||
preparsedAttrValue);
|
||||
}
|
||||
|
||||
// Hold a script blocker while calling ParseAttribute since that can call
|
||||
@ -2191,6 +2193,11 @@ Element::SetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
|
||||
nsAttrValue attrValue;
|
||||
if (preparsedAttrValue) {
|
||||
attrValue.SwapValueWith(*preparsedAttrValue);
|
||||
}
|
||||
// Even the value was pre-parsed in BeforeSetAttr, we still need to call
|
||||
// ParseAttribute because it can have side effects.
|
||||
if (!ParseAttribute(aNamespaceID, aName, aValue, attrValue)) {
|
||||
attrValue.SetTo(aValue);
|
||||
}
|
||||
@ -2230,7 +2237,8 @@ Element::SetParsedAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNotify) {
|
||||
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType);
|
||||
nsNodeUtils::AttributeWillChange(this, aNamespaceID, aName, modType,
|
||||
&aParsedValue);
|
||||
}
|
||||
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
||||
@ -2257,10 +2265,10 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
nsMutationGuard::DidMutate();
|
||||
|
||||
// Copy aParsedValue for later use since it will be lost when we call
|
||||
// SetAndTakeMappedAttr below
|
||||
nsAttrValue aValueForAfterSetAttr;
|
||||
// SetAndSwapMappedAttr below
|
||||
nsAttrValue valueForAfterSetAttr;
|
||||
if (aCallAfterSetAttr) {
|
||||
aValueForAfterSetAttr.SetTo(aParsedValue);
|
||||
valueForAfterSetAttr.SetTo(aParsedValue);
|
||||
}
|
||||
|
||||
bool hadValidDir = false;
|
||||
@ -2276,7 +2284,7 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
// stuff to Element?
|
||||
if (!IsAttributeMapped(aName) ||
|
||||
!SetMappedAttribute(document, aName, aParsedValue, &rv)) {
|
||||
rv = mAttrsAndChildren.SetAndTakeAttr(aName, aParsedValue);
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(aName, aParsedValue);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -2285,8 +2293,13 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
aNamespaceID,
|
||||
nsIDOMNode::ATTRIBUTE_NODE);
|
||||
|
||||
rv = mAttrsAndChildren.SetAndTakeAttr(ni, aParsedValue);
|
||||
rv = mAttrsAndChildren.SetAndSwapAttr(ni, aParsedValue);
|
||||
}
|
||||
|
||||
// If the old value owns its own data, we know it is OK to keep using it.
|
||||
const nsAttrValue* oldValue =
|
||||
aParsedValue.StoresOwnData() ? &aParsedValue : &aOldValue;
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (document || HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
@ -2300,8 +2313,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
|
||||
nsIDocument* ownerDoc = OwnerDoc();
|
||||
if (ownerDoc && GetCustomElementData()) {
|
||||
nsCOMPtr<nsIAtom> oldValueAtom = aOldValue.GetAsAtom();
|
||||
nsCOMPtr<nsIAtom> newValueAtom = aValueForAfterSetAttr.GetAsAtom();
|
||||
nsCOMPtr<nsIAtom> oldValueAtom = oldValue->GetAsAtom();
|
||||
nsCOMPtr<nsIAtom> newValueAtom = valueForAfterSetAttr.GetAsAtom();
|
||||
LifecycleCallbackArgs args = {
|
||||
nsDependentAtomString(aName),
|
||||
aModType == nsIDOMMutationEvent::ADDITION ?
|
||||
@ -2313,17 +2326,21 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
}
|
||||
|
||||
if (aCallAfterSetAttr) {
|
||||
rv = AfterSetAttr(aNamespaceID, aName, &aValueForAfterSetAttr, aNotify);
|
||||
rv = AfterSetAttr(aNamespaceID, aName, &valueForAfterSetAttr, aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNamespaceID == kNameSpaceID_None && aName == nsGkAtoms::dir) {
|
||||
OnSetDirAttr(this, &aValueForAfterSetAttr,
|
||||
OnSetDirAttr(this, &valueForAfterSetAttr,
|
||||
hadValidDir, hadDirAuto, aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
if (aNotify) {
|
||||
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
|
||||
// Don't pass aOldValue to AttributeChanged since it may not be reliable.
|
||||
// Callers only compute aOldValue under certain conditions which may not
|
||||
// be triggered by all nsIMutationObservers.
|
||||
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType,
|
||||
oldValue == &aParsedValue ? &aParsedValue : nullptr);
|
||||
}
|
||||
|
||||
if (aFireMutation) {
|
||||
@ -2341,8 +2358,8 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
if (!newValue.IsEmpty()) {
|
||||
mutation.mNewAttrValue = do_GetAtom(newValue);
|
||||
}
|
||||
if (!aOldValue.IsEmptyString()) {
|
||||
mutation.mPrevAttrValue = aOldValue.GetAsAtom();
|
||||
if (!oldValue->IsEmptyString()) {
|
||||
mutation.mPrevAttrValue = oldValue->GetAsAtom();
|
||||
}
|
||||
mutation.mAttrChange = aModType;
|
||||
|
||||
@ -2353,6 +2370,25 @@ Element::SetAttrAndNotify(int32_t aNamespaceID,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Element::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue, bool aNotify)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::_class) {
|
||||
// aValue->GetAttrValue will only be non-null here when this is called
|
||||
// via Element::SetParsedAttr. This shouldn't happen for "class", but
|
||||
// this will handle it.
|
||||
if (aValue && !aValue->GetAttrValue()) {
|
||||
nsAttrValue attr;
|
||||
attr.ParseAtomArray(aValue->String());
|
||||
aValue->TakeParsedValue(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
Element::ParseAttribute(int32_t aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
@ -2362,7 +2398,7 @@ Element::ParseAttribute(int32_t aNamespaceID,
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::_class) {
|
||||
SetFlags(NODE_MAY_HAVE_CLASS);
|
||||
aResult.ParseAtomArray(aValue);
|
||||
// Result should have been preparsed above.
|
||||
return true;
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::id) {
|
||||
@ -2469,7 +2505,8 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
|
||||
if (aNotify) {
|
||||
nsNodeUtils::AttributeWillChange(this, aNameSpaceID, aName,
|
||||
nsIDOMMutationEvent::REMOVAL);
|
||||
nsIDOMMutationEvent::REMOVAL,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
bool hasMutationListeners = aNotify &&
|
||||
@ -2535,8 +2572,10 @@ Element::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
}
|
||||
|
||||
if (aNotify) {
|
||||
// We can always pass oldValue here since there is no new value which could
|
||||
// have corrupted it.
|
||||
nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
|
||||
nsIDOMMutationEvent::REMOVAL);
|
||||
nsIDOMMutationEvent::REMOVAL, &oldValue);
|
||||
}
|
||||
|
||||
rv = AfterSetAttr(aNameSpaceID, aName, nullptr, aNotify);
|
||||
@ -3494,4 +3533,4 @@ Element::GetReferrerPolicy()
|
||||
}
|
||||
}
|
||||
return net::RP_Unset;
|
||||
}
|
||||
}
|
||||
|
@ -477,6 +477,8 @@ public:
|
||||
|
||||
virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
|
||||
const nsAString& aValue, bool aNotify) override;
|
||||
// aParsedValue receives the old value of the attribute. That's useful if
|
||||
// either the input or output value of aParsedValue is StoresOwnData.
|
||||
nsresult SetParsedAttr(int32_t aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
|
||||
nsAttrValue& aParsedValue, bool aNotify);
|
||||
// GetAttr is not inlined on purpose, to keep down codesize from all
|
||||
@ -1087,10 +1089,15 @@ protected:
|
||||
* @param aNamespaceID namespace of attribute
|
||||
* @param aAttribute local-name of attribute
|
||||
* @param aPrefix aPrefix of attribute
|
||||
* @param aOldValue previous value of attribute. Only needed if
|
||||
* aFireMutation is true or if the element is a
|
||||
* custom element (in web components).
|
||||
* @param aParsedValue parsed new value of attribute
|
||||
* @param aOldValue The old value of the attribute to use as a fallback
|
||||
* in the cases where the actual old value (i.e.
|
||||
* its current value) is !StoresOwnData() --- in which
|
||||
* case the current value is probably already useless.
|
||||
* If the current value is StoresOwnData() (or absent),
|
||||
* aOldValue will not be used.
|
||||
* @param aParsedValue parsed new value of attribute. Replaced by the
|
||||
* old value of the attribute. This old value is only
|
||||
* useful if either it or the new value is StoresOwnData.
|
||||
* @param aModType nsIDOMMutationEvent::MODIFICATION or ADDITION. Only
|
||||
* needed if aFireMutation or aNotify is true.
|
||||
* @param aFireMutation should mutation-events be fired?
|
||||
@ -1163,17 +1170,16 @@ protected:
|
||||
* @param aName the localname of the attribute being set
|
||||
* @param aValue the value it's being set to represented as either a string or
|
||||
* a parsed nsAttrValue. Alternatively, if the attr is being removed it
|
||||
* will be null.
|
||||
* will be null. BeforeSetAttr is allowed to modify aValue by parsing
|
||||
* the string to an nsAttrValue (to avoid having to reparse it in
|
||||
* ParseAttribute).
|
||||
* @param aNotify Whether we plan to notify document observers.
|
||||
*/
|
||||
// Note that this is inlined so that when subclasses call it it gets
|
||||
// inlined. Those calls don't go through a vtable.
|
||||
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify);
|
||||
|
||||
/**
|
||||
* Hook that is called by Element::SetAttr to allow subclasses to
|
||||
|
@ -607,7 +607,8 @@ ShadowRoot::AttributeChanged(nsIDocument* aDocument,
|
||||
Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
if (!IsPooledNode(aElement, aElement->GetParent(), mPoolHost)) {
|
||||
return;
|
||||
|
@ -387,14 +387,12 @@ nsAttrAndChildArray::AttrAt(uint32_t aPos) const
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
|
||||
nsAttrAndChildArray::SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
|
||||
{
|
||||
uint32_t i, slotCount = AttrSlotCount();
|
||||
for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) {
|
||||
if (ATTRS(mImpl)[i].mName.Equals(aLocalName)) {
|
||||
ATTRS(mImpl)[i].mValue.Reset();
|
||||
ATTRS(mImpl)[i].mValue.SwapValueWith(aValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -414,12 +412,12 @@ nsAttrAndChildArray::SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAttrAndChildArray::SetAndTakeAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue)
|
||||
nsAttrAndChildArray::SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue)
|
||||
{
|
||||
int32_t namespaceID = aName->NamespaceID();
|
||||
nsIAtom* localName = aName->NameAtom();
|
||||
if (namespaceID == kNameSpaceID_None) {
|
||||
return SetAndTakeAttr(localName, aValue);
|
||||
return SetAndSwapAttr(localName, aValue);
|
||||
}
|
||||
|
||||
uint32_t i, slotCount = AttrSlotCount();
|
||||
|
@ -88,8 +88,9 @@ public:
|
||||
const nsAttrValue* GetAttr(const nsAString& aName,
|
||||
nsCaseTreatment aCaseSensitive) const;
|
||||
const nsAttrValue* AttrAt(uint32_t aPos) const;
|
||||
nsresult SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
|
||||
nsresult SetAndTakeAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue);
|
||||
// SetAndSwapAttr swaps the current attribute value with aValue.
|
||||
nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue);
|
||||
nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue);
|
||||
|
||||
// Remove the attr at position aPos. The value of the attr is placed in
|
||||
// aValue; any value that was already in aValue is destroyed.
|
||||
|
@ -127,6 +127,12 @@ public:
|
||||
static void Shutdown();
|
||||
|
||||
ValueType Type() const;
|
||||
// Returns true when this value is self-contained and does not depend on
|
||||
// the state of its associated element.
|
||||
// Returns false when this value depends on the state of its associated
|
||||
// element and may be invalid if that state has been changed by changes to
|
||||
// that element state outside of attribute setting.
|
||||
inline bool StoresOwnData() const;
|
||||
|
||||
void Reset();
|
||||
|
||||
|
@ -191,6 +191,16 @@ nsAttrValue::IsSVGType(ValueType aType) const
|
||||
return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd;
|
||||
}
|
||||
|
||||
inline bool
|
||||
nsAttrValue::StoresOwnData() const
|
||||
{
|
||||
if (BaseType() != eOtherBase) {
|
||||
return true;
|
||||
}
|
||||
ValueType t = Type();
|
||||
return t != eCSSStyleRule && !IsSVGType(t);
|
||||
}
|
||||
|
||||
inline void
|
||||
nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType)
|
||||
{
|
||||
|
@ -49,6 +49,21 @@ public:
|
||||
, mCheapString(nullptr)
|
||||
{ }
|
||||
|
||||
void TakeParsedValue(nsAttrValue& aValue)
|
||||
{
|
||||
mStoredAttrValue.SwapValueWith(aValue);
|
||||
mAttrValue = &mStoredAttrValue;
|
||||
mStringPtr = nullptr;
|
||||
}
|
||||
/**
|
||||
* If TakeParsedValue has been called, returns the value that it set.
|
||||
*/
|
||||
nsAttrValue* GetStoredAttrValue()
|
||||
{
|
||||
return mAttrValue == &mStoredAttrValue ? &mStoredAttrValue : nullptr;
|
||||
}
|
||||
const nsAttrValue* GetAttrValue() { return mAttrValue; }
|
||||
|
||||
/**
|
||||
* Returns a reference to the string value of the contents of this object.
|
||||
*
|
||||
@ -74,6 +89,7 @@ protected:
|
||||
const nsAttrValue* mAttrValue;
|
||||
mutable const nsAString* mStringPtr;
|
||||
mutable nsCheapString mCheapString;
|
||||
nsAttrValue mStoredAttrValue;
|
||||
};
|
||||
|
||||
#endif // nsAttrValueOrString_h___
|
||||
|
@ -659,7 +659,8 @@ nsContentList::Item(uint32_t aIndex)
|
||||
void
|
||||
nsContentList::AttributeChanged(nsIDocument *aDocument, Element* aElement,
|
||||
int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
NS_PRECONDITION(aElement, "Must have a content node to work with");
|
||||
|
||||
|
@ -555,21 +555,15 @@ nsDOMAttributeMap::Enumerate(AttrCache::EnumReadFunction aFunc,
|
||||
return mAttributeCache.EnumerateRead(aFunc, aUserArg);
|
||||
}
|
||||
|
||||
size_t
|
||||
AttrCacheSizeEnumerator(const nsAttrKey& aKey,
|
||||
const nsRefPtr<Attr>& aValue,
|
||||
MallocSizeOf aMallocSizeOf,
|
||||
void* aUserArg)
|
||||
{
|
||||
return aMallocSizeOf(aValue.get());
|
||||
}
|
||||
|
||||
size_t
|
||||
nsDOMAttributeMap::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += mAttributeCache.SizeOfExcludingThis(AttrCacheSizeEnumerator,
|
||||
aMallocSizeOf);
|
||||
|
||||
n += mAttributeCache.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (auto iter = mAttributeCache.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
n += aMallocSizeOf(iter.Data().get());
|
||||
}
|
||||
|
||||
// NB: mContent is non-owning and thus not counted.
|
||||
return n;
|
||||
|
@ -117,7 +117,8 @@ nsMutationReceiver::AttributeWillChange(nsIDocument* aDocument,
|
||||
mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue)
|
||||
{
|
||||
if (nsAutoMutationBatch::IsBatching() ||
|
||||
!ObservesAttr(RegisterTarget(), aElement, aNameSpaceID, aAttribute)) {
|
||||
|
@ -374,7 +374,7 @@ public:
|
||||
{
|
||||
// We can reuse AttributeWillChange implementation.
|
||||
AttributeWillChange(aDocument, aElement, aNameSpaceID, aAttribute,
|
||||
nsIDOMMutationEvent::MODIFICATION);
|
||||
nsIDOMMutationEvent::MODIFICATION, nullptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -12635,7 +12635,7 @@ nsDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
|
||||
0;
|
||||
|
||||
aWindowSizes->mDOMOtherSize +=
|
||||
mStyledLinks.SizeOfExcludingThis(nullptr, aWindowSizes->mMallocSizeOf);
|
||||
mStyledLinks.ShallowSizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
|
||||
|
||||
aWindowSizes->mDOMOtherSize +=
|
||||
mIdentifierMap.SizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
|
||||
|
@ -156,6 +156,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
|
||||
, mVisible(true)
|
||||
{
|
||||
ResetPermissionManagerStatus();
|
||||
mRemoteFrame = ShouldUseRemoteProcess();
|
||||
}
|
||||
|
||||
nsFrameLoader::~nsFrameLoader()
|
||||
@ -301,20 +302,12 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
PROFILER_LABEL("nsFrameLoader", "ReallyStartLoading",
|
||||
js::ProfileEntry::Category::OTHER);
|
||||
|
||||
nsresult rv = MaybeCreateDocShell();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (mRemoteFrame) {
|
||||
if (IsRemoteFrame()) {
|
||||
if (!mRemoteBrowser && !TryRemoteBrowser()) {
|
||||
NS_WARNING("Couldn't create child process for iframe.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Execute pending frame scripts before loading URL
|
||||
EnsureMessageManager();
|
||||
|
||||
// FIXME get error codes from child
|
||||
mRemoteBrowser->LoadURL(mURIToLoad);
|
||||
|
||||
@ -325,6 +318,10 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = MaybeCreateDocShell();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
NS_ASSERTION(mDocShell,
|
||||
"MaybeCreateDocShell succeeded with a null mDocShell");
|
||||
|
||||
@ -444,11 +441,7 @@ nsFrameLoader::CheckURILoad(nsIURI* aURI)
|
||||
}
|
||||
|
||||
// Bail out if this is an infinite recursion scenario
|
||||
rv = MaybeCreateDocShell();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (mRemoteFrame) {
|
||||
if (IsRemoteFrame()) {
|
||||
return NS_OK;
|
||||
}
|
||||
return CheckForRecursiveLoad(aURI);
|
||||
@ -460,14 +453,16 @@ nsFrameLoader::GetDocShell(nsIDocShell **aDocShell)
|
||||
*aDocShell = nullptr;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (IsRemoteFrame()) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// If we have an owner, make sure we have a docshell and return
|
||||
// that. If not, we're most likely in the middle of being torn down,
|
||||
// then we just return null.
|
||||
if (mOwnerContent) {
|
||||
nsresult rv = MaybeCreateDocShell();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (mRemoteFrame) {
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
NS_ASSERTION(mDocShell,
|
||||
@ -625,42 +620,42 @@ nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight,
|
||||
AutoResetInShow resetInShow(this);
|
||||
mInShow = true;
|
||||
|
||||
ScreenIntSize size = frame->GetSubdocumentSize();
|
||||
if (IsRemoteFrame()) {
|
||||
return ShowRemoteFrame(size, frame);
|
||||
}
|
||||
|
||||
nsresult rv = MaybeCreateDocShell();
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mRemoteFrame) {
|
||||
if (!mDocShell)
|
||||
return false;
|
||||
|
||||
mDocShell->SetMarginWidth(marginWidth);
|
||||
mDocShell->SetMarginHeight(marginHeight);
|
||||
|
||||
nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
|
||||
if (sc) {
|
||||
sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
|
||||
scrollbarPrefX);
|
||||
sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
|
||||
scrollbarPrefY);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
|
||||
if (presShell) {
|
||||
// Ensure root scroll frame is reflowed in case scroll preferences or
|
||||
// margins have changed
|
||||
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
|
||||
if (rootScrollFrame) {
|
||||
presShell->FrameNeedsReflow(rootScrollFrame, nsIPresShell::eResize,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
NS_ASSERTION(mDocShell,
|
||||
"MaybeCreateDocShell succeeded, but null mDocShell");
|
||||
if (!mDocShell) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScreenIntSize size = frame->GetSubdocumentSize();
|
||||
if (mRemoteFrame) {
|
||||
return ShowRemoteFrame(size, frame);
|
||||
mDocShell->SetMarginWidth(marginWidth);
|
||||
mDocShell->SetMarginHeight(marginHeight);
|
||||
|
||||
nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
|
||||
if (sc) {
|
||||
sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
|
||||
scrollbarPrefX);
|
||||
sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
|
||||
scrollbarPrefY);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
|
||||
if (presShell) {
|
||||
// Ensure root scroll frame is reflowed in case scroll preferences or
|
||||
// margins have changed
|
||||
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
|
||||
if (rootScrollFrame) {
|
||||
presShell->FrameNeedsReflow(rootScrollFrame, nsIPresShell::eResize,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsView* view = frame->EnsureInnerView();
|
||||
@ -682,7 +677,7 @@ nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight,
|
||||
// sub-document. This shouldn't be necessary, but given the way our
|
||||
// editor works, it is. See
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=284245
|
||||
nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
|
||||
presShell = mDocShell->GetPresShell();
|
||||
if (presShell) {
|
||||
nsCOMPtr<nsIDOMHTMLDocument> doc =
|
||||
do_QueryInterface(presShell->GetDocument());
|
||||
@ -729,7 +724,7 @@ nsFrameLoader::MarginsChanged(uint32_t aMarginWidth,
|
||||
uint32_t aMarginHeight)
|
||||
{
|
||||
// We assume that the margins are always zero for remote frames.
|
||||
if (mRemoteFrame)
|
||||
if (IsRemoteFrame())
|
||||
return;
|
||||
|
||||
// If there's no docshell, we're probably not up and running yet.
|
||||
@ -754,7 +749,7 @@ bool
|
||||
nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
|
||||
nsSubDocumentFrame *aFrame)
|
||||
{
|
||||
NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames.");
|
||||
NS_ASSERTION(IsRemoteFrame(), "ShowRemote only makes sense on remote frames.");
|
||||
|
||||
if (!mRemoteBrowser && !TryRemoteBrowser()) {
|
||||
NS_ERROR("Couldn't create child process.");
|
||||
@ -790,9 +785,6 @@ nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
|
||||
mRemoteBrowser->Show(size, parentIsActive);
|
||||
mRemoteBrowserShown = true;
|
||||
|
||||
EnsureMessageManager();
|
||||
|
||||
InitializeBrowserAPI();
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
@ -967,11 +959,11 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
|
||||
"Swapping some sort of random loaders?");
|
||||
NS_ENSURE_STATE(!mInShow && !aOther->mInShow);
|
||||
|
||||
if (mRemoteFrame && aOther->mRemoteFrame) {
|
||||
if (IsRemoteFrame() && aOther->IsRemoteFrame()) {
|
||||
return SwapWithOtherRemoteLoader(aOther, aFirstToSwap, aSecondToSwap);
|
||||
}
|
||||
|
||||
if (mRemoteFrame || aOther->mRemoteFrame) {
|
||||
if (IsRemoteFrame() || aOther->IsRemoteFrame()) {
|
||||
NS_WARNING("Swapping remote and non-remote frames is not currently supported");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
@ -1641,22 +1633,27 @@ nsFrameLoader::ShouldUseRemoteProcess()
|
||||
eCaseMatters);
|
||||
}
|
||||
|
||||
bool
|
||||
nsFrameLoader::IsRemoteFrame()
|
||||
{
|
||||
if (mRemoteFrame) {
|
||||
MOZ_ASSERT(!mDocShell, "Found a remote frame with a DocShell");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrameLoader::MaybeCreateDocShell()
|
||||
{
|
||||
if (mDocShell) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (mRemoteFrame) {
|
||||
if (IsRemoteFrame()) {
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ENSURE_STATE(!mDestroyCalled);
|
||||
|
||||
if (ShouldUseRemoteProcess()) {
|
||||
mRemoteFrame = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get our parent docshell off the document of mOwnerContent
|
||||
// XXXbz this is such a total hack.... We really need to have a
|
||||
// better setup for doing this.
|
||||
@ -1789,8 +1786,6 @@ nsFrameLoader::MaybeCreateDocShell()
|
||||
webNav->SetSessionHistory(sessionHistory);
|
||||
}
|
||||
|
||||
EnsureMessageManager();
|
||||
|
||||
if (OwnerIsAppFrame()) {
|
||||
// You can't be both an app and a browser frame.
|
||||
MOZ_ASSERT(!OwnerIsBrowserFrame());
|
||||
@ -1818,18 +1813,7 @@ nsFrameLoader::MaybeCreateDocShell()
|
||||
mDocShell->SetIsBrowserInsideApp(containingAppId);
|
||||
}
|
||||
|
||||
InitializeBrowserAPI();
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
"inprocess-browser-shown", nullptr);
|
||||
}
|
||||
|
||||
if (OwnerIsBrowserOrAppFrame() && mMessageManager) {
|
||||
mMessageManager->LoadFrameScript(
|
||||
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
|
||||
/* allowDelayedLoad = */ true,
|
||||
/* aRunInGlobalScope */ true);
|
||||
if (OwnerIsBrowserOrAppFrame()) {
|
||||
// For inproc frames, set the docshell properties.
|
||||
nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(docShell);
|
||||
nsAutoString name;
|
||||
@ -1856,6 +1840,15 @@ nsFrameLoader::MaybeCreateDocShell()
|
||||
}
|
||||
}
|
||||
|
||||
ReallyLoadFrameScripts();
|
||||
InitializeBrowserAPI();
|
||||
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
"inprocess-browser-shown", nullptr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1876,13 +1869,16 @@ nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
MOZ_ASSERT(!IsRemoteFrame(),
|
||||
"Shouldn't call CheckForRecursiveLoad on remote frames.");
|
||||
|
||||
mDepthTooGreat = false;
|
||||
rv = MaybeCreateDocShell();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
NS_ASSERTION(!mRemoteFrame,
|
||||
"Shouldn't call CheckForRecursiveLoad on remote frames.");
|
||||
NS_ASSERTION(mDocShell,
|
||||
"MaybeCreateDocShell succeeded, but null mDocShell");
|
||||
if (!mDocShell) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2004,7 +2000,7 @@ nsFrameLoader::GetWindowDimensions(nsIntRect& aRect)
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame)
|
||||
{
|
||||
if (mRemoteFrame) {
|
||||
if (IsRemoteFrame()) {
|
||||
if (mRemoteBrowser) {
|
||||
ScreenIntSize size = aIFrame->GetSubdocumentSize();
|
||||
nsIntRect dimensions;
|
||||
@ -2232,7 +2228,10 @@ nsFrameLoader::TryRemoteBrowser()
|
||||
unused << mRemoteBrowser->SendSetUpdateHitRegion(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
ReallyLoadFrameScripts();
|
||||
InitializeBrowserAPI();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::dom::PBrowserParent*
|
||||
@ -2469,14 +2468,13 @@ nsFrameLoader::EnsureMessageManager()
|
||||
{
|
||||
NS_ENSURE_STATE(mOwnerContent);
|
||||
|
||||
nsresult rv = MaybeCreateDocShell();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
if (mMessageManager) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mIsTopLevelContent &&
|
||||
!OwnerIsBrowserOrAppFrame() &&
|
||||
!mRemoteFrame &&
|
||||
!IsRemoteFrame() &&
|
||||
!(mOwnerContent->IsXULElement() &&
|
||||
mOwnerContent->AttrValueIs(kNameSpaceID_None,
|
||||
nsGkAtoms::forcemessagemanager,
|
||||
@ -2484,14 +2482,6 @@ nsFrameLoader::EnsureMessageManager()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool useRemoteProcess = ShouldUseRemoteProcess();
|
||||
if (mMessageManager) {
|
||||
if (useRemoteProcess && mRemoteBrowser) {
|
||||
mMessageManager->InitWithCallback(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMChromeWindow> chromeWindow =
|
||||
do_QueryInterface(GetOwnerDoc()->GetWindow());
|
||||
nsCOMPtr<nsIMessageBroadcaster> parentManager;
|
||||
@ -2510,18 +2500,33 @@ nsFrameLoader::EnsureMessageManager()
|
||||
}
|
||||
}
|
||||
|
||||
if (useRemoteProcess) {
|
||||
mMessageManager = new nsFrameMessageManager(mRemoteBrowser ? this : nullptr,
|
||||
static_cast<nsFrameMessageManager*>(parentManager.get()),
|
||||
MM_CHROME);
|
||||
} else {
|
||||
mMessageManager = new nsFrameMessageManager(nullptr,
|
||||
static_cast<nsFrameMessageManager*>(parentManager.get()),
|
||||
MM_CHROME);
|
||||
|
||||
mMessageManager = new nsFrameMessageManager(nullptr,
|
||||
static_cast<nsFrameMessageManager*>(parentManager.get()),
|
||||
MM_CHROME);
|
||||
if (!IsRemoteFrame()) {
|
||||
nsresult rv = MaybeCreateDocShell();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
NS_ASSERTION(mDocShell,
|
||||
"MaybeCreateDocShell succeeded, but null mDocShell");
|
||||
if (!mDocShell) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mChildMessageManager =
|
||||
new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager);
|
||||
// Force pending frame scripts to be loaded.
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrameLoader::ReallyLoadFrameScripts()
|
||||
{
|
||||
nsresult rv = EnsureMessageManager();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (mMessageManager) {
|
||||
mMessageManager->InitWithCallback(this);
|
||||
}
|
||||
return NS_OK;
|
||||
@ -2555,6 +2560,8 @@ nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
|
||||
mRemoteFrame = true;
|
||||
mRemoteBrowser = TabParent::GetFrom(aTabParent);
|
||||
mChildID = mRemoteBrowser ? mRemoteBrowser->Manager()->ChildID() : 0;
|
||||
ReallyLoadFrameScripts();
|
||||
InitializeBrowserAPI();
|
||||
ShowRemoteFrame(ScreenIntSize(0, 0));
|
||||
}
|
||||
|
||||
@ -2590,7 +2597,8 @@ nsFrameLoader::AttributeChanged(nsIDocument* aDocument,
|
||||
mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
MOZ_ASSERT(mObservingOwnerContent);
|
||||
// TODO: Implement ContentShellAdded for remote browsers (bug 658304)
|
||||
@ -2820,8 +2828,22 @@ nsFrameLoader::GetLoadContext(nsILoadContext** aLoadContext)
|
||||
void
|
||||
nsFrameLoader::InitializeBrowserAPI()
|
||||
{
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
|
||||
if (browserFrame) {
|
||||
browserFrame->InitializeBrowserAPI();
|
||||
if (OwnerIsBrowserOrAppFrame()) {
|
||||
if (!IsRemoteFrame()) {
|
||||
nsresult rv = EnsureMessageManager();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
if (mMessageManager) {
|
||||
mMessageManager->LoadFrameScript(
|
||||
NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"),
|
||||
/* allowDelayedLoad = */ true,
|
||||
/* aRunInGlobalScope */ true);
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
|
||||
if (browserFrame) {
|
||||
browserFrame->InitializeBrowserAPI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,6 +222,11 @@ private:
|
||||
|
||||
bool ShouldUseRemoteProcess();
|
||||
|
||||
/**
|
||||
* Return true if the frame is a remote frame. Return false otherwise
|
||||
*/
|
||||
bool IsRemoteFrame();
|
||||
|
||||
/**
|
||||
* Is this a frameloader for a bona fide <iframe mozbrowser> or
|
||||
* <iframe mozapp>? (I.e., does the frame return true for
|
||||
@ -270,6 +275,7 @@ private:
|
||||
*/
|
||||
nsresult MaybeCreateDocShell();
|
||||
nsresult EnsureMessageManager();
|
||||
nsresult ReallyLoadFrameScripts();
|
||||
|
||||
// Updates the subdocument position and size. This gets called only
|
||||
// when we have our own in-process DocShell.
|
||||
|
@ -1432,6 +1432,14 @@ nsFrameMessageManager::GetInitialProcessData(JSContext* aCx, JS::MutableHandleVa
|
||||
init.setObject(*obj);
|
||||
}
|
||||
|
||||
if (!mChrome && XRE_IsParentProcess()) {
|
||||
// This is the cpmm in the parent process. We should use the same object as the ppmm.
|
||||
nsCOMPtr<nsIGlobalProcessScriptLoader> ppmm =
|
||||
do_GetService("@mozilla.org/parentprocessmessagemanager;1");
|
||||
ppmm->GetInitialProcessData(aCx, &init);
|
||||
mInitialProcessData = init;
|
||||
}
|
||||
|
||||
if (!JS_WrapValue(aCx, &init)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -2164,7 +2172,6 @@ NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
|
||||
NS_ENSURE_TRUE(global->Init(), NS_ERROR_UNEXPECTED);
|
||||
global.forget(aResult);
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
|
@ -13598,12 +13598,8 @@ nsGlobalWindow::AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
|
||||
mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
|
||||
}
|
||||
|
||||
// The things pointed to by the entries will be measured below, so we
|
||||
// use nullptr for the callback here.
|
||||
aWindowSizes->mDOMEventTargetsSize +=
|
||||
mEventTargetObjects.SizeOfExcludingThis(nullptr,
|
||||
aWindowSizes->mMallocSizeOf);
|
||||
|
||||
mEventTargetObjects.ShallowSizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
|
||||
|
||||
for (auto iter = mEventTargetObjects.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
DOMEventTargetHelper* et = iter.Get()->GetKey();
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsAttrValue;
|
||||
class nsIAtom;
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
@ -21,8 +22,8 @@ class Element;
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_IMUTATION_OBSERVER_IID \
|
||||
{ 0x16fe5e3e, 0xeadc, 0x4312, \
|
||||
{ 0x9d, 0x44, 0xb6, 0xbe, 0xdd, 0x6b, 0x54, 0x74 } }
|
||||
{ 0xdd74f0cc, 0x2849, 0x4d05, \
|
||||
{ 0x9c, 0xe3, 0xb0, 0x95, 0x3e, 0xc2, 0xfd, 0x44 } }
|
||||
|
||||
/**
|
||||
* Information details about a characterdata change. Basically, we
|
||||
@ -157,6 +158,8 @@ public:
|
||||
* @param aModType Whether or not the attribute will be added, changed, or
|
||||
* removed. The constants are defined in
|
||||
* nsIDOMMutationEvent.h.
|
||||
* @param aNewValue The new value, IF it has been preparsed by
|
||||
* BeforeSetAttr, otherwise null.
|
||||
*
|
||||
* @note Callers of this method might not hold a strong reference to the
|
||||
* observer. The observer is responsible for making sure it stays
|
||||
@ -168,7 +171,8 @@ public:
|
||||
mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType) = 0;
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue) = 0;
|
||||
|
||||
/**
|
||||
* Notification that an attribute of an element has changed.
|
||||
@ -180,6 +184,8 @@ public:
|
||||
* @param aModType Whether or not the attribute was added, changed, or
|
||||
* removed. The constants are defined in
|
||||
* nsIDOMMutationEvent.h.
|
||||
* @param aOldValue The old value, if either the old value or the new
|
||||
* value are StoresOwnData() (or absent); null otherwise.
|
||||
*
|
||||
* @note Callers of this method might not hold a strong reference to the
|
||||
* observer. The observer is responsible for making sure it stays
|
||||
@ -191,7 +197,8 @@ public:
|
||||
mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType) = 0;
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue) = 0;
|
||||
|
||||
/**
|
||||
* Notification that an attribute of an element has been
|
||||
@ -336,14 +343,16 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver, NS_IMUTATION_OBSERVER_IID)
|
||||
mozilla::dom::Element* aElement, \
|
||||
int32_t aNameSpaceID, \
|
||||
nsIAtom* aAttribute, \
|
||||
int32_t aModType) override;
|
||||
int32_t aModType, \
|
||||
const nsAttrValue* aNewValue) override;
|
||||
|
||||
#define NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED \
|
||||
virtual void AttributeChanged(nsIDocument* aDocument, \
|
||||
mozilla::dom::Element* aElement, \
|
||||
int32_t aNameSpaceID, \
|
||||
nsIAtom* aAttribute, \
|
||||
int32_t aModType) override;
|
||||
int32_t aModType, \
|
||||
const nsAttrValue* aOldValue) override;
|
||||
|
||||
#define NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED \
|
||||
virtual void ContentAppended(nsIDocument* aDocument, \
|
||||
@ -405,7 +414,8 @@ _class::AttributeWillChange(nsIDocument* aDocument, \
|
||||
mozilla::dom::Element* aElement, \
|
||||
int32_t aNameSpaceID, \
|
||||
nsIAtom* aAttribute, \
|
||||
int32_t aModType) \
|
||||
int32_t aModType, \
|
||||
const nsAttrValue* aNewValue) \
|
||||
{ \
|
||||
} \
|
||||
void \
|
||||
@ -413,7 +423,8 @@ _class::AttributeChanged(nsIDocument* aDocument, \
|
||||
mozilla::dom::Element* aElement, \
|
||||
int32_t aNameSpaceID, \
|
||||
nsIAtom* aAttribute, \
|
||||
int32_t aModType) \
|
||||
int32_t aModType, \
|
||||
const nsAttrValue* aOldValue) \
|
||||
{ \
|
||||
} \
|
||||
void \
|
||||
|
@ -123,24 +123,26 @@ void
|
||||
nsNodeUtils::AttributeWillChange(Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue)
|
||||
{
|
||||
nsIDocument* doc = aElement->OwnerDoc();
|
||||
IMPL_MUTATION_NOTIFICATION(AttributeWillChange, aElement,
|
||||
(doc, aElement, aNameSpaceID, aAttribute,
|
||||
aModType));
|
||||
aModType, aNewValue));
|
||||
}
|
||||
|
||||
void
|
||||
nsNodeUtils::AttributeChanged(Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
nsIDocument* doc = aElement->OwnerDoc();
|
||||
IMPL_MUTATION_NOTIFICATION(AttributeChanged, aElement,
|
||||
(doc, aElement, aNameSpaceID, aAttribute,
|
||||
aModType));
|
||||
aModType, aOldValue));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -48,12 +48,15 @@ public:
|
||||
* @param aNameSpaceID Namespace of changing attribute
|
||||
* @param aAttribute Local-name of changing attribute
|
||||
* @param aModType Type of change (add/change/removal)
|
||||
* @param aNewValue The parsed new value, but only if BeforeSetAttr
|
||||
* preparsed it!!!
|
||||
* @see nsIMutationObserver::AttributeWillChange
|
||||
*/
|
||||
static void AttributeWillChange(mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType);
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue);
|
||||
|
||||
/**
|
||||
* Send AttributeChanged notifications to nsIMutationObservers.
|
||||
@ -61,12 +64,16 @@ public:
|
||||
* @param aNameSpaceID Namespace of changed attribute
|
||||
* @param aAttribute Local-name of changed attribute
|
||||
* @param aModType Type of change (add/change/removal)
|
||||
* @param aOldValue If the old value was StoresOwnData() (or absent),
|
||||
* that value, otherwise null
|
||||
* @see nsIMutationObserver::AttributeChanged
|
||||
*/
|
||||
static void AttributeChanged(mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType);
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue);
|
||||
|
||||
/**
|
||||
* Send AttributeSetToCurrentValue notifications to nsIMutationObservers.
|
||||
* @param aElement Element whose data changed
|
||||
|
@ -83,7 +83,8 @@ nsScriptElement::AttributeChanged(nsIDocument* aDocument,
|
||||
Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
MaybeProcessScript();
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ nsStyledElementNotElementCSSInlineStyle::ReparseStyleAttribute(bool aForceInData
|
||||
ParseStyleAttribute(stringValue, attrValue, aForceInDataDoc);
|
||||
// Don't bother going through SetInlineStyleRule, we don't want to fire off
|
||||
// mutation events or document notifications anyway
|
||||
nsresult rv = mAttrsAndChildren.SetAndTakeAttr(nsGkAtoms::style, attrValue);
|
||||
nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,8 @@ nsAttributeTextNode::AttributeChanged(nsIDocument* aDocument,
|
||||
Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
if (aNameSpaceID == mNameSpaceID && aAttribute == mAttrName &&
|
||||
aElement == mGrandparent) {
|
||||
|
@ -85,7 +85,7 @@ function CameraTestSuite() {
|
||||
var self = this;
|
||||
this._window.addEventListener('beforeunload', function() {
|
||||
if (isDefinedObj(self.viewfinder)) {
|
||||
self.viewfinder.mozSrcObject = null;
|
||||
self.viewfinder.srcObject = null;
|
||||
}
|
||||
|
||||
self.hw = null;
|
||||
@ -211,7 +211,7 @@ CameraTestSuite.prototype = {
|
||||
function postTest(pass) {
|
||||
ok(pass, test.name + ' finished');
|
||||
var camera = self.camera;
|
||||
self.viewfinder.mozSrcObject = null;
|
||||
self.viewfinder.srcObject = null;
|
||||
self.camera = null;
|
||||
|
||||
if (!isDefinedObj(camera)) {
|
||||
@ -325,7 +325,7 @@ CameraTestSuite.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
self.viewfinder.mozSrcObject = self.camera;
|
||||
self.viewfinder.srcObject = self.camera;
|
||||
self.viewfinder.play();
|
||||
self.camera.addEventListener('previewstatechange', onPreviewStateChange);
|
||||
});
|
||||
|
@ -42,7 +42,7 @@ var Camera = {
|
||||
var camera = d.camera;
|
||||
var cfg = d.configuration;
|
||||
Camera.cameraObj = camera;
|
||||
Camera.viewfinder.mozSrcObject = camera;
|
||||
Camera.viewfinder.srcObject = camera;
|
||||
Camera.viewfinder.play();
|
||||
|
||||
// Check the default configuration
|
||||
@ -66,7 +66,7 @@ var Camera = {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.addEventListener('beforeunload', function() {
|
||||
Camera.viewfinder.mozSrcObject = null;
|
||||
Camera.viewfinder.srcObject = null;
|
||||
if (Camera.cameraObj) {
|
||||
Camera.cameraObj.release();
|
||||
Camera.cameraObj = null;
|
||||
|
@ -232,7 +232,7 @@ var Camera = {
|
||||
Camera.cameraObj.addEventListener('configurationchanged', Camera.onConfigChange);
|
||||
Camera.cameraObj.addEventListener('shutter', Camera.shutter);
|
||||
Camera.cameraObj.addEventListener('picture', Camera.takePictureEvent.bind(Camera));
|
||||
Camera.viewfinder.mozSrcObject = d.camera;
|
||||
Camera.viewfinder.srcObject = d.camera;
|
||||
Camera.viewfinder.play();
|
||||
SimpleTest.expectAssertions(0);
|
||||
ok(true, "Camera Control object has been successfully initialized");
|
||||
@ -245,7 +245,7 @@ var Camera = {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.addEventListener('beforeunload', function() {
|
||||
Camera.viewfinder.mozSrcObject = null;
|
||||
Camera.viewfinder.srcObject = null;
|
||||
Camera.cameraObj.release();
|
||||
Camera.cameraObj = null;
|
||||
});
|
||||
|
@ -179,7 +179,7 @@ var Camera = {
|
||||
Camera.cameraObj = d.camera;
|
||||
Camera.cameraObj.addEventListener('previewstatechange', Camera.onPreviewStateChange);
|
||||
Camera.cameraObj.addEventListener('shutter', Camera.shutter);
|
||||
Camera.viewfinder.mozSrcObject = d.camera;
|
||||
Camera.viewfinder.srcObject = d.camera;
|
||||
Camera.viewfinder.play();
|
||||
SimpleTest.expectAssertions(0);
|
||||
};
|
||||
@ -190,7 +190,7 @@ var Camera = {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.addEventListener('beforeunload', function() {
|
||||
Camera.viewfinder.mozSrcObject = null;
|
||||
Camera.viewfinder.srcObject = null;
|
||||
Camera.cameraObj.release();
|
||||
Camera.cameraObj = null;
|
||||
});
|
||||
|
@ -54,7 +54,7 @@ var Camera = {
|
||||
function onSuccess(d) {
|
||||
Camera.cameraObj = d.camera;
|
||||
Camera.cameraObj.addEventListener('previewstatechange', Camera.onPreviewStateChange);
|
||||
Camera.viewfinder.mozSrcObject = d.camera;
|
||||
Camera.viewfinder.srcObject = d.camera;
|
||||
Camera.viewfinder.play();
|
||||
};
|
||||
navigator.mozCameras.getCamera(whichCamera, options).then(onSuccess, onError);
|
||||
@ -64,7 +64,7 @@ var Camera = {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
window.addEventListener('beforeunload', function() {
|
||||
Camera.viewfinder.mozSrcObject = null;
|
||||
Camera.viewfinder.srcObject = null;
|
||||
Camera.cameraObj.release();
|
||||
Camera.cameraObj = null;
|
||||
});
|
||||
|
@ -357,15 +357,10 @@ public:
|
||||
private:
|
||||
WebGL2Context();
|
||||
|
||||
JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) override;
|
||||
virtual bool IsTexParamValid(GLenum pname) const override;
|
||||
|
||||
void UpdateBoundQuery(GLenum target, WebGLQuery* query);
|
||||
|
||||
bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
|
||||
bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
const char* info);
|
||||
|
||||
// CreateVertexArrayImpl is assumed to be infallible.
|
||||
virtual WebGLVertexArray* CreateVertexArrayImpl() override;
|
||||
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) override;
|
||||
|
@ -10,485 +10,126 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool
|
||||
WebGL2Context::ValidateSizedInternalFormat(GLenum internalformat, const char* info)
|
||||
{
|
||||
switch (internalformat) {
|
||||
// Sized Internal Formats
|
||||
// https://www.khronos.org/opengles/sdk/docs/man3/html/glTexStorage2D.xhtml
|
||||
case LOCAL_GL_R8:
|
||||
case LOCAL_GL_R8_SNORM:
|
||||
case LOCAL_GL_R16F:
|
||||
case LOCAL_GL_R32F:
|
||||
case LOCAL_GL_R8UI:
|
||||
case LOCAL_GL_R8I:
|
||||
case LOCAL_GL_R16UI:
|
||||
case LOCAL_GL_R16I:
|
||||
case LOCAL_GL_R32UI:
|
||||
case LOCAL_GL_R32I:
|
||||
case LOCAL_GL_RG8:
|
||||
case LOCAL_GL_RG8_SNORM:
|
||||
case LOCAL_GL_RG16F:
|
||||
case LOCAL_GL_RG32F:
|
||||
case LOCAL_GL_RG8UI:
|
||||
case LOCAL_GL_RG8I:
|
||||
case LOCAL_GL_RG16UI:
|
||||
case LOCAL_GL_RG16I:
|
||||
case LOCAL_GL_RG32UI:
|
||||
case LOCAL_GL_RG32I:
|
||||
case LOCAL_GL_RGB8:
|
||||
case LOCAL_GL_SRGB8:
|
||||
case LOCAL_GL_RGB565:
|
||||
case LOCAL_GL_RGB8_SNORM:
|
||||
case LOCAL_GL_R11F_G11F_B10F:
|
||||
case LOCAL_GL_RGB9_E5:
|
||||
case LOCAL_GL_RGB16F:
|
||||
case LOCAL_GL_RGB32F:
|
||||
case LOCAL_GL_RGB8UI:
|
||||
case LOCAL_GL_RGB8I:
|
||||
case LOCAL_GL_RGB16UI:
|
||||
case LOCAL_GL_RGB16I:
|
||||
case LOCAL_GL_RGB32UI:
|
||||
case LOCAL_GL_RGB32I:
|
||||
case LOCAL_GL_RGBA8:
|
||||
case LOCAL_GL_SRGB8_ALPHA8:
|
||||
case LOCAL_GL_RGBA8_SNORM:
|
||||
case LOCAL_GL_RGB5_A1:
|
||||
case LOCAL_GL_RGBA4:
|
||||
case LOCAL_GL_RGB10_A2:
|
||||
case LOCAL_GL_RGBA16F:
|
||||
case LOCAL_GL_RGBA32F:
|
||||
case LOCAL_GL_RGBA8UI:
|
||||
case LOCAL_GL_RGBA8I:
|
||||
case LOCAL_GL_RGB10_A2UI:
|
||||
case LOCAL_GL_RGBA16UI:
|
||||
case LOCAL_GL_RGBA16I:
|
||||
case LOCAL_GL_RGBA32I:
|
||||
case LOCAL_GL_RGBA32UI:
|
||||
case LOCAL_GL_DEPTH_COMPONENT16:
|
||||
case LOCAL_GL_DEPTH_COMPONENT24:
|
||||
case LOCAL_GL_DEPTH_COMPONENT32F:
|
||||
case LOCAL_GL_DEPTH24_STENCIL8:
|
||||
case LOCAL_GL_DEPTH32F_STENCIL8:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsCompressedTextureFormat(internalformat))
|
||||
return true;
|
||||
|
||||
nsCString name;
|
||||
EnumName(internalformat, &name);
|
||||
ErrorInvalidEnum("%s: invalid internal format %s", info, name.get());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Validates parameters to texStorage{2D,3D} */
|
||||
bool
|
||||
WebGL2Context::ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
const char* info)
|
||||
{
|
||||
// GL_INVALID_OPERATION is generated if the default texture object is curently bound to target.
|
||||
WebGLTexture* tex = ActiveBoundTextureForTarget(target);
|
||||
if (!tex) {
|
||||
ErrorInvalidOperation("%s: no texture is bound to target %s", info, EnumName(target));
|
||||
return false;
|
||||
}
|
||||
|
||||
// GL_INVALID_OPERATION is generated if the texture object currently bound to target already has
|
||||
// GL_TEXTURE_IMMUTABLE_FORMAT set to GL_TRUE.
|
||||
if (tex->IsImmutable()) {
|
||||
ErrorInvalidOperation("%s: texture bound to target %s is already immutable", info, EnumName(target));
|
||||
return false;
|
||||
}
|
||||
|
||||
// GL_INVALID_ENUM is generated if internalformat is not a valid sized internal format.
|
||||
if (!ValidateSizedInternalFormat(internalformat, info))
|
||||
return false;
|
||||
|
||||
// GL_INVALID_VALUE is generated if width, height or levels are less than 1.
|
||||
if (width < 1) { ErrorInvalidValue("%s: width is < 1", info); return false; }
|
||||
if (height < 1) { ErrorInvalidValue("%s: height is < 1", info); return false; }
|
||||
if (depth < 1) { ErrorInvalidValue("%s: depth is < 1", info); return false; }
|
||||
if (levels < 1) { ErrorInvalidValue("%s: levels is < 1", info); return false; }
|
||||
|
||||
// GL_INVALID_OPERATION is generated if levels is greater than floor(log2(max(width, height, depth)))+1.
|
||||
if (FloorLog2(std::max(std::max(width, height), depth)) + 1 < levels) {
|
||||
ErrorInvalidOperation("%s: too many levels for given texture dimensions", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Texture objects
|
||||
|
||||
void
|
||||
WebGL2Context::TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
|
||||
WebGL2Context::TexStorage2D(GLenum rawTexTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height)
|
||||
{
|
||||
if (IsContextLost())
|
||||
const char funcName[] = "TexStorage2D";
|
||||
TexTarget texTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexTarget(this, rawTexTarget, funcName, &texTarget, &tex))
|
||||
return;
|
||||
|
||||
// GL_INVALID_ENUM is generated if target is not one of the accepted target enumerants.
|
||||
if (target != LOCAL_GL_TEXTURE_2D && target != LOCAL_GL_TEXTURE_CUBE_MAP)
|
||||
return ErrorInvalidEnum("texStorage2D: target is not TEXTURE_2D or TEXTURE_CUBE_MAP");
|
||||
|
||||
if (!ValidateTexStorage(target, levels, internalformat, width, height, 1, "texStorage2D"))
|
||||
return;
|
||||
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
gl->fTexStorage2D(target, levels, internalformat, width, height);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
return GenerateWarning("texStorage2D generated error %s", ErrorName(error));
|
||||
}
|
||||
|
||||
WebGLTexture* tex = ActiveBoundTextureForTarget(target);
|
||||
tex->SetImmutable();
|
||||
|
||||
const size_t facesCount = (target == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
|
||||
GLsizei w = width;
|
||||
GLsizei h = height;
|
||||
for (size_t l = 0; l < size_t(levels); l++) {
|
||||
for (size_t f = 0; f < facesCount; f++) {
|
||||
tex->SetImageInfo(TexImageTargetForTargetAndFace(target, f),
|
||||
l, w, h, 1,
|
||||
internalformat,
|
||||
WebGLImageDataStatus::UninitializedImageData);
|
||||
}
|
||||
w = std::max(1, w / 2);
|
||||
h = std::max(1, h / 2);
|
||||
}
|
||||
tex->TexStorage2D(texTarget, levels, internalFormat, width, height);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat,
|
||||
WebGL2Context::TexStorage3D(GLenum rawTexTarget, GLsizei levels, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth)
|
||||
{
|
||||
if (IsContextLost())
|
||||
const char funcName[] = "texStorage3D";
|
||||
TexTarget texTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexTarget(this, rawTexTarget, funcName, &texTarget, &tex))
|
||||
return;
|
||||
|
||||
// GL_INVALID_ENUM is generated if target is not one of the accepted target enumerants.
|
||||
if (target != LOCAL_GL_TEXTURE_3D)
|
||||
return ErrorInvalidEnum("texStorage3D: target is not TEXTURE_3D");
|
||||
|
||||
if (!ValidateTexStorage(target, levels, internalformat, width, height, depth, "texStorage3D"))
|
||||
return;
|
||||
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
gl->fTexStorage3D(target, levels, internalformat, width, height, depth);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
return GenerateWarning("texStorage3D generated error %s", ErrorName(error));
|
||||
}
|
||||
|
||||
WebGLTexture* tex = ActiveBoundTextureForTarget(target);
|
||||
tex->SetImmutable();
|
||||
|
||||
GLsizei w = width;
|
||||
GLsizei h = height;
|
||||
GLsizei d = depth;
|
||||
for (size_t l = 0; l < size_t(levels); l++) {
|
||||
tex->SetImageInfo(TexImageTargetForTargetAndFace(target, 0),
|
||||
l, w, h, d,
|
||||
internalformat,
|
||||
WebGLImageDataStatus::UninitializedImageData);
|
||||
w = std::max(1, w >> 1);
|
||||
h = std::max(1, h >> 1);
|
||||
d = std::max(1, d >> 1);
|
||||
}
|
||||
tex->TexStorage3D(texTarget, levels, internalFormat, width, height, depth);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::TexImage3D(GLenum target, GLint level, GLenum internalformat,
|
||||
WebGL2Context::TexImage3D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLint border, GLenum format, GLenum type,
|
||||
const dom::Nullable<dom::ArrayBufferView> &pixels,
|
||||
ErrorResult& rv)
|
||||
GLint border, GLenum unpackFormat, GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
void* data;
|
||||
size_t dataLength;
|
||||
js::Scalar::Type jsArrayType;
|
||||
if (pixels.IsNull()) {
|
||||
data = nullptr;
|
||||
dataLength = 0;
|
||||
jsArrayType = js::Scalar::MaxTypedArrayViewType;
|
||||
} else {
|
||||
const dom::ArrayBufferView& view = pixels.Value();
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
data = view.Data();
|
||||
dataLength = view.Length();
|
||||
jsArrayType = view.Type();
|
||||
}
|
||||
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
|
||||
|
||||
if (!ValidateTexImageTarget(target, func, dims))
|
||||
return;
|
||||
|
||||
TexImageTarget texImageTarget = target;
|
||||
|
||||
if (!ValidateTexImage(texImageTarget, level, internalformat,
|
||||
0, 0, 0,
|
||||
width, height, depth,
|
||||
border, format, type, func, dims))
|
||||
const char funcName[] = "texImage3D";
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, funcName, &texImageTarget, &tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateTexInputData(type, jsArrayType, func, dims))
|
||||
return;
|
||||
|
||||
TexInternalFormat effectiveInternalFormat =
|
||||
EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
|
||||
|
||||
if (effectiveInternalFormat == LOCAL_GL_NONE) {
|
||||
return ErrorInvalidOperation("texImage3D: bad combination of internalformat and type");
|
||||
}
|
||||
|
||||
// we need to find the exact sized format of the source data. Slightly abusing
|
||||
// EffectiveInternalFormatFromInternalFormatAndType for that purpose. Really, an unsized source format
|
||||
// is the same thing as an unsized internalformat.
|
||||
TexInternalFormat effectiveSourceFormat =
|
||||
EffectiveInternalFormatFromInternalFormatAndType(format, type);
|
||||
MOZ_ASSERT(effectiveSourceFormat != LOCAL_GL_NONE); // should have validated format/type combo earlier
|
||||
const size_t srcbitsPerTexel = GetBitsPerTexel(effectiveSourceFormat);
|
||||
MOZ_ASSERT((srcbitsPerTexel % 8) == 0); // should not have compressed formats here.
|
||||
size_t srcTexelSize = srcbitsPerTexel / 8;
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, depth, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
|
||||
if (!checked_neededByteLength.isValid())
|
||||
return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
|
||||
|
||||
uint32_t bytesNeeded = checked_neededByteLength.value();
|
||||
|
||||
if (dataLength && dataLength < bytesNeeded)
|
||||
return ErrorInvalidOperation("texImage3D: not enough data for operation (need %d, have %d)",
|
||||
bytesNeeded, dataLength);
|
||||
|
||||
WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
|
||||
|
||||
if (!tex)
|
||||
return ErrorInvalidOperation("texImage3D: no texture is bound to this target");
|
||||
|
||||
if (tex->IsImmutable()) {
|
||||
return ErrorInvalidOperation(
|
||||
"texImage3D: disallowed because the texture "
|
||||
"bound to this target has already been made immutable by texStorage3D");
|
||||
}
|
||||
|
||||
GLenum driverType = LOCAL_GL_NONE;
|
||||
GLenum driverInternalFormat = LOCAL_GL_NONE;
|
||||
GLenum driverFormat = LOCAL_GL_NONE;
|
||||
DriverFormatsFromEffectiveInternalFormat(gl,
|
||||
effectiveInternalFormat,
|
||||
&driverInternalFormat,
|
||||
&driverFormat,
|
||||
&driverType);
|
||||
|
||||
MakeContextCurrent();
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
gl->fTexImage3D(texImageTarget.get(), level,
|
||||
driverInternalFormat,
|
||||
width, height, depth,
|
||||
0, driverFormat, driverType,
|
||||
data);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
return GenerateWarning("texImage3D generated error %s", ErrorName(error));
|
||||
}
|
||||
|
||||
tex->SetImageInfo(texImageTarget, level,
|
||||
width, height, depth,
|
||||
effectiveInternalFormat,
|
||||
data ? WebGLImageDataStatus::InitializedImageData
|
||||
: WebGLImageDataStatus::UninitializedImageData);
|
||||
tex->TexImage3D(texImageTarget, level, internalFormat, width, height, depth, border,
|
||||
unpackFormat, unpackType, maybeView, &out_rv);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level,
|
||||
GLint xOffset, GLint yOffset, GLint zOffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum format, GLenum type,
|
||||
const dom::Nullable<dom::ArrayBufferView>& pixels,
|
||||
ErrorResult& rv)
|
||||
GLenum unpackFormat, GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (pixels.IsNull())
|
||||
return ErrorInvalidValue("texSubImage3D: pixels must not be null!");
|
||||
|
||||
const dom::ArrayBufferView& view = pixels.Value();
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
|
||||
|
||||
if (!ValidateTexImageTarget(rawTarget, func, dims))
|
||||
return;
|
||||
|
||||
TexImageTarget texImageTarget(rawTarget);
|
||||
|
||||
WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
|
||||
if (!tex) {
|
||||
return ErrorInvalidOperation("texSubImage3D: no texture bound on active texture unit");
|
||||
}
|
||||
|
||||
if (!tex->HasImageInfoAt(texImageTarget, level)) {
|
||||
return ErrorInvalidOperation("texSubImage3D: no previously defined texture image");
|
||||
}
|
||||
|
||||
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
|
||||
const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
|
||||
TexInternalFormat existingUnsizedInternalFormat = LOCAL_GL_NONE;
|
||||
TexType existingType = LOCAL_GL_NONE;
|
||||
UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(existingEffectiveInternalFormat,
|
||||
&existingUnsizedInternalFormat,
|
||||
&existingType);
|
||||
|
||||
if (!ValidateTexImage(texImageTarget, level, existingEffectiveInternalFormat.get(),
|
||||
xoffset, yoffset, zoffset,
|
||||
width, height, depth,
|
||||
0, format, type, func, dims))
|
||||
const char funcName[] = "texSubImage3D";
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, funcName, &texImageTarget, &tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != existingType) {
|
||||
return ErrorInvalidOperation("texSubImage3D: type differs from that of the existing image");
|
||||
}
|
||||
|
||||
js::Scalar::Type jsArrayType = view.Type();
|
||||
void* data = view.Data();
|
||||
size_t dataLength = view.Length();
|
||||
|
||||
if (!ValidateTexInputData(type, jsArrayType, func, dims))
|
||||
return;
|
||||
|
||||
const size_t bitsPerTexel = GetBitsPerTexel(existingEffectiveInternalFormat);
|
||||
MOZ_ASSERT((bitsPerTexel % 8) == 0); // should not have compressed formats here.
|
||||
size_t srcTexelSize = bitsPerTexel / 8;
|
||||
|
||||
if (width == 0 || height == 0 || depth == 0)
|
||||
return; // no effect, we better return right now
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, depth, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
|
||||
if (!checked_neededByteLength.isValid())
|
||||
return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
|
||||
|
||||
uint32_t bytesNeeded = checked_neededByteLength.value();
|
||||
|
||||
if (dataLength < bytesNeeded)
|
||||
return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, dataLength);
|
||||
|
||||
if (imageInfo.HasUninitializedImageData()) {
|
||||
bool coversWholeImage = xoffset == 0 &&
|
||||
yoffset == 0 &&
|
||||
zoffset == 0 &&
|
||||
width == imageInfo.Width() &&
|
||||
height == imageInfo.Height() &&
|
||||
depth == imageInfo.Depth();
|
||||
if (coversWholeImage) {
|
||||
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
} else {
|
||||
if (!tex->EnsureInitializedImageData(texImageTarget, level))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum driverType = LOCAL_GL_NONE;
|
||||
GLenum driverInternalFormat = LOCAL_GL_NONE;
|
||||
GLenum driverFormat = LOCAL_GL_NONE;
|
||||
DriverFormatsFromEffectiveInternalFormat(gl,
|
||||
existingEffectiveInternalFormat,
|
||||
&driverInternalFormat,
|
||||
&driverFormat,
|
||||
&driverType);
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fTexSubImage3D(texImageTarget.get(), level,
|
||||
xoffset, yoffset, zoffset,
|
||||
width, height, depth,
|
||||
driverFormat, driverType, data);
|
||||
tex->TexSubImage3D(texImageTarget, level, xOffset, yOffset, zOffset, width, height,
|
||||
depth, unpackFormat, unpackType, maybeView, &out_rv);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::TexSubImage3D(GLenum target, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLenum format, GLenum type, dom::ImageData* data,
|
||||
ErrorResult& rv)
|
||||
GLint xOffset, GLint yOffset, GLint zOffset,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
GenerateWarning("texSubImage3D: Not implemented.");
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::CopyTexSubImage3D(GLenum target, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLint xOffset, GLint yOffset, GLint zOffset,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height)
|
||||
{
|
||||
GenerateWarning("copyTexSubImage3D: Not implemented.");
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat,
|
||||
WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLint border, GLsizei imageSize, const dom::ArrayBufferView& data)
|
||||
GLint border, GLsizei imageSize, const dom::ArrayBufferView& view)
|
||||
{
|
||||
GenerateWarning("compressedTexImage3D: Not implemented.");
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum format, GLsizei imageSize, const dom::ArrayBufferView& data)
|
||||
GLenum unpackFormat, GLsizei imageSize, const dom::ArrayBufferView& view)
|
||||
{
|
||||
GenerateWarning("compressedTexSubImage3D: Not implemented.");
|
||||
}
|
||||
|
||||
JS::Value
|
||||
WebGL2Context::GetTexParameterInternal(const TexTarget& target, GLenum pname)
|
||||
bool
|
||||
WebGL2Context::IsTexParamValid(GLenum pname) const
|
||||
{
|
||||
switch (pname) {
|
||||
case LOCAL_GL_TEXTURE_BASE_LEVEL:
|
||||
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
|
||||
case LOCAL_GL_TEXTURE_COMPARE_MODE:
|
||||
case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
|
||||
case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
|
||||
case LOCAL_GL_TEXTURE_MAX_LEVEL:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_A:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_B:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_G:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_R:
|
||||
case LOCAL_GL_TEXTURE_WRAP_R:
|
||||
{
|
||||
GLint i = 0;
|
||||
gl->fGetTexParameteriv(target.get(), pname, &i);
|
||||
return JS::NumberValue(uint32_t(i));
|
||||
}
|
||||
case LOCAL_GL_TEXTURE_BASE_LEVEL:
|
||||
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
|
||||
case LOCAL_GL_TEXTURE_COMPARE_MODE:
|
||||
case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
|
||||
case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
|
||||
case LOCAL_GL_TEXTURE_MAX_LEVEL:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_A:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_B:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_G:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_R:
|
||||
case LOCAL_GL_TEXTURE_WRAP_R:
|
||||
case LOCAL_GL_TEXTURE_MAX_LOD:
|
||||
case LOCAL_GL_TEXTURE_MIN_LOD:
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_TEXTURE_MAX_LOD:
|
||||
case LOCAL_GL_TEXTURE_MIN_LOD:
|
||||
{
|
||||
GLfloat f = 0.0f;
|
||||
gl->fGetTexParameterfv(target.get(), pname, &f);
|
||||
return JS::NumberValue(float(f));
|
||||
}
|
||||
default:
|
||||
return WebGLContext::IsTexParamValid(pname);
|
||||
}
|
||||
|
||||
return WebGLContext::GetTexParameterInternal(target, pname);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -1821,158 +1821,6 @@ WebGLContext::DidRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
|
||||
GLint level, GLenum internalFormat,
|
||||
GLenum format, GLenum type,
|
||||
mozilla::dom::Element& elt)
|
||||
{
|
||||
if (type == LOCAL_GL_HALF_FLOAT_OES &&
|
||||
!gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float))
|
||||
{
|
||||
type = LOCAL_GL_HALF_FLOAT;
|
||||
}
|
||||
|
||||
if (!ValidateTexImageFormatAndType(format, type,
|
||||
WebGLTexImageFunc::TexImage,
|
||||
WebGLTexDimensions::Tex2D))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HTMLVideoElement* video = HTMLVideoElement::FromContentOrNull(&elt);
|
||||
if (!video)
|
||||
return false;
|
||||
|
||||
uint16_t readyState;
|
||||
if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
|
||||
readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)
|
||||
{
|
||||
//No frame inside, just return
|
||||
return false;
|
||||
}
|
||||
|
||||
// If it doesn't have a principal, just bail
|
||||
nsCOMPtr<nsIPrincipal> principal = video->GetCurrentPrincipal();
|
||||
if (!principal)
|
||||
return false;
|
||||
|
||||
mozilla::layers::ImageContainer* container = video->GetImageContainer();
|
||||
if (!container)
|
||||
return false;
|
||||
|
||||
if (video->GetCORSMode() == CORS_NONE) {
|
||||
bool subsumes;
|
||||
nsresult rv = mCanvasElement->NodePrincipal()->Subsumes(principal, &subsumes);
|
||||
if (NS_FAILED(rv) || !subsumes) {
|
||||
GenerateWarning("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
|
||||
"See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AutoLockImage lockedImage(container);
|
||||
Image* srcImage = lockedImage.GetImage();
|
||||
if (!srcImage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gl->MakeCurrent();
|
||||
|
||||
WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
|
||||
|
||||
const WebGLTexture::ImageInfo& info = tex->ImageInfoAt(texImageTarget, 0);
|
||||
bool dimensionsMatch = info.Width() == srcImage->GetSize().width &&
|
||||
info.Height() == srcImage->GetSize().height;
|
||||
if (!dimensionsMatch) {
|
||||
// we need to allocation
|
||||
gl->fTexImage2D(texImageTarget.get(), level, internalFormat,
|
||||
srcImage->GetSize().width, srcImage->GetSize().height,
|
||||
0, format, type, nullptr);
|
||||
}
|
||||
|
||||
const gl::OriginPos destOrigin = mPixelStoreFlipY ? gl::OriginPos::BottomLeft
|
||||
: gl::OriginPos::TopLeft;
|
||||
bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage,
|
||||
srcImage->GetSize(),
|
||||
tex->mGLName,
|
||||
texImageTarget.get(),
|
||||
destOrigin);
|
||||
if (ok) {
|
||||
TexInternalFormat effectiveInternalFormat =
|
||||
EffectiveInternalFormatFromInternalFormatAndType(internalFormat,
|
||||
type);
|
||||
MOZ_ASSERT(effectiveInternalFormat != LOCAL_GL_NONE);
|
||||
tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width,
|
||||
srcImage->GetSize().height, 1,
|
||||
effectiveInternalFormat,
|
||||
WebGLImageDataStatus::InitializedImageData);
|
||||
tex->Bind(TexImageTargetToTexTarget(texImageTarget));
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLenum format, GLenum type,
|
||||
dom::Element* elt, ErrorResult* const out_rv)
|
||||
{
|
||||
// TODO: Consolidate all the parameter validation
|
||||
// checks. Instead of spreading out the cheks in multple
|
||||
// places, consolidate into one spot.
|
||||
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateTexImageTarget(rawTexImageTarget,
|
||||
WebGLTexImageFunc::TexSubImage,
|
||||
WebGLTexDimensions::Tex2D))
|
||||
{
|
||||
ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget);
|
||||
return;
|
||||
}
|
||||
|
||||
const TexImageTarget texImageTarget(rawTexImageTarget);
|
||||
|
||||
if (level < 0)
|
||||
return ErrorInvalidValue("texSubImage2D: level is negative");
|
||||
|
||||
const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
|
||||
if (level > maxLevel) {
|
||||
ErrorInvalidValue("texSubImage2D: level %d is too large, max is %d",
|
||||
level, maxLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
|
||||
if (!tex)
|
||||
return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
|
||||
|
||||
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
|
||||
const TexInternalFormat internalFormat = imageInfo.EffectiveInternalFormat();
|
||||
|
||||
// Trying to handle the video by GPU directly first
|
||||
if (TexImageFromVideoElement(texImageTarget, level,
|
||||
internalFormat.get(), format, type, *elt))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> data;
|
||||
WebGLTexelFormat srcFormat;
|
||||
nsLayoutUtils::SurfaceFromElementResult res = SurfaceFromElement(*elt);
|
||||
*out_rv = SurfaceFromElementResultToImageSurface(res, data, &srcFormat);
|
||||
if (out_rv->Failed() || !data)
|
||||
return;
|
||||
|
||||
gfx::IntSize size = data->GetSize();
|
||||
uint32_t byteLength = data->Stride() * size.height;
|
||||
TexSubImage2D_base(texImageTarget.get(), level, xoffset, yoffset, size.width,
|
||||
size.height, data->Stride(), format, type, data->GetData(),
|
||||
byteLength, js::Scalar::MaxTypedArrayViewType, srcFormat,
|
||||
res.mIsPremultiplied);
|
||||
}
|
||||
|
||||
size_t
|
||||
RoundUpToMultipleOf(size_t value, size_t multiple)
|
||||
{
|
||||
@ -1980,6 +1828,12 @@ RoundUpToMultipleOf(size_t value, size_t multiple)
|
||||
return overshoot - (overshoot % multiple);
|
||||
}
|
||||
|
||||
CheckedUint32
|
||||
RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y)
|
||||
{
|
||||
return ((x + y - 1) / y) * y;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
|
||||
|
@ -282,9 +282,6 @@ public:
|
||||
// Returns hex formatted version of glenum if glenum is unknown.
|
||||
static void EnumName(GLenum glenum, nsACString* out_name);
|
||||
|
||||
bool IsCompressedTextureFormat(GLenum format);
|
||||
bool IsTextureFormatCompressed(TexInternalFormat format);
|
||||
|
||||
void DummyFramebufferOperation(const char* funcName);
|
||||
|
||||
WebGLTexture* ActiveBoundTextureForTarget(const TexTarget texTarget) const {
|
||||
@ -374,13 +371,11 @@ public:
|
||||
dom::Nullable< nsTArray<nsString> >& retval);
|
||||
void GetExtension(JSContext* cx, const nsAString& name,
|
||||
JS::MutableHandle<JSObject*> retval, ErrorResult& rv);
|
||||
void ActiveTexture(GLenum texture);
|
||||
void AttachShader(WebGLProgram* prog, WebGLShader* shader);
|
||||
void BindAttribLocation(WebGLProgram* prog, GLuint location,
|
||||
const nsAString& name);
|
||||
void BindFramebuffer(GLenum target, WebGLFramebuffer* fb);
|
||||
void BindRenderbuffer(GLenum target, WebGLRenderbuffer* fb);
|
||||
void BindTexture(GLenum target, WebGLTexture* tex);
|
||||
void BindVertexArray(WebGLVertexArray* vao);
|
||||
void BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a);
|
||||
void BlendEquation(GLenum mode);
|
||||
@ -397,24 +392,9 @@ public:
|
||||
void CompileShader(WebGLShader* shader);
|
||||
void CompileShaderANGLE(WebGLShader* shader);
|
||||
void CompileShaderBypass(WebGLShader* shader, const nsCString& shaderSource);
|
||||
void CompressedTexImage2D(GLenum target, GLint level,
|
||||
GLenum internalformat, GLsizei width,
|
||||
GLsizei height, GLint border,
|
||||
const dom::ArrayBufferView& view);
|
||||
void CompressedTexSubImage2D(GLenum texImageTarget, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLsizei width,
|
||||
GLsizei height, GLenum format,
|
||||
const dom::ArrayBufferView& view);
|
||||
void CopyTexImage2D(GLenum texImageTarget, GLint level,
|
||||
GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLint border);
|
||||
void CopyTexSubImage2D(GLenum texImageTarget, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height);
|
||||
already_AddRefed<WebGLFramebuffer> CreateFramebuffer();
|
||||
already_AddRefed<WebGLProgram> CreateProgram();
|
||||
already_AddRefed<WebGLRenderbuffer> CreateRenderbuffer();
|
||||
already_AddRefed<WebGLTexture> CreateTexture();
|
||||
already_AddRefed<WebGLShader> CreateShader(GLenum type);
|
||||
already_AddRefed<WebGLVertexArray> CreateVertexArray();
|
||||
void CullFace(GLenum face);
|
||||
@ -423,7 +403,6 @@ public:
|
||||
void DeleteRenderbuffer(WebGLRenderbuffer* rb);
|
||||
void DeleteShader(WebGLShader* shader);
|
||||
void DeleteVertexArray(WebGLVertexArray* vao);
|
||||
void DeleteTexture(WebGLTexture* tex);
|
||||
void DepthFunc(GLenum func);
|
||||
void DepthMask(WebGLboolean b);
|
||||
void DepthRange(GLclampf zNear, GLclampf zFar);
|
||||
@ -442,7 +421,6 @@ public:
|
||||
GLenum attachment, const char* funcName);
|
||||
|
||||
void FrontFace(GLenum mode);
|
||||
void GenerateMipmap(GLenum target);
|
||||
already_AddRefed<WebGLActiveInfo> GetActiveAttrib(WebGLProgram* prog,
|
||||
GLuint index);
|
||||
already_AddRefed<WebGLActiveInfo> GetActiveUniform(WebGLProgram* prog,
|
||||
@ -508,13 +486,6 @@ public:
|
||||
void GetShaderInfoLog(WebGLShader* shader, nsAString& retval);
|
||||
void GetShaderSource(WebGLShader* shader, nsAString& retval);
|
||||
void GetShaderTranslatedSource(WebGLShader* shader, nsAString& retval);
|
||||
JS::Value GetTexParameter(GLenum target, GLenum pname);
|
||||
|
||||
void GetTexParameter(JSContext*, GLenum target, GLenum pname,
|
||||
JS::MutableHandle<JS::Value> retval)
|
||||
{
|
||||
retval.set(GetTexParameter(target, pname));
|
||||
}
|
||||
|
||||
JS::Value GetUniform(JSContext* cx, WebGLProgram* prog,
|
||||
WebGLUniformLocation* loc);
|
||||
@ -534,7 +505,6 @@ public:
|
||||
bool IsProgram(WebGLProgram* prog);
|
||||
bool IsRenderbuffer(WebGLRenderbuffer* rb);
|
||||
bool IsShader(WebGLShader* shader);
|
||||
bool IsTexture(WebGLTexture* tex);
|
||||
bool IsVertexArray(WebGLVertexArray* vao);
|
||||
void LineWidth(GLfloat width);
|
||||
void LinkProgram(WebGLProgram* prog);
|
||||
@ -561,105 +531,6 @@ public:
|
||||
void StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
|
||||
void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail,
|
||||
GLenum dppass);
|
||||
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||
GLenum type, const dom::Nullable<dom::ArrayBufferView>& pixels,
|
||||
ErrorResult& rv);
|
||||
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum format, GLenum type, dom::ImageData* pixels,
|
||||
ErrorResult& rv);
|
||||
// Allow whatever element types the bindings are willing to pass
|
||||
// us in TexImage2D
|
||||
bool TexImageFromVideoElement(TexImageTarget texImageTarget, GLint level,
|
||||
GLenum internalFormat, GLenum format,
|
||||
GLenum type, mozilla::dom::Element& image);
|
||||
|
||||
template<class ElementType>
|
||||
void TexImage2D(GLenum rawTexImageTarget, GLint level,
|
||||
GLenum internalFormat, GLenum format, GLenum type,
|
||||
ElementType& elt, ErrorResult& rv)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateTexImageTarget(rawTexImageTarget,
|
||||
WebGLTexImageFunc::TexImage,
|
||||
WebGLTexDimensions::Tex2D))
|
||||
{
|
||||
ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget);
|
||||
return;
|
||||
}
|
||||
|
||||
const TexImageTarget texImageTarget(rawTexImageTarget);
|
||||
|
||||
if (level < 0)
|
||||
return ErrorInvalidValue("texImage2D: level is negative");
|
||||
|
||||
const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
|
||||
if (level > maxLevel) {
|
||||
ErrorInvalidValue("texImage2D: level %d is too large, max is %d",
|
||||
level, maxLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
|
||||
|
||||
if (!tex)
|
||||
return ErrorInvalidOperation("no texture is bound to this target");
|
||||
|
||||
// Trying to handle the video by GPU directly first
|
||||
if (TexImageFromVideoElement(texImageTarget, level, internalFormat,
|
||||
format, type, elt))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> data;
|
||||
WebGLTexelFormat srcFormat;
|
||||
nsLayoutUtils::SurfaceFromElementResult res = SurfaceFromElement(elt);
|
||||
rv = SurfaceFromElementResultToImageSurface(res, data, &srcFormat);
|
||||
if (rv.Failed() || !data)
|
||||
return;
|
||||
|
||||
gfx::IntSize size = data->GetSize();
|
||||
uint32_t byteLength = data->Stride() * size.height;
|
||||
return TexImage2D_base(texImageTarget, level, internalFormat,
|
||||
size.width, size.height, data->Stride(), 0,
|
||||
format, type, data->GetData(), byteLength,
|
||||
js::Scalar::MaxTypedArrayViewType, srcFormat,
|
||||
res.mIsPremultiplied);
|
||||
}
|
||||
|
||||
void TexParameterf(GLenum target, GLenum pname, GLfloat param) {
|
||||
TexParameter_base(target, pname, nullptr, ¶m);
|
||||
}
|
||||
void TexParameteri(GLenum target, GLenum pname, GLint param) {
|
||||
TexParameter_base(target, pname, ¶m, nullptr);
|
||||
}
|
||||
|
||||
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
const dom::Nullable<dom::ArrayBufferView>& pixels,
|
||||
ErrorResult& rv);
|
||||
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLenum format, GLenum type,
|
||||
dom::ImageData* pixels, ErrorResult& rv);
|
||||
|
||||
void TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLenum format, GLenum type,
|
||||
dom::Element* elt, ErrorResult* const out_rv);
|
||||
|
||||
// Allow whatever element types the bindings are willing to pass
|
||||
// us in TexSubImage2D
|
||||
template<class ElementType>
|
||||
void TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xoffset,
|
||||
GLint yoffset, GLenum format, GLenum type,
|
||||
ElementType& elt, ErrorResult& out_rv)
|
||||
{
|
||||
TexSubImage2D(rawTexImageTarget, level, xoffset, yoffset, format, type, &elt,
|
||||
&out_rv);
|
||||
}
|
||||
|
||||
void Uniform1i(WebGLUniformLocation* loc, GLint x);
|
||||
void Uniform2i(WebGLUniformLocation* loc, GLint x, GLint y);
|
||||
@ -940,6 +811,97 @@ private:
|
||||
bool ValidateCapabilityEnum(GLenum cap, const char* info);
|
||||
realGLboolean* GetStateTrackingSlot(GLenum cap);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Texture funcions (WebGLContextTextures.cpp)
|
||||
public:
|
||||
void ActiveTexture(GLenum texUnit);
|
||||
void BindTexture(GLenum texTarget, WebGLTexture* tex);
|
||||
already_AddRefed<WebGLTexture> CreateTexture();
|
||||
void DeleteTexture(WebGLTexture* tex);
|
||||
void GenerateMipmap(GLenum texTarget);
|
||||
|
||||
void GetTexParameter(JSContext*, GLenum texTarget, GLenum pname,
|
||||
JS::MutableHandle<JS::Value> retval)
|
||||
{
|
||||
retval.set(GetTexParameter(texTarget, pname));
|
||||
}
|
||||
|
||||
bool IsTexture(WebGLTexture* tex);
|
||||
|
||||
void TexParameterf(GLenum texTarget, GLenum pname, GLfloat param) {
|
||||
TexParameter_base(texTarget, pname, nullptr, ¶m);
|
||||
}
|
||||
|
||||
void TexParameteri(GLenum texTarget, GLenum pname, GLint param) {
|
||||
TexParameter_base(texTarget, pname, ¶m, nullptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
JS::Value GetTexParameter(GLenum texTarget, GLenum pname);
|
||||
void TexParameter_base(GLenum texTarget, GLenum pname, GLint* maybeIntParam,
|
||||
GLfloat* maybeFloatParam);
|
||||
|
||||
virtual bool IsTexParamValid(GLenum pname) const;
|
||||
|
||||
// Upload funcs
|
||||
public:
|
||||
void CompressedTexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border,
|
||||
const dom::ArrayBufferView& view);
|
||||
void CompressedTexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLsizei width, GLsizei height,
|
||||
GLenum unpackFormat, const dom::ArrayBufferView& view);
|
||||
|
||||
void CopyTexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
|
||||
void CopyTexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height);
|
||||
|
||||
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
|
||||
GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv);
|
||||
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
|
||||
ErrorResult& out_rv);
|
||||
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
|
||||
ErrorResult* const out_rv);
|
||||
|
||||
|
||||
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
|
||||
GLsizei width, GLsizei height, GLenum unpackFormat,
|
||||
GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv);
|
||||
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
|
||||
ErrorResult& out_rv);
|
||||
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
|
||||
ErrorResult* const out_rv);
|
||||
|
||||
// Allow whatever element unpackTypes the bindings are willing to pass
|
||||
// us in Tex(Sub)Image2D
|
||||
template<typename ElementT>
|
||||
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum unpackFormat, GLenum unpackType, ElementT& elem,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
TexImage2D(texImageTarget, level, internalFormat, unpackFormat, unpackType, &elem,
|
||||
&out_rv);
|
||||
}
|
||||
template<typename ElementT>
|
||||
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
|
||||
GLenum unpackFormat, GLenum unpackType, ElementT& elem,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
TexSubImage2D(texImageTarget, level, xOffset, yOffset, unpackFormat, unpackType,
|
||||
&elem, &out_rv);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Vertices Feature (WebGLContextVertices.cpp)
|
||||
public:
|
||||
@ -1057,14 +1019,6 @@ protected:
|
||||
GLsizei depth, uint32_t pixelSize,
|
||||
uint32_t alignment);
|
||||
|
||||
virtual JS::Value GetTexParameterInternal(const TexTarget& target,
|
||||
GLenum pname);
|
||||
|
||||
// Returns x rounded to the next highest multiple of y.
|
||||
static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
|
||||
return ((x + y - 1) / y) * y;
|
||||
}
|
||||
|
||||
inline void InvalidateBufferFetching()
|
||||
{
|
||||
mBufferFetchingIsVerified = false;
|
||||
@ -1227,8 +1181,6 @@ protected:
|
||||
GLint width, GLint height, GLint depth,
|
||||
GLint border, GLenum format, GLenum type,
|
||||
WebGLTexImageFunc func, WebGLTexDimensions dims);
|
||||
bool ValidateTexImageTarget(GLenum texImageTarget, WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateTexImageFormat(GLenum internalFormat, WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims);
|
||||
bool ValidateTexImageType(GLenum type, WebGLTexImageFunc func,
|
||||
@ -1272,24 +1224,6 @@ protected:
|
||||
|
||||
// helpers
|
||||
|
||||
// If jsArrayType is MaxTypedArrayViewType, it means no array.
|
||||
void TexImage2D_base(TexImageTarget texImageTarget, GLint level,
|
||||
GLenum internalFormat, GLsizei width,
|
||||
GLsizei height, GLsizei srcStrideOrZero, GLint border,
|
||||
GLenum format, GLenum type, void* data,
|
||||
uint32_t byteLength, js::Scalar::Type jsArrayType,
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied);
|
||||
void TexSubImage2D_base(GLenum texImageTarget, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLsizei width,
|
||||
GLsizei height, GLsizei srcStrideOrZero,
|
||||
GLenum format, GLenum type, void* pixels,
|
||||
uint32_t byteLength, js::Scalar::Type jsArrayType,
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied);
|
||||
|
||||
void TexParameter_base(GLenum target, GLenum pname,
|
||||
GLint* const out_intParam,
|
||||
GLfloat* const out_floatParam);
|
||||
|
||||
bool ConvertImage(size_t width, size_t height, size_t srcStride,
|
||||
size_t dstStride, const uint8_t* src, uint8_t* dst,
|
||||
WebGLTexelFormat srcFormat, bool srcPremultiplied,
|
||||
@ -1321,11 +1255,6 @@ protected:
|
||||
RefPtr<gfx::DataSourceSurface>& imageOut,
|
||||
WebGLTexelFormat* format);
|
||||
|
||||
void CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
||||
GLint level, TexInternalFormat internalFormat,
|
||||
GLint xoffset, GLint yoffset, GLint x, GLint y,
|
||||
GLsizei width, GLsizei height, bool isSub);
|
||||
|
||||
// Returns false if `object` is null or not valid.
|
||||
template<class ObjectType>
|
||||
bool ValidateObject(const char* info, ObjectType* object);
|
||||
@ -1382,14 +1311,6 @@ protected:
|
||||
GLenum CheckedBufferData(GLenum target, GLsizeiptr size, const GLvoid* data,
|
||||
GLenum usage);
|
||||
|
||||
/** Like glTexImage2D, but if the call may change the texture size, checks
|
||||
* any GL error generated by this glTexImage2D call and returns it.
|
||||
*/
|
||||
GLenum CheckedTexImage2D(TexImageTarget texImageTarget, GLint level,
|
||||
TexInternalFormat internalFormat, GLsizei width,
|
||||
GLsizei height, GLint border, TexFormat format,
|
||||
TexType type, const GLvoid* data);
|
||||
|
||||
void ForceLoseContext(bool simulateLoss = false);
|
||||
void ForceRestoreContext();
|
||||
|
||||
@ -1691,6 +1612,17 @@ private:
|
||||
|
||||
size_t RoundUpToMultipleOf(size_t value, size_t multiple);
|
||||
|
||||
bool
|
||||
ValidateTexTarget(WebGLContext* webgl, GLenum rawTexTarget, const char* funcName,
|
||||
TexTarget* const out_texTarget, WebGLTexture** const out_tex);
|
||||
bool
|
||||
ValidateTexImageTarget(WebGLContext* webgl, GLenum rawTexImageTarget,
|
||||
const char* funcName, TexImageTarget* const out_texImageTarget,
|
||||
WebGLTexture** const out_tex);
|
||||
|
||||
// Returns x rounded to the next highest multiple of y.
|
||||
CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
@ -25,9 +25,8 @@ static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
|
||||
bool
|
||||
WebGLContext::DrawInstanced_check(const char* info)
|
||||
{
|
||||
// This restriction was removed in GLES3, so WebGL2 shouldn't have it.
|
||||
if (!IsWebGL2() &&
|
||||
IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays) &&
|
||||
if ((IsWebGL2() ||
|
||||
IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) &&
|
||||
!mBufferFetchingHasPerVertex)
|
||||
{
|
||||
/* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
|
||||
|
File diff suppressed because it is too large
Load Diff
469
dom/canvas/WebGLContextTextures.cpp
Normal file
469
dom/canvas/WebGLContextTextures.cpp
Normal file
@ -0,0 +1,469 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
#include "WebGLBuffer.h"
|
||||
#include "WebGLVertexAttribData.h"
|
||||
#include "WebGLShader.h"
|
||||
#include "WebGLProgram.h"
|
||||
#include "WebGLUniformLocation.h"
|
||||
#include "WebGLFramebuffer.h"
|
||||
#include "WebGLRenderbuffer.h"
|
||||
#include "WebGLShaderPrecisionFormat.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLExtensions.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "GLContext.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#include "CanvasUtils.h"
|
||||
#include "gfxUtils.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "WebGLTexelConversions.h"
|
||||
#include "WebGLValidateStrings.h"
|
||||
#include <algorithm>
|
||||
|
||||
// needed to check if current OS is lower than 10.7
|
||||
#if defined(MOZ_WIDGET_COCOA)
|
||||
#include "nsCocoaFeatures.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ImageData.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/Endian.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static bool
|
||||
IsValidTexTarget(WebGLContext* webgl, GLenum rawTexTarget, TexTarget* const out)
|
||||
{
|
||||
switch (rawTexTarget) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
if (!webgl->IsWebGL2())
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = rawTexTarget;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsValidTexImageTarget(WebGLContext* webgl, GLenum rawTexImageTarget,
|
||||
TexImageTarget* const out)
|
||||
{
|
||||
switch (rawTexImageTarget) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
if (!webgl->IsWebGL2())
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = rawTexImageTarget;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ValidateTexTarget(WebGLContext* webgl, GLenum rawTexTarget, const char* funcName,
|
||||
TexTarget* const out_texTarget, WebGLTexture** const out_tex)
|
||||
{
|
||||
if (webgl->IsContextLost())
|
||||
return false;
|
||||
|
||||
TexTarget texTarget;
|
||||
if (!IsValidTexTarget(webgl, rawTexTarget, &texTarget)) {
|
||||
webgl->ErrorInvalidEnum("%s: Invalid texTarget.", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
WebGLTexture* tex = webgl->ActiveBoundTextureForTarget(texTarget);
|
||||
if (!tex) {
|
||||
webgl->ErrorInvalidOperation("%s: No texture is bound to this target.", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_texTarget = texTarget;
|
||||
*out_tex = tex;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ValidateTexImageTarget(WebGLContext* webgl, GLenum rawTexImageTarget,
|
||||
const char* funcName, TexImageTarget* const out_texImageTarget,
|
||||
WebGLTexture** const out_tex)
|
||||
{
|
||||
if (webgl->IsContextLost())
|
||||
return false;
|
||||
|
||||
TexImageTarget texImageTarget;
|
||||
if (!IsValidTexImageTarget(webgl, rawTexImageTarget, &texImageTarget)) {
|
||||
webgl->ErrorInvalidEnum("%s: Invalid texImageTarget.", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
WebGLTexture* tex = webgl->ActiveBoundTextureForTexImageTarget(texImageTarget);
|
||||
if (!tex) {
|
||||
webgl->ErrorInvalidOperation("%s: No texture is bound to this target.", funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_texImageTarget = texImageTarget;
|
||||
*out_tex = tex;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::IsTexParamValid(GLenum pname) const
|
||||
{
|
||||
switch (pname) {
|
||||
case LOCAL_GL_TEXTURE_MIN_FILTER:
|
||||
case LOCAL_GL_TEXTURE_MAG_FILTER:
|
||||
case LOCAL_GL_TEXTURE_WRAP_S:
|
||||
case LOCAL_GL_TEXTURE_WRAP_T:
|
||||
return true;
|
||||
|
||||
case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
|
||||
return IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GL calls
|
||||
|
||||
void
|
||||
WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex))
|
||||
return;
|
||||
|
||||
// Need to check rawTarget first before comparing against newTex->Target() as
|
||||
// newTex->Target() returns a TexTarget, which will assert on invalid value.
|
||||
WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
|
||||
switch (rawTarget) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
currentTexPtr = &mBound2DTextures[mActiveTexture];
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
||||
currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
if (!IsWebGL2())
|
||||
return ErrorInvalidEnum("bindTexture: target TEXTURE_3D is only available in WebGL version 2.0 or newer");
|
||||
|
||||
currentTexPtr = &mBound3DTextures[mActiveTexture];
|
||||
break;
|
||||
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
|
||||
}
|
||||
const TexTarget texTarget(rawTarget);
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (newTex && !newTex->BindTexture(texTarget))
|
||||
return;
|
||||
|
||||
if (!newTex) {
|
||||
gl->fBindTexture(texTarget.get(), 0);
|
||||
}
|
||||
|
||||
*currentTexPtr = newTex;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::GenerateMipmap(GLenum rawTexTarget)
|
||||
{
|
||||
TexTarget texTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexTarget(this, rawTexTarget, "texParameter", &texTarget, &tex))
|
||||
return;
|
||||
|
||||
tex->GenerateMipmap(texTarget);
|
||||
}
|
||||
|
||||
JS::Value
|
||||
WebGLContext::GetTexParameter(GLenum rawTexTarget, GLenum pname)
|
||||
{
|
||||
TexTarget texTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexTarget(this, rawTexTarget, "texParameter", &texTarget, &tex))
|
||||
return JS::NullValue();
|
||||
|
||||
if (!IsTexParamValid(pname)) {
|
||||
ErrorInvalidEnumInfo("getTexParameter: pname", pname);
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
return tex->GetTexParameter(texTarget, pname);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::IsTexture(WebGLTexture* tex)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return false;
|
||||
|
||||
if (!ValidateObjectAllowDeleted("isTexture", tex))
|
||||
return false;
|
||||
|
||||
return tex->IsTexture();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::TexParameter_base(GLenum rawTexTarget, GLenum pname, GLint* maybeIntParam,
|
||||
GLfloat* maybeFloatParam)
|
||||
{
|
||||
MOZ_ASSERT(maybeIntParam || maybeFloatParam);
|
||||
|
||||
TexTarget texTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexTarget(this, rawTexTarget, "texParameter", &texTarget, &tex))
|
||||
return;
|
||||
|
||||
tex->TexParameter(texTarget, pname, maybeIntParam, maybeFloatParam);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Uploads
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TexImage
|
||||
|
||||
void
|
||||
WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
|
||||
ErrorResult* const out_rv)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "texImage2D", &texImageTarget,
|
||||
&tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->TexImage2D(texImageTarget, level, internalFormat, unpackFormat, unpackType, elem,
|
||||
out_rv);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
|
||||
GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "texImage2D", &texImageTarget,
|
||||
&tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->TexImage2D(texImageTarget, level, internalFormat, width, height, border,
|
||||
unpackFormat, unpackType, maybeView, &out_rv);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum unpackFormat, GLenum unpackType,
|
||||
dom::ImageData* imageData, ErrorResult& out_rv)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "texImage2D", &texImageTarget,
|
||||
&tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->TexImage2D(texImageTarget, level, internalFormat, unpackFormat, unpackType,
|
||||
imageData, &out_rv);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TexSubImage
|
||||
|
||||
|
||||
void
|
||||
WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLenum unpackFormat, GLenum unpackType,
|
||||
dom::Element* elem, ErrorResult* const out_rv)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "texSubImage2D", &texImageTarget,
|
||||
&tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->TexSubImage2D(texImageTarget, level, xOffset, yOffset, unpackFormat, unpackType,
|
||||
elem, out_rv);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLsizei width, GLsizei height,
|
||||
GLenum unpackFormat, GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "texSubImage2D", &texImageTarget,
|
||||
&tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->TexSubImage2D(texImageTarget, level, xOffset, yOffset, width, height,
|
||||
unpackFormat, unpackType, maybeView, &out_rv);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset, GLint yOffset,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "texSubImage2D", &texImageTarget,
|
||||
&tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->TexSubImage2D(texImageTarget, level, xOffset, yOffset, unpackFormat, unpackType,
|
||||
imageData, &out_rv);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CopyTex(Sub)Image
|
||||
|
||||
|
||||
void
|
||||
WebGLContext::CopyTexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLint border)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "copyTexImage2D",
|
||||
&texImageTarget, &tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->CopyTexImage2D(texImageTarget, level, internalFormat, x, y, width, height,
|
||||
border);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::CopyTexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "copyTexSubImage2D",
|
||||
&texImageTarget, &tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->CopyTexSubImage2D(texImageTarget, level, xOffset, yOffset, x, y, width, height);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CompressedTex(Sub)Image
|
||||
|
||||
|
||||
void
|
||||
WebGLContext::CompressedTexImage2D(GLenum rawTexImageTarget, GLint level,
|
||||
GLenum internalFormat, GLsizei width, GLsizei height,
|
||||
GLint border, const dom::ArrayBufferView& view)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "compressedTexImage2D",
|
||||
&texImageTarget, &tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->CompressedTexImage2D(texImageTarget, level, internalFormat, width, height,
|
||||
border, view);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::CompressedTexSubImage2D(GLenum rawTexImageTarget, GLint level,
|
||||
GLint xOffset, GLint yOffset, GLsizei width,
|
||||
GLsizei height, GLenum unpackFormat,
|
||||
const dom::ArrayBufferView& view)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
if (!ValidateTexImageTarget(this, rawTexImageTarget, "compressedTexSubImage2D",
|
||||
&texImageTarget, &tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tex->CompressedTexSubImage2D(texImageTarget, level, xOffset, yOffset, width, height,
|
||||
unpackFormat, view);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1001,7 +1001,7 @@ WebGLContext::EnumName(GLenum glenum, nsACString* out_name)
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::IsCompressedTextureFormat(GLenum format)
|
||||
IsCompressedTextureFormat(GLenum format)
|
||||
{
|
||||
switch (format) {
|
||||
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
||||
@ -1034,7 +1034,7 @@ WebGLContext::IsCompressedTextureFormat(GLenum format)
|
||||
|
||||
|
||||
bool
|
||||
WebGLContext::IsTextureFormatCompressed(TexInternalFormat format)
|
||||
IsTextureFormatCompressed(TexInternalFormat format)
|
||||
{
|
||||
return IsCompressedTextureFormat(format.get());
|
||||
}
|
||||
|
@ -61,6 +61,9 @@ TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget);
|
||||
// Helper function to create a JS::Value from a C string
|
||||
JS::Value StringValue(JSContext* cx, const char* str, ErrorResult& rv);
|
||||
|
||||
bool IsCompressedTextureFormat(GLenum format);
|
||||
bool IsTextureFormatCompressed(TexInternalFormat format);
|
||||
|
||||
struct GLComponents
|
||||
{
|
||||
unsigned char mComponents;
|
||||
|
@ -607,40 +607,6 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func,
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given texture target is valid for TexImage.
|
||||
*/
|
||||
bool
|
||||
WebGLContext::ValidateTexImageTarget(GLenum target, WebGLTexImageFunc func,
|
||||
WebGLTexDimensions dims)
|
||||
{
|
||||
switch (dims) {
|
||||
case WebGLTexDimensions::Tex2D:
|
||||
if (target == LOCAL_GL_TEXTURE_2D ||
|
||||
IsTexImageCubemapTarget(target))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
|
||||
return false;
|
||||
|
||||
case WebGLTexDimensions::Tex3D:
|
||||
if (target == LOCAL_GL_TEXTURE_3D)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
|
||||
return false;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT(false, "ValidateTexImageTarget: Invalid dims");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if type is a valid texture image type for source,
|
||||
* taking into account enabled WebGL extensions.
|
||||
|
@ -8,13 +8,13 @@
|
||||
#include <algorithm>
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/Scoped.h"
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
#include "WebGLTexelConversions.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -730,6 +730,289 @@ WebGLTexture::SetFakeBlackStatus(WebGLTextureFakeBlackStatus x)
|
||||
mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GL calls
|
||||
|
||||
bool
|
||||
WebGLTexture::BindTexture(TexTarget texTarget)
|
||||
{
|
||||
// silently ignore a deleted texture
|
||||
if (IsDeleted())
|
||||
return false;
|
||||
|
||||
if (HasEverBeenBound() && mTarget != texTarget) {
|
||||
mContext->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
|
||||
return false;
|
||||
}
|
||||
|
||||
mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
|
||||
Bind(texTarget);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::GenerateMipmap(TexTarget texTarget)
|
||||
{
|
||||
const TexImageTarget imageTarget = (texTarget == LOCAL_GL_TEXTURE_2D)
|
||||
? LOCAL_GL_TEXTURE_2D
|
||||
: LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
|
||||
if (!IsMipmapRangeValid())
|
||||
{
|
||||
return mContext->ErrorInvalidOperation("generateMipmap: Texture does not have a valid mipmap range.");
|
||||
}
|
||||
if (!HasImageInfoAt(imageTarget, EffectiveBaseMipmapLevel()))
|
||||
{
|
||||
return mContext->ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
|
||||
}
|
||||
|
||||
if (!mContext->IsWebGL2() && !IsFirstImagePowerOfTwo())
|
||||
return mContext->ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
|
||||
|
||||
TexInternalFormat internalformat = ImageInfoAt(imageTarget, 0).EffectiveInternalFormat();
|
||||
if (IsTextureFormatCompressed(internalformat))
|
||||
return mContext->ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
|
||||
|
||||
if (mContext->IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
|
||||
(IsGLDepthFormat(internalformat) || IsGLDepthStencilFormat(internalformat)))
|
||||
{
|
||||
return mContext->ErrorInvalidOperation("generateMipmap: "
|
||||
"A texture that has a base internal format of "
|
||||
"DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
|
||||
}
|
||||
|
||||
if (!AreAllLevel0ImageInfosEqual())
|
||||
return mContext->ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
|
||||
|
||||
SetGeneratedMipmap();
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
|
||||
if (gl->WorkAroundDriverBugs()) {
|
||||
// bug 696495 - to work around failures in the texture-mips.html test on various drivers, we
|
||||
// set the minification filter before calling glGenerateMipmap. This should not carry a significant performance
|
||||
// overhead so we do it unconditionally.
|
||||
//
|
||||
// note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105.
|
||||
gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST);
|
||||
gl->fGenerateMipmap(texTarget.get());
|
||||
gl->fTexParameteri(texTarget.get(), LOCAL_GL_TEXTURE_MIN_FILTER, MinFilter().get());
|
||||
} else {
|
||||
gl->fGenerateMipmap(texTarget.get());
|
||||
}
|
||||
}
|
||||
|
||||
JS::Value
|
||||
WebGLTexture::GetTexParameter(TexTarget texTarget, GLenum pname)
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
|
||||
GLint i = 0;
|
||||
GLfloat f = 0.0f;
|
||||
|
||||
switch (pname) {
|
||||
case LOCAL_GL_TEXTURE_MIN_FILTER:
|
||||
case LOCAL_GL_TEXTURE_MAG_FILTER:
|
||||
case LOCAL_GL_TEXTURE_WRAP_S:
|
||||
case LOCAL_GL_TEXTURE_WRAP_T:
|
||||
case LOCAL_GL_TEXTURE_BASE_LEVEL:
|
||||
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
|
||||
case LOCAL_GL_TEXTURE_COMPARE_MODE:
|
||||
case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
|
||||
case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
|
||||
case LOCAL_GL_TEXTURE_MAX_LEVEL:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_A:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_B:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_G:
|
||||
case LOCAL_GL_TEXTURE_SWIZZLE_R:
|
||||
case LOCAL_GL_TEXTURE_WRAP_R:
|
||||
mContext->gl->fGetTexParameteriv(texTarget.get(), pname, &i);
|
||||
return JS::NumberValue(uint32_t(i));
|
||||
|
||||
case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
|
||||
case LOCAL_GL_TEXTURE_MAX_LOD:
|
||||
case LOCAL_GL_TEXTURE_MIN_LOD:
|
||||
mContext->gl->fGetTexParameterfv(texTarget.get(), pname, &f);
|
||||
return JS::NumberValue(float(f));
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unhandled pname.");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLTexture::IsTexture() const
|
||||
{
|
||||
return HasEverBeenBound() && !IsDeleted();
|
||||
}
|
||||
|
||||
// Here we have to support all pnames with both int and float params.
|
||||
// See this discussion:
|
||||
// https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
|
||||
void
|
||||
WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, GLint* maybeIntParam,
|
||||
GLfloat* maybeFloatParam)
|
||||
{
|
||||
MOZ_ASSERT(maybeIntParam || maybeFloatParam);
|
||||
|
||||
GLint intParam = maybeIntParam ? *maybeIntParam : GLint(*maybeFloatParam);
|
||||
GLfloat floatParam = maybeFloatParam ? *maybeFloatParam : GLfloat(*maybeIntParam);
|
||||
|
||||
bool paramBadEnum = false;
|
||||
bool paramBadValue = false;
|
||||
|
||||
switch (pname) {
|
||||
case LOCAL_GL_TEXTURE_BASE_LEVEL:
|
||||
case LOCAL_GL_TEXTURE_MAX_LEVEL:
|
||||
if (!mContext->IsWebGL2())
|
||||
return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
|
||||
|
||||
if (intParam < 0) {
|
||||
paramBadValue = true;
|
||||
break;
|
||||
}
|
||||
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
|
||||
if (pname == LOCAL_GL_TEXTURE_BASE_LEVEL)
|
||||
mBaseMipmapLevel = intParam;
|
||||
else
|
||||
mMaxMipmapLevel = intParam;
|
||||
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_COMPARE_MODE:
|
||||
if (!mContext->IsWebGL2())
|
||||
return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
|
||||
|
||||
paramBadValue = (intParam != LOCAL_GL_NONE &&
|
||||
intParam != LOCAL_GL_COMPARE_REF_TO_TEXTURE);
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
|
||||
if (!mContext->IsWebGL2())
|
||||
return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
|
||||
|
||||
switch (intParam) {
|
||||
case LOCAL_GL_LEQUAL:
|
||||
case LOCAL_GL_GEQUAL:
|
||||
case LOCAL_GL_LESS:
|
||||
case LOCAL_GL_GREATER:
|
||||
case LOCAL_GL_EQUAL:
|
||||
case LOCAL_GL_NOTEQUAL:
|
||||
case LOCAL_GL_ALWAYS:
|
||||
case LOCAL_GL_NEVER:
|
||||
break;
|
||||
|
||||
default:
|
||||
paramBadValue = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_MIN_FILTER:
|
||||
switch (intParam) {
|
||||
case LOCAL_GL_NEAREST:
|
||||
case LOCAL_GL_LINEAR:
|
||||
case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
|
||||
case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
|
||||
case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
|
||||
case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
mMinFilter = intParam;
|
||||
break;
|
||||
|
||||
default:
|
||||
paramBadEnum = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_MAG_FILTER:
|
||||
switch (intParam) {
|
||||
case LOCAL_GL_NEAREST:
|
||||
case LOCAL_GL_LINEAR:
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
mMagFilter = intParam;
|
||||
break;
|
||||
|
||||
default:
|
||||
paramBadEnum = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_WRAP_S:
|
||||
switch (intParam) {
|
||||
case LOCAL_GL_CLAMP_TO_EDGE:
|
||||
case LOCAL_GL_MIRRORED_REPEAT:
|
||||
case LOCAL_GL_REPEAT:
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
mWrapS = intParam;
|
||||
break;
|
||||
|
||||
default:
|
||||
paramBadEnum = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_WRAP_T:
|
||||
switch (intParam) {
|
||||
case LOCAL_GL_CLAMP_TO_EDGE:
|
||||
case LOCAL_GL_MIRRORED_REPEAT:
|
||||
case LOCAL_GL_REPEAT:
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
mWrapT = intParam;
|
||||
break;
|
||||
|
||||
default:
|
||||
paramBadEnum = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
|
||||
if (!mContext->IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic))
|
||||
return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
|
||||
|
||||
if (maybeFloatParam && floatParam < 1.0f)
|
||||
paramBadValue = true;
|
||||
else if (maybeIntParam && intParam < 1)
|
||||
paramBadValue = true;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return mContext->ErrorInvalidEnumInfo("texParameter: pname", pname);
|
||||
}
|
||||
|
||||
if (paramBadEnum) {
|
||||
if (maybeIntParam) {
|
||||
mContext->ErrorInvalidEnum("texParameteri: pname 0x%04x: Invalid param"
|
||||
" 0x%04x.",
|
||||
pname, intParam);
|
||||
} else {
|
||||
mContext->ErrorInvalidEnum("texParameterf: pname 0x%04x: Invalid param %g.",
|
||||
pname, floatParam);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (paramBadValue) {
|
||||
if (maybeIntParam) {
|
||||
mContext->ErrorInvalidValue("texParameteri: pname 0x%04x: Invalid param %i"
|
||||
" (0x%x).",
|
||||
pname, intParam, intParam);
|
||||
} else {
|
||||
mContext->ErrorInvalidValue("texParameterf: pname 0x%04x: Invalid param %g.",
|
||||
pname, floatParam);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
if (maybeIntParam)
|
||||
mContext->gl->fTexParameteri(texTarget.get(), pname, intParam);
|
||||
else
|
||||
mContext->gl->fTexParameterf(texTarget.get(), pname, floatParam);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture, AddRef)
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
@ -18,6 +19,12 @@
|
||||
#include "WebGLStrongTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
class Element;
|
||||
class ImageData;
|
||||
} // namespace dom
|
||||
|
||||
// Zero is not an integer power of two.
|
||||
inline bool
|
||||
@ -27,6 +34,10 @@ IsPOTAssumingNonnegative(GLsizei x)
|
||||
return x && (x & (x-1)) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
DoesTargetMatchDimensions(WebGLContext* webgl, TexImageTarget target, uint8_t dims,
|
||||
const char* funcName);
|
||||
|
||||
// NOTE: When this class is switched to new DOM bindings, update the (then-slow)
|
||||
// WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
|
||||
class WebGLTexture final
|
||||
@ -36,7 +47,35 @@ class WebGLTexture final
|
||||
, public WebGLContextBoundObject
|
||||
, public WebGLFramebufferAttachable
|
||||
{
|
||||
friend class WebGLContext;
|
||||
friend class WebGLFramebuffer;
|
||||
|
||||
public:
|
||||
class ImageInfo;
|
||||
|
||||
const GLuint mGLName;
|
||||
|
||||
protected:
|
||||
GLenum mTarget;
|
||||
TexMinFilter mMinFilter;
|
||||
TexMagFilter mMagFilter;
|
||||
TexWrap mWrapS, mWrapT;
|
||||
|
||||
size_t mFacesCount, mMaxLevelWithCustomImages;
|
||||
nsTArray<ImageInfo> mImageInfos;
|
||||
|
||||
bool mHaveGeneratedMipmap; // Set by generateMipmap
|
||||
bool mImmutable; // Set by texStorage*
|
||||
|
||||
size_t mBaseMipmapLevel; // Set by texParameter (defaults to 0)
|
||||
size_t mMaxMipmapLevel; // Set by texParameter (defaults to 1000)
|
||||
|
||||
WebGLTextureFakeBlackStatus mFakeBlackStatus;
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
|
||||
|
||||
explicit WebGLTexture(WebGLContext* webgl, GLuint tex);
|
||||
|
||||
void Delete();
|
||||
@ -50,27 +89,156 @@ public:
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
|
||||
|
||||
protected:
|
||||
~WebGLTexture() {
|
||||
DeleteOnce();
|
||||
}
|
||||
|
||||
friend class WebGLContext;
|
||||
friend class WebGLFramebuffer;
|
||||
|
||||
// We store information about the various images that are part of this
|
||||
// texture. (cubemap faces, mipmap levels)
|
||||
|
||||
public:
|
||||
const GLuint mGLName;
|
||||
////////////////////////////////////
|
||||
// GL calls
|
||||
bool BindTexture(TexTarget texTarget);
|
||||
void GenerateMipmap(TexTarget texTarget);
|
||||
JS::Value GetTexParameter(TexTarget texTarget, GLenum pname);
|
||||
bool IsTexture() const;
|
||||
void TexParameter(TexTarget texTarget, GLenum pname, GLint* maybeIntParam,
|
||||
GLfloat* maybeFloatParam);
|
||||
|
||||
////////////////////////////////////
|
||||
// WebGLTextureUpload.cpp
|
||||
|
||||
void CompressedTexImage2D(TexImageTarget texImageTarget, GLint level,
|
||||
GLenum internalFormat, GLsizei width, GLsizei height,
|
||||
GLint border, const dom::ArrayBufferView& view);
|
||||
|
||||
void CompressedTexImage3D(TexImageTarget texImageTarget, GLint level,
|
||||
GLenum internalFormat, GLsizei width, GLsizei height,
|
||||
GLsizei depth, GLint border, GLsizei imageSize,
|
||||
const dom::ArrayBufferView& view);
|
||||
|
||||
|
||||
void CompressedTexSubImage2D(TexImageTarget texImageTarget, GLint level,
|
||||
GLint xOffset, GLint yOffset, GLsizei width,
|
||||
GLsizei height, GLenum unpackFormat,
|
||||
const dom::ArrayBufferView& view);
|
||||
|
||||
void CompressedTexSubImage3D(TexImageTarget texImageTarget, GLint level,
|
||||
GLint xOffset, GLint yOffset, GLint zOffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum unpackFormat, GLsizei imageSize,
|
||||
const dom::ArrayBufferView& view);
|
||||
|
||||
|
||||
void CopyTexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
|
||||
|
||||
|
||||
void CopyTexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height);
|
||||
|
||||
void CopyTexSubImage3D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset, GLint x, GLint y, GLsizei width,
|
||||
GLsizei height);
|
||||
|
||||
|
||||
void TexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
|
||||
GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv);
|
||||
void TexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
|
||||
ErrorResult* const out_rv);
|
||||
void TexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
|
||||
ErrorResult* const out_rv);
|
||||
|
||||
void TexImage3D(TexImageTarget target, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth, GLint border,
|
||||
GLenum unpackFormat, GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv);
|
||||
|
||||
|
||||
void TexStorage2D(TexTarget texTarget, GLsizei levels, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height);
|
||||
void TexStorage3D(TexTarget texTarget, GLsizei levels, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth);
|
||||
|
||||
|
||||
void TexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLsizei width, GLsizei height, GLenum unpackFormat,
|
||||
GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv);
|
||||
void TexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLenum unpackFormat, GLenum unpackType,
|
||||
dom::ImageData* imageData, ErrorResult* const out_rv);
|
||||
void TexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLenum unpackFormat, GLenum unpackType,
|
||||
dom::Element* elem, ErrorResult* const out_rv);
|
||||
|
||||
void TexSubImage3D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
|
||||
GLsizei depth, GLenum unpackFormat, GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv);
|
||||
void TexSubImage3D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset, GLenum unpackFormat,
|
||||
GLenum unpackType, dom::ImageData* imageData,
|
||||
ErrorResult* const out_rv);
|
||||
void TexSubImage3D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset, GLenum unpackFormat,
|
||||
GLenum unpackType, dom::Element* elem, ErrorResult* const out_rv);
|
||||
|
||||
protected:
|
||||
GLenum mTarget;
|
||||
|
||||
/** Like glTexImage2D, but if the call may change the texture size, checks
|
||||
* any GL error generated by this glTexImage2D call and returns it.
|
||||
*/
|
||||
GLenum CheckedTexImage2D(TexImageTarget texImageTarget, GLint level,
|
||||
TexInternalFormat internalFormat, GLsizei width,
|
||||
GLsizei height, GLint border, TexFormat format,
|
||||
TexType type, const GLvoid* data);
|
||||
|
||||
bool ValidateTexStorage(TexImageTarget texImageTarget, GLsizei levels, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
const char* funcName);
|
||||
void SpecifyTexStorage(GLsizei levels, TexInternalFormat internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth);
|
||||
|
||||
void CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
||||
GLint level, TexInternalFormat internalFormat,
|
||||
GLint xoffset, GLint yoffset, GLint x, GLint y,
|
||||
GLsizei width, GLsizei height, bool isSub);
|
||||
|
||||
bool TexImageFromVideoElement(TexImageTarget texImageTarget, GLint level,
|
||||
GLenum internalFormat, GLenum unpackFormat,
|
||||
GLenum unpackType, dom::Element* elem);
|
||||
|
||||
// If jsArrayType is MaxTypedArrayViewType, it means no array.
|
||||
void TexImage2D_base(TexImageTarget texImageTarget, GLint level,
|
||||
GLenum internalFormat, GLsizei width, GLsizei height,
|
||||
GLsizei srcStrideOrZero, GLint border, GLenum unpackFormat,
|
||||
GLenum unpackType, void* data, uint32_t byteLength,
|
||||
js::Scalar::Type jsArrayType, WebGLTexelFormat srcFormat,
|
||||
bool srcPremultiplied);
|
||||
void TexSubImage2D_base(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLsizei width, GLsizei height,
|
||||
GLsizei srcStrideOrZero, GLenum unpackFormat,
|
||||
GLenum unpackType, void* pixels, uint32_t byteLength,
|
||||
js::Scalar::Type jsArrayType, WebGLTexelFormat srcFormat,
|
||||
bool srcPremultiplied);
|
||||
|
||||
bool ValidateTexStorage(TexTarget texTarget, GLsizei levels, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
const char* info);
|
||||
bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
|
||||
|
||||
|
||||
public:
|
||||
// We store information about the various images that are part of this
|
||||
// texture. (cubemap faces, mipmap levels)
|
||||
class ImageInfo
|
||||
: public WebGLRectangleObject
|
||||
{
|
||||
@ -216,20 +384,6 @@ public:
|
||||
bool EnsureInitializedImageData(TexImageTarget imageTarget, GLint level);
|
||||
|
||||
protected:
|
||||
TexMinFilter mMinFilter;
|
||||
TexMagFilter mMagFilter;
|
||||
TexWrap mWrapS, mWrapT;
|
||||
|
||||
size_t mFacesCount, mMaxLevelWithCustomImages;
|
||||
nsTArray<ImageInfo> mImageInfos;
|
||||
|
||||
bool mHaveGeneratedMipmap; // Set by generateMipmap
|
||||
bool mImmutable; // Set by texStorage*
|
||||
|
||||
size_t mBaseMipmapLevel; // Set by texParameter (defaults to 0)
|
||||
size_t mMaxMipmapLevel; // Set by texParameter (defaults to 1000)
|
||||
|
||||
WebGLTextureFakeBlackStatus mFakeBlackStatus;
|
||||
|
||||
void EnsureMaxLevelWithCustomImagesAtLeast(size_t maxLevelWithCustomImages) {
|
||||
mMaxLevelWithCustomImages = std::max(mMaxLevelWithCustomImages,
|
||||
|
1419
dom/canvas/WebGLTextureUpload.cpp
Normal file
1419
dom/canvas/WebGLTextureUpload.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -78,6 +78,7 @@ UNIFIED_SOURCES += [
|
||||
'WebGLContextGL.cpp',
|
||||
'WebGLContextLossHandler.cpp',
|
||||
'WebGLContextState.cpp',
|
||||
'WebGLContextTextures.cpp',
|
||||
'WebGLContextUnchecked.cpp',
|
||||
'WebGLContextUtils.cpp',
|
||||
'WebGLContextValidate.cpp',
|
||||
@ -125,6 +126,7 @@ UNIFIED_SOURCES += [
|
||||
'WebGLSync.cpp',
|
||||
'WebGLTexelConversions.cpp',
|
||||
'WebGLTexture.cpp',
|
||||
'WebGLTextureUpload.cpp',
|
||||
'WebGLTimerQuery.cpp',
|
||||
'WebGLTransformFeedback.cpp',
|
||||
'WebGLUniformLocation.cpp',
|
||||
|
@ -35,7 +35,7 @@ CaptureStreamTestHelper.prototype = {
|
||||
/* Request a frame from the stream played by |video|. */
|
||||
requestFrame: function (video) {
|
||||
info("Requesting frame from " + video.id);
|
||||
video.mozSrcObject.requestFrame();
|
||||
video.srcObject.requestFrame();
|
||||
},
|
||||
|
||||
/* Tests the top left pixel of |video| against |refData|. Format [R,G,B,A]. */
|
||||
|
@ -19,7 +19,7 @@ function runTest() {
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
var video = document.getElementById('video');
|
||||
video.mozSrcObject = canvas.captureStream(0);
|
||||
video.srcObject = canvas.captureStream(0);
|
||||
video.play();
|
||||
video.onloadeddata = finished;
|
||||
video.onerror = finished;
|
||||
|
@ -33,7 +33,7 @@ function runTest() {
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
var video = document.getElementById('video');
|
||||
video.mozSrcObject = canvas.captureStream(0);
|
||||
video.srcObject = canvas.captureStream(0);
|
||||
video.play();
|
||||
video.onloadeddata = finished;
|
||||
video.onerror = finished;
|
||||
|
@ -19,9 +19,9 @@ function checkDrawColorInitialRed() {
|
||||
|
||||
h.drawColor(c, h.red);
|
||||
|
||||
vauto.mozSrcObject = c.captureStream();
|
||||
vmanual.mozSrcObject = c.captureStream(0);
|
||||
vrate.mozSrcObject = c.captureStream(10);
|
||||
vauto.srcObject = c.captureStream();
|
||||
vmanual.srcObject = c.captureStream(0);
|
||||
vrate.srcObject = c.captureStream(10);
|
||||
|
||||
ok(h.testPixel(vauto, [0, 0, 0, 0], 0), "vauto hould not be drawn to before stable state");
|
||||
ok(h.testPixel(vrate, [0, 0, 0, 0], 0), "vrate Should not be drawn to before stable state");
|
||||
|
@ -50,9 +50,9 @@ function checkClearColorInitialRed() {
|
||||
|
||||
h.clearColor(c, h.red);
|
||||
|
||||
vauto.mozSrcObject = c.captureStream();
|
||||
vmanual.mozSrcObject = c.captureStream(0);
|
||||
vrate.mozSrcObject = c.captureStream(10);
|
||||
vauto.srcObject = c.captureStream();
|
||||
vmanual.srcObject = c.captureStream(0);
|
||||
vrate.srcObject = c.captureStream(10);
|
||||
|
||||
ok(h.testPixel(vauto, [0, 0, 0, 0], 0), "Should not be drawn to before stable state");
|
||||
ok(h.testPixel(vrate, [0, 0, 0, 0], 0), "Should not be drawn to before stable state");
|
||||
|
@ -744,7 +744,8 @@ IMEContentObserver::AttributeWillChange(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aNewValue)
|
||||
{
|
||||
nsIContent *content = GetContentBR(aElement);
|
||||
mPreAttrChangeLength = content ?
|
||||
@ -756,7 +757,8 @@ IMEContentObserver::AttributeChanged(nsIDocument* aDocument,
|
||||
dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
mEndOfAddedTextCache.Clear();
|
||||
mStartOfRemovingTextRangeCache.Clear();
|
||||
|
@ -493,7 +493,7 @@ HTMLButtonElement::DoneCreatingElement()
|
||||
|
||||
nsresult
|
||||
HTMLButtonElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aNotify && aName == nsGkAtoms::disabled &&
|
||||
|
@ -80,7 +80,7 @@ public:
|
||||
* Called when an attribute is about to be changed
|
||||
*/
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
/**
|
||||
* Called when an attribute has just been changed
|
||||
|
@ -375,7 +375,7 @@ HTMLImageElement::GetAttributeMappingFunction() const
|
||||
|
||||
nsresult
|
||||
HTMLImageElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
|
||||
|
@ -334,7 +334,7 @@ protected:
|
||||
void UpdateFormOwner();
|
||||
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
|
@ -1020,7 +1020,7 @@ HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) co
|
||||
|
||||
nsresult
|
||||
HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aNameSpaceID == kNameSpaceID_None) {
|
||||
|
@ -865,7 +865,7 @@ protected:
|
||||
* Called when an attribute is about to be changed
|
||||
*/
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
/**
|
||||
* Called when an attribute has just been changed
|
||||
|
@ -527,6 +527,30 @@ HTMLMediaElement::GetMozMediaSourceObject() const
|
||||
return source.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMediaStream>
|
||||
HTMLMediaElement::GetSrcObject() const
|
||||
{
|
||||
NS_ASSERTION(!mSrcAttrStream || mSrcAttrStream->GetStream(),
|
||||
"MediaStream should have been set up properly");
|
||||
nsRefPtr<DOMMediaStream> stream = mSrcAttrStream;
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::SetSrcObject(DOMMediaStream& aValue)
|
||||
{
|
||||
SetMozSrcObject(&aValue);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::SetSrcObject(DOMMediaStream* aValue)
|
||||
{
|
||||
mSrcAttrStream = aValue;
|
||||
DoLoad();
|
||||
}
|
||||
|
||||
// TODO: Remove prefixed versions soon (1183495)
|
||||
|
||||
already_AddRefed<DOMMediaStream>
|
||||
HTMLMediaElement::GetMozSrcObject() const
|
||||
{
|
||||
|
@ -547,8 +547,12 @@ public:
|
||||
}
|
||||
|
||||
already_AddRefed<MediaSource> GetMozMediaSourceObject() const;
|
||||
already_AddRefed<DOMMediaStream> GetMozSrcObject() const;
|
||||
already_AddRefed<DOMMediaStream> GetSrcObject() const;
|
||||
void SetSrcObject(DOMMediaStream& aValue);
|
||||
void SetSrcObject(DOMMediaStream* aValue);
|
||||
|
||||
// TODO: remove prefixed versions soon (1183495).
|
||||
already_AddRefed<DOMMediaStream> GetMozSrcObject() const;
|
||||
void SetMozSrcObject(DOMMediaStream& aValue);
|
||||
void SetMozSrcObject(DOMMediaStream* aValue);
|
||||
|
||||
|
@ -182,7 +182,7 @@ HTMLOptionElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
||||
|
||||
nsresult
|
||||
HTMLOptionElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
nsresult rv = nsGenericHTMLElement::BeforeSetAttr(aNamespaceID, aName,
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
int32_t aModType) const override;
|
||||
|
||||
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
@ -153,7 +153,8 @@ HTMLPropertiesCollection::NamedItem(const nsAString& aName)
|
||||
void
|
||||
HTMLPropertiesCollection::AttributeChanged(nsIDocument *aDocument, Element* aElement,
|
||||
int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
mIsDirty = true;
|
||||
}
|
||||
@ -427,7 +428,8 @@ PropertyNodeList::GetValues(JSContext* aCx, nsTArray<JS::Value >& aResult,
|
||||
void
|
||||
PropertyNodeList::AttributeChanged(nsIDocument* aDocument, Element* aElement,
|
||||
int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue)
|
||||
{
|
||||
mIsDirty = true;
|
||||
}
|
||||
|
@ -1325,7 +1325,7 @@ HTMLSelectElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
|
||||
nsresult
|
||||
HTMLSelectElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aNotify && aName == nsGkAtoms::disabled &&
|
||||
|
@ -372,7 +372,7 @@ public:
|
||||
bool aCompileEventHandlers) override;
|
||||
virtual void UnbindFromTree(bool aDeep, bool aNullParent) override;
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue, bool aNotify) override;
|
||||
|
@ -954,7 +954,7 @@ HTMLTableElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
|
||||
nsresult
|
||||
HTMLTableElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aName == nsGkAtoms::cellpadding && aNameSpaceID == kNameSpaceID_None) {
|
||||
|
@ -190,7 +190,7 @@ public:
|
||||
* Called when an attribute is about to be changed
|
||||
*/
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
/**
|
||||
* Called when an attribute has just been changed
|
||||
|
@ -1212,7 +1212,7 @@ HTMLTextAreaElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
|
||||
nsresult
|
||||
HTMLTextAreaElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify)
|
||||
{
|
||||
if (aNotify && aName == nsGkAtoms::disabled &&
|
||||
|
@ -140,7 +140,7 @@ public:
|
||||
* Called when an attribute is about to be changed
|
||||
*/
|
||||
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValueOrString* aValue,
|
||||
nsAttrValueOrString* aValue,
|
||||
bool aNotify) override;
|
||||
|
||||
// nsIMutationObserver
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user