зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2ginbound, a=merge
This commit is contained in:
Коммит
5530340073
|
@ -533,11 +533,6 @@ public:
|
|||
*/
|
||||
virtual void SetSelected(bool aSelect);
|
||||
|
||||
/**
|
||||
* Extend selection to this accessible.
|
||||
*/
|
||||
void ExtendSelection() { };
|
||||
|
||||
/**
|
||||
* Select the accessible within its container.
|
||||
*/
|
||||
|
|
|
@ -192,10 +192,5 @@ OuterDocAccessible::RemoteChildDoc() const
|
|||
if (!tab)
|
||||
return nullptr;
|
||||
|
||||
if (DocAccessibleParent* doc = tab->GetTopLevelDocAccessible()) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "no top level tab document?");
|
||||
return nullptr;
|
||||
return tab->GetTopLevelDocAccessible();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class Accessible;
|
|||
* Mozilla creates the implementations of nsIAccessible on demand.
|
||||
* See http://www.mozilla.org/projects/ui/accessibility for more information.
|
||||
*/
|
||||
[scriptable, uuid(66b110b0-c25a-4784-8623-f6ba40c7cfee)]
|
||||
[scriptable, uuid(de2869d9-563c-4943-996b-31a4daa4d097)]
|
||||
interface nsIAccessible : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -231,12 +231,6 @@ interface nsIAccessible : nsISupports
|
|||
*/
|
||||
void setSelected(in boolean isSelected);
|
||||
|
||||
/**
|
||||
* Extend the current selection from its current accessible anchor node
|
||||
* to this accessible
|
||||
*/
|
||||
void extendSelection();
|
||||
|
||||
/**
|
||||
* Select this accessible node only
|
||||
*/
|
||||
|
|
|
@ -1621,6 +1621,28 @@ DocAccessibleChild::RecvUnselectAll(const uint64_t& aID,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvTakeSelection(const uint64_t& aID)
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
if (acc) {
|
||||
acc->TakeSelection();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvSetSelected(const uint64_t& aID, const bool& aSelect)
|
||||
{
|
||||
Accessible* acc = IdToAccessible(aID);
|
||||
if (acc) {
|
||||
acc->SetSelected(aSelect);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DocAccessibleChild::RecvDoAction(const uint64_t& aID,
|
||||
const uint8_t& aIndex,
|
||||
|
|
|
@ -401,6 +401,10 @@ public:
|
|||
virtual bool RecvUnselectAll(const uint64_t& aID,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual bool RecvTakeSelection(const uint64_t& aID) override;
|
||||
virtual bool RecvSetSelected(const uint64_t& aID,
|
||||
const bool& aSelect) override;
|
||||
|
||||
virtual bool RecvDoAction(const uint64_t& aID,
|
||||
const uint8_t& aIndex,
|
||||
bool* aSuccess) override;
|
||||
|
|
|
@ -216,6 +216,9 @@ child:
|
|||
prio(high) sync SelectAll(uint64_t aID) returns(bool aSuccess);
|
||||
prio(high) sync UnselectAll(uint64_t aID) returns(bool aSuccess);
|
||||
|
||||
async TakeSelection(uint64_t aID);
|
||||
async SetSelected(uint64_t aID, bool aSelected);
|
||||
|
||||
prio(high) sync DoAction(uint64_t aID, uint8_t aIndex) returns(bool aSuccess);
|
||||
prio(high) sync ActionCount(uint64_t aID) returns(uint8_t aCount);
|
||||
prio(high) sync ActionDescriptionAt(uint64_t aID, uint8_t aIndex) returns(nsString aDescription);
|
||||
|
|
|
@ -906,6 +906,18 @@ ProxyAccessible::UnselectAll()
|
|||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::TakeSelection()
|
||||
{
|
||||
unused << mDoc->SendTakeSelection(mID);
|
||||
}
|
||||
|
||||
void
|
||||
ProxyAccessible::SetSelected(bool aSelect)
|
||||
{
|
||||
unused << mDoc->SendSetSelected(mID, aSelect);
|
||||
}
|
||||
|
||||
bool
|
||||
ProxyAccessible::DoAction(uint8_t aIndex)
|
||||
{
|
||||
|
|
|
@ -309,6 +309,9 @@ public:
|
|||
bool SelectAll();
|
||||
bool UnselectAll();
|
||||
|
||||
void TakeSelection();
|
||||
void SetSelected(bool aSelect);
|
||||
|
||||
bool DoAction(uint8_t aIndex);
|
||||
uint8_t ActionCount();
|
||||
void ActionDescriptionAt(uint8_t aIndex, nsString& aDescription);
|
||||
|
|
|
@ -913,9 +913,6 @@ AccessibleWrap::accSelect(
|
|||
if (flagsSelect & SELFLAG_REMOVESELECTION)
|
||||
xpAccessible->SetSelected(false);
|
||||
|
||||
if (flagsSelect & SELFLAG_EXTENDSELECTION)
|
||||
xpAccessible->ExtendSelection();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -498,16 +498,6 @@ xpcAccessible::SetSelected(bool aSelect)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::ExtendSelection()
|
||||
{
|
||||
if (!Intl())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
Intl()->ExtendSelection();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::TakeSelection()
|
||||
{
|
||||
|
|
|
@ -73,7 +73,6 @@ public:
|
|||
final override;
|
||||
|
||||
NS_IMETHOD SetSelected(bool aSelect) final override;
|
||||
NS_IMETHOD ExtendSelection() final override;
|
||||
NS_IMETHOD TakeSelection() final override;
|
||||
NS_IMETHOD TakeFocus() final override;
|
||||
|
||||
|
|
|
@ -1104,9 +1104,6 @@ var PageInfoListener = {
|
|||
|
||||
serializeElementInfo: function(document, url, type, alt, item, isBG)
|
||||
{
|
||||
// Interface for image loading content.
|
||||
const nsIImageLoadingContent = Components.interfaces.nsIImageLoadingContent;
|
||||
|
||||
let result = {};
|
||||
|
||||
let imageText;
|
||||
|
@ -1130,10 +1127,9 @@ var PageInfoListener = {
|
|||
result.mimeType = item.type;
|
||||
}
|
||||
|
||||
if (!result.mimeType && !isBG && item instanceof nsIImageLoadingContent) {
|
||||
if (!result.mimeType && !isBG && item instanceof Ci.nsIImageLoadingContent) {
|
||||
// Interface for image loading content.
|
||||
const nsIImageLoadingContent = Components.interfaces.nsIImageLoadingContent;
|
||||
let imageRequest = item.getRequest(nsIImageLoadingContent.CURRENT_REQUEST);
|
||||
let imageRequest = item.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
|
||||
if (imageRequest) {
|
||||
result.mimeType = imageRequest.mimeType;
|
||||
let image = !(imageRequest.imageStatus & imageRequest.STATUS_ERROR) && imageRequest.image;
|
||||
|
@ -1158,7 +1154,18 @@ var PageInfoListener = {
|
|||
result.HTMLVideoElement = item instanceof content.HTMLVideoElement;
|
||||
result.HTMLAudioElement = item instanceof content.HTMLAudioElement;
|
||||
|
||||
if (!isBG) {
|
||||
if (isBG) {
|
||||
// Items that are showing this image as a background
|
||||
// image might not necessarily have a width or height,
|
||||
// so we'll dynamically generate an image and send up the
|
||||
// natural dimensions.
|
||||
let img = content.document.createElement("img");
|
||||
img.src = url;
|
||||
result.naturalWidth = img.naturalWidth;
|
||||
result.naturalHeight = img.naturalHeight;
|
||||
} else {
|
||||
// Otherwise, we can use the current width and height
|
||||
// of the image.
|
||||
result.width = item.width;
|
||||
result.height = item.height;
|
||||
}
|
||||
|
|
|
@ -895,6 +895,14 @@ function makePreview(row)
|
|||
// "width" and "height" attributes must be set to newImage,
|
||||
// even if there is no "width" or "height attribute in item;
|
||||
// otherwise, the preview image cannot be displayed correctly.
|
||||
// Since the image might have been loaded out-of-process, we expect
|
||||
// the item to tell us its width / height dimensions. Failing that
|
||||
// the item should tell us the natural dimensions of the image. Finally
|
||||
// failing that, we'll assume that the image was never loaded in the
|
||||
// other process (this can be true for favicons, for example), and so
|
||||
// we'll assume that we can use the natural dimensions of the newImage
|
||||
// we just created. If the natural dimensions of newImage are not known
|
||||
// then the image is probably broken.
|
||||
if (!isBG) {
|
||||
newImage.width = ("width" in item && item.width) || newImage.naturalWidth;
|
||||
newImage.height = ("height" in item && item.height) || newImage.naturalHeight;
|
||||
|
@ -902,8 +910,8 @@ function makePreview(row)
|
|||
else {
|
||||
// the Width and Height of an HTML tag should not be used for its background image
|
||||
// (for example, "table" can have "width" or "height" attributes)
|
||||
newImage.width = newImage.naturalWidth;
|
||||
newImage.height = newImage.naturalHeight;
|
||||
newImage.width = item.naturalWidth || newImage.naturalWidth;
|
||||
newImage.height = item.naturalHeight || newImage.naturalHeight;
|
||||
}
|
||||
|
||||
if (item.SVGImageElement) {
|
||||
|
|
|
@ -635,8 +635,9 @@ Sanitizer.prototype = {
|
|||
let newWindow = existingWindow.openDialog("chrome://browser/content/", "_blank",
|
||||
features, defaultArgs);
|
||||
|
||||
let onFullScreen = null;
|
||||
if (AppConstants.platform == "macosx") {
|
||||
let onFullScreen = function(e) {
|
||||
onFullScreen = function(e) {
|
||||
newWindow.removeEventListener("fullscreen", onFullScreen);
|
||||
let docEl = newWindow.document.documentElement;
|
||||
let sizemode = docEl.getAttribute("sizemode");
|
||||
|
@ -658,7 +659,7 @@ Sanitizer.prototype = {
|
|||
// closes) and/or run too late (and not have a fully-formed window yet
|
||||
// in existence). See bug 1088137.
|
||||
let newWindowOpened = false;
|
||||
function onWindowOpened(subject, topic, data) {
|
||||
let onWindowOpened = function(subject, topic, data) {
|
||||
if (subject != newWindow)
|
||||
return;
|
||||
|
||||
|
@ -675,7 +676,7 @@ Sanitizer.prototype = {
|
|||
}
|
||||
|
||||
let numWindowsClosing = windowList.length;
|
||||
function onWindowClosed() {
|
||||
let onWindowClosed = function() {
|
||||
numWindowsClosing--;
|
||||
if (numWindowsClosing == 0) {
|
||||
Services.obs.removeObserver(onWindowClosed, "xul-window-destroyed");
|
||||
|
@ -686,9 +687,9 @@ Sanitizer.prototype = {
|
|||
}
|
||||
}
|
||||
}
|
||||
Services.obs.addObserver(onWindowOpened, "browser-delayed-startup-finished", false);
|
||||
Services.obs.addObserver(onWindowClosed, "xul-window-destroyed", false);
|
||||
});
|
||||
Services.obs.addObserver(onWindowOpened, "browser-delayed-startup-finished", false);
|
||||
Services.obs.addObserver(onWindowClosed, "xul-window-destroyed", false);
|
||||
|
||||
// Start the process of closing windows
|
||||
while (windowList.length) {
|
||||
|
|
|
@ -243,10 +243,12 @@
|
|||
see bug 492960 comment 20. -->
|
||||
<menupopup id="customizationPanelItemContextMenu">
|
||||
<menuitem oncommand="gCustomizeMode.addToToolbar(document.popupNode)"
|
||||
closemenu="single"
|
||||
class="customize-context-moveToToolbar"
|
||||
accesskey="&customizeMenu.moveToToolbar.accesskey;"
|
||||
label="&customizeMenu.moveToToolbar.label;"/>
|
||||
<menuitem oncommand="gCustomizeMode.removeFromArea(document.popupNode)"
|
||||
closemenu="single"
|
||||
class="customize-context-removeFromPanel"
|
||||
accesskey="&customizeMenu.removeFromMenu.accesskey;"
|
||||
label="&customizeMenu.removeFromMenu.label;"/>
|
||||
|
|
|
@ -2621,11 +2621,11 @@ ContentPermissionPrompt.prototype = {
|
|||
},
|
||||
|
||||
_promptWebNotifications : function(aRequest) {
|
||||
var message = gBrowserBundle.GetStringFromName("webNotifications.showFromSite2");
|
||||
var message = gBrowserBundle.GetStringFromName("webNotifications.receiveFromSite");
|
||||
|
||||
var actions = [
|
||||
{
|
||||
stringId: "webNotifications.alwaysShow",
|
||||
stringId: "webNotifications.alwaysReceive",
|
||||
action: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
expireType: null,
|
||||
callback: function() {},
|
||||
|
|
|
@ -178,8 +178,9 @@ PlacesTreeView.prototype = {
|
|||
|
||||
let row = -1;
|
||||
let useNodeIndex = typeof(aNodeIndex) == "number";
|
||||
if (parent == this._rootNode)
|
||||
if (parent == this._rootNode) {
|
||||
row = useNodeIndex ? aNodeIndex : this._rootNode.getChildIndex(aNode);
|
||||
}
|
||||
else if (useNodeIndex && typeof(aParentRow) == "number") {
|
||||
// If we have both the row of the parent node, and the node's index, we
|
||||
// can avoid searching the rows array if the parent is a plain container.
|
||||
|
@ -855,8 +856,7 @@ PlacesTreeView.prototype = {
|
|||
.then(aLivemark => {
|
||||
this._controller.cacheLivemarkInfo(aNode, aLivemark);
|
||||
let properties = this._cellProperties.get(aNode);
|
||||
this._cellProperties.set(aNode, properties += " livemark ");
|
||||
|
||||
this._cellProperties.set(aNode, properties += " livemark");
|
||||
// The livemark attribute is set as a cell property on the title cell.
|
||||
this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
|
||||
}, Components.utils.reportError);
|
||||
|
@ -1175,7 +1175,8 @@ PlacesTreeView.prototype = {
|
|||
PlacesUtils.livemarks.getLivemark({ id: node.itemId })
|
||||
.then(aLivemark => {
|
||||
this._controller.cacheLivemarkInfo(node, aLivemark);
|
||||
properties += " livemark";
|
||||
let props = this._cellProperties.get(node);
|
||||
this._cellProperties.set(node, props += " livemark");
|
||||
// The livemark attribute is set as a cell property on the title cell.
|
||||
this._invalidateCellValue(node, this.COLUMN_TYPE_TITLE);
|
||||
}, () => undefined);
|
||||
|
|
|
@ -375,11 +375,11 @@ geolocation.neverShareLocation.accesskey=N
|
|||
geolocation.shareWithSite2=Would you like to share your location with this site?
|
||||
geolocation.shareWithFile2=Would you like to share your location with this file?
|
||||
|
||||
webNotifications.alwaysShow=Always Show Notifications
|
||||
webNotifications.alwaysShow.accesskey=A
|
||||
webNotifications.alwaysReceive=Always Receive Notifications
|
||||
webNotifications.alwaysReceive.accesskey=A
|
||||
webNotifications.neverShow=Always Block Notifications
|
||||
webNotifications.neverShow.accesskey=N
|
||||
webNotifications.showFromSite2=Would you like to show notifications from this site?
|
||||
webNotifications.receiveFromSite=Would you like to receive notifications from this site?
|
||||
|
||||
# Pointer lock UI
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Dan Abramov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,9 @@
|
|||
"react-redux" uses UMD style loading to work in many different environments.
|
||||
It assumes that "react" and "redux" are both included via `require("react")`
|
||||
as in node or browserify, but the paths to our react and redux installation are different.
|
||||
|
||||
If upgrading react-redux, define the correct paths and replace the require statements
|
||||
for the module.exports case with the correct paths.
|
||||
|
||||
Path to react: "devtools/client/shared/vendor/react"
|
||||
Path to redux: "devtools/client/shared/vendor/redux"
|
|
@ -12,6 +12,7 @@ if CONFIG['DEBUG_JS_MODULES']:
|
|||
]
|
||||
|
||||
modules += [
|
||||
'react-redux.js',
|
||||
'react.js',
|
||||
'redux.js',
|
||||
]
|
||||
|
|
|
@ -0,0 +1,724 @@
|
|||
var REACT_PATH = "devtools/client/shared/vendor/react";
|
||||
var REDUX_PATH = "devtools/client/shared/vendor/redux";
|
||||
|
||||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
if(typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = factory(require(REACT_PATH), require(REDUX_PATH));
|
||||
else if(typeof define === 'function' && define.amd)
|
||||
define(["react", "redux"], factory);
|
||||
else if(typeof exports === 'object')
|
||||
exports["ReactRedux"] = factory(require("react"), require("redux"));
|
||||
else
|
||||
root["ReactRedux"] = factory(root["React"], root["Redux"]);
|
||||
})(this, function(__WEBPACK_EXTERNAL_MODULE_10__, __WEBPACK_EXTERNAL_MODULE_11__) {
|
||||
return /******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId])
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ exports: {},
|
||||
/******/ id: moduleId,
|
||||
/******/ loaded: false
|
||||
/******/ };
|
||||
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.loaded = true;
|
||||
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
|
||||
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.__esModule = true;
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
|
||||
|
||||
var _react = __webpack_require__(10);
|
||||
|
||||
var _react2 = _interopRequireDefault(_react);
|
||||
|
||||
var _componentsCreateAll = __webpack_require__(2);
|
||||
|
||||
var _componentsCreateAll2 = _interopRequireDefault(_componentsCreateAll);
|
||||
|
||||
var _createAll = _componentsCreateAll2['default'](_react2['default']);
|
||||
|
||||
var Provider = _createAll.Provider;
|
||||
var connect = _createAll.connect;
|
||||
exports.Provider = Provider;
|
||||
exports.connect = connect;
|
||||
|
||||
/***/ },
|
||||
/* 1 */
|
||||
/***/ function(module, exports) {
|
||||
|
||||
"use strict";
|
||||
|
||||
exports.__esModule = true;
|
||||
exports["default"] = createStoreShape;
|
||||
|
||||
function createStoreShape(PropTypes) {
|
||||
return PropTypes.shape({
|
||||
subscribe: PropTypes.func.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
getState: PropTypes.func.isRequired
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = exports["default"];
|
||||
|
||||
/***/ },
|
||||
/* 2 */
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.__esModule = true;
|
||||
exports['default'] = createAll;
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
|
||||
|
||||
var _createProvider = __webpack_require__(4);
|
||||
|
||||
var _createProvider2 = _interopRequireDefault(_createProvider);
|
||||
|
||||
var _createConnect = __webpack_require__(3);
|
||||
|
||||
var _createConnect2 = _interopRequireDefault(_createConnect);
|
||||
|
||||
function createAll(React) {
|
||||
var Provider = _createProvider2['default'](React);
|
||||
var connect = _createConnect2['default'](React);
|
||||
|
||||
return { Provider: Provider, connect: connect };
|
||||
}
|
||||
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 3 */
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.__esModule = true;
|
||||
|
||||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||
|
||||
exports['default'] = createConnect;
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
var _utilsCreateStoreShape = __webpack_require__(1);
|
||||
|
||||
var _utilsCreateStoreShape2 = _interopRequireDefault(_utilsCreateStoreShape);
|
||||
|
||||
var _utilsShallowEqual = __webpack_require__(6);
|
||||
|
||||
var _utilsShallowEqual2 = _interopRequireDefault(_utilsShallowEqual);
|
||||
|
||||
var _utilsIsPlainObject = __webpack_require__(5);
|
||||
|
||||
var _utilsIsPlainObject2 = _interopRequireDefault(_utilsIsPlainObject);
|
||||
|
||||
var _utilsWrapActionCreators = __webpack_require__(7);
|
||||
|
||||
var _utilsWrapActionCreators2 = _interopRequireDefault(_utilsWrapActionCreators);
|
||||
|
||||
var _hoistNonReactStatics = __webpack_require__(8);
|
||||
|
||||
var _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics);
|
||||
|
||||
var _invariant = __webpack_require__(9);
|
||||
|
||||
var _invariant2 = _interopRequireDefault(_invariant);
|
||||
|
||||
var defaultMapStateToProps = function defaultMapStateToProps() {
|
||||
return {};
|
||||
};
|
||||
var defaultMapDispatchToProps = function defaultMapDispatchToProps(dispatch) {
|
||||
return { dispatch: dispatch };
|
||||
};
|
||||
var defaultMergeProps = function defaultMergeProps(stateProps, dispatchProps, parentProps) {
|
||||
return _extends({}, parentProps, stateProps, dispatchProps);
|
||||
};
|
||||
|
||||
function getDisplayName(Component) {
|
||||
return Component.displayName || Component.name || 'Component';
|
||||
}
|
||||
|
||||
// Helps track hot reloading.
|
||||
var nextVersion = 0;
|
||||
|
||||
function createConnect(React) {
|
||||
var Component = React.Component;
|
||||
var PropTypes = React.PropTypes;
|
||||
|
||||
var storeShape = _utilsCreateStoreShape2['default'](PropTypes);
|
||||
|
||||
return function connect(mapStateToProps, mapDispatchToProps, mergeProps) {
|
||||
var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
|
||||
|
||||
var shouldSubscribe = Boolean(mapStateToProps);
|
||||
var finalMapStateToProps = mapStateToProps || defaultMapStateToProps;
|
||||
var finalMapDispatchToProps = _utilsIsPlainObject2['default'](mapDispatchToProps) ? _utilsWrapActionCreators2['default'](mapDispatchToProps) : mapDispatchToProps || defaultMapDispatchToProps;
|
||||
var finalMergeProps = mergeProps || defaultMergeProps;
|
||||
var shouldUpdateStateProps = finalMapStateToProps.length > 1;
|
||||
var shouldUpdateDispatchProps = finalMapDispatchToProps.length > 1;
|
||||
var _options$pure = options.pure;
|
||||
var pure = _options$pure === undefined ? true : _options$pure;
|
||||
|
||||
// Helps track hot reloading.
|
||||
var version = nextVersion++;
|
||||
|
||||
function computeStateProps(store, props) {
|
||||
var state = store.getState();
|
||||
var stateProps = shouldUpdateStateProps ? finalMapStateToProps(state, props) : finalMapStateToProps(state);
|
||||
|
||||
_invariant2['default'](_utilsIsPlainObject2['default'](stateProps), '`mapStateToProps` must return an object. Instead received %s.', stateProps);
|
||||
return stateProps;
|
||||
}
|
||||
|
||||
function computeDispatchProps(store, props) {
|
||||
var dispatch = store.dispatch;
|
||||
|
||||
var dispatchProps = shouldUpdateDispatchProps ? finalMapDispatchToProps(dispatch, props) : finalMapDispatchToProps(dispatch);
|
||||
|
||||
_invariant2['default'](_utilsIsPlainObject2['default'](dispatchProps), '`mapDispatchToProps` must return an object. Instead received %s.', dispatchProps);
|
||||
return dispatchProps;
|
||||
}
|
||||
|
||||
function _computeNextState(stateProps, dispatchProps, parentProps) {
|
||||
var mergedProps = finalMergeProps(stateProps, dispatchProps, parentProps);
|
||||
_invariant2['default'](_utilsIsPlainObject2['default'](mergedProps), '`mergeProps` must return an object. Instead received %s.', mergedProps);
|
||||
return mergedProps;
|
||||
}
|
||||
|
||||
return function wrapWithConnect(WrappedComponent) {
|
||||
var Connect = (function (_Component) {
|
||||
_inherits(Connect, _Component);
|
||||
|
||||
Connect.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) {
|
||||
if (!pure) {
|
||||
this.updateStateProps(nextProps);
|
||||
this.updateDispatchProps(nextProps);
|
||||
this.updateState(nextProps);
|
||||
return true;
|
||||
}
|
||||
|
||||
var storeChanged = nextState.storeState !== this.state.storeState;
|
||||
var propsChanged = !_utilsShallowEqual2['default'](nextProps, this.props);
|
||||
var mapStateProducedChange = false;
|
||||
var dispatchPropsChanged = false;
|
||||
|
||||
if (storeChanged || propsChanged && shouldUpdateStateProps) {
|
||||
mapStateProducedChange = this.updateStateProps(nextProps);
|
||||
}
|
||||
|
||||
if (propsChanged && shouldUpdateDispatchProps) {
|
||||
dispatchPropsChanged = this.updateDispatchProps(nextProps);
|
||||
}
|
||||
|
||||
if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
|
||||
this.updateState(nextProps);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
function Connect(props, context) {
|
||||
_classCallCheck(this, Connect);
|
||||
|
||||
_Component.call(this, props, context);
|
||||
this.version = version;
|
||||
this.store = props.store || context.store;
|
||||
|
||||
_invariant2['default'](this.store, 'Could not find "store" in either the context or ' + ('props of "' + this.constructor.displayName + '". ') + 'Either wrap the root component in a <Provider>, ' + ('or explicitly pass "store" as a prop to "' + this.constructor.displayName + '".'));
|
||||
|
||||
this.stateProps = computeStateProps(this.store, props);
|
||||
this.dispatchProps = computeDispatchProps(this.store, props);
|
||||
this.state = { storeState: null };
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
Connect.prototype.computeNextState = function computeNextState() {
|
||||
var props = arguments.length <= 0 || arguments[0] === undefined ? this.props : arguments[0];
|
||||
|
||||
return _computeNextState(this.stateProps, this.dispatchProps, props);
|
||||
};
|
||||
|
||||
Connect.prototype.updateStateProps = function updateStateProps() {
|
||||
var props = arguments.length <= 0 || arguments[0] === undefined ? this.props : arguments[0];
|
||||
|
||||
var nextStateProps = computeStateProps(this.store, props);
|
||||
if (_utilsShallowEqual2['default'](nextStateProps, this.stateProps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.stateProps = nextStateProps;
|
||||
return true;
|
||||
};
|
||||
|
||||
Connect.prototype.updateDispatchProps = function updateDispatchProps() {
|
||||
var props = arguments.length <= 0 || arguments[0] === undefined ? this.props : arguments[0];
|
||||
|
||||
var nextDispatchProps = computeDispatchProps(this.store, props);
|
||||
if (_utilsShallowEqual2['default'](nextDispatchProps, this.dispatchProps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.dispatchProps = nextDispatchProps;
|
||||
return true;
|
||||
};
|
||||
|
||||
Connect.prototype.updateState = function updateState() {
|
||||
var props = arguments.length <= 0 || arguments[0] === undefined ? this.props : arguments[0];
|
||||
|
||||
this.nextState = this.computeNextState(props);
|
||||
};
|
||||
|
||||
Connect.prototype.isSubscribed = function isSubscribed() {
|
||||
return typeof this.unsubscribe === 'function';
|
||||
};
|
||||
|
||||
Connect.prototype.trySubscribe = function trySubscribe() {
|
||||
if (shouldSubscribe && !this.unsubscribe) {
|
||||
this.unsubscribe = this.store.subscribe(this.handleChange.bind(this));
|
||||
this.handleChange();
|
||||
}
|
||||
};
|
||||
|
||||
Connect.prototype.tryUnsubscribe = function tryUnsubscribe() {
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
this.unsubscribe = null;
|
||||
}
|
||||
};
|
||||
|
||||
Connect.prototype.componentDidMount = function componentDidMount() {
|
||||
this.trySubscribe();
|
||||
};
|
||||
|
||||
Connect.prototype.componentWillUnmount = function componentWillUnmount() {
|
||||
this.tryUnsubscribe();
|
||||
};
|
||||
|
||||
Connect.prototype.handleChange = function handleChange() {
|
||||
if (!this.unsubscribe) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
storeState: this.store.getState()
|
||||
});
|
||||
};
|
||||
|
||||
Connect.prototype.getWrappedInstance = function getWrappedInstance() {
|
||||
return this.refs.wrappedInstance;
|
||||
};
|
||||
|
||||
Connect.prototype.render = function render() {
|
||||
return React.createElement(WrappedComponent, _extends({ ref: 'wrappedInstance'
|
||||
}, this.nextState));
|
||||
};
|
||||
|
||||
return Connect;
|
||||
})(Component);
|
||||
|
||||
Connect.displayName = 'Connect(' + getDisplayName(WrappedComponent) + ')';
|
||||
Connect.WrappedComponent = WrappedComponent;
|
||||
Connect.contextTypes = {
|
||||
store: storeShape
|
||||
};
|
||||
Connect.propTypes = {
|
||||
store: storeShape
|
||||
};
|
||||
|
||||
if (true) {
|
||||
Connect.prototype.componentWillUpdate = function componentWillUpdate() {
|
||||
if (this.version === version) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We are hot reloading!
|
||||
this.version = version;
|
||||
|
||||
// Update the state and bindings.
|
||||
this.trySubscribe();
|
||||
this.updateStateProps();
|
||||
this.updateDispatchProps();
|
||||
this.updateState();
|
||||
};
|
||||
}
|
||||
|
||||
return _hoistNonReactStatics2['default'](Connect, WrappedComponent);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 4 */
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.__esModule = true;
|
||||
exports['default'] = createProvider;
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
var _utilsCreateStoreShape = __webpack_require__(1);
|
||||
|
||||
var _utilsCreateStoreShape2 = _interopRequireDefault(_utilsCreateStoreShape);
|
||||
|
||||
function isUsingOwnerContext(React) {
|
||||
var version = React.version;
|
||||
|
||||
if (typeof version !== 'string') {
|
||||
return true;
|
||||
}
|
||||
|
||||
var sections = version.split('.');
|
||||
var major = parseInt(sections[0], 10);
|
||||
var minor = parseInt(sections[1], 10);
|
||||
|
||||
return major === 0 && minor === 13;
|
||||
}
|
||||
|
||||
function createProvider(React) {
|
||||
var Component = React.Component;
|
||||
var PropTypes = React.PropTypes;
|
||||
var Children = React.Children;
|
||||
|
||||
var storeShape = _utilsCreateStoreShape2['default'](PropTypes);
|
||||
var requireFunctionChild = isUsingOwnerContext(React);
|
||||
|
||||
var didWarnAboutChild = false;
|
||||
function warnAboutFunctionChild() {
|
||||
if (didWarnAboutChild || requireFunctionChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
didWarnAboutChild = true;
|
||||
console.error( // eslint-disable-line no-console
|
||||
'With React 0.14 and later versions, you no longer need to ' + 'wrap <Provider> child into a function.');
|
||||
}
|
||||
function warnAboutElementChild() {
|
||||
if (didWarnAboutChild || !requireFunctionChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
didWarnAboutChild = true;
|
||||
console.error( // eslint-disable-line no-console
|
||||
'With React 0.13, you need to ' + 'wrap <Provider> child into a function. ' + 'This restriction will be removed with React 0.14.');
|
||||
}
|
||||
|
||||
var didWarnAboutReceivingStore = false;
|
||||
function warnAboutReceivingStore() {
|
||||
if (didWarnAboutReceivingStore) {
|
||||
return;
|
||||
}
|
||||
|
||||
didWarnAboutReceivingStore = true;
|
||||
console.error( // eslint-disable-line no-console
|
||||
'<Provider> does not support changing `store` on the fly. ' + 'It is most likely that you see this error because you updated to ' + 'Redux 2.x and React Redux 2.x which no longer hot reload reducers ' + 'automatically. See https://github.com/rackt/react-redux/releases/' + 'tag/v2.0.0 for the migration instructions.');
|
||||
}
|
||||
|
||||
var Provider = (function (_Component) {
|
||||
_inherits(Provider, _Component);
|
||||
|
||||
Provider.prototype.getChildContext = function getChildContext() {
|
||||
return { store: this.store };
|
||||
};
|
||||
|
||||
function Provider(props, context) {
|
||||
_classCallCheck(this, Provider);
|
||||
|
||||
_Component.call(this, props, context);
|
||||
this.store = props.store;
|
||||
}
|
||||
|
||||
Provider.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
|
||||
var store = this.store;
|
||||
var nextStore = nextProps.store;
|
||||
|
||||
if (store !== nextStore) {
|
||||
warnAboutReceivingStore();
|
||||
}
|
||||
};
|
||||
|
||||
Provider.prototype.render = function render() {
|
||||
var children = this.props.children;
|
||||
|
||||
if (typeof children === 'function') {
|
||||
warnAboutFunctionChild();
|
||||
children = children();
|
||||
} else {
|
||||
warnAboutElementChild();
|
||||
}
|
||||
|
||||
return Children.only(children);
|
||||
};
|
||||
|
||||
return Provider;
|
||||
})(Component);
|
||||
|
||||
Provider.childContextTypes = {
|
||||
store: storeShape.isRequired
|
||||
};
|
||||
Provider.propTypes = {
|
||||
store: storeShape.isRequired,
|
||||
children: (requireFunctionChild ? PropTypes.func : PropTypes.element).isRequired
|
||||
};
|
||||
|
||||
return Provider;
|
||||
}
|
||||
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 5 */
|
||||
/***/ function(module, exports) {
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.__esModule = true;
|
||||
exports['default'] = isPlainObject;
|
||||
var fnToString = function fnToString(fn) {
|
||||
return Function.prototype.toString.call(fn);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} obj The object to inspect.
|
||||
* @returns {boolean} True if the argument appears to be a plain object.
|
||||
*/
|
||||
|
||||
function isPlainObject(obj) {
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var proto = typeof obj.constructor === 'function' ? Object.getPrototypeOf(obj) : Object.prototype;
|
||||
|
||||
if (proto === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var constructor = proto.constructor;
|
||||
|
||||
return typeof constructor === 'function' && constructor instanceof constructor && fnToString(constructor) === fnToString(Object);
|
||||
}
|
||||
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 6 */
|
||||
/***/ function(module, exports) {
|
||||
|
||||
"use strict";
|
||||
|
||||
exports.__esModule = true;
|
||||
exports["default"] = shallowEqual;
|
||||
|
||||
function shallowEqual(objA, objB) {
|
||||
if (objA === objB) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var keysA = Object.keys(objA);
|
||||
var keysB = Object.keys(objB);
|
||||
|
||||
if (keysA.length !== keysB.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test for A's keys different from B.
|
||||
var hasOwn = Object.prototype.hasOwnProperty;
|
||||
for (var i = 0; i < keysA.length; i++) {
|
||||
if (!hasOwn.call(objB, keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = exports["default"];
|
||||
|
||||
/***/ },
|
||||
/* 7 */
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.__esModule = true;
|
||||
exports['default'] = wrapActionCreators;
|
||||
|
||||
var _redux = __webpack_require__(11);
|
||||
|
||||
function wrapActionCreators(actionCreators) {
|
||||
return function (dispatch) {
|
||||
return _redux.bindActionCreators(actionCreators, dispatch);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 8 */
|
||||
/***/ function(module, exports) {
|
||||
|
||||
/**
|
||||
* Copyright 2015, Yahoo! Inc.
|
||||
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var REACT_STATICS = {
|
||||
childContextTypes: true,
|
||||
contextTypes: true,
|
||||
defaultProps: true,
|
||||
displayName: true,
|
||||
getDefaultProps: true,
|
||||
mixins: true,
|
||||
propTypes: true,
|
||||
type: true
|
||||
};
|
||||
|
||||
var KNOWN_STATICS = {
|
||||
name: true,
|
||||
length: true,
|
||||
prototype: true,
|
||||
caller: true,
|
||||
arguments: true,
|
||||
arity: true
|
||||
};
|
||||
|
||||
module.exports = function hoistNonReactStatics(targetComponent, sourceComponent) {
|
||||
var keys = Object.getOwnPropertyNames(sourceComponent);
|
||||
for (var i=0; i<keys.length; ++i) {
|
||||
if (!REACT_STATICS[keys[i]] && !KNOWN_STATICS[keys[i]]) {
|
||||
targetComponent[keys[i]] = sourceComponent[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
return targetComponent;
|
||||
};
|
||||
|
||||
|
||||
/***/ },
|
||||
/* 9 */
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
/**
|
||||
* Copyright 2013-2015, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule invariant
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Use invariant() to assert state which your program assumes to be true.
|
||||
*
|
||||
* Provide sprintf-style format (only %s is supported) and arguments
|
||||
* to provide information about what broke and what you were
|
||||
* expecting.
|
||||
*
|
||||
* The invariant message will be stripped in production, but the invariant
|
||||
* will remain to ensure logic does not differ in production.
|
||||
*/
|
||||
|
||||
var invariant = function(condition, format, a, b, c, d, e, f) {
|
||||
if (true) {
|
||||
if (format === undefined) {
|
||||
throw new Error('invariant requires an error message argument');
|
||||
}
|
||||
}
|
||||
|
||||
if (!condition) {
|
||||
var error;
|
||||
if (format === undefined) {
|
||||
error = new Error(
|
||||
'Minified exception occurred; use the non-minified dev environment ' +
|
||||
'for the full error message and additional helpful warnings.'
|
||||
);
|
||||
} else {
|
||||
var args = [a, b, c, d, e, f];
|
||||
var argIndex = 0;
|
||||
error = new Error(
|
||||
'Invariant Violation: ' +
|
||||
format.replace(/%s/g, function() { return args[argIndex++]; })
|
||||
);
|
||||
}
|
||||
|
||||
error.framesToPop = 1; // we don't care about invariant's own frame
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = invariant;
|
||||
|
||||
|
||||
/***/ },
|
||||
/* 10 */
|
||||
/***/ function(module, exports) {
|
||||
|
||||
module.exports = __WEBPACK_EXTERNAL_MODULE_10__;
|
||||
|
||||
/***/ },
|
||||
/* 11 */
|
||||
/***/ function(module, exports) {
|
||||
|
||||
module.exports = __WEBPACK_EXTERNAL_MODULE_11__;
|
||||
|
||||
/***/ }
|
||||
/******/ ])
|
||||
});
|
||||
;
|
|
@ -2432,13 +2432,8 @@ class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase,
|
|||
public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToChild(JSContext* aCx,
|
||||
nsFrameLoader* aFrameLoader,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
|
||||
nsAsyncMessageToChild(JSContext* aCx, JS::Handle<JSObject*> aCpows, nsFrameLoader* aFrameLoader)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aCpows)
|
||||
, mFrameLoader(aFrameLoader)
|
||||
{
|
||||
}
|
||||
|
@ -2457,7 +2452,7 @@ public:
|
|||
nsRefPtr<nsFrameLoader> mFrameLoader;
|
||||
};
|
||||
|
||||
bool
|
||||
nsresult
|
||||
nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
|
@ -2469,27 +2464,37 @@ nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
|
|||
ClonedMessageData data;
|
||||
nsIContentParent* cp = tabParent->Manager();
|
||||
if (!BuildClonedMessageDataForParent(cp, aData, data)) {
|
||||
return false;
|
||||
MOZ_CRASH();
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
|
||||
jsipc::CPOWManager* mgr = cp->GetCPOWManager();
|
||||
if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) {
|
||||
return false;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (tabParent->SendAsyncMessage(nsString(aMessage), data, cpows,
|
||||
IPC::Principal(aPrincipal))) {
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows,
|
||||
IPC::Principal(aPrincipal));
|
||||
}
|
||||
|
||||
if (mChildMessageManager) {
|
||||
nsCOMPtr<nsIRunnable> ev = new nsAsyncMessageToChild(aCx, this, aMessage,
|
||||
aData, aCpows,
|
||||
aPrincipal);
|
||||
NS_DispatchToCurrentThread(ev);
|
||||
return true;
|
||||
nsRefPtr<nsAsyncMessageToChild> ev = new nsAsyncMessageToChild(aCx, aCpows, this);
|
||||
nsresult rv = ev->Init(aCx, aMessage, aData, aPrincipal);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = NS_DispatchToCurrentThread(ev);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We don't have any targets to send our asynchronous message to.
|
||||
return false;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -92,11 +92,11 @@ public:
|
|||
*/
|
||||
virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
|
||||
bool aRunInGlobalScope) override;
|
||||
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
mozilla::dom::ipc::StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
virtual nsresult DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
mozilla::dom::ipc::StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
virtual bool CheckPermission(const nsAString& aPermission) override;
|
||||
virtual bool CheckManifestURL(const nsAString& aManifestURL) override;
|
||||
virtual bool CheckAppHasPermission(const nsAString& aPermission) override;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/IntentionalCrash.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/nsIContentParent.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
|
@ -809,8 +810,9 @@ nsFrameMessageManager::DispatchAsyncMessageInternal(JSContext* aCx,
|
|||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (!mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = mCallback->DoSendAsyncMessage(aCx, aMessage, aData, aCpows, aPrincipal);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1889,15 +1891,9 @@ class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase,
|
|||
public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToSameProcessChild(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
|
||||
{
|
||||
}
|
||||
|
||||
nsAsyncMessageToSameProcessChild(JSContext* aCx, JS::Handle<JSObject*> aCpows)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aCpows)
|
||||
{ }
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsFrameMessageManager* ppm = nsFrameMessageManager::GetChildProcessManager();
|
||||
|
@ -1931,17 +1927,24 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override
|
||||
virtual nsresult DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows,
|
||||
aPrincipal);
|
||||
NS_DispatchToCurrentThread(ev);
|
||||
return true;
|
||||
nsRefPtr<nsAsyncMessageToSameProcessChild> ev =
|
||||
new nsAsyncMessageToSameProcessChild(aCx, aCpows);
|
||||
|
||||
nsresult rv = ev->Init(aCx, aMessage, aData, aPrincipal);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = NS_DispatchToCurrentThread(ev);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool CheckPermission(const nsAString& aPermission) override
|
||||
|
@ -2014,29 +2017,32 @@ public:
|
|||
IPC::Principal(aPrincipal), aRetVal);
|
||||
}
|
||||
|
||||
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override
|
||||
virtual nsresult DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override
|
||||
{
|
||||
mozilla::dom::ContentChild* cc =
|
||||
mozilla::dom::ContentChild::GetSingleton();
|
||||
if (!cc) {
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
ClonedMessageData data;
|
||||
if (!BuildClonedMessageDataForChild(cc, aData, data)) {
|
||||
return false;
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
|
||||
if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
|
||||
return false;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (!cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
|
||||
IPC::Principal(aPrincipal))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
|
||||
IPC::Principal(aPrincipal));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -2044,15 +2050,9 @@ class nsAsyncMessageToSameProcessParent : public nsSameProcessAsyncMessageBase,
|
|||
public SameProcessMessageQueue::Runnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToSameProcessParent(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
|
||||
{
|
||||
}
|
||||
|
||||
nsAsyncMessageToSameProcessParent(JSContext* aCx, JS::Handle<JSObject*> aCpows)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aCpows)
|
||||
{ }
|
||||
virtual nsresult HandleMessage() override
|
||||
{
|
||||
nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager;
|
||||
|
@ -2096,7 +2096,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
||||
virtual nsresult DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
|
@ -2104,9 +2104,14 @@ public:
|
|||
{
|
||||
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
|
||||
nsRefPtr<nsAsyncMessageToSameProcessParent> ev =
|
||||
new nsAsyncMessageToSameProcessParent(aCx, aMessage, aData, aCpows, aPrincipal);
|
||||
new nsAsyncMessageToSameProcessParent(aCx, aCpows);
|
||||
nsresult rv = ev->Init(aCx, aMessage, aData, aPrincipal);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
queue->Push(ev);
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -2202,23 +2207,28 @@ nsFrameMessageManager::MarkForCC()
|
|||
return true;
|
||||
}
|
||||
|
||||
nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject*> aCpows,
|
||||
nsIPrincipal* aPrincipal)
|
||||
: mRuntime(js::GetRuntime(aCx)),
|
||||
mMessage(aMessage),
|
||||
mCpows(aCx, aCpows),
|
||||
mPrincipal(aPrincipal)
|
||||
nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx, JS::Handle<JSObject*> aCpows)
|
||||
: mRuntime(nullptr)
|
||||
, mCpows(aCx, aCpows)
|
||||
{ }
|
||||
|
||||
|
||||
nsresult
|
||||
nsSameProcessAsyncMessageBase::Init(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
if (!mData.Copy(aData)) {
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncMessageOOM"),
|
||||
NS_ConvertUTF16toUTF8(aMessage));
|
||||
#endif
|
||||
NS_ABORT_OOM(aData.DataLength());
|
||||
Telemetry::Accumulate(Telemetry::IPC_SAME_PROCESS_MESSAGE_COPY_OOM_KB, aData.DataLength());
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mRuntime = js::GetRuntime(aCx);
|
||||
mMessage = aMessage;
|
||||
mPrincipal = aPrincipal;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2226,6 +2236,8 @@ nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget,
|
|||
nsIFrameLoader* aTargetFrameLoader,
|
||||
nsFrameMessageManager* aManager)
|
||||
{
|
||||
// Make sure that we have called Init() and it has succeeded.
|
||||
MOZ_ASSERT(mRuntime);
|
||||
if (aManager) {
|
||||
SameProcessCpowHolder cpows(mRuntime, mCpows);
|
||||
|
||||
|
|
|
@ -73,13 +73,13 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject*> aCpows,
|
||||
nsIPrincipal* aPrincipal)
|
||||
virtual nsresult DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject*> aCpows,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual bool CheckPermission(const nsAString& aPermission)
|
||||
|
@ -317,28 +317,32 @@ private:
|
|||
|
||||
class MyAsyncMessage : public nsSameProcessAsyncMessageBase, public nsRunnable
|
||||
{
|
||||
// Initialize nsSameProcessAsyncMessageBase...
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
ReceiveMessage(..., ...);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
nsRefPtr<nsSameProcessAsyncMessageBase> ev = new MyAsyncMessage();
|
||||
nsresult rv = ev->Init(...);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_DispatchToMainThread(ev);
|
||||
}
|
||||
*/
|
||||
class nsSameProcessAsyncMessageBase
|
||||
{
|
||||
public:
|
||||
typedef mozilla::dom::ipc::StructuredCloneData StructuredCloneData;
|
||||
|
||||
nsSameProcessAsyncMessageBase(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject*> aCpows,
|
||||
nsIPrincipal* aPrincipal);
|
||||
nsSameProcessAsyncMessageBase(JSContext* aCx, JS::Handle<JSObject*> aCpows);
|
||||
nsresult Init(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
void ReceiveMessage(nsISupports* aTarget, nsIFrameLoader* aTargetFrameLoader,
|
||||
nsFrameMessageManager* aManager);
|
||||
|
||||
private:
|
||||
nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
|
||||
|
||||
|
|
|
@ -49,16 +49,10 @@ class nsAsyncMessageToParent : public nsSameProcessAsyncMessageBase,
|
|||
public SameProcessMessageQueue::Runnable
|
||||
{
|
||||
public:
|
||||
nsAsyncMessageToParent(JSContext* aCx,
|
||||
nsInProcessTabChildGlobal* aTabChild,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal),
|
||||
mTabChild(aTabChild)
|
||||
{
|
||||
}
|
||||
nsAsyncMessageToParent(JSContext* aCx, JS::Handle<JSObject*> aCpows, nsInProcessTabChildGlobal* aTabChild)
|
||||
: nsSameProcessAsyncMessageBase(aCx, aCpows)
|
||||
, mTabChild(aTabChild)
|
||||
{ }
|
||||
|
||||
virtual nsresult HandleMessage() override
|
||||
{
|
||||
|
@ -69,7 +63,7 @@ public:
|
|||
nsRefPtr<nsInProcessTabChildGlobal> mTabChild;
|
||||
};
|
||||
|
||||
bool
|
||||
nsresult
|
||||
nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
|
@ -78,9 +72,15 @@ nsInProcessTabChildGlobal::DoSendAsyncMessage(JSContext* aCx,
|
|||
{
|
||||
SameProcessMessageQueue* queue = SameProcessMessageQueue::Get();
|
||||
nsRefPtr<nsAsyncMessageToParent> ev =
|
||||
new nsAsyncMessageToParent(aCx, this, aMessage, aData, aCpows, aPrincipal);
|
||||
new nsAsyncMessageToParent(aCx, aCpows, this);
|
||||
|
||||
nsresult rv = ev->Init(aCx, aMessage, aData, aPrincipal);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
queue->Push(ev);
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
|
||||
|
|
|
@ -88,11 +88,11 @@ public:
|
|||
nsIPrincipal* aPrincipal,
|
||||
nsTArray<StructuredCloneData>* aRetVal,
|
||||
bool aIsSync) override;
|
||||
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
virtual nsresult DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
|
||||
virtual nsresult PreHandleEvent(
|
||||
mozilla::EventChainPreVisitor& aVisitor) override;
|
||||
|
|
|
@ -189,11 +189,11 @@ nsScriptNameSpaceManager* GetNameSpaceManager();
|
|||
nsScriptNameSpaceManager* PeekNameSpaceManager();
|
||||
|
||||
// Runnable that's used to do async error reporting
|
||||
class AsyncErrorReporter : public nsRunnable
|
||||
class AsyncErrorReporter final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
// aWindow may be null if this error report is not associated with a window
|
||||
AsyncErrorReporter(JSRuntime* aRuntime, xpc::ErrorReport* aReport)
|
||||
explicit AsyncErrorReporter(xpc::ErrorReport* aReport)
|
||||
: mReport(aReport)
|
||||
{}
|
||||
|
||||
|
|
|
@ -1235,7 +1235,7 @@ bool CanvasRenderingContext2D::SwitchRenderingMode(RenderingMode aRenderingMode)
|
|||
mTarget->DrawSurface(snapshot, r, r);
|
||||
|
||||
// Restore the clips and transform
|
||||
for (uint32_t i = 0; i < CurrentState().clipsPushed.size(); i++) {
|
||||
for (uint32_t i = 0; i < CurrentState().clipsPushed.Length(); i++) {
|
||||
mTarget->PushClip(CurrentState().clipsPushed[i]);
|
||||
}
|
||||
|
||||
|
@ -1719,7 +1719,7 @@ CanvasRenderingContext2D::Restore()
|
|||
|
||||
TransformWillUpdate();
|
||||
|
||||
for (uint32_t i = 0; i < CurrentState().clipsPushed.size(); i++) {
|
||||
for (uint32_t i = 0; i < CurrentState().clipsPushed.Length(); i++) {
|
||||
mTarget->PopClip();
|
||||
}
|
||||
|
||||
|
@ -2864,7 +2864,7 @@ CanvasRenderingContext2D::Clip(const CanvasWindingRule& winding)
|
|||
}
|
||||
|
||||
mTarget->PushClip(mPath);
|
||||
CurrentState().clipsPushed.push_back(mPath);
|
||||
CurrentState().clipsPushed.AppendElement(mPath);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2879,7 +2879,7 @@ CanvasRenderingContext2D::Clip(const CanvasPath& path, const CanvasWindingRule&
|
|||
}
|
||||
|
||||
mTarget->PushClip(gfxpath);
|
||||
CurrentState().clipsPushed.push_back(gfxpath);
|
||||
CurrentState().clipsPushed.AppendElement(gfxpath);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -984,7 +984,7 @@ protected:
|
|||
return std::min(SIGMA_MAX, shadowBlur / 2.0f);
|
||||
}
|
||||
|
||||
std::vector<mozilla::RefPtr<mozilla::gfx::Path> > clipsPushed;
|
||||
nsTArray<mozilla::RefPtr<mozilla::gfx::Path> > clipsPushed;
|
||||
|
||||
nsRefPtr<gfxFontGroup> fontGroup;
|
||||
nsCOMPtr<nsIAtom> fontLanguage;
|
||||
|
|
|
@ -24,6 +24,7 @@ class WebGLVertexArrayObject;
|
|||
namespace dom {
|
||||
class OwningUnsignedLongOrUint32ArrayOrBoolean;
|
||||
class OwningWebGLBufferOrLongLong;
|
||||
class ArrayBufferViewOrSharedArrayBufferView;
|
||||
} // namespace dom
|
||||
|
||||
class WebGL2Context
|
||||
|
@ -51,8 +52,16 @@ public:
|
|||
|
||||
void CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
||||
GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
|
||||
|
||||
private:
|
||||
template<typename BufferT>
|
||||
void GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT& data);
|
||||
|
||||
public:
|
||||
void GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData);
|
||||
void GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::SharedArrayBuffer& data);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -88,12 +97,12 @@ public:
|
|||
void TexImage3D(GLenum target, GLint level, GLenum internalformat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLint border, GLenum format, GLenum type,
|
||||
const dom::Nullable<dom::ArrayBufferView>& pixels,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
|
||||
ErrorResult& rv);
|
||||
void TexSubImage3D(GLenum target, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum format, GLenum type, const dom::Nullable<dom::ArrayBufferView>& pixels,
|
||||
GLenum format, GLenum type, const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
|
||||
ErrorResult& rv);
|
||||
void TexSubImage3D(GLenum target, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
|
@ -109,10 +118,10 @@ public:
|
|||
GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
void 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::ArrayBufferViewOrSharedArrayBufferView& data);
|
||||
void 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 format, GLsizei imageSize, const dom::ArrayBufferViewOrSharedArrayBufferView& data);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
@ -138,9 +138,12 @@ WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
|||
}
|
||||
}
|
||||
|
||||
// BufferT may be one of
|
||||
// const dom::ArrayBuffer&
|
||||
// const dom::SharedArrayBuffer&
|
||||
template<typename BufferT>
|
||||
void
|
||||
WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData)
|
||||
WebGL2Context::GetBufferSubDataT(GLenum target, GLintptr offset, const BufferT& data)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
@ -159,11 +162,6 @@ WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
|||
if (offset < 0)
|
||||
return ErrorInvalidValue("getBufferSubData: negative offset");
|
||||
|
||||
// If returnedData is null then an INVALID_VALUE error is
|
||||
// generated.
|
||||
if (maybeData.IsNull())
|
||||
return ErrorInvalidValue("getBufferSubData: returnedData is null");
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
if (!boundBuffer)
|
||||
|
@ -171,7 +169,6 @@ WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
|||
|
||||
// If offset + returnedData.byteLength would extend beyond the end
|
||||
// of the buffer an INVALID_VALUE error is generated.
|
||||
const dom::ArrayBuffer& data = maybeData.Value();
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.Length();
|
||||
|
@ -225,4 +222,22 @@ WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
|||
}
|
||||
}
|
||||
|
||||
void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData)
|
||||
{
|
||||
// If returnedData is null then an INVALID_VALUE error is
|
||||
// generated.
|
||||
if (maybeData.IsNull())
|
||||
return ErrorInvalidValue("getBufferSubData: returnedData is null");
|
||||
|
||||
const dom::ArrayBuffer& data = maybeData.Value();
|
||||
GetBufferSubDataT(target, offset, data);
|
||||
}
|
||||
|
||||
void WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
||||
const dom::SharedArrayBuffer& data)
|
||||
{
|
||||
GetBufferSubDataT(target, offset, data);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -39,7 +39,7 @@ void
|
|||
WebGL2Context::TexImage3D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLint border, GLenum unpackFormat, GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
const char funcName[] = "texImage3D";
|
||||
|
@ -59,7 +59,7 @@ WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level,
|
|||
GLint xOffset, GLint yOffset, GLint zOffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum unpackFormat, GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
const char funcName[] = "texSubImage3D";
|
||||
|
@ -95,7 +95,7 @@ WebGL2Context::CopyTexSubImage3D(GLenum target, GLint level,
|
|||
void
|
||||
WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLint border, GLsizei imageSize, const dom::ArrayBufferView& view)
|
||||
GLint border, GLsizei imageSize, const dom::ArrayBufferViewOrSharedArrayBufferView& view)
|
||||
{
|
||||
GenerateWarning("compressedTexImage3D: Not implemented.");
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalF
|
|||
void
|
||||
WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum unpackFormat, GLsizei imageSize, const dom::ArrayBufferView& view)
|
||||
GLenum unpackFormat, GLsizei imageSize, const dom::ArrayBufferViewOrSharedArrayBufferView& view)
|
||||
{
|
||||
GenerateWarning("compressedTexSubImage3D: Not implemented.");
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
|
||||
class nsIDocShell;
|
||||
|
||||
|
@ -100,6 +100,7 @@ class Element;
|
|||
class ImageData;
|
||||
class OwningHTMLCanvasElementOrOffscreenCanvas;
|
||||
struct WebGLContextAttributes;
|
||||
class ArrayBufferViewOrSharedArrayBufferView;
|
||||
template<typename> struct Nullable;
|
||||
} // namespace dom
|
||||
|
||||
|
@ -528,7 +529,7 @@ public:
|
|||
void PolygonOffset(GLfloat factor, GLfloat units);
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
const dom::Nullable<dom::ArrayBufferView>& pixels,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
|
||||
ErrorResult& rv);
|
||||
void RenderbufferStorage(GLenum target, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height);
|
||||
|
@ -749,8 +750,8 @@ public:
|
|||
WebGLintptr offset, WebGLsizeiptr size);
|
||||
|
||||
private:
|
||||
void BufferDataUnchecked(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
|
||||
void BufferData(GLenum target, WebGLsizeiptr size, void* data, GLenum usage);
|
||||
template<typename BufferT>
|
||||
void BufferDataT(GLenum target, const BufferT& data, GLenum usage);
|
||||
|
||||
public:
|
||||
void BufferData(GLenum target, WebGLsizeiptr size, GLenum usage);
|
||||
|
@ -758,16 +759,25 @@ public:
|
|||
GLenum usage);
|
||||
void BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeData,
|
||||
GLenum usage);
|
||||
void BufferData(GLenum target, const dom::SharedArrayBuffer& data,
|
||||
GLenum usage);
|
||||
void BufferData(GLenum target, const dom::SharedArrayBufferView& data,
|
||||
GLenum usage);
|
||||
|
||||
private:
|
||||
void BufferSubDataUnchecked(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
|
||||
void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
|
||||
template<typename BufferT>
|
||||
void BufferSubDataT(GLenum target, WebGLsizeiptr byteOffset,
|
||||
const BufferT& data);
|
||||
|
||||
public:
|
||||
void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
const dom::ArrayBufferView& data);
|
||||
void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData);
|
||||
void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
const dom::SharedArrayBuffer& data);
|
||||
void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
const dom::SharedArrayBufferView& data);
|
||||
already_AddRefed<WebGLBuffer> CreateBuffer();
|
||||
void DeleteBuffer(WebGLBuffer* buf);
|
||||
bool IsBuffer(WebGLBuffer* buf);
|
||||
|
@ -864,10 +874,10 @@ protected:
|
|||
public:
|
||||
void CompressedTexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border,
|
||||
const dom::ArrayBufferView& view);
|
||||
const dom::ArrayBufferViewOrSharedArrayBufferView& view);
|
||||
void CompressedTexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLsizei width, GLsizei height,
|
||||
GLenum unpackFormat, const dom::ArrayBufferView& view);
|
||||
GLenum unpackFormat, const dom::ArrayBufferViewOrSharedArrayBufferView& view);
|
||||
|
||||
void CopyTexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
|
||||
|
@ -878,7 +888,7 @@ public:
|
|||
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
|
||||
GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv);
|
||||
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
|
||||
|
@ -891,7 +901,7 @@ public:
|
|||
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
|
||||
GLsizei width, GLsizei height, GLenum unpackFormat,
|
||||
GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv);
|
||||
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
|
||||
|
@ -1634,6 +1644,11 @@ ValidateTexImageTarget(WebGLContext* webgl, GLenum rawTexImageTarget,
|
|||
// Returns x rounded to the next highest multiple of y.
|
||||
CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y);
|
||||
|
||||
void
|
||||
ComputeLengthAndData(const dom::ArrayBufferViewOrSharedArrayBufferView& view,
|
||||
void** const out_data, size_t* const out_length,
|
||||
js::Scalar::Type* const out_type);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
|
@ -182,25 +182,25 @@ WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
|
|||
}
|
||||
}
|
||||
|
||||
// BufferT may be one of
|
||||
// const dom::ArrayBuffer&
|
||||
// const dom::SharedArrayBuffer&
|
||||
// const dom::ArrayBufferView&
|
||||
// const dom::SharedArrayBufferView&
|
||||
template<typename BufferT>
|
||||
void
|
||||
WebGLContext::BufferData(GLenum target,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData,
|
||||
GLenum usage)
|
||||
WebGLContext::BufferDataT(GLenum target,
|
||||
const BufferT& data,
|
||||
GLenum usage)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (maybeData.IsNull()) {
|
||||
// see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
|
||||
return ErrorInvalidValue("bufferData: null object passed");
|
||||
}
|
||||
|
||||
if (!ValidateBufferTarget(target, "bufferData"))
|
||||
return;
|
||||
|
||||
const WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
|
||||
const dom::ArrayBuffer& data = maybeData.Value();
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
// Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
|
||||
|
@ -231,20 +231,61 @@ WebGLContext::BufferData(GLenum target,
|
|||
return ErrorOutOfMemory("bufferData: out of memory");
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BufferData(GLenum target,
|
||||
const dom::SharedArrayBuffer& data,
|
||||
GLenum usage)
|
||||
{
|
||||
BufferDataT(target, data, usage);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BufferData(GLenum target,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData,
|
||||
GLenum usage)
|
||||
{
|
||||
if (maybeData.IsNull()) {
|
||||
// see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
|
||||
return ErrorInvalidValue("bufferData: null object passed");
|
||||
}
|
||||
BufferDataT(target, maybeData.Value(), usage);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& data,
|
||||
GLenum usage)
|
||||
{
|
||||
BufferDataT(target, data, usage);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BufferData(GLenum target, const dom::SharedArrayBufferView& data,
|
||||
GLenum usage)
|
||||
{
|
||||
BufferDataT(target, data, usage);
|
||||
}
|
||||
|
||||
// BufferT may be one of
|
||||
// const dom::ArrayBuffer&
|
||||
// const dom::SharedArrayBuffer&
|
||||
// const dom::ArrayBufferView&
|
||||
// const dom::SharedArrayBufferView&
|
||||
template<typename BufferT>
|
||||
void
|
||||
WebGLContext::BufferSubDataT(GLenum target,
|
||||
WebGLsizeiptr byteOffset,
|
||||
const BufferT& data)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!ValidateBufferTarget(target, "bufferData"))
|
||||
if (!ValidateBufferTarget(target, "bufferSubData"))
|
||||
return;
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
|
||||
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
|
||||
return;
|
||||
if (byteOffset < 0)
|
||||
return ErrorInvalidValue("bufferSubData: negative offset");
|
||||
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
if (!boundBuffer)
|
||||
|
@ -252,119 +293,60 @@ WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& data,
|
|||
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
// Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
|
||||
// is like intptr_t.
|
||||
if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
|
||||
return ErrorOutOfMemory("bufferData: bad size");
|
||||
CheckedInt<WebGLsizeiptr> checked_neededByteLength =
|
||||
CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
|
||||
|
||||
InvalidateBufferFetching();
|
||||
MakeContextCurrent();
|
||||
|
||||
GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
|
||||
if (error) {
|
||||
GenerateWarning("bufferData generated error %s", ErrorName(error));
|
||||
if (!checked_neededByteLength.isValid()) {
|
||||
ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
|
||||
" byte length.");
|
||||
return;
|
||||
}
|
||||
|
||||
boundBuffer->SetByteLength(data.Length());
|
||||
if (!boundBuffer->ElementArrayCacheBufferData(data.Data(), data.Length()))
|
||||
return ErrorOutOfMemory("bufferData: out of memory");
|
||||
if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
|
||||
ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
|
||||
" %d bytes, but buffer only has %d bytes.",
|
||||
checked_neededByteLength.value(),
|
||||
boundBuffer->ByteLength());
|
||||
return;
|
||||
}
|
||||
|
||||
boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.Data(),
|
||||
data.Length());
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fBufferSubData(target, byteOffset, data.Length(), data.Data());
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
const dom::Nullable<dom::ArrayBuffer>& maybeData)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (maybeData.IsNull()) {
|
||||
// see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
|
||||
return;
|
||||
}
|
||||
BufferSubDataT(target, byteOffset, maybeData.Value());
|
||||
}
|
||||
|
||||
if (!ValidateBufferTarget(target, "bufferSubData"))
|
||||
return;
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
|
||||
if (byteOffset < 0)
|
||||
return ErrorInvalidValue("bufferSubData: negative offset");
|
||||
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("bufferData: no buffer bound!");
|
||||
|
||||
const dom::ArrayBuffer& data = maybeData.Value();
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
CheckedInt<WebGLsizeiptr> checked_neededByteLength =
|
||||
CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
|
||||
|
||||
if (!checked_neededByteLength.isValid()) {
|
||||
ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
|
||||
" byte length.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
|
||||
ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
|
||||
" %d bytes, but buffer only has %d bytes.",
|
||||
checked_neededByteLength.value(),
|
||||
boundBuffer->ByteLength());
|
||||
return;
|
||||
}
|
||||
|
||||
boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.Data(),
|
||||
data.Length());
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fBufferSubData(target, byteOffset, data.Length(), data.Data());
|
||||
void
|
||||
WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
const dom::SharedArrayBuffer& data)
|
||||
{
|
||||
BufferSubDataT(target, byteOffset, data);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
const dom::ArrayBufferView& data)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
BufferSubDataT(target, byteOffset, data);
|
||||
}
|
||||
|
||||
if (!ValidateBufferTarget(target, "bufferSubData"))
|
||||
return;
|
||||
|
||||
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
||||
|
||||
if (byteOffset < 0)
|
||||
return ErrorInvalidValue("bufferSubData: negative offset");
|
||||
|
||||
WebGLBuffer* boundBuffer = bufferSlot.get();
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("bufferSubData: no buffer bound!");
|
||||
|
||||
data.ComputeLengthAndData();
|
||||
|
||||
CheckedInt<WebGLsizeiptr> checked_neededByteLength =
|
||||
CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
|
||||
|
||||
if (!checked_neededByteLength.isValid()) {
|
||||
ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
|
||||
" byte length.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
|
||||
ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
|
||||
" %d bytes, but buffer only has %d bytes.",
|
||||
checked_neededByteLength.value(),
|
||||
boundBuffer->ByteLength());
|
||||
return;
|
||||
}
|
||||
|
||||
boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.Data(),
|
||||
data.Length());
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fBufferSubData(target, byteOffset, data.Length(), data.Data());
|
||||
void
|
||||
WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
||||
const dom::SharedArrayBufferView& data)
|
||||
{
|
||||
BufferSubDataT(target, byteOffset, data);
|
||||
}
|
||||
|
||||
already_AddRefed<WebGLBuffer>
|
||||
|
|
|
@ -1381,10 +1381,32 @@ IsFormatAndTypeUnpackable(GLenum format, GLenum type)
|
|||
}
|
||||
}
|
||||
|
||||
// This function is temporary, and will be removed once https://bugzilla.mozilla.org/show_bug.cgi?id=1176214 lands, which will
|
||||
// collapse the SharedArrayBufferView and ArrayBufferView into one.
|
||||
void
|
||||
ComputeLengthAndData(const dom::ArrayBufferViewOrSharedArrayBufferView& view,
|
||||
void** const out_data, size_t* const out_length,
|
||||
js::Scalar::Type* const out_type)
|
||||
{
|
||||
if (view.IsArrayBufferView()) {
|
||||
const dom::ArrayBufferView& pixbuf = view.GetAsArrayBufferView();
|
||||
pixbuf.ComputeLengthAndData();
|
||||
*out_length = pixbuf.Length();
|
||||
*out_data = pixbuf.Data();
|
||||
*out_type = JS_GetArrayBufferViewType(pixbuf.Obj());
|
||||
} else {
|
||||
const dom::SharedArrayBufferView& pixbuf = view.GetAsSharedArrayBufferView();
|
||||
pixbuf.ComputeLengthAndData();
|
||||
*out_length = pixbuf.Length();
|
||||
*out_data = pixbuf.Data();
|
||||
*out_type = JS_GetSharedArrayBufferViewType(pixbuf.Obj());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLenum format,
|
||||
GLenum type, const dom::Nullable<dom::ArrayBufferView>& pixels,
|
||||
GLenum type, const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
if (IsContextLost())
|
||||
|
@ -1460,8 +1482,13 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
MOZ_CRASH("bad `type`");
|
||||
}
|
||||
|
||||
const dom::ArrayBufferView& pixbuf = pixels.Value();
|
||||
int dataType = pixbuf.Type();
|
||||
const dom::ArrayBufferViewOrSharedArrayBufferView &view = pixels.Value();
|
||||
// Compute length and data. Don't reenter after this point, lest the
|
||||
// precomputed go out of sync with the instant length/data.
|
||||
size_t dataByteLen;
|
||||
void* data;
|
||||
js::Scalar::Type dataType;
|
||||
ComputeLengthAndData(view, &data, &dataByteLen, &dataType);
|
||||
|
||||
// Check the pixels param type
|
||||
if (dataType != requiredDataType)
|
||||
|
@ -1479,15 +1506,9 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
if (!checked_neededByteLength.isValid())
|
||||
return ErrorInvalidOperation("readPixels: integer overflow computing the needed buffer size");
|
||||
|
||||
// Compute length and data. Don't reenter after this point, lest the
|
||||
// precomputed go out of sync with the instant length/data.
|
||||
pixbuf.ComputeLengthAndData();
|
||||
|
||||
uint32_t dataByteLen = pixbuf.Length();
|
||||
if (checked_neededByteLength.value() > dataByteLen)
|
||||
return ErrorInvalidOperation("readPixels: buffer too small");
|
||||
|
||||
void* data = pixbuf.Data();
|
||||
if (!data) {
|
||||
ErrorOutOfMemory("readPixels: buffer storage is null. Did we run out of memory?");
|
||||
return rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
|
|
|
@ -298,7 +298,7 @@ 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,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
|
@ -356,7 +356,7 @@ 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,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult& out_rv)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
|
@ -434,7 +434,7 @@ WebGLContext::CopyTexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOf
|
|||
void
|
||||
WebGLContext::CompressedTexImage2D(GLenum rawTexImageTarget, GLint level,
|
||||
GLenum internalFormat, GLsizei width, GLsizei height,
|
||||
GLint border, const dom::ArrayBufferView& view)
|
||||
GLint border, const dom::ArrayBufferViewOrSharedArrayBufferView& view)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
|
@ -452,7 +452,7 @@ void
|
|||
WebGLContext::CompressedTexSubImage2D(GLenum rawTexImageTarget, GLint level,
|
||||
GLint xOffset, GLint yOffset, GLsizei width,
|
||||
GLsizei height, GLenum unpackFormat,
|
||||
const dom::ArrayBufferView& view)
|
||||
const dom::ArrayBufferViewOrSharedArrayBufferView& view)
|
||||
{
|
||||
TexImageTarget texImageTarget;
|
||||
WebGLTexture* tex;
|
||||
|
|
|
@ -24,6 +24,7 @@ class ErrorResult;
|
|||
namespace dom {
|
||||
class Element;
|
||||
class ImageData;
|
||||
class ArrayBufferViewOrSharedArrayBufferView;
|
||||
} // namespace dom
|
||||
|
||||
// Zero is not an integer power of two.
|
||||
|
@ -108,24 +109,24 @@ public:
|
|||
|
||||
void CompressedTexImage2D(TexImageTarget texImageTarget, GLint level,
|
||||
GLenum internalFormat, GLsizei width, GLsizei height,
|
||||
GLint border, const dom::ArrayBufferView& view);
|
||||
GLint border, const dom::ArrayBufferViewOrSharedArrayBufferView& view);
|
||||
|
||||
void CompressedTexImage3D(TexImageTarget texImageTarget, GLint level,
|
||||
GLenum internalFormat, GLsizei width, GLsizei height,
|
||||
GLsizei depth, GLint border, GLsizei imageSize,
|
||||
const dom::ArrayBufferView& view);
|
||||
const dom::ArrayBufferViewOrSharedArrayBufferView& view);
|
||||
|
||||
|
||||
void CompressedTexSubImage2D(TexImageTarget texImageTarget, GLint level,
|
||||
GLint xOffset, GLint yOffset, GLsizei width,
|
||||
GLsizei height, GLenum unpackFormat,
|
||||
const dom::ArrayBufferView& view);
|
||||
const dom::ArrayBufferViewOrSharedArrayBufferView& 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);
|
||||
const dom::ArrayBufferViewOrSharedArrayBufferView& view);
|
||||
|
||||
|
||||
void CopyTexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
|
||||
|
@ -144,7 +145,7 @@ public:
|
|||
void TexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
|
||||
GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv);
|
||||
void TexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
|
||||
|
@ -156,7 +157,7 @@ public:
|
|||
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,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv);
|
||||
|
||||
|
||||
|
@ -169,7 +170,7 @@ public:
|
|||
void TexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLsizei width, GLsizei height, GLenum unpackFormat,
|
||||
GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv);
|
||||
void TexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLenum unpackFormat, GLenum unpackType,
|
||||
|
@ -181,7 +182,7 @@ public:
|
|||
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,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv);
|
||||
void TexSubImage3D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset, GLenum unpackFormat,
|
||||
|
|
|
@ -58,7 +58,7 @@ WebGLTexture::CompressedTexImage2D(TexImageTarget texImageTarget,
|
|||
GLint level,
|
||||
GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLint border,
|
||||
const dom::ArrayBufferView& view)
|
||||
const dom::ArrayBufferViewOrSharedArrayBufferView& view)
|
||||
{
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
|
||||
|
@ -76,9 +76,11 @@ WebGLTexture::CompressedTexImage2D(TexImageTarget texImageTarget,
|
|||
return;
|
||||
}
|
||||
|
||||
view.ComputeLengthAndData();
|
||||
size_t byteLength;
|
||||
void* data;
|
||||
js::Scalar::Type dataType;
|
||||
ComputeLengthAndData(view, &data, &byteLength, &dataType);
|
||||
|
||||
uint32_t byteLength = view.Length();
|
||||
if (!mContext->ValidateCompTexImageDataSize(level, internalFormat, width, height, byteLength, func, dims)) {
|
||||
return;
|
||||
}
|
||||
|
@ -96,7 +98,7 @@ WebGLTexture::CompressedTexImage2D(TexImageTarget texImageTarget,
|
|||
|
||||
mContext->MakeContextCurrent();
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
gl->fCompressedTexImage2D(texImageTarget.get(), level, internalFormat, width, height, border, byteLength, view.Data());
|
||||
gl->fCompressedTexImage2D(texImageTarget.get(), level, internalFormat, width, height, border, byteLength, data);
|
||||
|
||||
SetImageInfo(texImageTarget, level, width, height, 1, internalFormat,
|
||||
WebGLImageDataStatus::InitializedImageData);
|
||||
|
@ -106,7 +108,7 @@ void
|
|||
WebGLTexture::CompressedTexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
|
||||
GLint yOffset, GLsizei width, GLsizei height,
|
||||
GLenum internalFormat,
|
||||
const dom::ArrayBufferView& view)
|
||||
const dom::ArrayBufferViewOrSharedArrayBufferView& view)
|
||||
{
|
||||
const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage;
|
||||
const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
|
||||
|
@ -131,9 +133,11 @@ WebGLTexture::CompressedTexSubImage2D(TexImageTarget texImageTarget, GLint level
|
|||
return mContext->ErrorInvalidOperation("compressedTexImage2D: internalFormat does not match the existing image");
|
||||
}
|
||||
|
||||
view.ComputeLengthAndData();
|
||||
size_t byteLength;
|
||||
void* data;
|
||||
js::Scalar::Type dataType;
|
||||
ComputeLengthAndData(view, &data, &byteLength, &dataType);
|
||||
|
||||
uint32_t byteLength = view.Length();
|
||||
if (!mContext->ValidateCompTexImageDataSize(level, internalFormat, width, height, byteLength, func, dims))
|
||||
return;
|
||||
|
||||
|
@ -161,7 +165,7 @@ WebGLTexture::CompressedTexSubImage2D(TexImageTarget texImageTarget, GLint level
|
|||
|
||||
mContext->MakeContextCurrent();
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xOffset, yOffset, width, height, internalFormat, byteLength, view.Data());
|
||||
gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xOffset, yOffset, width, height, internalFormat, byteLength, data);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -614,23 +618,19 @@ void
|
|||
WebGLTexture::TexImage2D(TexImageTarget texImageTarget, GLint level,
|
||||
GLenum internalFormat, GLsizei width,
|
||||
GLsizei height, GLint border, GLenum unpackFormat,
|
||||
GLenum unpackType, const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
GLenum unpackType, const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv)
|
||||
{
|
||||
void* data;
|
||||
uint32_t length;
|
||||
size_t length;
|
||||
js::Scalar::Type jsArrayType;
|
||||
if (maybeView.IsNull()) {
|
||||
data = nullptr;
|
||||
length = 0;
|
||||
jsArrayType = js::Scalar::MaxTypedArrayViewType;
|
||||
} else {
|
||||
const dom::ArrayBufferView& view = maybeView.Value();
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
data = view.Data();
|
||||
length = view.Length();
|
||||
jsArrayType = view.Type();
|
||||
const auto& view = maybeView.Value();
|
||||
ComputeLengthAndData(view, &data, &length, &jsArrayType);
|
||||
}
|
||||
|
||||
const char funcName[] = "texImage2D";
|
||||
|
@ -850,14 +850,17 @@ WebGLTexture::TexSubImage2D(TexImageTarget texImageTarget, GLint level,
|
|||
GLint xOffset, GLint yOffset,
|
||||
GLsizei width, GLsizei height,
|
||||
GLenum unpackFormat, GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv)
|
||||
{
|
||||
if (maybeView.IsNull())
|
||||
return mContext->ErrorInvalidValue("texSubImage2D: pixels must not be null!");
|
||||
|
||||
const dom::ArrayBufferView& view = maybeView.Value();
|
||||
view.ComputeLengthAndData();
|
||||
const auto& view = maybeView.Value();
|
||||
size_t length;
|
||||
void* data;
|
||||
js::Scalar::Type jsArrayType;
|
||||
ComputeLengthAndData(view, &data, &length, &jsArrayType);
|
||||
|
||||
const char funcName[] = "texSubImage2D";
|
||||
if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
|
||||
|
@ -865,7 +868,7 @@ WebGLTexture::TexSubImage2D(TexImageTarget texImageTarget, GLint level,
|
|||
|
||||
return TexSubImage2D_base(texImageTarget, level, xOffset, yOffset,
|
||||
width, height, 0, unpackFormat, unpackType,
|
||||
view.Data(), view.Length(), view.Type(),
|
||||
data, length, jsArrayType,
|
||||
WebGLTexelFormat::Auto, false);
|
||||
}
|
||||
|
||||
|
@ -1211,7 +1214,7 @@ void
|
|||
WebGLTexture::TexImage3D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLint border, GLenum unpackFormat, GLenum unpackType,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv)
|
||||
{
|
||||
void* data;
|
||||
|
@ -1222,12 +1225,8 @@ WebGLTexture::TexImage3D(TexImageTarget texImageTarget, GLint level, GLenum inte
|
|||
dataLength = 0;
|
||||
jsArrayType = js::Scalar::MaxTypedArrayViewType;
|
||||
} else {
|
||||
const dom::ArrayBufferView& view = maybeView.Value();
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
data = view.Data();
|
||||
dataLength = view.Length();
|
||||
jsArrayType = view.Type();
|
||||
const auto& view = maybeView.Value();
|
||||
ComputeLengthAndData(view, &data, &dataLength, &jsArrayType);
|
||||
}
|
||||
|
||||
const char funcName[] = "texImage3D";
|
||||
|
@ -1318,14 +1317,17 @@ WebGLTexture::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,
|
||||
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
|
||||
ErrorResult* const out_rv)
|
||||
{
|
||||
if (maybeView.IsNull())
|
||||
return mContext->ErrorInvalidValue("texSubImage3D: pixels must not be null!");
|
||||
|
||||
const dom::ArrayBufferView& view = maybeView.Value();
|
||||
view.ComputeLengthAndData();
|
||||
const auto& view = maybeView.Value();
|
||||
void* data;
|
||||
size_t dataLength;
|
||||
js::Scalar::Type jsArrayType;
|
||||
ComputeLengthAndData(view, &data, &dataLength, &jsArrayType);
|
||||
|
||||
const char funcName[] = "texSubImage3D";
|
||||
if (!DoesTargetMatchDimensions(mContext, texImageTarget, 3, funcName))
|
||||
|
@ -1358,10 +1360,6 @@ WebGLTexture::TexSubImage3D(TexImageTarget texImageTarget, GLint level,
|
|||
return mContext->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 (!mContext->ValidateTexInputData(unpackType, jsArrayType, func, dims))
|
||||
return;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ skip-if = android_version == '10' || android_version == '18' #Android 2.3 and 4.
|
|||
[webgl-mochitest/test_noprog_draw.html]
|
||||
[webgl-mochitest/test_privileged_exts.html]
|
||||
[webgl-mochitest/test_renderer_strings.html]
|
||||
[webgl-mochitest/test_sab_with_webgl.html]
|
||||
[webgl-mochitest/test_texsubimage_float.html]
|
||||
[webgl-mochitest/test_uninit_data.html]
|
||||
[webgl-mochitest/test_webgl_available.html]
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<script src='/tests/SimpleTest/SimpleTest.js'></script>
|
||||
<link rel='stylesheet' href='/tests/SimpleTest/test.css'>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id='c' width='200' height='200'></canvas>
|
||||
<canvas id='c2' width='200' height='200'></canvas>
|
||||
|
||||
<script>
|
||||
|
||||
var gl;
|
||||
|
||||
function RGBAToString(arr) {
|
||||
return '[' + arr[0].toPrecision(4) + ', ' +
|
||||
arr[1].toPrecision(4) + ', ' +
|
||||
arr[2].toPrecision(4) + ', ' +
|
||||
arr[3].toPrecision(4) + ']';
|
||||
}
|
||||
|
||||
function TestScreenColor(gl, r, g, b, a) {
|
||||
var arr = new SharedArrayBuffer(4);
|
||||
var view = new SharedUint8Array(arr);
|
||||
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, view);
|
||||
|
||||
var err = gl.getError();
|
||||
ok(err == 0, 'Should be no errors.');
|
||||
if (err)
|
||||
return;
|
||||
|
||||
var floatArr;
|
||||
floatArr = new Float32Array(4);
|
||||
floatArr[0] = view[0] / 255.0;
|
||||
floatArr[1] = view[1] / 255.0;
|
||||
floatArr[2] = view[2] / 255.0;
|
||||
floatArr[3] = view[3] / 255.0;
|
||||
|
||||
var testText = RGBAToString(floatArr);
|
||||
var refText = RGBAToString([r, g, b, a]);
|
||||
|
||||
var eps = 1.0 / 255.0;
|
||||
var isSame = (Math.abs(floatArr[0] - r) < eps &&
|
||||
Math.abs(floatArr[1] - g) < eps &&
|
||||
Math.abs(floatArr[2] - b) < eps &&
|
||||
Math.abs(floatArr[3] - a) < eps);
|
||||
|
||||
ok(isSame, 'Should be ' + refText + ', was ' + testText + ',');
|
||||
}
|
||||
|
||||
// Give ourselves a scope to return early from:
|
||||
(function() {
|
||||
var canvas = document.getElementById('c');
|
||||
var attribs = {
|
||||
antialias: false,
|
||||
depth: false,
|
||||
};
|
||||
gl = canvas.getContext('experimental-webgl', attribs);
|
||||
if (!gl) {
|
||||
todo(false, 'WebGL is unavailable.');
|
||||
return;
|
||||
}
|
||||
if (typeof SharedArrayBuffer === 'undefined') {
|
||||
todo(false, 'SharedArrayBuffer is unavailable.');
|
||||
return;
|
||||
}
|
||||
if (SharedFloat32Array === 'undefined') {
|
||||
todo(false, 'SharedFloat32Array is unavailable.');
|
||||
return;
|
||||
}
|
||||
|
||||
var vs = gl.createShader(gl.VERTEX_SHADER);
|
||||
gl.shaderSource(vs, "attribute vec2 aVertCoord; void main(void) { gl_Position = vec4(aVertCoord, 0.0, 1.0); }");
|
||||
gl.compileShader(vs);
|
||||
var fs = gl.createShader(gl.FRAGMENT_SHADER);
|
||||
gl.shaderSource(fs, "precision mediump float; uniform vec4 uFragColor; void main(void) { gl_FragColor = uFragColor; }");
|
||||
gl.compileShader(fs);
|
||||
var prog = gl.createProgram();
|
||||
gl.attachShader(prog, vs);
|
||||
gl.attachShader(prog, fs);
|
||||
gl.linkProgram(prog);
|
||||
|
||||
var success = gl.getProgramParameter(prog, gl.LINK_STATUS);
|
||||
if (!success) {
|
||||
console.log('Error linking program for \'' + vsId + '\' and \'' + fsId + '\'.');
|
||||
console.log('\nLink log: ' + gl.getProgramInfoLog(prog));
|
||||
console.log('\nVert shader log: ' + gl.getShaderInfoLog(vs));
|
||||
console.log('\nFrag shader log: ' + gl.getShaderInfoLog(fs));
|
||||
}
|
||||
ok(prog, 'Program should link.');
|
||||
if (!prog) {
|
||||
return;
|
||||
}
|
||||
|
||||
prog.aVertCoord = gl.getAttribLocation(prog, 'aVertCoord');
|
||||
prog.uFragColor = gl.getUniformLocation(prog, 'uFragColor');
|
||||
|
||||
gl.useProgram(prog);
|
||||
|
||||
// Test gl.bufferData(), gl.bufferSubData() and gl.readPixels() APIs with SAB as input.
|
||||
var arr = new SharedArrayBuffer(8*4);
|
||||
var view = new SharedFloat32Array(arr);
|
||||
view.set(new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]));
|
||||
var vb = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
|
||||
ok(gl.getError() == 0, 'bufferData with SAB as input parameter works ok.');
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 0, arr);
|
||||
ok(gl.getError() == 0, 'bufferSubData with SAB as input parameter works ok.');
|
||||
gl.enableVertexAttribArray(0);
|
||||
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.clearColor(0, 0, 0, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
gl.uniform4f(prog.uFragColor, 0.2, 0.4, 0.6, 1.0);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
var arr = new Uint8Array(4);
|
||||
TestScreenColor(gl, 0.2, 0.4, 0.6, 1.0);
|
||||
|
||||
// Test gl.texImage2D() and gl.texSubImage2D() APIs with SAB as input.
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
var width = 4;
|
||||
var height = 4;
|
||||
var numChannels = 4;
|
||||
var sab = new SharedArrayBuffer(width * height * numChannels);
|
||||
var data = new SharedUint8Array(sab);
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
data[i] = i;
|
||||
}
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
ok(gl.getError() == 0, 'texImage2D() with SAB as input parameter works ok.');
|
||||
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
ok(gl.getError() == 0, 'texSubImage2D() with SAB as input parameter works ok.');
|
||||
|
||||
ok(gl.getError() == 0, 'Should be no errors after test.');
|
||||
})();
|
||||
|
||||
// Test WebGL 2
|
||||
(function() {
|
||||
var canvas = document.getElementById('c2');
|
||||
var attribs = {
|
||||
antialias: false,
|
||||
depth: false,
|
||||
};
|
||||
gl = canvas.getContext('webgl2', attribs);
|
||||
if (!gl) {
|
||||
todo(false, 'WebGL 2 is unavailable.');
|
||||
return;
|
||||
}
|
||||
if (typeof SharedArrayBuffer === 'undefined') {
|
||||
todo(false, 'SharedArrayBuffer is unavailable.');
|
||||
return;
|
||||
}
|
||||
if (SharedFloat32Array === 'undefined') {
|
||||
todo(false, 'SharedFloat32Array is unavailable.');
|
||||
return;
|
||||
}
|
||||
|
||||
var arr = new SharedArrayBuffer(8*4);
|
||||
var view = new SharedFloat32Array(arr);
|
||||
view.set(new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]));
|
||||
var vb = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
|
||||
|
||||
var arr2 = new SharedArrayBuffer(8*4);
|
||||
gl.getBufferSubData(gl.ARRAY_BUFFER, 0, arr2);
|
||||
var view2 = new SharedFloat32Array(arr2);
|
||||
var equal = true;
|
||||
for(var i = 0; i < 8; ++i) {
|
||||
if (view[i] != view2[i]) equal = false;
|
||||
}
|
||||
ok(equal, 'getBufferSubData with SAB as input parameter works ok.');
|
||||
|
||||
// Test gl.texImage3D() and gl.texSubImage3D() APIs with SAB as input.
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_3D, tex);
|
||||
var width = 4;
|
||||
var height = 4;
|
||||
var depth = 4;
|
||||
var numChannels = 4;
|
||||
var sab = new SharedArrayBuffer(width * height * depth* numChannels);
|
||||
var data = new SharedUint8Array(sab);
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
data[i] = i;
|
||||
}
|
||||
gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, width, height, depth, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
ok(gl.getError() == 0, 'texImage3D() with SAB as input parameter works ok.');
|
||||
gl.texSubImage3D(gl.TEXTURE_3D, 0, 0, 0, 0, width, height, depth, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
ok(gl.getError() == 0, 'texSubImage3D() with SAB as input parameter works ok.');
|
||||
|
||||
ok(gl.getError() == 0, 'Should be no errors after test.');
|
||||
})();
|
||||
|
||||
ok(true, 'TEST COMPLETE');
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -46,7 +46,7 @@ TextEncoder::Encode(JSContext* aCx,
|
|||
// Run the steps of the encoding algorithm.
|
||||
int32_t srcLen = aString.Length();
|
||||
int32_t maxLen;
|
||||
const char16_t* data = PromiseFlatString(aString).get();
|
||||
const char16_t* data = aString.BeginReading();
|
||||
nsresult rv = mEncoder->GetMaxLength(data, srcLen, &maxLen);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
|
|
|
@ -1277,7 +1277,7 @@ nsresult HTMLMediaElement::LoadResource()
|
|||
if (IsAutoplayEnabled()) {
|
||||
mJoinLatency.Start();
|
||||
}
|
||||
return FinishDecoderSetup(decoder, resource, nullptr, nullptr);
|
||||
return FinishDecoderSetup(decoder, resource, nullptr);
|
||||
}
|
||||
|
||||
// determine what security checks need to be performed in AsyncOpen2().
|
||||
|
@ -2777,7 +2777,7 @@ nsresult HTMLMediaElement::InitializeDecoderAsClone(MediaDecoder* aOriginal)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return FinishDecoderSetup(decoder, resource, nullptr, aOriginal);
|
||||
return FinishDecoderSetup(decoder, resource, nullptr);
|
||||
}
|
||||
|
||||
nsresult HTMLMediaElement::InitializeDecoderForChannel(nsIChannel* aChannel,
|
||||
|
@ -2821,14 +2821,13 @@ nsresult HTMLMediaElement::InitializeDecoderForChannel(nsIChannel* aChannel,
|
|||
}
|
||||
return NS_OK;
|
||||
} else {
|
||||
return FinishDecoderSetup(decoder, resource, aListener, nullptr);
|
||||
return FinishDecoderSetup(decoder, resource, aListener);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
MediaResource* aStream,
|
||||
nsIStreamListener** aListener,
|
||||
MediaDecoder* aCloneDonor)
|
||||
nsIStreamListener** aListener)
|
||||
{
|
||||
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
|
||||
|
||||
|
@ -2858,7 +2857,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
|||
// can affect how we feed data to MediaStreams
|
||||
NotifyDecoderPrincipalChanged();
|
||||
|
||||
nsresult rv = aDecoder->Load(aListener, aCloneDonor);
|
||||
nsresult rv = aDecoder->Load(aListener);
|
||||
if (NS_FAILED(rv)) {
|
||||
ShutdownDecoder();
|
||||
LOG(LogLevel::Debug, ("%p Failed to load for decoder %p", this, aDecoder));
|
||||
|
|
|
@ -651,7 +651,7 @@ public:
|
|||
* A public wrapper for FinishDecoderSetup()
|
||||
*/
|
||||
nsresult FinishDecoderSetup(MediaDecoder* aDecoder, MediaResource* aStream) {
|
||||
return FinishDecoderSetup(aDecoder, aStream, nullptr, nullptr);
|
||||
return FinishDecoderSetup(aDecoder, aStream, nullptr);
|
||||
}
|
||||
|
||||
// Returns true if the media element is being destroyed. Used in
|
||||
|
@ -811,8 +811,7 @@ protected:
|
|||
*/
|
||||
nsresult FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
MediaResource* aStream,
|
||||
nsIStreamListener **aListener,
|
||||
MediaDecoder* aCloneDonor);
|
||||
nsIStreamListener **aListener);
|
||||
|
||||
/**
|
||||
* Call this after setting up mLoadingSrc and mDecoder.
|
||||
|
|
|
@ -69,20 +69,14 @@ HTMLOptGroupElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|||
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
Element*
|
||||
HTMLOptGroupElement::GetSelect()
|
||||
{
|
||||
nsIContent* parent = this;
|
||||
while ((parent = parent->GetParent()) && parent->IsHTMLElement()) {
|
||||
if (parent->IsHTMLElement(nsGkAtoms::select)) {
|
||||
return parent;
|
||||
}
|
||||
if (!parent->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
break;
|
||||
}
|
||||
Element* parent = nsINode::GetParentElement();
|
||||
if (!parent || !parent->IsHTMLElement(nsGkAtoms::select)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return parent;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -76,7 +76,7 @@ protected:
|
|||
* Get the select content element that contains this option
|
||||
* @param aSelectElement the select element [OUT]
|
||||
*/
|
||||
nsIContent* GetSelect();
|
||||
Element* GetSelect();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -226,7 +226,33 @@ HTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions,
|
|||
bool aNotify)
|
||||
{
|
||||
int32_t insertIndex = aListIndex;
|
||||
InsertOptionsIntoListRecurse(aOptions, &insertIndex, aDepth);
|
||||
|
||||
HTMLOptionElement* optElement = HTMLOptionElement::FromContent(aOptions);
|
||||
if (optElement) {
|
||||
mOptions->InsertOptionAt(optElement, insertIndex);
|
||||
insertIndex++;
|
||||
} else {
|
||||
// If it's at the top level, then we just found out there are non-options
|
||||
// at the top level, which will throw off the insert count
|
||||
if (aDepth == 0) {
|
||||
mNonOptionChildren++;
|
||||
}
|
||||
|
||||
// Deal with optgroups
|
||||
if (aOptions->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
mOptGroupCount++;
|
||||
|
||||
for (nsIContent* child = aOptions->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
optElement = HTMLOptionElement::FromContent(child);
|
||||
if (optElement) {
|
||||
mOptions->InsertOptionAt(optElement, insertIndex);
|
||||
insertIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with the selected list
|
||||
if (insertIndex - aListIndex) {
|
||||
|
@ -282,9 +308,40 @@ HTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
|
|||
bool aNotify)
|
||||
{
|
||||
int32_t numRemoved = 0;
|
||||
nsresult rv = RemoveOptionsFromListRecurse(aOptions, aListIndex, &numRemoved,
|
||||
aDepth);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
HTMLOptionElement* optElement = HTMLOptionElement::FromContent(aOptions);
|
||||
if (optElement) {
|
||||
if (mOptions->ItemAsOption(aListIndex) != optElement) {
|
||||
NS_ERROR("wrong option at index");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mOptions->RemoveOptionAt(aListIndex);
|
||||
numRemoved++;
|
||||
} else {
|
||||
// Yay, one less artifact at the top level.
|
||||
if (aDepth == 0) {
|
||||
mNonOptionChildren--;
|
||||
}
|
||||
|
||||
// Recurse down deeper for options
|
||||
if (mOptGroupCount && aOptions->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
mOptGroupCount--;
|
||||
|
||||
for (nsIContent* child = aOptions->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
optElement = HTMLOptionElement::FromContent(child);
|
||||
if (optElement) {
|
||||
if (mOptions->ItemAsOption(aListIndex) != optElement) {
|
||||
NS_ERROR("wrong option at index");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mOptions->RemoveOptionAt(aListIndex);
|
||||
numRemoved++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numRemoved) {
|
||||
// Tell the widget we removed the options
|
||||
|
@ -324,91 +381,6 @@ HTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// If the document is such that recursing over these options gets us
|
||||
// deeper than four levels, there is something terribly wrong with the
|
||||
// world.
|
||||
void
|
||||
HTMLSelectElement::InsertOptionsIntoListRecurse(nsIContent* aOptions,
|
||||
int32_t* aInsertIndex,
|
||||
int32_t aDepth)
|
||||
{
|
||||
// We *assume* here that someone's brain has not gone horribly
|
||||
// wrong by putting <option> inside of <option>. I'm sorry, I'm
|
||||
// just not going to look for an option inside of an option.
|
||||
// Sue me.
|
||||
|
||||
HTMLOptionElement* optElement = HTMLOptionElement::FromContent(aOptions);
|
||||
if (optElement) {
|
||||
mOptions->InsertOptionAt(optElement, *aInsertIndex);
|
||||
(*aInsertIndex)++;
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's at the top level, then we just found out there are non-options
|
||||
// at the top level, which will throw off the insert count
|
||||
if (aDepth == 0) {
|
||||
mNonOptionChildren++;
|
||||
}
|
||||
|
||||
// Recurse down into optgroups
|
||||
if (aOptions->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
mOptGroupCount++;
|
||||
|
||||
for (nsIContent* child = aOptions->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
InsertOptionsIntoListRecurse(child, aInsertIndex, aDepth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the document is such that recursing over these options gets us deeper than
|
||||
// four levels, there is something terribly wrong with the world.
|
||||
nsresult
|
||||
HTMLSelectElement::RemoveOptionsFromListRecurse(nsIContent* aOptions,
|
||||
int32_t aRemoveIndex,
|
||||
int32_t* aNumRemoved,
|
||||
int32_t aDepth)
|
||||
{
|
||||
// We *assume* here that someone's brain has not gone horribly
|
||||
// wrong by putting <option> inside of <option>. I'm sorry, I'm
|
||||
// just not going to look for an option inside of an option.
|
||||
// Sue me.
|
||||
|
||||
nsCOMPtr<nsIDOMHTMLOptionElement> optElement(do_QueryInterface(aOptions));
|
||||
if (optElement) {
|
||||
if (mOptions->ItemAsOption(aRemoveIndex) != optElement) {
|
||||
NS_ERROR("wrong option at index");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
mOptions->RemoveOptionAt(aRemoveIndex);
|
||||
(*aNumRemoved)++;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Yay, one less artifact at the top level.
|
||||
if (aDepth == 0) {
|
||||
mNonOptionChildren--;
|
||||
}
|
||||
|
||||
// Recurse down deeper for options
|
||||
if (mOptGroupCount && aOptions->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
mOptGroupCount--;
|
||||
|
||||
for (nsIContent* child = aOptions->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
nsresult rv = RemoveOptionsFromListRecurse(child,
|
||||
aRemoveIndex,
|
||||
aNumRemoved,
|
||||
aDepth + 1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXXldb Doing the processing before the content nodes have been added
|
||||
// to the document (as the name of this function seems to require, and
|
||||
// as the callers do), is highly unusual. Passing around unparented
|
||||
|
@ -420,10 +392,10 @@ HTMLSelectElement::WillAddOptions(nsIContent* aOptions,
|
|||
int32_t aContentIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
int32_t level = GetContentDepth(aParent);
|
||||
if (level == -1) {
|
||||
return NS_ERROR_FAILURE;
|
||||
if (this != aParent && this != aParent->GetParent()) {
|
||||
return NS_OK;
|
||||
}
|
||||
int32_t level = aParent == this ? 0 : 1;
|
||||
|
||||
// Get the index where the options will be inserted
|
||||
int32_t ind = -1;
|
||||
|
@ -462,11 +434,10 @@ HTMLSelectElement::WillRemoveOptions(nsIContent* aParent,
|
|||
int32_t aContentIndex,
|
||||
bool aNotify)
|
||||
{
|
||||
int32_t level = GetContentDepth(aParent);
|
||||
NS_ASSERTION(level >= 0, "getting notified by unexpected content");
|
||||
if (level == -1) {
|
||||
return NS_ERROR_FAILURE;
|
||||
if (this != aParent && this != aParent->GetParent()) {
|
||||
return NS_OK;
|
||||
}
|
||||
int32_t level = this == aParent ? 0 : 1;
|
||||
|
||||
// Get the index where the options will be removed
|
||||
nsIContent* currentKid = aParent->GetChildAt(aContentIndex);
|
||||
|
@ -489,24 +460,6 @@ HTMLSelectElement::WillRemoveOptions(nsIContent* aParent,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
HTMLSelectElement::GetContentDepth(nsIContent* aContent)
|
||||
{
|
||||
nsIContent* content = aContent;
|
||||
|
||||
int32_t retval = 0;
|
||||
while (content != this) {
|
||||
retval++;
|
||||
content = content->GetParent();
|
||||
if (!content) {
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int32_t
|
||||
HTMLSelectElement::GetOptionIndexAt(nsIContent* aOptions)
|
||||
{
|
||||
|
@ -528,9 +481,7 @@ HTMLSelectElement::GetOptionIndexAfter(nsIContent* aOptions)
|
|||
// in the parent.
|
||||
// - If it's not there, search for the first option after the parent.
|
||||
if (aOptions == this) {
|
||||
uint32_t len;
|
||||
GetLength(&len);
|
||||
return len;
|
||||
return Length();
|
||||
}
|
||||
|
||||
int32_t retval = -1;
|
||||
|
@ -558,8 +509,6 @@ HTMLSelectElement::GetFirstOptionIndex(nsIContent* aOptions)
|
|||
HTMLOptionElement* optElement = HTMLOptionElement::FromContent(aOptions);
|
||||
if (optElement) {
|
||||
GetOptionIndex(optElement, 0, true, &listIndex);
|
||||
// If you nested stuff under the option, you're just plain
|
||||
// screwed. *I'm* not going to aid and abet your evil deed.
|
||||
return listIndex;
|
||||
}
|
||||
|
||||
|
@ -1785,16 +1734,23 @@ HTMLSelectElement::DispatchContentReset()
|
|||
}
|
||||
|
||||
static void
|
||||
AddOptionsRecurse(nsIContent* aRoot, HTMLOptionsCollection* aArray)
|
||||
AddOptions(nsIContent* aRoot, HTMLOptionsCollection* aArray)
|
||||
{
|
||||
for (nsIContent* cur = aRoot->GetFirstChild();
|
||||
cur;
|
||||
cur = cur->GetNextSibling()) {
|
||||
HTMLOptionElement* opt = HTMLOptionElement::FromContent(cur);
|
||||
for (nsIContent* child = aRoot->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
HTMLOptionElement* opt = HTMLOptionElement::FromContent(child);
|
||||
if (opt) {
|
||||
aArray->AppendOption(opt);
|
||||
} else if (cur->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
AddOptionsRecurse(cur, aArray);
|
||||
} else if (child->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
for (nsIContent* grandchild = child->GetFirstChild();
|
||||
grandchild;
|
||||
grandchild = grandchild->GetNextSibling()) {
|
||||
opt = HTMLOptionElement::FromContent(grandchild);
|
||||
if (opt) {
|
||||
aArray->AppendOption(opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1803,7 +1759,7 @@ void
|
|||
HTMLSelectElement::RebuildOptionsArray(bool aNotify)
|
||||
{
|
||||
mOptions->Clear();
|
||||
AddOptionsRecurse(this, mOptions);
|
||||
AddOptions(this, mOptions);
|
||||
FindSelectedIndex(0, aNotify);
|
||||
}
|
||||
|
||||
|
@ -1863,28 +1819,29 @@ HTMLSelectElement::GetValidationMessage(nsAString& aValidationMessage,
|
|||
|
||||
#ifdef DEBUG
|
||||
|
||||
static void
|
||||
VerifyOptionsRecurse(nsIContent* aRoot, int32_t& aIndex,
|
||||
HTMLOptionsCollection* aArray)
|
||||
{
|
||||
for (nsIContent* cur = aRoot->GetFirstChild();
|
||||
cur;
|
||||
cur = cur->GetNextSibling()) {
|
||||
nsCOMPtr<nsIDOMHTMLOptionElement> opt = do_QueryInterface(cur);
|
||||
if (opt) {
|
||||
NS_ASSERTION(opt == aArray->ItemAsOption(aIndex++),
|
||||
"Options collection broken");
|
||||
} else if (cur->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
VerifyOptionsRecurse(cur, aIndex, aArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSelectElement::VerifyOptionsArray()
|
||||
{
|
||||
int32_t aIndex = 0;
|
||||
VerifyOptionsRecurse(this, aIndex, mOptions);
|
||||
int32_t index = 0;
|
||||
for (nsIContent* child = nsINode::GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
HTMLOptionElement* opt = HTMLOptionElement::FromContent(child);
|
||||
if (opt) {
|
||||
NS_ASSERTION(opt == mOptions->ItemAsOption(index++),
|
||||
"Options collection broken");
|
||||
} else if (child->IsHTMLElement(nsGkAtoms::optgroup)) {
|
||||
for (nsIContent* grandchild = child->GetFirstChild();
|
||||
grandchild;
|
||||
grandchild = grandchild->GetNextSibling()) {
|
||||
opt = HTMLOptionElement::FromContent(grandchild);
|
||||
if (opt) {
|
||||
NS_ASSERTION(opt == mOptions->ItemAsOption(index++),
|
||||
"Options collection broken");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -502,37 +502,11 @@ protected:
|
|||
int32_t aListIndex,
|
||||
int32_t aDepth,
|
||||
bool aNotify);
|
||||
/**
|
||||
* Insert option(s) into the options[] array (called by InsertOptionsIntoList)
|
||||
* @param aOptions the option or optgroup being added
|
||||
* @param aInsertIndex the index to start adding options into the list at
|
||||
* @param aDepth the depth of aOptions (1=direct child of select ...)
|
||||
*/
|
||||
void InsertOptionsIntoListRecurse(nsIContent* aOptions,
|
||||
int32_t* aInsertIndex,
|
||||
int32_t aDepth);
|
||||
/**
|
||||
* Remove option(s) from the options[] array (called by RemoveOptionsFromList)
|
||||
* @param aOptions the option or optgroup being added
|
||||
* @param aListIndex the index to start removing options from the list at
|
||||
* @param aNumRemoved the number removed so far [OUT]
|
||||
* @param aDepth the depth of aOptions (1=direct child of select ...)
|
||||
*/
|
||||
nsresult RemoveOptionsFromListRecurse(nsIContent* aOptions,
|
||||
int32_t aRemoveIndex,
|
||||
int32_t* aNumRemoved,
|
||||
int32_t aDepth);
|
||||
|
||||
// nsIConstraintValidation
|
||||
void UpdateBarredFromConstraintValidation();
|
||||
bool IsValueMissing();
|
||||
|
||||
/**
|
||||
* Find out how deep this content is from the select (1=direct child)
|
||||
* @param aContent the content to check
|
||||
* @return the depth
|
||||
*/
|
||||
int32_t GetContentDepth(nsIContent* aContent);
|
||||
/**
|
||||
* Get the index of the first option at, under or following the content in
|
||||
* the select, or length of options[] if none are found
|
||||
|
|
|
@ -4567,7 +4567,7 @@ ContentParent::DoLoadMessageManagerScript(const nsAString& aURL,
|
|||
return SendLoadProcessScript(nsString(aURL));
|
||||
}
|
||||
|
||||
bool
|
||||
nsresult
|
||||
ContentParent::DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aHelper,
|
||||
|
@ -4576,18 +4576,21 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx,
|
|||
{
|
||||
ClonedMessageData data;
|
||||
if (!BuildClonedMessageDataForParent(this, aHelper, data)) {
|
||||
return false;
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
InfallibleTArray<CpowEntry> cpows;
|
||||
jsipc::CPOWManager* mgr = GetCPOWManager();
|
||||
if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) {
|
||||
return false;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (IsReadyNuwaProcess()) {
|
||||
// Nuwa won't receive frame messages after it is frozen.
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
return SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal));
|
||||
if (!SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -206,11 +206,11 @@ public:
|
|||
*/
|
||||
virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
|
||||
bool aRunInGlobalScope) override;
|
||||
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
virtual nsresult DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
virtual bool CheckPermission(const nsAString& aPermission) override;
|
||||
virtual bool CheckManifestURL(const nsAString& aManifestURL) override;
|
||||
virtual bool CheckAppHasPermission(const nsAString& aPermission) override;
|
||||
|
|
|
@ -2921,7 +2921,7 @@ TabChild::DoSendBlockingMessage(JSContext* aCx,
|
|||
Principal(aPrincipal), aRetVal);
|
||||
}
|
||||
|
||||
bool
|
||||
nsresult
|
||||
TabChild::DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
|
@ -2930,14 +2930,17 @@ TabChild::DoSendAsyncMessage(JSContext* aCx,
|
|||
{
|
||||
ClonedMessageData data;
|
||||
if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
|
||||
return false;
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
InfallibleTArray<CpowEntry> cpows;
|
||||
if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
|
||||
return false;
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
|
||||
Principal(aPrincipal));
|
||||
if (!SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
|
||||
Principal(aPrincipal))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
TabChild*
|
||||
|
|
|
@ -280,11 +280,11 @@ public:
|
|||
nsIPrincipal* aPrincipal,
|
||||
nsTArray<StructuredCloneData>* aRetVal,
|
||||
bool aIsSync) override;
|
||||
virtual bool DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
virtual nsresult DoSendAsyncMessage(JSContext* aCx,
|
||||
const nsAString& aMessage,
|
||||
StructuredCloneData& aData,
|
||||
JS::Handle<JSObject *> aCpows,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
virtual bool DoUpdateZoomConstraints(const uint32_t& aPresShellId,
|
||||
const ViewID& aViewId,
|
||||
const Maybe<ZoomConstraints>& aConstraints) override;
|
||||
|
|
|
@ -1454,6 +1454,9 @@ TabParent::GetTopLevelDocAccessible() const
|
|||
return doc;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(docCount == 0, "If there isn't a top level accessible doc "
|
||||
"there shouldn't be an accessible doc at all!");
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -509,8 +509,7 @@ MediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
|
|||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoder::Load(nsIStreamListener** aStreamListener,
|
||||
MediaDecoder* aCloneDonor)
|
||||
MediaDecoder::Load(nsIStreamListener** aStreamListener)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mResource, "Can't load without a MediaResource");
|
||||
|
@ -521,18 +520,16 @@ MediaDecoder::Load(nsIStreamListener** aStreamListener,
|
|||
SetStateMachine(CreateStateMachine());
|
||||
NS_ENSURE_TRUE(GetStateMachine(), NS_ERROR_FAILURE);
|
||||
|
||||
return InitializeStateMachine(aCloneDonor);
|
||||
return InitializeStateMachine();
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoder::InitializeStateMachine(MediaDecoder* aCloneDonor)
|
||||
MediaDecoder::InitializeStateMachine()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ASSERTION(mDecoderStateMachine, "Cannot initialize null state machine!");
|
||||
|
||||
MediaDecoder* cloneDonor = static_cast<MediaDecoder*>(aCloneDonor);
|
||||
nsresult rv = mDecoderStateMachine->Init(
|
||||
cloneDonor ? cloneDonor->mDecoderStateMachine.get() : nullptr);
|
||||
nsresult rv = mDecoderStateMachine->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If some parameters got set before the state machine got created,
|
||||
|
|
|
@ -323,8 +323,7 @@ public:
|
|||
// Start downloading the media. Decode the downloaded data up to the
|
||||
// point of the first frame of data.
|
||||
// This is called at most once per decoder, after Init().
|
||||
virtual nsresult Load(nsIStreamListener** aListener,
|
||||
MediaDecoder* aCloneDonor);
|
||||
virtual nsresult Load(nsIStreamListener** aListener);
|
||||
|
||||
// Called in |Load| to open mResource.
|
||||
nsresult OpenResource(nsIStreamListener** aStreamListener);
|
||||
|
@ -363,7 +362,7 @@ public:
|
|||
virtual nsresult Seek(double aTime, SeekTarget::Type aSeekType);
|
||||
|
||||
// Initialize state machine and schedule it.
|
||||
nsresult InitializeStateMachine(MediaDecoder* aCloneDonor);
|
||||
nsresult InitializeStateMachine();
|
||||
|
||||
// Start playback of a video. 'Load' must have previously been
|
||||
// called.
|
||||
|
|
|
@ -96,7 +96,28 @@ public:
|
|||
|
||||
// Release media resources they should be released in dormant state
|
||||
// The reader can be made usable again by calling ReadMetadata().
|
||||
virtual void ReleaseMediaResources() {};
|
||||
void ReleaseMediaResources()
|
||||
{
|
||||
if (OnTaskQueue()) {
|
||||
ReleaseMediaResourcesInternal();
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
|
||||
this, &MediaDecoderReader::ReleaseMediaResourcesInternal);
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
}
|
||||
|
||||
void DisableHardwareAcceleration()
|
||||
{
|
||||
if (OnTaskQueue()) {
|
||||
DisableHardwareAccelerationInternal();
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
|
||||
this, &MediaDecoderReader::DisableHardwareAccelerationInternal);
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
}
|
||||
|
||||
// Breaks reference-counted cycles. Called during shutdown.
|
||||
// WARNING: If you override this, you must call the base implementation
|
||||
// in your override.
|
||||
|
@ -243,6 +264,10 @@ public:
|
|||
virtual size_t SizeOfVideoQueueInFrames();
|
||||
virtual size_t SizeOfAudioQueueInFrames();
|
||||
|
||||
private:
|
||||
virtual void ReleaseMediaResourcesInternal() {}
|
||||
virtual void DisableHardwareAccelerationInternal() {}
|
||||
|
||||
protected:
|
||||
friend class TrackBuffer;
|
||||
virtual void NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset) { }
|
||||
|
@ -322,8 +347,6 @@ public:
|
|||
// decoding.
|
||||
virtual bool VideoIsHardwareAccelerated() const { return false; }
|
||||
|
||||
virtual void DisableHardwareAcceleration() {}
|
||||
|
||||
TimedMetadataEventSource& TimedMetadataEvent() {
|
||||
return mTimedMetadataEvent;
|
||||
}
|
||||
|
|
|
@ -1030,7 +1030,7 @@ bool MediaDecoderStateMachine::IsPlaying() const
|
|||
return mMediaSink->IsPlaying();
|
||||
}
|
||||
|
||||
nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
|
||||
nsresult MediaDecoderStateMachine::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsresult rv = mReader->Init();
|
||||
|
@ -1269,8 +1269,7 @@ MediaDecoderStateMachine::SetDormant(bool aDormant)
|
|||
// that run after ResetDecode are supposed to run with a clean slate. We rely
|
||||
// on that in other places (i.e. seeking), so it seems reasonable to rely on
|
||||
// it here as well.
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources);
|
||||
DecodeTaskQueue()->Dispatch(r.forget());
|
||||
mReader->ReleaseMediaResources();
|
||||
} else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
|
||||
ScheduleStateMachine();
|
||||
mDecodingFirstFrame = true;
|
||||
|
@ -2464,9 +2463,7 @@ MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
|
|||
if (mReader->VideoIsHardwareAccelerated() &&
|
||||
frameStats.GetPresentedFrames() > 60 &&
|
||||
mCorruptFrames.mean() >= 2 /* 20% */) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(mReader, &MediaDecoderReader::DisableHardwareAcceleration);
|
||||
DecodeTaskQueue()->Dispatch(task.forget());
|
||||
mReader->DisableHardwareAcceleration();
|
||||
mCorruptFrames.clear();
|
||||
gfxCriticalNote << "Too many dropped/corrupted frames, disabling DXVA";
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ public:
|
|||
MediaDecoderReader* aReader,
|
||||
bool aRealTime = false);
|
||||
|
||||
nsresult Init(MediaDecoderStateMachine* aCloneDonor);
|
||||
nsresult Init();
|
||||
|
||||
// Enumeration for the valid decoding states
|
||||
enum State {
|
||||
|
|
|
@ -534,7 +534,7 @@ MediaFormatReader::GetDecoderData(TrackType aTrack)
|
|||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::DisableHardwareAcceleration()
|
||||
MediaFormatReader::DisableHardwareAccelerationInternal()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
if (HasVideo() && !mHardwareAccelerationDisabled) {
|
||||
|
@ -1569,8 +1569,9 @@ MediaFormatReader::GetBuffered()
|
|||
return intervals.Shift(media::TimeUnit::FromMicroseconds(-startTime));
|
||||
}
|
||||
|
||||
void MediaFormatReader::ReleaseMediaResources()
|
||||
void MediaFormatReader::ReleaseMediaResourcesInternal()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
// Before freeing a video codec, all video buffers needed to be released
|
||||
// even from graphics pipeline.
|
||||
VideoFrameContainer* container =
|
||||
|
|
|
@ -70,9 +70,6 @@ public:
|
|||
|
||||
virtual bool ForceZeroStartTime() const override;
|
||||
|
||||
// For Media Resource Management
|
||||
void ReleaseMediaResources() override;
|
||||
|
||||
nsresult ResetDecode() override;
|
||||
|
||||
nsRefPtr<ShutdownPromise> Shutdown() override;
|
||||
|
@ -81,8 +78,6 @@ public:
|
|||
|
||||
bool VideoIsHardwareAccelerated() const override;
|
||||
|
||||
void DisableHardwareAcceleration() override;
|
||||
|
||||
bool IsWaitForDataSupported() override { return true; }
|
||||
nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) override;
|
||||
|
||||
|
@ -436,6 +431,11 @@ private:
|
|||
#if defined(READER_DORMANT_HEURISTIC)
|
||||
const bool mDormantEnabled;
|
||||
#endif
|
||||
|
||||
private:
|
||||
// For Media Resource Management
|
||||
void ReleaseMediaResourcesInternal() override;
|
||||
void DisableHardwareAccelerationInternal() override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -315,7 +315,7 @@ MediaKeySession::Close(ErrorResult& aRv)
|
|||
return promise.forget();
|
||||
}
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->CloseSession(mSessionId, mKeys->StorePromise(promise));
|
||||
mKeys->GetCDMProxy()->CloseSession(mSessionId, pid);
|
||||
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Close() sent to CDM, promiseId=%d",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
|
||||
|
|
|
@ -180,6 +180,13 @@ MediaKeys::StorePromise(DetailedPromise* aPromise)
|
|||
// promises are rejected in Shutdown().
|
||||
AddRef();
|
||||
|
||||
#ifdef DEBUG
|
||||
// We should not have already stored this promise!
|
||||
for (auto iter = mPromises.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
MOZ_ASSERT(iter.Data() != aPromise);
|
||||
}
|
||||
#endif
|
||||
|
||||
mPromises.Put(id, aPromise);
|
||||
return id;
|
||||
}
|
||||
|
@ -274,6 +281,7 @@ MediaKeys::ResolvePromise(PromiseId aId)
|
|||
} else {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
}
|
||||
MOZ_ASSERT(!mPromises.Contains(aId));
|
||||
}
|
||||
|
||||
already_AddRefed<DetailedPromise>
|
||||
|
|
|
@ -599,21 +599,10 @@ GMPChild::GetGMPStorage()
|
|||
return mStorage;
|
||||
}
|
||||
|
||||
static MOZ_NEVER_INLINE void
|
||||
CrashForApiTimeout()
|
||||
{
|
||||
// Never inline so that crash reports are distinctive.
|
||||
MOZ_CRASH("Bug 1209385; GMP API actor failed to respond.");
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::RecvCrashPluginNow(const GMPCrashReason& aReason)
|
||||
GMPChild::RecvCrashPluginNow()
|
||||
{
|
||||
if (aReason == kGmpApiTimeout) {
|
||||
CrashForApiTimeout();
|
||||
} else {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
MOZ_CRASH();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ private:
|
|||
ProcessId aOtherPid) override;
|
||||
void GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild);
|
||||
|
||||
virtual bool RecvCrashPluginNow(const GMPCrashReason& aReason) override;
|
||||
virtual bool RecvCrashPluginNow() override;
|
||||
virtual bool RecvBeginAsyncShutdown() override;
|
||||
virtual bool RecvCloseActive() override;
|
||||
|
||||
|
|
|
@ -118,18 +118,6 @@ GMPContentParent::DecryptorDestroyed(GMPDecryptorParent* aSession)
|
|||
CloseIfUnused();
|
||||
}
|
||||
|
||||
void
|
||||
GMPContentParent::CrashPluginNow(GMPCrashReason aReason)
|
||||
{
|
||||
if (mParent) {
|
||||
mParent->Crash(aReason);
|
||||
} else {
|
||||
nsRefPtr<GeckoMediaPluginServiceChild> gmp(
|
||||
GeckoMediaPluginServiceChild::GetSingleton());
|
||||
gmp->CrashPluginNow(mPluginId, aReason);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GMPContentParent::CloseIfUnused()
|
||||
{
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "mozilla/gmp/PGMPContentParent.h"
|
||||
#include "GMPSharedMemManager.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "GMPUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -62,8 +61,6 @@ public:
|
|||
return mPluginId;
|
||||
}
|
||||
|
||||
void CrashPluginNow(GMPCrashReason aReason);
|
||||
|
||||
private:
|
||||
~GMPContentParent();
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#include "gmp-audio-codec.h"
|
||||
#include "gmp-decryption.h"
|
||||
|
||||
#include "GMPUtils.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
|
@ -249,13 +247,6 @@ struct ParamTraits<GMPVideoCodec>
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::GMPCrashReason>
|
||||
: public ContiguousEnumSerializer<mozilla::GMPCrashReason,
|
||||
mozilla::kPrefChange,
|
||||
mozilla::kInvalid>
|
||||
{};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // GMPMessageUtils_h_
|
||||
|
|
|
@ -119,10 +119,10 @@ GMPParent::Init(GeckoMediaPluginServiceParent* aService, nsIFile* aPluginDir)
|
|||
}
|
||||
|
||||
void
|
||||
GMPParent::Crash(GMPCrashReason aReason)
|
||||
GMPParent::Crash()
|
||||
{
|
||||
if (mState != GMPStateNotLoaded) {
|
||||
unused << SendCrashPluginNow(aReason);
|
||||
unused << SendCrashPluginNow();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "nsTArray.h"
|
||||
#include "nsIFile.h"
|
||||
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
||||
#include "GMPUtils.h"
|
||||
|
||||
class nsIThread;
|
||||
|
||||
|
@ -80,7 +79,7 @@ public:
|
|||
nsresult Init(GeckoMediaPluginServiceParent* aService, nsIFile* aPluginDir);
|
||||
nsresult CloneFrom(const GMPParent* aOther);
|
||||
|
||||
void Crash(GMPCrashReason aReason);
|
||||
void Crash();
|
||||
|
||||
nsresult LoadProcess();
|
||||
|
||||
|
|
|
@ -215,38 +215,6 @@ GeckoMediaPluginServiceChild::UpdateTrialCreateState(const nsAString& aKeySystem
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginServiceChild::CrashPluginNow(uint32_t aPluginId, GMPCrashReason aReason)
|
||||
{
|
||||
if (NS_GetCurrentThread() != mGMPThread) {
|
||||
mGMPThread->Dispatch(NS_NewRunnableMethodWithArgs<uint32_t, GMPCrashReason>(
|
||||
this, &GeckoMediaPluginServiceChild::CrashPluginNow,
|
||||
aPluginId, aReason), NS_DISPATCH_NORMAL);
|
||||
return;
|
||||
}
|
||||
|
||||
class Callback : public GetServiceChildCallback
|
||||
{
|
||||
public:
|
||||
Callback(uint32_t aPluginId, GMPCrashReason aReason)
|
||||
: mPluginId(aPluginId)
|
||||
, mReason(aReason)
|
||||
{ }
|
||||
|
||||
virtual void Done(GMPServiceChild* aService) override
|
||||
{
|
||||
aService->SendCrashPluginNow(mPluginId, mReason);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t mPluginId;
|
||||
GMPCrashReason mReason;
|
||||
};
|
||||
|
||||
UniquePtr<GetServiceChildCallback> callback(new Callback(aPluginId, aReason));
|
||||
GetServiceChild(Move(callback));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginServiceChild::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "mozilla/ipc/Transport.h"
|
||||
#include "mozilla/gmp/PGMPServiceChild.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "GMPUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -53,8 +52,6 @@ public:
|
|||
NS_IMETHOD UpdateTrialCreateState(const nsAString& aKeySystem,
|
||||
uint32_t aState) override;
|
||||
|
||||
void CrashPluginNow(uint32_t aPluginId, GMPCrashReason aReason);
|
||||
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
void SetServiceChild(UniquePtr<GMPServiceChild>&& aServiceChild);
|
||||
|
|
|
@ -84,7 +84,6 @@ NS_IMPL_ISUPPORTS_INHERITED(GeckoMediaPluginServiceParent,
|
|||
|
||||
static int32_t sMaxAsyncShutdownWaitMs = 0;
|
||||
static bool sHaveSetTimeoutPrefCache = false;
|
||||
static bool sKillHungPlugins = true;
|
||||
|
||||
GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
|
||||
: mShuttingDown(false)
|
||||
|
@ -100,9 +99,6 @@ GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
|
|||
Preferences::AddIntVarCache(&sMaxAsyncShutdownWaitMs,
|
||||
"media.gmp.async-shutdown-timeout",
|
||||
GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT);
|
||||
Preferences::AddBoolVarCache(&sKillHungPlugins,
|
||||
"media.gmp.kill-hung-plugins",
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -668,7 +664,7 @@ GeckoMediaPluginServiceParent::CrashPlugins()
|
|||
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (size_t i = 0; i < mPlugins.Length(); i++) {
|
||||
mPlugins[i]->Crash(kPrefChange);
|
||||
mPlugins[i]->Crash();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1378,24 +1374,6 @@ GeckoMediaPluginServiceParent::UpdateTrialCreateState(const nsAString& aKeySyste
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GeckoMediaPluginServiceParent::CrashPluginNow(uint32_t aPluginId, GMPCrashReason aReason)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
if (aReason == kGmpApiTimeout && !sKillHungPlugins) {
|
||||
LOGD(("%s::%s(%u, %u) but killing hung plugins disabled.",
|
||||
__CLASS__, __FUNCTION__, aPluginId, aReason));
|
||||
return;
|
||||
}
|
||||
LOGD(("%s::%s(%u, %u)", __CLASS__, __FUNCTION__, aPluginId, aReason));
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (const auto& plugin : mPlugins) {
|
||||
if (plugin->GetPluginId() == aPluginId) {
|
||||
plugin->Crash(aReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
ExtractHostName(const nsACString& aOrigin, nsACString& aOutData)
|
||||
{
|
||||
|
@ -1730,14 +1708,6 @@ GMPServiceParent::~GMPServiceParent()
|
|||
new DeleteTask<Transport>(GetTransport()));
|
||||
}
|
||||
|
||||
bool
|
||||
GMPServiceParent::RecvCrashPluginNow(const uint32_t& aPluginId,
|
||||
const GMPCrashReason& aReason)
|
||||
{
|
||||
mService->CrashPluginNow(aPluginId, aReason);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPServiceParent::RecvLoadGMP(const nsCString& aNodeId,
|
||||
const nsCString& aAPI,
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "nsDataHashtable.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "GMPUtils.h"
|
||||
|
||||
template <class> struct already_AddRefed;
|
||||
|
||||
|
@ -58,8 +57,6 @@ public:
|
|||
void SetAsyncShutdownPluginState(GMPParent* aGMPParent, char aId, const nsCString& aState);
|
||||
#endif // MOZ_CRASHREPORTER
|
||||
|
||||
void CrashPluginNow(uint32_t aPluginId, GMPCrashReason aReason);
|
||||
|
||||
private:
|
||||
friend class GMPServiceParent;
|
||||
|
||||
|
@ -226,8 +223,6 @@ public:
|
|||
nsCString* aVersion);
|
||||
virtual bool RecvUpdateGMPTrialCreateState(const nsString& aKeySystem,
|
||||
const uint32_t& aState) override;
|
||||
virtual bool RecvCrashPluginNow(const uint32_t& aPluginId,
|
||||
const GMPCrashReason& aReason) override;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
|
|
|
@ -37,12 +37,6 @@ SplitAt(const char* aDelims,
|
|||
nsCString
|
||||
ToBase64(const nsTArray<uint8_t>& aBytes);
|
||||
|
||||
enum GMPCrashReason {
|
||||
kPrefChange, // media.gmp.plugin.crash has been toggled.
|
||||
kGmpApiTimeout, // Some API did not respond.
|
||||
kInvalid,
|
||||
};
|
||||
|
||||
bool
|
||||
FileExists(nsIFile* aFile);
|
||||
|
||||
|
|
|
@ -188,7 +188,6 @@ GMPVideoDecoderParent::Reset()
|
|||
LOGD(("GMPVideoDecoderParent[%p]::ResetCompleteTimeout() timed out waiting for ResetComplete", self.get()));
|
||||
self->mResetCompleteTimeout = nullptr;
|
||||
LogToBrowserConsole(NS_LITERAL_STRING("GMPVideoDecoderParent timed out waiting for ResetComplete()"));
|
||||
self->mPlugin->CrashPluginNow(kGmpApiTimeout);
|
||||
});
|
||||
CancelResetCompleteTimeout();
|
||||
mResetCompleteTimeout = SimpleTimer::Create(task, 5000, mPlugin->GMPThread());
|
||||
|
|
|
@ -9,7 +9,6 @@ include protocol PGMPTimer;
|
|||
include protocol PGMPStorage;
|
||||
|
||||
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
|
||||
using mozilla::GMPCrashReason from "GMPUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -34,7 +33,7 @@ parent:
|
|||
|
||||
child:
|
||||
async BeginAsyncShutdown();
|
||||
async CrashPluginNow(GMPCrashReason aReason);
|
||||
async CrashPluginNow();
|
||||
intr StartPlugin();
|
||||
async SetNodeId(nsCString nodeId);
|
||||
async CloseActive();
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
include protocol PGMP;
|
||||
|
||||
using base::ProcessId from "base/process.h";
|
||||
using mozilla::GMPCrashReason from "GMPUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -24,8 +23,6 @@ parent:
|
|||
returns (nsCString id);
|
||||
|
||||
async UpdateGMPTrialCreateState(nsString keySystem, uint32_t status);
|
||||
|
||||
async CrashPluginNow(uint32_t pluginId, GMPCrashReason aReason);
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
|
|
@ -51,7 +51,7 @@ MediaSourceDecoder::CreateStateMachine()
|
|||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceDecoder::Load(nsIStreamListener**, MediaDecoder*)
|
||||
MediaSourceDecoder::Load(nsIStreamListener**)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!GetStateMachine());
|
||||
|
@ -61,7 +61,7 @@ MediaSourceDecoder::Load(nsIStreamListener**, MediaDecoder*)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = GetStateMachine()->Init(nullptr);
|
||||
nsresult rv = GetStateMachine()->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
SetStateMachineParameters();
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
|
||||
virtual MediaDecoder* Clone() override;
|
||||
virtual MediaDecoderStateMachine* CreateStateMachine() override;
|
||||
virtual nsresult Load(nsIStreamListener**, MediaDecoder*) override;
|
||||
virtual nsresult Load(nsIStreamListener**) override;
|
||||
virtual media::TimeIntervals GetSeekable() override;
|
||||
media::TimeIntervals GetBuffered() override;
|
||||
|
||||
|
|
|
@ -284,8 +284,10 @@ MediaCodecReader::~MediaCodecReader()
|
|||
}
|
||||
|
||||
void
|
||||
MediaCodecReader::ReleaseMediaResources()
|
||||
MediaCodecReader::ReleaseMediaResourcesInternal()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
// Stop the mSource because we are in the dormant state and the stop function
|
||||
// will rewind the mSource to the beginning of the stream.
|
||||
if (mVideoTrack.mSource != nullptr && !mVideoTrack.mSourceIsStopped) {
|
||||
|
|
|
@ -60,9 +60,6 @@ public:
|
|||
MediaCodecReader(AbstractMediaDecoder* aDecoder);
|
||||
virtual ~MediaCodecReader();
|
||||
|
||||
// Release media resources they should be released in dormant state
|
||||
virtual void ReleaseMediaResources();
|
||||
|
||||
// Destroys the decoding state. The reader cannot be made usable again.
|
||||
// This is different from ReleaseMediaResources() as Shutdown() is
|
||||
// irreversible, whereas ReleaseMediaResources() is reversible.
|
||||
|
@ -436,6 +433,10 @@ private:
|
|||
nsTArray<ReleaseItem> mPendingReleaseItems;
|
||||
|
||||
NotifyDataArrivedFilter mFilter;
|
||||
|
||||
private:
|
||||
// Release media resources they should be released in dormant state
|
||||
virtual void ReleaseMediaResourcesInternal() override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -170,8 +170,10 @@ MediaOmxReader::Shutdown()
|
|||
return p;
|
||||
}
|
||||
|
||||
void MediaOmxReader::ReleaseMediaResources()
|
||||
void MediaOmxReader::ReleaseMediaResourcesInternal()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
mMediaResourceRequest.DisconnectIfExists();
|
||||
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
|
||||
|
|
|
@ -95,8 +95,6 @@ public:
|
|||
return mHasVideo;
|
||||
}
|
||||
|
||||
virtual void ReleaseMediaResources();
|
||||
|
||||
virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata() override;
|
||||
|
||||
virtual nsRefPtr<SeekPromise>
|
||||
|
@ -118,6 +116,8 @@ private:
|
|||
class ProcessCachedDataTask;
|
||||
class NotifyDataArrivedRunnable;
|
||||
|
||||
virtual void ReleaseMediaResourcesInternal() override;
|
||||
|
||||
bool IsShutdown() {
|
||||
MutexAutoLock lock(mShutdownMutex);
|
||||
return mIsShutdown;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXPCOM.h"
|
||||
|
||||
#undef LOG
|
||||
#undef LOG_ENABLED
|
||||
|
@ -142,6 +143,79 @@ private:
|
|||
int mResult;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(CamerasParent, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
CamerasParent::Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const char16_t *aData)
|
||||
{
|
||||
MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID));
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
MOZ_ASSERT(obs);
|
||||
obs->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
|
||||
StopVideoCapture();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CamerasParent::DispatchToVideoCaptureThread(nsRunnable *event)
|
||||
{
|
||||
MonitorAutoLock lock(mThreadMonitor);
|
||||
|
||||
while(mChildIsAlive && mWebRTCAlive &&
|
||||
(!mVideoCaptureThread || !mVideoCaptureThread->IsRunning())) {
|
||||
mThreadMonitor.Wait();
|
||||
}
|
||||
if (!mVideoCaptureThread || !mVideoCaptureThread->IsRunning()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mVideoCaptureThread->message_loop()->PostTask(FROM_HERE,
|
||||
new RunnableTask(event));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CamerasParent::StopVideoCapture()
|
||||
{
|
||||
// We are called from the main thread (xpcom-shutdown) or
|
||||
// from PBackground (when the Actor shuts down).
|
||||
// Shut down the WebRTC stack (on the capture thread)
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> webrtc_runnable =
|
||||
media::NewRunnableFrom([self]() -> nsresult {
|
||||
MonitorAutoLock lock(self->mThreadMonitor);
|
||||
self->CloseEngines();
|
||||
self->mThreadMonitor.NotifyAll();
|
||||
return NS_OK;
|
||||
});
|
||||
DispatchToVideoCaptureThread(webrtc_runnable);
|
||||
// Hold here until the WebRTC thread is gone. We need to dispatch
|
||||
// the thread deletion *now*, or there will be no more possibility
|
||||
// to get to the main thread.
|
||||
MonitorAutoLock lock(mThreadMonitor);
|
||||
while (mWebRTCAlive) {
|
||||
mThreadMonitor.Wait();
|
||||
}
|
||||
// After closing the WebRTC stack, clean up the
|
||||
// VideoCapture thread.
|
||||
if (self->mVideoCaptureThread) {
|
||||
base::Thread *thread = self->mVideoCaptureThread;
|
||||
self->mVideoCaptureThread = nullptr;
|
||||
nsRefPtr<nsRunnable> threadShutdown =
|
||||
media::NewRunnableFrom([thread]() -> nsresult {
|
||||
if (thread->IsRunning()) {
|
||||
thread->Stop();
|
||||
}
|
||||
delete thread;
|
||||
return NS_OK;
|
||||
});
|
||||
if (NS_FAILED(NS_DispatchToMainThread(threadShutdown))) {
|
||||
LOG(("Could not dispatch VideoCaptureThread destruction"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
CamerasParent::DeliverFrameOverIPC(CaptureEngine cap_engine,
|
||||
int cap_id,
|
||||
|
@ -235,6 +309,7 @@ CamerasParent::RecvReleaseFrame(mozilla::ipc::Shmem&& s) {
|
|||
bool
|
||||
CamerasParent::SetupEngine(CaptureEngine aCapEngine)
|
||||
{
|
||||
MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
|
||||
EngineHelper *helper = &mEngines[aCapEngine];
|
||||
|
||||
// Already initialized
|
||||
|
@ -308,51 +383,57 @@ CamerasParent::SetupEngine(CaptureEngine aCapEngine)
|
|||
void
|
||||
CamerasParent::CloseEngines()
|
||||
{
|
||||
{
|
||||
MutexAutoLock lock(mCallbackMutex);
|
||||
// Stop the callers
|
||||
while (mCallbacks.Length()) {
|
||||
auto capEngine = mCallbacks[0]->mCapEngine;
|
||||
auto capNum = mCallbacks[0]->mCapturerId;
|
||||
LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, capNum));
|
||||
{
|
||||
MutexAutoUnlock unlock(mCallbackMutex);
|
||||
RecvStopCapture(capEngine, capNum);
|
||||
RecvReleaseCaptureDevice(capEngine, capNum);
|
||||
}
|
||||
// The callbacks list might have changed while we released the lock,
|
||||
// but note that due to the loop construct this will not break us.
|
||||
if (!mWebRTCAlive) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
|
||||
|
||||
// Stop the callers
|
||||
while (mCallbacks.Length()) {
|
||||
auto capEngine = mCallbacks[0]->mCapEngine;
|
||||
auto capNum = mCallbacks[0]->mCapturerId;
|
||||
LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, capNum));
|
||||
RecvStopCapture(capEngine, capNum);
|
||||
RecvReleaseCaptureDevice(capEngine, capNum);
|
||||
}
|
||||
|
||||
for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
|
||||
if (mEngines[i].mEngineIsRunning) {
|
||||
LOG(("Being closed down while engine %d is running!", i));
|
||||
}
|
||||
if (mEngines[i].mPtrViERender) {
|
||||
mEngines[i].mPtrViERender->Release();
|
||||
mEngines[i].mPtrViERender = nullptr;
|
||||
}
|
||||
if (mEngines[i].mPtrViECapture) {
|
||||
mEngines[i].mPtrViECapture->Release();
|
||||
mEngines[i].mPtrViECapture = nullptr;
|
||||
}
|
||||
if(mEngines[i].mPtrViEBase) {
|
||||
mEngines[i].mPtrViEBase->Release();
|
||||
mEngines[i].mPtrViEBase = nullptr;
|
||||
}
|
||||
if (mEngines[i].mEngine) {
|
||||
mEngines[i].mEngine->SetTraceCallback(nullptr);
|
||||
webrtc::VideoEngine::Delete(mEngines[i].mEngine);
|
||||
mEngines[i].mEngine = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mEngineMutex);
|
||||
for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
|
||||
if (mEngines[i].mEngineIsRunning) {
|
||||
LOG(("Being closed down while engine %d is running!", i));
|
||||
}
|
||||
if (mEngines[i].mPtrViERender) {
|
||||
mEngines[i].mPtrViERender->Release();
|
||||
mEngines[i].mPtrViERender = nullptr;
|
||||
}
|
||||
if (mEngines[i].mPtrViECapture) {
|
||||
mEngines[i].mPtrViECapture->Release();
|
||||
mEngines[i].mPtrViECapture = nullptr;
|
||||
}
|
||||
if(mEngines[i].mPtrViEBase) {
|
||||
mEngines[i].mPtrViEBase->Release();
|
||||
mEngines[i].mPtrViEBase = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
mWebRTCAlive = false;
|
||||
}
|
||||
|
||||
bool
|
||||
CamerasParent::EnsureInitialized(int aEngine)
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
// We're shutting down, don't try to do new WebRTC ops.
|
||||
if (!mWebRTCAlive) {
|
||||
return false;
|
||||
}
|
||||
CaptureEngine capEngine = static_cast<CaptureEngine>(aEngine);
|
||||
if (!SetupEngine(capEngine)) {
|
||||
LOG(("CamerasParent failed to initialize engine"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -368,18 +449,12 @@ bool
|
|||
CamerasParent::RecvNumberOfCaptureDevices(const int& aCapEngine)
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
if (!EnsureInitialized(aCapEngine)) {
|
||||
LOG(("RecvNumberOfCaptureDevices fails to initialize"));
|
||||
unused << SendReplyFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> webrtc_runnable =
|
||||
media::NewRunnableFrom([self, aCapEngine]() -> nsresult {
|
||||
MutexAutoLock lock(self->mEngineMutex);
|
||||
int num = -1;
|
||||
if (self->mEngines[aCapEngine].mPtrViECapture) {
|
||||
if (self->EnsureInitialized(aCapEngine)) {
|
||||
num = self->mEngines[aCapEngine].mPtrViECapture->NumberOfCaptureDevices();
|
||||
}
|
||||
nsRefPtr<nsIRunnable> ipc_runnable =
|
||||
|
@ -400,8 +475,7 @@ CamerasParent::RecvNumberOfCaptureDevices(const int& aCapEngine)
|
|||
self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
});
|
||||
mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
|
||||
|
||||
DispatchToVideoCaptureThread(webrtc_runnable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -410,19 +484,13 @@ CamerasParent::RecvNumberOfCapabilities(const int& aCapEngine,
|
|||
const nsCString& unique_id)
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
if (!EnsureInitialized(aCapEngine)) {
|
||||
LOG(("RecvNumberOfCapabilities fails to initialize"));
|
||||
unused << SendReplyFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(("Getting caps for %s", unique_id.get()));
|
||||
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> webrtc_runnable =
|
||||
media::NewRunnableFrom([self, unique_id, aCapEngine]() -> nsresult {
|
||||
MutexAutoLock lock(self->mEngineMutex);
|
||||
int num = -1;
|
||||
if (self->mEngines[aCapEngine].mPtrViECapture) {
|
||||
if (self->EnsureInitialized(aCapEngine)) {
|
||||
num =
|
||||
self->mEngines[aCapEngine].mPtrViECapture->NumberOfCapabilities(
|
||||
unique_id.get(),
|
||||
|
@ -446,7 +514,7 @@ CamerasParent::RecvNumberOfCapabilities(const int& aCapEngine,
|
|||
self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
});
|
||||
mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
|
||||
DispatchToVideoCaptureThread(webrtc_runnable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -456,21 +524,14 @@ CamerasParent::RecvGetCaptureCapability(const int &aCapEngine,
|
|||
const int& num)
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
if (!EnsureInitialized(aCapEngine)) {
|
||||
LOG(("Fails to initialize"));
|
||||
unused << SendReplyFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(("RecvGetCaptureCapability: %s %d", unique_id.get(), num));
|
||||
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> webrtc_runnable =
|
||||
media::NewRunnableFrom([self, unique_id, aCapEngine, num]() -> nsresult {
|
||||
webrtc::CaptureCapability webrtcCaps;
|
||||
MutexAutoLock lock(self->mEngineMutex);
|
||||
int error = -1;
|
||||
if (self->mEngines[aCapEngine].mPtrViECapture) {
|
||||
if (self->EnsureInitialized(aCapEngine)) {
|
||||
error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureCapability(
|
||||
unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, num, webrtcCaps);
|
||||
}
|
||||
|
@ -503,7 +564,7 @@ CamerasParent::RecvGetCaptureCapability(const int &aCapEngine,
|
|||
self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
});
|
||||
mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
|
||||
DispatchToVideoCaptureThread(webrtc_runnable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -512,13 +573,7 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine,
|
|||
const int& aListNumber)
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
if (!EnsureInitialized(aCapEngine)) {
|
||||
LOG(("Fails to initialize"));
|
||||
unused << SendReplyFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(("RecvGetCaptureDevice"));
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> webrtc_runnable =
|
||||
media::NewRunnableFrom([self, aCapEngine, aListNumber]() -> nsresult {
|
||||
|
@ -526,20 +581,18 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine,
|
|||
char deviceUniqueId[MediaEngineSource::kMaxUniqueIdLength];
|
||||
nsCString name;
|
||||
nsCString uniqueId;
|
||||
MutexAutoLock lock(self->mEngineMutex);
|
||||
int error = -1;
|
||||
if (self->mEngines[aCapEngine].mPtrViECapture) {
|
||||
error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureDevice(aListNumber,
|
||||
deviceName,
|
||||
sizeof(deviceName),
|
||||
deviceUniqueId,
|
||||
sizeof(deviceUniqueId));
|
||||
if (self->EnsureInitialized(aCapEngine)) {
|
||||
error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureDevice(aListNumber,
|
||||
deviceName,
|
||||
sizeof(deviceName),
|
||||
deviceUniqueId,
|
||||
sizeof(deviceUniqueId));
|
||||
}
|
||||
if (!error) {
|
||||
name.Assign(deviceName);
|
||||
uniqueId.Assign(deviceUniqueId);
|
||||
}
|
||||
|
||||
nsRefPtr<nsIRunnable> ipc_runnable =
|
||||
media::NewRunnableFrom([self, error, name, uniqueId]() -> nsresult {
|
||||
if (self->IsShuttingDown()) {
|
||||
|
@ -558,7 +611,7 @@ CamerasParent::RecvGetCaptureDevice(const int& aCapEngine,
|
|||
self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
});
|
||||
mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
|
||||
DispatchToVideoCaptureThread(webrtc_runnable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -567,19 +620,13 @@ CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine,
|
|||
const nsCString& unique_id)
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
if (!EnsureInitialized(aCapEngine)) {
|
||||
LOG(("Fails to initialize"));
|
||||
unused << SendReplyFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> webrtc_runnable =
|
||||
media::NewRunnableFrom([self, aCapEngine, unique_id]() -> nsresult {
|
||||
int numdev = -1;
|
||||
MutexAutoLock lock(self->mEngineMutex);
|
||||
int error = -1;
|
||||
if (self->mEngines[aCapEngine].mPtrViECapture) {
|
||||
if (self->EnsureInitialized(aCapEngine)) {
|
||||
error = self->mEngines[aCapEngine].mPtrViECapture->AllocateCaptureDevice(
|
||||
unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, numdev);
|
||||
}
|
||||
|
@ -600,7 +647,7 @@ CamerasParent::RecvAllocateCaptureDevice(const int& aCapEngine,
|
|||
self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
});
|
||||
mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
|
||||
DispatchToVideoCaptureThread(webrtc_runnable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -609,19 +656,13 @@ CamerasParent::RecvReleaseCaptureDevice(const int& aCapEngine,
|
|||
const int& numdev)
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
if (!EnsureInitialized(aCapEngine)) {
|
||||
LOG(("Fails to initialize"));
|
||||
unused << SendReplyFailure();
|
||||
return false;
|
||||
}
|
||||
LOG(("RecvReleaseCamera device nr %d", numdev));
|
||||
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> webrtc_runnable =
|
||||
media::NewRunnableFrom([self, aCapEngine, numdev]() -> nsresult {
|
||||
LOG(("RecvReleaseCamera device nr %d", numdev));
|
||||
MutexAutoLock lock(self->mEngineMutex);
|
||||
int error = -1;
|
||||
if (self->mEngines[aCapEngine].mPtrViECapture) {
|
||||
if (self->EnsureInitialized(aCapEngine)) {
|
||||
error = self->mEngines[aCapEngine].mPtrViECapture->ReleaseCaptureDevice(numdev);
|
||||
}
|
||||
nsRefPtr<nsIRunnable> ipc_runnable =
|
||||
|
@ -641,12 +682,7 @@ CamerasParent::RecvReleaseCaptureDevice(const int& aCapEngine,
|
|||
self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
});
|
||||
#ifndef XP_MACOSX
|
||||
mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
|
||||
#else
|
||||
// Mac OS X hangs on shutdown if we don't do this on the main thread.
|
||||
NS_DispatchToMainThread(webrtc_runnable);
|
||||
#endif
|
||||
DispatchToVideoCaptureThread(webrtc_runnable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -656,11 +692,6 @@ CamerasParent::RecvStartCapture(const int& aCapEngine,
|
|||
const CaptureCapability& ipcCaps)
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
if (!EnsureInitialized(aCapEngine)) {
|
||||
LOG(("Failure to initialize"));
|
||||
unused << SendReplyFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> webrtc_runnable =
|
||||
|
@ -668,23 +699,15 @@ CamerasParent::RecvStartCapture(const int& aCapEngine,
|
|||
CallbackHelper** cbh;
|
||||
webrtc::ExternalRenderer* render;
|
||||
EngineHelper* helper = nullptr;
|
||||
int error;
|
||||
{
|
||||
MutexAutoLock lockCallback(self->mCallbackMutex);
|
||||
int error = -1;
|
||||
if (self->EnsureInitialized(aCapEngine)) {
|
||||
cbh = self->mCallbacks.AppendElement(
|
||||
new CallbackHelper(static_cast<CaptureEngine>(aCapEngine), capnum, self));
|
||||
render = static_cast<webrtc::ExternalRenderer*>(*cbh);
|
||||
}
|
||||
{
|
||||
MutexAutoLock lockEngine(self->mEngineMutex);
|
||||
if (self->mEngines[aCapEngine].mPtrViECapture) {
|
||||
helper = &self->mEngines[aCapEngine];
|
||||
error =
|
||||
helper->mPtrViERender->AddRenderer(capnum, webrtc::kVideoI420, render);
|
||||
} else {
|
||||
error = -1;
|
||||
}
|
||||
|
||||
helper = &self->mEngines[aCapEngine];
|
||||
error =
|
||||
helper->mPtrViERender->AddRenderer(capnum, webrtc::kVideoI420, render);
|
||||
if (!error) {
|
||||
error = helper->mPtrViERender->StartRender(capnum);
|
||||
}
|
||||
|
@ -705,7 +728,6 @@ CamerasParent::RecvStartCapture(const int& aCapEngine,
|
|||
helper->mEngineIsRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<nsIRunnable> ipc_runnable =
|
||||
media::NewRunnableFrom([self, error]() -> nsresult {
|
||||
if (self->IsShuttingDown()) {
|
||||
|
@ -722,7 +744,7 @@ CamerasParent::RecvStartCapture(const int& aCapEngine,
|
|||
self->mPBackgroundThread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
});
|
||||
mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
|
||||
DispatchToVideoCaptureThread(webrtc_runnable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -731,40 +753,32 @@ CamerasParent::RecvStopCapture(const int& aCapEngine,
|
|||
const int& capnum)
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
if (!EnsureInitialized(aCapEngine)) {
|
||||
LOG(("Failure to initialize"));
|
||||
unused << SendReplyFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> webrtc_runnable =
|
||||
media::NewRunnableFrom([self, aCapEngine, capnum]() -> nsresult {
|
||||
{
|
||||
MutexAutoLock lock(self->mEngineMutex);
|
||||
// We only need to check mPtrViECapture as all other engines are guaranteed
|
||||
// to be nulled under the same lock.
|
||||
if (self->mEngines[aCapEngine].mPtrViECapture) {
|
||||
self->mEngines[aCapEngine].mPtrViECapture->StopCapture(capnum);
|
||||
self->mEngines[aCapEngine].mPtrViERender->StopRender(capnum);
|
||||
self->mEngines[aCapEngine].mPtrViERender->RemoveRenderer(capnum);
|
||||
self->mEngines[aCapEngine].mEngineIsRunning = false;
|
||||
}
|
||||
}
|
||||
MutexAutoLock lock(self->mCallbackMutex);
|
||||
for (unsigned int i = 0; i < self->mCallbacks.Length(); i++) {
|
||||
if (self->mCallbacks[i]->mCapEngine == aCapEngine
|
||||
&& self->mCallbacks[i]->mCapturerId == capnum) {
|
||||
delete self->mCallbacks[i];
|
||||
self->mCallbacks.RemoveElementAt(i);
|
||||
break;
|
||||
if (self->EnsureInitialized(aCapEngine)) {
|
||||
self->mEngines[aCapEngine].mPtrViECapture->StopCapture(capnum);
|
||||
self->mEngines[aCapEngine].mPtrViERender->StopRender(capnum);
|
||||
self->mEngines[aCapEngine].mPtrViERender->RemoveRenderer(capnum);
|
||||
self->mEngines[aCapEngine].mEngineIsRunning = false;
|
||||
|
||||
for (size_t i = 0; i < self->mCallbacks.Length(); i++) {
|
||||
if (self->mCallbacks[i]->mCapEngine == aCapEngine
|
||||
&& self->mCallbacks[i]->mCapturerId == capnum) {
|
||||
delete self->mCallbacks[i];
|
||||
self->mCallbacks.RemoveElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
});
|
||||
|
||||
mVideoCaptureThread->message_loop()->PostTask(FROM_HERE, new RunnableTask(webrtc_runnable));
|
||||
return SendReplySuccess();
|
||||
if (NS_SUCCEEDED(DispatchToVideoCaptureThread(webrtc_runnable))) {
|
||||
return SendReplySuccess();
|
||||
} else {
|
||||
return SendReplyFailure();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -788,49 +802,24 @@ CamerasParent::RecvAllDone()
|
|||
return Send__delete__(this);
|
||||
}
|
||||
|
||||
void CamerasParent::DoShutdown()
|
||||
{
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
CloseEngines();
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mEngineMutex);
|
||||
for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
|
||||
if (mEngines[i].mEngine) {
|
||||
mEngines[i].mEngine->SetTraceCallback(nullptr);
|
||||
webrtc::VideoEngine::Delete(mEngines[i].mEngine);
|
||||
mEngines[i].mEngine = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mPBackgroundThread = nullptr;
|
||||
|
||||
if (mVideoCaptureThread) {
|
||||
if (mVideoCaptureThread->IsRunning()) {
|
||||
mVideoCaptureThread->Stop();
|
||||
}
|
||||
delete mVideoCaptureThread;
|
||||
mVideoCaptureThread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CamerasParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
// No more IPC from here
|
||||
LOG((__PRETTY_FUNCTION__));
|
||||
StopIPC();
|
||||
CloseEngines();
|
||||
// Shut down WebRTC (if we're not in full shutdown, else this
|
||||
// will already have happened)
|
||||
StopVideoCapture();
|
||||
}
|
||||
|
||||
CamerasParent::CamerasParent()
|
||||
: mCallbackMutex("CamerasParent.mCallbackMutex"),
|
||||
mEngineMutex("CamerasParent.mEngineMutex"),
|
||||
mShmemPool(CaptureEngine::MaxEngine),
|
||||
: mShmemPool(CaptureEngine::MaxEngine),
|
||||
mThreadMonitor("CamerasParent::mThreadMonitor"),
|
||||
mVideoCaptureThread(nullptr),
|
||||
mChildIsAlive(true),
|
||||
mDestroyed(false)
|
||||
mDestroyed(false),
|
||||
mWebRTCAlive(true)
|
||||
{
|
||||
if (!gCamerasParentLog) {
|
||||
gCamerasParentLog = PR_NewLogModule("CamerasParent");
|
||||
|
@ -841,16 +830,37 @@ CamerasParent::CamerasParent()
|
|||
MOZ_ASSERT(mPBackgroundThread != nullptr, "GetCurrentThread failed");
|
||||
|
||||
LOG(("Spinning up WebRTC Cameras Thread"));
|
||||
mVideoCaptureThread = new base::Thread("VideoCapture");
|
||||
base::Thread::Options options;
|
||||
|
||||
nsRefPtr<CamerasParent> self(this);
|
||||
nsRefPtr<nsRunnable> threadStart =
|
||||
media::NewRunnableFrom([self]() -> nsresult {
|
||||
// Register thread shutdown observer
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (NS_WARN_IF(!obs)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv =
|
||||
obs->AddObserver(self, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
// Start the thread
|
||||
MonitorAutoLock lock(self->mThreadMonitor);
|
||||
self->mVideoCaptureThread = new base::Thread("VideoCapture");
|
||||
base::Thread::Options options;
|
||||
#if defined(_WIN32)
|
||||
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
|
||||
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
|
||||
#else
|
||||
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
|
||||
|
||||
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
|
||||
#endif
|
||||
if (!mVideoCaptureThread->StartWithOptions(options)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
if (!self->mVideoCaptureThread->StartWithOptions(options)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
self->mThreadMonitor.NotifyAll();
|
||||
return NS_OK;
|
||||
});
|
||||
NS_DispatchToMainThread(threadStart);
|
||||
|
||||
MOZ_COUNT_CTOR(CamerasParent);
|
||||
}
|
||||
|
@ -860,7 +870,15 @@ CamerasParent::~CamerasParent()
|
|||
LOG(("~CamerasParent: %p", this));
|
||||
|
||||
MOZ_COUNT_DTOR(CamerasParent);
|
||||
DoShutdown();
|
||||
#ifdef DEBUG
|
||||
// Verify we have shut down the webrtc engines, this is
|
||||
// supposed to happen in ActorDestroy.
|
||||
// That runnable takes a ref to us, so it must have finished
|
||||
// by the time we get here.
|
||||
for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
|
||||
MOZ_ASSERT(!mEngines[i].mEngine);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
already_AddRefed<CamerasParent>
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
#ifndef mozilla_CamerasParent_h
|
||||
#define mozilla_CamerasParent_h
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/camera/PCamerasParent.h"
|
||||
#include "mozilla/ipc/Shmem.h"
|
||||
#include "mozilla/ShmemPool.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
// conflicts with #include of scoped_ptr.h
|
||||
#undef FF
|
||||
|
@ -73,9 +75,11 @@ public:
|
|||
bool mEngineIsRunning;
|
||||
};
|
||||
|
||||
class CamerasParent : public PCamerasParent
|
||||
class CamerasParent : public PCamerasParent,
|
||||
public nsIObserver
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CamerasParent);
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
public:
|
||||
static already_AddRefed<CamerasParent> Create();
|
||||
|
@ -94,7 +98,9 @@ public:
|
|||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
nsIThread* GetBackgroundThread() { return mPBackgroundThread; };
|
||||
bool IsShuttingDown() { return !mChildIsAlive || mDestroyed; };
|
||||
bool IsShuttingDown() { return !mChildIsAlive
|
||||
|| mDestroyed
|
||||
|| !mWebRTCAlive; };
|
||||
ShmemBuffer GetBuffer(size_t aSize);
|
||||
|
||||
// helper to forward to the PBackground thread
|
||||
|
@ -116,15 +122,12 @@ protected:
|
|||
bool SetupEngine(CaptureEngine aCapEngine);
|
||||
void CloseEngines();
|
||||
bool EnsureInitialized(int aEngine);
|
||||
void DoShutdown();
|
||||
void StopIPC();
|
||||
void StopVideoCapture();
|
||||
nsresult DispatchToVideoCaptureThread(nsRunnable *event);
|
||||
|
||||
EngineHelper mEngines[CaptureEngine::MaxEngine];
|
||||
nsTArray<CallbackHelper*> mCallbacks;
|
||||
// Protects the callback arrays
|
||||
Mutex mCallbackMutex;
|
||||
// Protects the engines array
|
||||
Mutex mEngineMutex;
|
||||
|
||||
// image buffers
|
||||
mozilla::ShmemPool mShmemPool;
|
||||
|
@ -132,12 +135,18 @@ protected:
|
|||
// PBackground parent thread
|
||||
nsCOMPtr<nsIThread> mPBackgroundThread;
|
||||
|
||||
// Monitors creation of the thread below
|
||||
Monitor mThreadMonitor;
|
||||
|
||||
// video processing thread - where webrtc.org capturer code runs
|
||||
base::Thread* mVideoCaptureThread;
|
||||
|
||||
// Shutdown handling
|
||||
bool mChildIsAlive;
|
||||
bool mDestroyed;
|
||||
// Above 2 are PBackground only, but this is potentially
|
||||
// read cross-thread.
|
||||
mozilla::Atomic<bool> mWebRTCAlive;
|
||||
};
|
||||
|
||||
PCamerasParent* CreateCamerasParent();
|
||||
|
|
|
@ -68,19 +68,19 @@ public:
|
|||
Pledge& operator = (const Pledge&) = delete;
|
||||
|
||||
template<typename OnSuccessType>
|
||||
void Then(OnSuccessType aOnSuccess)
|
||||
void Then(OnSuccessType&& aOnSuccess)
|
||||
{
|
||||
Then(aOnSuccess, [](ErrorType&){});
|
||||
Then(Forward<OnSuccessType>(aOnSuccess), [](ErrorType&){});
|
||||
}
|
||||
|
||||
template<typename OnSuccessType, typename OnFailureType>
|
||||
void Then(OnSuccessType aOnSuccess, OnFailureType aOnFailure)
|
||||
void Then(OnSuccessType&& aOnSuccess, OnFailureType&& aOnFailure)
|
||||
{
|
||||
class Functors : public FunctorsBase
|
||||
{
|
||||
public:
|
||||
Functors(OnSuccessType& aOnSuccess, OnFailureType& aOnFailure)
|
||||
: mOnSuccess(aOnSuccess), mOnFailure(aOnFailure) {}
|
||||
Functors(OnSuccessType&& aOnSuccess, OnFailureType&& aOnFailure)
|
||||
: mOnSuccess(Move(aOnSuccess)), mOnFailure(Move(aOnFailure)) {}
|
||||
|
||||
void Succeed(ValueType& result)
|
||||
{
|
||||
|
@ -94,8 +94,8 @@ public:
|
|||
OnSuccessType mOnSuccess;
|
||||
OnFailureType mOnFailure;
|
||||
};
|
||||
mFunctors = new Functors(aOnSuccess, aOnFailure);
|
||||
|
||||
mFunctors = new Functors(Forward<OnSuccessType>(aOnSuccess),
|
||||
Forward<OnFailureType>(aOnFailure));
|
||||
if (mDone) {
|
||||
if (!mRejected) {
|
||||
mFunctors->Succeed(mValue);
|
||||
|
@ -186,7 +186,7 @@ template<typename OnRunType>
|
|||
class LambdaRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit LambdaRunnable(OnRunType& aOnRun) : mOnRun(aOnRun) {}
|
||||
explicit LambdaRunnable(OnRunType&& aOnRun) : mOnRun(Move(aOnRun)) {}
|
||||
private:
|
||||
NS_IMETHODIMP
|
||||
Run()
|
||||
|
@ -198,16 +198,16 @@ private:
|
|||
|
||||
template<typename OnRunType>
|
||||
LambdaRunnable<OnRunType>*
|
||||
NewRunnableFrom(OnRunType aOnRun)
|
||||
NewRunnableFrom(OnRunType&& aOnRun)
|
||||
{
|
||||
return new LambdaRunnable<OnRunType>(aOnRun);
|
||||
return new LambdaRunnable<OnRunType>(Forward<OnRunType>(aOnRun));
|
||||
}
|
||||
|
||||
template<typename OnRunType>
|
||||
class LambdaTask : public Task
|
||||
{
|
||||
public:
|
||||
explicit LambdaTask(OnRunType& aOnRun) : mOnRun(aOnRun) {}
|
||||
explicit LambdaTask(OnRunType&& aOnRun) : mOnRun(Move(aOnRun)) {}
|
||||
private:
|
||||
void
|
||||
Run()
|
||||
|
@ -219,9 +219,9 @@ private:
|
|||
|
||||
template<typename OnRunType>
|
||||
LambdaTask<OnRunType>*
|
||||
NewTaskFrom(OnRunType aOnRun)
|
||||
NewTaskFrom(OnRunType&& aOnRun)
|
||||
{
|
||||
return new LambdaTask<OnRunType>(aOnRun);
|
||||
return new LambdaTask<OnRunType>(Forward<OnRunType>(aOnRun));
|
||||
}
|
||||
|
||||
/* media::CoatCheck - There and back again. Park an object in exchange for an id.
|
||||
|
|
|
@ -277,6 +277,19 @@ function SetupEME(test, token, params)
|
|||
{
|
||||
var v = document.createElement("video");
|
||||
v.crossOrigin = test.crossOrigin || false;
|
||||
v.sessions = [];
|
||||
|
||||
v.closeSessions = function() {
|
||||
return Promise.all(v.sessions.map(s => s.close().then(() => s.closed))).then(
|
||||
() => {
|
||||
v.setMediaKeys(null);
|
||||
if (v.parentNode) {
|
||||
v.parentNode.removeChild(v);
|
||||
}
|
||||
v.onerror = null;
|
||||
v.src = null;
|
||||
});
|
||||
};
|
||||
|
||||
// Log events dispatched to make debugging easier...
|
||||
[ "canplay", "canplaythrough", "ended", "error", "loadeddata",
|
||||
|
@ -311,6 +324,7 @@ function SetupEME(test, token, params)
|
|||
if (params && params.onsessioncreated) {
|
||||
params.onsessioncreated(session);
|
||||
}
|
||||
v.sessions.push(session);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
session.addEventListener("message", UpdateSessionFunc(test, token, sessionType, resolve, reject));
|
||||
|
|
|
@ -95,7 +95,7 @@ function startTest(test, token)
|
|||
ok(keyIdsReceived[kid], TimeStamp(token) + " key with id " + kid + " was usable as expected");
|
||||
}
|
||||
|
||||
manager.finished(token);
|
||||
v.closeSessions().then(() => manager.finished(token));
|
||||
});
|
||||
|
||||
LoadTest(test, v, token)
|
||||
|
|
|
@ -1231,8 +1231,7 @@ Promise::MaybeReportRejected()
|
|||
NS_WARNING("!!! Trying to report rejected Promise after MainThread shutdown");
|
||||
}
|
||||
if (mainThread) {
|
||||
nsRefPtr<AsyncErrorReporter> r =
|
||||
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(), xpcReport);
|
||||
nsRefPtr<AsyncErrorReporter> r = new AsyncErrorReporter(xpcReport);
|
||||
mainThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,6 +319,7 @@ interface WebGL2RenderingContext : WebGLRenderingContext
|
|||
void copyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset,
|
||||
GLintptr writeOffset, GLsizeiptr size);
|
||||
void getBufferSubData(GLenum target, GLintptr offset, ArrayBuffer? returnedData);
|
||||
void getBufferSubData(GLenum target, GLintptr offset, SharedArrayBuffer returnedData);
|
||||
|
||||
/* Framebuffer objects */
|
||||
void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
|
||||
|
@ -347,10 +348,10 @@ interface WebGL2RenderingContext : WebGLRenderingContext
|
|||
void texImage3D(GLenum target, GLint level, GLenum internalformat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLint border, GLenum format,
|
||||
GLenum type, ArrayBufferView? pixels);
|
||||
GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
|
||||
[Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
|
||||
ArrayBufferView? pixels);
|
||||
(ArrayBufferView or SharedArrayBufferView)? pixels);
|
||||
[Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLenum format, GLenum type, ImageData? data);
|
||||
[Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
|
@ -363,10 +364,10 @@ interface WebGL2RenderingContext : WebGLRenderingContext
|
|||
GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
void compressedTexImage3D(GLenum target, GLint level, GLenum internalformat,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLint border, GLsizei imageSize, ArrayBufferView data);
|
||||
GLint border, GLsizei imageSize, (ArrayBufferView or SharedArrayBufferView) data);
|
||||
void compressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
GLenum format, GLsizei imageSize, ArrayBufferView data);
|
||||
GLenum format, GLsizei imageSize, (ArrayBufferView or SharedArrayBufferView) data);
|
||||
|
||||
/* Programs and shaders */
|
||||
[WebGLHandlesContextLoss] GLint getFragDataLocation(WebGLProgram? program, DOMString name);
|
||||
|
|
|
@ -552,9 +552,13 @@ interface WebGLRenderingContext {
|
|||
|
||||
void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
|
||||
void bufferData(GLenum target, ArrayBufferView data, GLenum usage);
|
||||
void bufferData(GLenum target, SharedArrayBufferView data, GLenum usage);
|
||||
void bufferData(GLenum target, ArrayBuffer? data, GLenum usage);
|
||||
void bufferData(GLenum target, SharedArrayBuffer data, GLenum usage);
|
||||
void bufferSubData(GLenum target, GLintptr offset, ArrayBufferView data);
|
||||
void bufferSubData(GLenum target, GLintptr offset, SharedArrayBufferView data);
|
||||
void bufferSubData(GLenum target, GLintptr offset, ArrayBuffer? data);
|
||||
void bufferSubData(GLenum target, GLintptr offset, SharedArrayBuffer data);
|
||||
|
||||
[WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
|
||||
void clear(GLbitfield mask);
|
||||
|
@ -566,11 +570,11 @@ interface WebGLRenderingContext {
|
|||
|
||||
void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
|
||||
GLsizei width, GLsizei height, GLint border,
|
||||
ArrayBufferView data);
|
||||
(ArrayBufferView or SharedArrayBufferView) data);
|
||||
void compressedTexSubImage2D(GLenum target, GLint level,
|
||||
GLint xoffset, GLint yoffset,
|
||||
GLsizei width, GLsizei height, GLenum format,
|
||||
ArrayBufferView data);
|
||||
(ArrayBufferView or SharedArrayBufferView) data);
|
||||
|
||||
void copyTexImage2D(GLenum target, GLint level, GLenum internalformat,
|
||||
GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
|
@ -673,7 +677,7 @@ interface WebGLRenderingContext {
|
|||
|
||||
[Throws]
|
||||
void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, ArrayBufferView? pixels);
|
||||
GLenum format, GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
|
||||
|
||||
void renderbufferStorage(GLenum target, GLenum internalformat,
|
||||
GLsizei width, GLsizei height);
|
||||
|
@ -693,7 +697,7 @@ interface WebGLRenderingContext {
|
|||
[Throws]
|
||||
void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
||||
GLsizei width, GLsizei height, GLint border, GLenum format,
|
||||
GLenum type, ArrayBufferView? pixels);
|
||||
GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
|
||||
[Throws]
|
||||
void texImage2D(GLenum target, GLint level, GLenum internalformat,
|
||||
GLenum format, GLenum type, ImageData? pixels);
|
||||
|
@ -713,7 +717,7 @@ interface WebGLRenderingContext {
|
|||
[Throws]
|
||||
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, ArrayBufferView? pixels);
|
||||
GLenum format, GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
|
||||
[Throws]
|
||||
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
||||
GLenum format, GLenum type, ImageData? pixels);
|
||||
|
|
|
@ -338,8 +338,7 @@ public:
|
|||
xpcReport->Init(report.report(), report.message(),
|
||||
/* aIsChrome = */ false, /* aWindowID = */ 0);
|
||||
|
||||
nsRefPtr<AsyncErrorReporter> aer =
|
||||
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(), xpcReport);
|
||||
nsRefPtr<AsyncErrorReporter> aer = new AsyncErrorReporter(xpcReport);
|
||||
NS_DispatchToMainThread(aer);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
54851
|
||||
54852
|
||||
0/nm
|
||||
0th/pt
|
||||
1/n1
|
||||
|
@ -42923,6 +42923,7 @@ prekindergarten/SM
|
|||
prelacy/M
|
||||
prelate/SM
|
||||
prelim/SM
|
||||
preliminarily
|
||||
preliminary/SM
|
||||
preliterate
|
||||
prelude/MS
|
||||
|
|
|
@ -681,17 +681,19 @@ ClientLayerManager::SetIsFirstPaint()
|
|||
}
|
||||
|
||||
TextureClientPool*
|
||||
ClientLayerManager::GetTexturePool(SurfaceFormat aFormat)
|
||||
ClientLayerManager::GetTexturePool(SurfaceFormat aFormat, TextureFlags aFlags)
|
||||
{
|
||||
for (size_t i = 0; i < mTexturePools.Length(); i++) {
|
||||
if (mTexturePools[i]->GetFormat() == aFormat) {
|
||||
if (mTexturePools[i]->GetFormat() == aFormat &&
|
||||
mTexturePools[i]->GetFlags() == aFlags) {
|
||||
return mTexturePools[i];
|
||||
}
|
||||
}
|
||||
|
||||
mTexturePools.AppendElement(
|
||||
new TextureClientPool(aFormat, IntSize(gfxPlatform::GetPlatform()->GetTileWidth(),
|
||||
gfxPlatform::GetPlatform()->GetTileHeight()),
|
||||
new TextureClientPool(aFormat, aFlags,
|
||||
IntSize(gfxPlatform::GetPlatform()->GetTileWidth(),
|
||||
gfxPlatform::GetPlatform()->GetTileHeight()),
|
||||
gfxPrefs::LayersTileMaxPoolSize(),
|
||||
gfxPrefs::LayersTileShrinkPoolTimeout(),
|
||||
mForwarder));
|
||||
|
@ -701,17 +703,20 @@ ClientLayerManager::GetTexturePool(SurfaceFormat aFormat)
|
|||
|
||||
void
|
||||
ClientLayerManager::ReturnTextureClientDeferred(TextureClient& aClient) {
|
||||
GetTexturePool(aClient.GetFormat())->ReturnTextureClientDeferred(&aClient);
|
||||
GetTexturePool(aClient.GetFormat(),
|
||||
aClient.GetFlags())->ReturnTextureClientDeferred(&aClient);
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::ReturnTextureClient(TextureClient& aClient) {
|
||||
GetTexturePool(aClient.GetFormat())->ReturnTextureClient(&aClient);
|
||||
GetTexturePool(aClient.GetFormat(),
|
||||
aClient.GetFlags())->ReturnTextureClient(&aClient);
|
||||
}
|
||||
|
||||
void
|
||||
ClientLayerManager::ReportClientLost(TextureClient& aClient) {
|
||||
GetTexturePool(aClient.GetFormat())->ReportClientLost();
|
||||
GetTexturePool(aClient.GetFormat(),
|
||||
aClient.GetFlags())->ReportClientLost();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
|
||||
virtual void SetIsFirstPaint() override;
|
||||
|
||||
TextureClientPool* GetTexturePool(gfx::SurfaceFormat aFormat);
|
||||
TextureClientPool* GetTexturePool(gfx::SurfaceFormat aFormat, TextureFlags aFlags);
|
||||
|
||||
/// Utility methods for managing texture clients.
|
||||
void ReturnTextureClientDeferred(TextureClient& aClient);
|
||||
|
|
|
@ -110,7 +110,7 @@ ClientSingleTiledLayerBuffer::GetTextureClient()
|
|||
{
|
||||
return mCompositableClient->CreateTextureClientForDrawing(
|
||||
gfx::ImageFormatToSurfaceFormat(mFormat), mSize, BackendSelector::Content,
|
||||
TextureFlags::IMMEDIATE_UPLOAD);
|
||||
TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -24,11 +24,13 @@ ShrinkCallback(nsITimer *aTimer, void *aClosure)
|
|||
}
|
||||
|
||||
TextureClientPool::TextureClientPool(gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags,
|
||||
gfx::IntSize aSize,
|
||||
uint32_t aMaxTextureClients,
|
||||
uint32_t aShrinkTimeoutMsec,
|
||||
CompositableForwarder* aAllocator)
|
||||
: mFormat(aFormat)
|
||||
, mFlags(aFlags)
|
||||
, mSize(aSize)
|
||||
, mMaxTextureClients(aMaxTextureClients)
|
||||
, mShrinkTimeoutMsec(aShrinkTimeoutMsec)
|
||||
|
@ -108,10 +110,10 @@ TextureClientPool::GetTextureClient()
|
|||
// gfx::BackendType::NONE means use the content backend
|
||||
textureClient = TextureClient::CreateForRawBufferAccess(mSurfaceAllocator,
|
||||
mFormat, mSize, gfx::BackendType::NONE,
|
||||
TextureFlags::IMMEDIATE_UPLOAD, ALLOC_DEFAULT);
|
||||
mFlags, ALLOC_DEFAULT);
|
||||
} else {
|
||||
textureClient = TextureClient::CreateForDrawing(mSurfaceAllocator,
|
||||
mFormat, mSize, BackendSelector::Content, TextureFlags::IMMEDIATE_UPLOAD);
|
||||
mFormat, mSize, BackendSelector::Content, mFlags);
|
||||
}
|
||||
|
||||
mOutstandingClients++;
|
||||
|
|
|
@ -42,7 +42,9 @@ class TextureClientPool final : public TextureClientAllocator
|
|||
~TextureClientPool();
|
||||
|
||||
public:
|
||||
TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
|
||||
TextureClientPool(gfx::SurfaceFormat aFormat,
|
||||
TextureFlags aFlags,
|
||||
gfx::IntSize aSize,
|
||||
uint32_t aMaxTextureClients,
|
||||
uint32_t aShrinkTimeoutMsec,
|
||||
CompositableForwarder* aAllocator);
|
||||
|
@ -101,6 +103,7 @@ public:
|
|||
void Clear();
|
||||
|
||||
gfx::SurfaceFormat GetFormat() { return mFormat; }
|
||||
TextureFlags GetFlags() const { return mFlags; }
|
||||
|
||||
private:
|
||||
// The minimum size of the pool (the number of tiles that will be kept after
|
||||
|
@ -110,6 +113,9 @@ private:
|
|||
/// Format is passed to the TextureClient for buffer creation.
|
||||
gfx::SurfaceFormat mFormat;
|
||||
|
||||
/// Flags passed to the TextureClient for buffer creation.
|
||||
const TextureFlags mFlags;
|
||||
|
||||
/// The width and height of the tiles to be used.
|
||||
gfx::IntSize mSize;
|
||||
|
||||
|
|
|
@ -1240,7 +1240,8 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
|
|||
if (aTile.IsPlaceholderTile()) {
|
||||
aTile.SetLayerManager(mManager);
|
||||
aTile.SetTextureAllocator(mManager->GetTexturePool(
|
||||
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content)));
|
||||
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content),
|
||||
TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD));
|
||||
}
|
||||
aTile.SetCompositableClient(mCompositableClient);
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче