зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c. a=merge
This commit is contained in:
Коммит
012e20629b
|
@ -32,7 +32,7 @@
|
|||
#include "nsIWebProgress.h"
|
||||
#include "nsCoreUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
|
@ -457,8 +457,10 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
|
|||
if (IPCAccessibilityActive()) {
|
||||
DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
|
||||
docAcc->SetIPCDoc(ipcDoc);
|
||||
auto contentChild = dom::ContentChild::GetSingleton();
|
||||
contentChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
|
||||
nsCOMPtr<nsITabChild> tabChild =
|
||||
do_GetInterface(aDocument->GetDocShell());
|
||||
static_cast<TabChild*>(tabChild.get())->
|
||||
SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
|
||||
}
|
||||
} else {
|
||||
parentDocAcc->BindChildDocument(docAcc);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "TextLeafAccessible.h"
|
||||
#include "TextUpdater.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
|
@ -292,8 +292,10 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
|
|||
|
||||
ipcDoc = new DocAccessibleChild(childDoc);
|
||||
childDoc->SetIPCDoc(ipcDoc);
|
||||
auto contentChild = dom::ContentChild::GetSingleton();
|
||||
contentChild->SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id);
|
||||
nsCOMPtr<nsITabChild> tabChild =
|
||||
do_GetInterface(mDocument->DocumentNode()->GetDocShell());
|
||||
static_cast<TabChild*>(tabChild.get())->
|
||||
SendPDocAccessibleConstructor(ipcDoc, parentIPCDoc, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
{
|
||||
MOZ_COUNT_DTOR_INHERITED(DocAccessibleParent, ProxyAccessible);
|
||||
MOZ_ASSERT(mChildDocs.Length() == 0);
|
||||
MOZ_ASSERT(!mParentDoc);
|
||||
MOZ_ASSERT(!ParentDoc());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
void Unbind()
|
||||
{
|
||||
mParent = nullptr;
|
||||
mParentDoc->mChildDocs.RemoveElement(this);
|
||||
ParentDoc()->mChildDocs.RemoveElement(this);
|
||||
mParentDoc = nullptr;
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ public:
|
|||
* Return the main processes representation of the parent document (if any)
|
||||
* of the document this object represents.
|
||||
*/
|
||||
DocAccessibleParent* Parent() const { return mParentDoc; }
|
||||
DocAccessibleParent* ParentDoc() const { return mParentDoc; }
|
||||
|
||||
/*
|
||||
* Called when a document in a content process notifies the main process of a
|
||||
|
@ -85,7 +85,7 @@ public:
|
|||
*/
|
||||
void RemoveChildDoc(DocAccessibleParent* aChildDoc)
|
||||
{
|
||||
aChildDoc->mParent->SetChildDoc(nullptr);
|
||||
aChildDoc->Parent()->SetChildDoc(nullptr);
|
||||
mChildDocs.RemoveElement(aChildDoc);
|
||||
aChildDoc->mParentDoc = nullptr;
|
||||
MOZ_ASSERT(aChildDoc->mChildDocs.Length() == 0);
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PContent;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PBrowser;
|
||||
|
||||
include "mozilla/GfxMessageUtils.h";
|
||||
|
||||
|
@ -44,7 +45,7 @@ struct RelationTargets
|
|||
|
||||
prio(normal upto high) sync protocol PDocAccessible
|
||||
{
|
||||
manager PContent;
|
||||
manager PBrowser;
|
||||
|
||||
parent:
|
||||
__delete__();
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
ProxyAccessible* ChildAt(uint32_t aIdx) const { return mChildren[aIdx]; }
|
||||
|
||||
// XXX evaluate if this is fast enough.
|
||||
size_t IndexInParent() const { return mParent->mChildren.IndexOf(this); }
|
||||
size_t IndexInParent() const { return Parent()->mChildren.IndexOf(this); }
|
||||
int32_t IndexOfEmbeddedChild(const ProxyAccessible*);
|
||||
bool MustPruneChildren() const;
|
||||
|
||||
|
|
|
@ -174,10 +174,17 @@ this.EventManager.prototype = {
|
|||
let event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent);
|
||||
let state = Utils.getState(event);
|
||||
if (state.contains(States.CHECKED)) {
|
||||
this.present(
|
||||
Presentation.
|
||||
actionInvoked(aEvent.accessible,
|
||||
event.isEnabled ? 'check' : 'uncheck'));
|
||||
if (aEvent.accessible.role === Roles.SWITCH) {
|
||||
this.present(
|
||||
Presentation.
|
||||
actionInvoked(aEvent.accessible,
|
||||
event.isEnabled ? 'on' : 'off'));
|
||||
} else {
|
||||
this.present(
|
||||
Presentation.
|
||||
actionInvoked(aEvent.accessible,
|
||||
event.isEnabled ? 'check' : 'uncheck'));
|
||||
}
|
||||
} else if (state.contains(States.SELECTED)) {
|
||||
this.present(
|
||||
Presentation.
|
||||
|
|
|
@ -210,7 +210,7 @@ let OutputGenerator = {
|
|||
aOutput.push({string: 'textInputType_' + typeName});
|
||||
},
|
||||
|
||||
_addState: function _addState(aOutput, aState) {}, // jshint ignore:line
|
||||
_addState: function _addState(aOutput, aState, aRoleStr) {}, // jshint ignore:line
|
||||
|
||||
_addRole: function _addRole(aOutput, aRoleStr) {}, // jshint ignore:line
|
||||
|
||||
|
@ -252,6 +252,7 @@ let OutputGenerator = {
|
|||
'outlineitem': INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
|
||||
'pagetab': INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
|
||||
'graphic': INCLUDE_DESC,
|
||||
'switch': INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
|
||||
'pushbutton': INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
|
||||
'checkbutton': INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
|
||||
'radiobutton': INCLUDE_DESC | NAME_FROM_SUBTREE_RULE,
|
||||
|
@ -307,7 +308,7 @@ let OutputGenerator = {
|
|||
let output = [];
|
||||
|
||||
if (aFlags & INCLUDE_DESC) {
|
||||
this._addState(output, aState);
|
||||
this._addState(output, aState, aRoleStr);
|
||||
this._addType(output, aAccessible, aRoleStr);
|
||||
this._addRole(output, aRoleStr);
|
||||
}
|
||||
|
@ -413,13 +414,15 @@ let OutputGenerator = {
|
|||
* not.
|
||||
*/
|
||||
this.UtteranceGenerator = { // jshint ignore:line
|
||||
__proto__: OutputGenerator,
|
||||
__proto__: OutputGenerator, // jshint ignore:line
|
||||
|
||||
gActionMap: {
|
||||
jump: 'jumpAction',
|
||||
press: 'pressAction',
|
||||
check: 'checkAction',
|
||||
uncheck: 'uncheckAction',
|
||||
on: 'onAction',
|
||||
off: 'offAction',
|
||||
select: 'selectAction',
|
||||
unselect: 'unselectAction',
|
||||
open: 'openAction',
|
||||
|
@ -475,7 +478,7 @@ this.UtteranceGenerator = { // jshint ignore:line
|
|||
|
||||
objectOutputFunctions: {
|
||||
|
||||
__proto__: OutputGenerator.objectOutputFunctions,
|
||||
__proto__: OutputGenerator.objectOutputFunctions, // jshint ignore:line
|
||||
|
||||
defaultFunc: function defaultFunc() {
|
||||
return this.objectOutputFunctions._generateBaseOutput.apply(
|
||||
|
@ -597,7 +600,7 @@ this.UtteranceGenerator = { // jshint ignore:line
|
|||
aOutput.push({string: this._getOutputName(aRoleStr)});
|
||||
},
|
||||
|
||||
_addState: function _addState(aOutput, aState) {
|
||||
_addState: function _addState(aOutput, aState, aRoleStr) {
|
||||
|
||||
if (aState.contains(States.UNAVAILABLE)) {
|
||||
aOutput.push({string: 'stateUnavailable'});
|
||||
|
@ -613,8 +616,13 @@ this.UtteranceGenerator = { // jshint ignore:line
|
|||
// regardless of the utterance ordering preference.
|
||||
if ((Utils.AndroidSdkVersion < 16 || Utils.MozBuildApp === 'browser') &&
|
||||
aState.contains(States.CHECKABLE)) {
|
||||
let statetr = aState.contains(States.CHECKED) ?
|
||||
'stateChecked' : 'stateNotChecked';
|
||||
let checked = aState.contains(States.CHECKED);
|
||||
let statetr;
|
||||
if (aRoleStr === 'switch') {
|
||||
statetr = checked ? 'stateOn' : 'stateOff';
|
||||
} else {
|
||||
statetr = checked ? 'stateChecked' : 'stateNotChecked';
|
||||
}
|
||||
aOutput.push({string: statetr});
|
||||
}
|
||||
|
||||
|
@ -662,7 +670,7 @@ this.UtteranceGenerator = { // jshint ignore:line
|
|||
};
|
||||
|
||||
this.BrailleGenerator = { // jshint ignore:line
|
||||
__proto__: OutputGenerator,
|
||||
__proto__: OutputGenerator, // jshint ignore:line
|
||||
|
||||
genForContext: function genForContext(aContext) {
|
||||
let output = OutputGenerator.genForContext.apply(this, arguments);
|
||||
|
@ -699,7 +707,7 @@ this.BrailleGenerator = { // jshint ignore:line
|
|||
|
||||
objectOutputFunctions: {
|
||||
|
||||
__proto__: OutputGenerator.objectOutputFunctions,
|
||||
__proto__: OutputGenerator.objectOutputFunctions, // jshint ignore:line
|
||||
|
||||
defaultFunc: function defaultFunc() {
|
||||
return this.objectOutputFunctions._generateBaseOutput.apply(
|
||||
|
@ -760,13 +768,17 @@ this.BrailleGenerator = { // jshint ignore:line
|
|||
_useStateNotRole:
|
||||
function _useStateNotRole(aAccessible, aRoleStr, aState, aFlags) {
|
||||
let braille = [];
|
||||
this._addState(braille, aState, aAccessible.role);
|
||||
this._addState(braille, aState, aRoleStr);
|
||||
this._addName(braille, aAccessible, aFlags);
|
||||
this._addLandmark(braille, aAccessible);
|
||||
|
||||
return braille;
|
||||
},
|
||||
|
||||
switch: function braille_generator_object_output_functions_switch() {
|
||||
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||
},
|
||||
|
||||
checkbutton: function checkbutton() {
|
||||
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||
},
|
||||
|
@ -796,7 +808,7 @@ this.BrailleGenerator = { // jshint ignore:line
|
|||
aBraille.push({string: this._getOutputName(aRoleStr)});
|
||||
},
|
||||
|
||||
_addState: function _addState(aBraille, aState, aRole) {
|
||||
_addState: function _addState(aBraille, aState, aRoleStr) {
|
||||
if (aState.contains(States.CHECKABLE)) {
|
||||
aBraille.push({
|
||||
string: aState.contains(States.CHECKED) ?
|
||||
|
@ -804,7 +816,7 @@ this.BrailleGenerator = { // jshint ignore:line
|
|||
this._getOutputName('stateUnchecked')
|
||||
});
|
||||
}
|
||||
if (aRole === Roles.TOGGLE_BUTTON) {
|
||||
if (aRoleStr === 'toggle button') {
|
||||
aBraille.push({
|
||||
string: aState.contains(States.PRESSED) ?
|
||||
this._getOutputName('statePressed') :
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* global PrefCache, Roles, Prefilters, States, Filters, Utils,
|
||||
TraversalRules */
|
||||
TraversalRules, Components, XPCOMUtils */
|
||||
/* exported TraversalRules */
|
||||
|
||||
'use strict';
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['TraversalRules']; // jshint ignore:line
|
||||
|
||||
|
@ -103,7 +101,8 @@ var gSimpleTraversalRoles =
|
|||
Roles.GRID_CELL,
|
||||
Roles.COLUMNHEADER,
|
||||
Roles.ROWHEADER,
|
||||
Roles.STATUSBAR];
|
||||
Roles.STATUSBAR,
|
||||
Roles.SWITCH];
|
||||
|
||||
var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
|
||||
// An object is simple, if it either has a single child lineage,
|
||||
|
@ -240,7 +239,8 @@ this.TraversalRules = { // jshint ignore:line
|
|||
Roles.RADIO_MENU_ITEM,
|
||||
Roles.SLIDER,
|
||||
Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM]),
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH]),
|
||||
|
||||
Graphic: new BaseTraversalRule(
|
||||
[Roles.GRAPHIC],
|
||||
|
@ -302,7 +302,8 @@ this.TraversalRules = { // jshint ignore:line
|
|||
|
||||
Checkbox: new BaseTraversalRule(
|
||||
[Roles.CHECKBUTTON,
|
||||
Roles.CHECK_MENU_ITEM]),
|
||||
Roles.CHECK_MENU_ITEM,
|
||||
Roles.SWITCH /* A type of checkbox that represents on/off values */]),
|
||||
|
||||
_shouldSkipImage: function _shouldSkipImage(aAccessible) {
|
||||
if (gSkipEmptyImages.value && aAccessible.name === '') {
|
||||
|
|
|
@ -55,6 +55,12 @@
|
|||
'aria-valuetext', 'medium');
|
||||
}
|
||||
|
||||
function toggleLight() {
|
||||
var lightSwitch = document.getElementById('light');
|
||||
lightSwitch.setAttribute('aria-checked',
|
||||
lightSwitch.getAttribute('aria-checked') === 'true' ? 'false' : 'true');
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
#windows {
|
||||
|
@ -100,6 +106,7 @@
|
|||
</div>
|
||||
<button id="home">Home</button>
|
||||
<button id="fruit" aria-label="apple"></button>
|
||||
<span id="light" role="switch" aria-label="Light" aria-checked="false" onclick="toggleLight()"></span>
|
||||
<div id="live" aria-live="polite" aria-label="live">
|
||||
<div id="slider" role="slider" aria-label="slider" aria-valuemin="0"
|
||||
aria-valuemax="10" aria-valuenow="0"></div>
|
||||
|
|
|
@ -143,5 +143,7 @@
|
|||
</table>
|
||||
<div id="statusbar-1" role="status">Last sync:<span>2 days ago</span></div>
|
||||
<div aria-label="Last sync: 30min ago" id="statusbar-2" role="status"></div>
|
||||
|
||||
<span id="switch-1" role="switch" aria-checked="false" aria-label="Light switch"></span>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -617,6 +617,18 @@ function ExpectedCheckAction(aChecked, aOptions) {
|
|||
|
||||
ExpectedCheckAction.prototype = Object.create(ExpectedPresent.prototype);
|
||||
|
||||
function ExpectedSwitchAction(aSwitched, aOptions) {
|
||||
ExpectedPresent.call(this, {
|
||||
eventType: 'action',
|
||||
data: [{ string: aSwitched ? 'onAction' : 'offAction' }]
|
||||
}, [{
|
||||
eventType: AndroidEvent.VIEW_CLICKED,
|
||||
checked: aSwitched
|
||||
}], aOptions);
|
||||
}
|
||||
|
||||
ExpectedSwitchAction.prototype = Object.create(ExpectedPresent.prototype);
|
||||
|
||||
function ExpectedNameChange(aName, aOptions) {
|
||||
ExpectedPresent.call(this, {
|
||||
eventType: 'name-change',
|
||||
|
|
|
@ -58,10 +58,22 @@
|
|||
new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
|
||||
[ContentMessages.simpleMoveNext,
|
||||
new ExpectedCursorChange(['apple', {'string': 'pushbutton'}])],
|
||||
[ContentMessages.simpleMoveNext,
|
||||
new ExpectedCursorChange(['Light', {"string": "stateOff"}, {'string': 'switch'}])],
|
||||
// switch on
|
||||
[ContentMessages.activateCurrent(),
|
||||
new ExpectedClickAction({ no_android: true }),
|
||||
new ExpectedSwitchAction(true)],
|
||||
[ContentMessages.simpleMoveNext,
|
||||
new ExpectedCursorChange(['slider', '0', {'string': 'slider'}])],
|
||||
|
||||
// Simple traversal backward
|
||||
[ContentMessages.simpleMovePrevious,
|
||||
new ExpectedCursorChange(['Light', {"string": "stateOn"}, {'string': 'switch'}])],
|
||||
// switch off
|
||||
[ContentMessages.activateCurrent(),
|
||||
new ExpectedClickAction({ no_android: true }),
|
||||
new ExpectedSwitchAction(false)],
|
||||
[ContentMessages.simpleMovePrevious,
|
||||
new ExpectedCursorChange(['apple', {'string': 'pushbutton'}])],
|
||||
[ContentMessages.simpleMovePrevious,
|
||||
|
|
|
@ -488,6 +488,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
|||
expectedUtterance: [["Last sync: 30min ago"],
|
||||
["Last sync: 30min ago"]],
|
||||
expectedBraille: [["Last sync: 30min ago"], ["Last sync: 30min ago"]]
|
||||
}, {
|
||||
accOrElmOrID: "switch-1",
|
||||
expectedUtterance: [[{"string": "stateOn"}, {"string": "switch"},
|
||||
"Simple switch"], ["Simple switch", {"string": "stateOn"},
|
||||
{"string": "switch"}]],
|
||||
expectedBraille: [[{"string": "stateCheckedAbbr"}, "Simple switch"],
|
||||
["Simple switch", {"string": "stateCheckedAbbr"}]]
|
||||
}, {
|
||||
accOrElmOrID: "switch-2",
|
||||
expectedUtterance: [[{"string": "stateOff"},
|
||||
{"string": "switch"}, "Another switch"], ["Another switch",
|
||||
{"string": "stateOff"}, {"string": "switch"}]],
|
||||
expectedBraille: [
|
||||
[{"string": "stateUncheckedAbbr"}, "Another switch"],
|
||||
["Another switch", {"string": "stateUncheckedAbbr"}]]
|
||||
}];
|
||||
|
||||
// Test all possible utterance order preference values.
|
||||
|
@ -645,6 +660,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
|||
</select>
|
||||
<div id="statusbar-1" role="status">Last sync:<span>2 days ago</span></div>
|
||||
<div aria-label="Last sync: 30min ago" id="statusbar-2" role="status"></div>
|
||||
<span id="switch-1" role="switch" aria-label="Simple switch" aria-checked="true"></span>
|
||||
<span id="switch-2" role="switch" aria-label="Another switch" aria-checked="false"></span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
'select-1-1', 'select-1-2', 'checkbox-1-2',
|
||||
'select-1-3', 'input-1-5', 'button-1-3',
|
||||
'button-2-1', 'button-2-2', 'button-2-3',
|
||||
'button-2-4', 'checkbox-1-5']);
|
||||
'button-2-4', 'checkbox-1-5', 'switch-1']);
|
||||
|
||||
queueTraversalSequence(gQueue, docAcc, TraversalRules.Button, null,
|
||||
['button-1-1', 'button-1-2', 'button-1-3',
|
||||
|
@ -67,7 +67,8 @@
|
|||
['radio-1-1', 'radio-1-2']);
|
||||
|
||||
queueTraversalSequence(gQueue, docAcc, TraversalRules.Checkbox, null,
|
||||
['checkbox-1-1', 'checkbox-1-2', 'checkbox-1-5']);
|
||||
['checkbox-1-1', 'checkbox-1-2', 'checkbox-1-5',
|
||||
'switch-1']);
|
||||
|
||||
queueTraversalSequence(gQueue, docAcc, TraversalRules.Combobox, null,
|
||||
['select-1-1', 'select-1-2', 'select-1-3']);
|
||||
|
@ -122,7 +123,8 @@
|
|||
'1', 'Sunday', 'M', 'Week 1', '3', '4', '7', '2',
|
||||
'5 8', 'gridcell4', 'Just an innocuous separator',
|
||||
'Dirty Words', 'Meaning', 'Mud', 'Wet Dirt',
|
||||
'Dirt', 'Messy Stuff', 'statusbar-1', 'statusbar-2']);
|
||||
'Dirt', 'Messy Stuff', 'statusbar-1', 'statusbar-2',
|
||||
'switch-1']);
|
||||
|
||||
gQueue.invoke();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@ ia2AccessibleAction::QueryInterface(REFIID iid, void** ppv)
|
|||
|
||||
*ppv = nullptr;
|
||||
|
||||
if (IID_IAccessibleAction == iid) {
|
||||
if (IID_IAccessibleAction == iid &&
|
||||
!static_cast<AccessibleWrap*>(this)->IsProxy()) {
|
||||
*ppv = static_cast<IAccessibleAction*>(this);
|
||||
(reinterpret_cast<IUnknown*>(*ppv))->AddRef();
|
||||
return S_OK;
|
||||
|
|
|
@ -55,7 +55,9 @@ ia2AccessibleHyperlink::get_anchor(long aIndex, VARIANT* aAnchor)
|
|||
if (!anchor)
|
||||
return S_FALSE;
|
||||
|
||||
aAnchor->punkVal = static_cast<IAccessibleHyperlink*>(WrapperFor(anchor));
|
||||
IUnknown* tmp = static_cast<IAccessibleHyperlink*>(WrapperFor(anchor));
|
||||
tmp->AddRef();
|
||||
aAnchor->punkVal = tmp;
|
||||
aAnchor->vt = VT_UNKNOWN;
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -115,21 +115,17 @@ AccessibleWrap::QueryInterface(REFIID iid, void** ppv)
|
|||
|
||||
if (IID_IUnknown == iid)
|
||||
*ppv = static_cast<IAccessible*>(this);
|
||||
|
||||
if (!*ppv && IsProxy())
|
||||
return E_NOINTERFACE;
|
||||
|
||||
if (IID_IDispatch == iid || IID_IAccessible == iid)
|
||||
else if (IID_IDispatch == iid || IID_IAccessible == iid)
|
||||
*ppv = static_cast<IAccessible*>(this);
|
||||
else if (IID_IEnumVARIANT == iid) {
|
||||
else if (IID_IEnumVARIANT == iid && !IsProxy()) {
|
||||
// Don't support this interface for leaf elements.
|
||||
if (!HasChildren() || nsAccUtils::MustPrune(this))
|
||||
return E_NOINTERFACE;
|
||||
|
||||
*ppv = static_cast<IEnumVARIANT*>(new ChildrenEnumVariant(this));
|
||||
} else if (IID_IServiceProvider == iid)
|
||||
} else if (IID_IServiceProvider == iid && !IsProxy())
|
||||
*ppv = new ServiceProvider(this);
|
||||
else if (IID_ISimpleDOMNode == iid) {
|
||||
else if (IID_ISimpleDOMNode == iid && !IsProxy()) {
|
||||
if (IsDefunct() || (!HasOwnContent() && !IsDoc()))
|
||||
return E_NOINTERFACE;
|
||||
|
||||
|
@ -142,7 +138,7 @@ AccessibleWrap::QueryInterface(REFIID iid, void** ppv)
|
|||
return hr;
|
||||
}
|
||||
|
||||
if (nullptr == *ppv) {
|
||||
if (nullptr == *ppv && !IsProxy()) {
|
||||
HRESULT hr = ia2AccessibleComponent::QueryInterface(iid, ppv);
|
||||
if (SUCCEEDED(hr))
|
||||
return hr;
|
||||
|
@ -154,7 +150,7 @@ AccessibleWrap::QueryInterface(REFIID iid, void** ppv)
|
|||
return hr;
|
||||
}
|
||||
|
||||
if (nullptr == *ppv) {
|
||||
if (nullptr == *ppv && !IsProxy()) {
|
||||
HRESULT hr = ia2AccessibleValue::QueryInterface(iid, ppv);
|
||||
if (SUCCEEDED(hr))
|
||||
return hr;
|
||||
|
|
|
@ -350,6 +350,7 @@ var shell = {
|
|||
this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
|
||||
this.contentBrowser.addEventListener('mozbrowserselectionstatechanged', this, true);
|
||||
this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true);
|
||||
this.contentBrowser.addEventListener('mozbrowsercaretstatechanged', this);
|
||||
|
||||
CustomEventManager.init();
|
||||
WebappsHelper.init();
|
||||
|
@ -380,6 +381,7 @@ var shell = {
|
|||
this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
|
||||
this.contentBrowser.removeEventListener('mozbrowserselectionstatechanged', this, true);
|
||||
this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true);
|
||||
this.contentBrowser.removeEventListener('mozbrowsercaretstatechanged', this);
|
||||
ppmm.removeMessageListener("content-handler", this);
|
||||
|
||||
UserAgentOverrides.uninit();
|
||||
|
@ -490,6 +492,28 @@ var shell = {
|
|||
detail: data,
|
||||
});
|
||||
break;
|
||||
case 'mozbrowsercaretstatechanged':
|
||||
{
|
||||
let elt = evt.target;
|
||||
let win = elt.ownerDocument.defaultView;
|
||||
let offsetX = win.mozInnerScreenX - window.mozInnerScreenX;
|
||||
let offsetY = win.mozInnerScreenY - window.mozInnerScreenY;
|
||||
|
||||
let rect = elt.getBoundingClientRect();
|
||||
offsetX += rect.left;
|
||||
offsetY += rect.top;
|
||||
|
||||
let data = evt.detail;
|
||||
data.offsetX = offsetX;
|
||||
data.offsetY = offsetY;
|
||||
data.sendDoCommandMsg = null;
|
||||
|
||||
shell.sendChromeEvent({
|
||||
type: 'caretstatechanged',
|
||||
detail: data,
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'MozApplicationManifest':
|
||||
try {
|
||||
|
@ -718,6 +742,10 @@ var CustomEventManager = {
|
|||
case 'do-command':
|
||||
DoCommandHelper.handleEvent(detail.cmd);
|
||||
break;
|
||||
case 'copypaste-do-command':
|
||||
Services.obs.notifyObservers({ wrappedJSObject: shell.contentBrowser },
|
||||
'ask-children-to-execute-copypaste-command', detail.cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1198,9 +1198,10 @@ pref("security.sandbox.windows.log", false);
|
|||
// On windows these levels are:
|
||||
// 0 - no sandbox
|
||||
// 1 - sandbox with USER_NON_ADMIN access token level
|
||||
// 2 - a more strict sandbox, which might cause functionality issues
|
||||
// 2 - a more strict sandbox, which might cause functionality issues. This now
|
||||
// includes running at low integrity.
|
||||
// 3 - the strongest settings we seem to be able to use without breaking
|
||||
// everything, but will definitely cause some functionality restrictions
|
||||
// everything, but will probably cause some functionality restrictions
|
||||
pref("dom.ipc.plugins.sandbox-level.default", 0);
|
||||
|
||||
#if defined(MOZ_CONTENT_SANDBOX)
|
||||
|
|
|
@ -529,14 +529,10 @@ AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
|||
aCx ? aCx : FindJSContext(aGlobalObject))
|
||||
, ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ true)
|
||||
, mWebIDLCallerPrincipal(nullptr)
|
||||
, mIsMainThread(aIsMainThread)
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
MOZ_ASSERT_IF(!aCx, aIsMainThread); // cx is mandatory off-main-thread.
|
||||
MOZ_ASSERT_IF(aCx && aIsMainThread, aCx == FindJSContext(aGlobalObject));
|
||||
if (aIsMainThread) {
|
||||
nsContentUtils::EnterMicroTask();
|
||||
}
|
||||
|
||||
if (aIsMainThread && gRunToCompletionListeners > 0) {
|
||||
mDocShellEntryMonitor.emplace(cx(), aReason);
|
||||
|
@ -545,10 +541,6 @@ AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
|||
|
||||
AutoEntryScript::~AutoEntryScript()
|
||||
{
|
||||
if (mIsMainThread) {
|
||||
nsContentUtils::LeaveMicroTask();
|
||||
}
|
||||
|
||||
// GC when we pop a script entry point. This is a useful heuristic that helps
|
||||
// us out on certain (flawed) benchmarks like sunspider, because it lets us
|
||||
// avoid GCing during the timing loop.
|
||||
|
@ -590,7 +582,10 @@ AutoEntryScript::DocshellEntryMonitor::Entry(JSContext* aCx, JSFunction* aFuncti
|
|||
if (rootedFunction) {
|
||||
JS::Rooted<JSString*> displayId(aCx, JS_GetFunctionDisplayId(rootedFunction));
|
||||
if (displayId) {
|
||||
functionName.initTwoByte(aCx, displayId);
|
||||
if (!functionName.initTwoByte(aCx, displayId)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -375,8 +375,6 @@ private:
|
|||
friend nsIPrincipal* GetWebIDLCallerPrincipal();
|
||||
|
||||
Maybe<DocshellEntryMonitor> mDocShellEntryMonitor;
|
||||
|
||||
bool mIsMainThread;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -219,6 +219,7 @@ nsJSUtils::EvaluateString(JSContext* aCx,
|
|||
// aCompileOptions.noScriptRval set to true.
|
||||
aRetValue.setUndefined();
|
||||
|
||||
nsAutoMicroTask mt;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
|
|
|
@ -1210,14 +1210,18 @@ nsScriptLoader::ProcessPendingRequests()
|
|||
child->RemoveExecuteBlocker();
|
||||
}
|
||||
|
||||
if (mDocumentParsingDone && mDocument && !mParserBlockingRequest &&
|
||||
mNonAsyncExternalScriptInsertedRequests.isEmpty() &&
|
||||
mXSLTRequests.isEmpty() && mDeferRequests.isEmpty() &&
|
||||
MaybeRemovedDeferRequests()) {
|
||||
return ProcessPendingRequests();
|
||||
}
|
||||
|
||||
if (mDocumentParsingDone && mDocument &&
|
||||
!mParserBlockingRequest && mLoadingAsyncRequests.isEmpty() &&
|
||||
mLoadedAsyncRequests.isEmpty() &&
|
||||
mNonAsyncExternalScriptInsertedRequests.isEmpty() &&
|
||||
mXSLTRequests.isEmpty() && mDeferRequests.isEmpty()) {
|
||||
if (MaybeRemovedDeferRequests()) {
|
||||
return ProcessPendingRequests();
|
||||
}
|
||||
// No more pending scripts; time to unblock onload.
|
||||
// OK to unblock onload synchronously here, since callers must be
|
||||
// prepared for the world changing anyway.
|
||||
|
|
|
@ -50,7 +50,7 @@ nsStyleLinkElement::~nsStyleLinkElement()
|
|||
void
|
||||
nsStyleLinkElement::Unlink()
|
||||
{
|
||||
mStyleSheet = nullptr;
|
||||
nsStyleLinkElement::SetStyleSheet(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -211,7 +211,9 @@ nsresult TestDirectives() {
|
|||
{ "script-src 'nonce-correctscriptnonce'",
|
||||
"script-src 'nonce-correctscriptnonce'" },
|
||||
{ "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='",
|
||||
"script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" }
|
||||
"script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" },
|
||||
{ "referrer no-referrer",
|
||||
"referrer no-referrer" }
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
|
@ -273,7 +275,9 @@ nsresult TestIgnoreUpperLowerCasePolicies() {
|
|||
{ "script-src 'NoncE-NONCENEEDSTOBEUPPERCASE'",
|
||||
"script-src 'nonce-NONCENEEDSTOBEUPPERCASE'" },
|
||||
{ "script-src 'SHA256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='",
|
||||
"script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" }
|
||||
"script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" },
|
||||
{ "refERRer No-refeRRer",
|
||||
"referrer No-refeRRer" }
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
|
|
|
@ -1456,6 +1456,11 @@ DOMInterfaces = {
|
|||
'headerFile': 'WebGLExtensions.h'
|
||||
},
|
||||
|
||||
'WebGLExtensionDisjointTimerQuery': {
|
||||
'nativeType': 'mozilla::WebGLExtensionDisjointTimerQuery',
|
||||
'headerFile': 'WebGLExtensions.h'
|
||||
},
|
||||
|
||||
'WebGLFramebuffer': {
|
||||
'nativeType': 'mozilla::WebGLFramebuffer',
|
||||
'headerFile': 'WebGLFramebuffer.h'
|
||||
|
@ -1514,6 +1519,11 @@ DOMInterfaces = {
|
|||
'headerFile': 'WebGLTexture.h'
|
||||
},
|
||||
|
||||
'WebGLTimerQuery': {
|
||||
'nativeType': 'mozilla::WebGLTimerQuery',
|
||||
'headerFile': 'WebGLTimerQuery.h'
|
||||
},
|
||||
|
||||
'WebGLTransformFeedback': {
|
||||
'nativeType': 'mozilla::WebGLTransformFeedback',
|
||||
'headerFile': 'WebGLTransformFeedback.h'
|
||||
|
|
|
@ -62,6 +62,10 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
|||
, mExceptionHandling(aExceptionHandling)
|
||||
, mIsMainThread(NS_IsMainThread())
|
||||
{
|
||||
if (mIsMainThread) {
|
||||
nsContentUtils::EnterMicroTask();
|
||||
}
|
||||
|
||||
// Compute the caller's subject principal (if necessary) early, before we
|
||||
// do anything that might perturb the relevant state.
|
||||
nsIPrincipal* webIDLCallerPrincipal = nullptr;
|
||||
|
@ -302,6 +306,12 @@ CallbackObject::CallSetup::~CallSetup()
|
|||
|
||||
mAutoIncumbentScript.reset();
|
||||
mAutoEntryScript.reset();
|
||||
|
||||
// It is important that this is the last thing we do, after leaving the
|
||||
// compartment and undoing all our entry/incumbent script changes
|
||||
if (mIsMainThread) {
|
||||
nsContentUtils::LeaveMicroTask();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsISupports>
|
||||
|
|
|
@ -34,12 +34,15 @@ function isTopBrowserElement(docShell) {
|
|||
}
|
||||
|
||||
if (!('BrowserElementIsPreloaded' in this)) {
|
||||
if (isTopBrowserElement(docShell) &&
|
||||
Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
|
||||
try {
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
|
||||
} catch (e) {
|
||||
if (isTopBrowserElement(docShell)) {
|
||||
if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
|
||||
try {
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
|
||||
}
|
||||
|
||||
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") == 1) {
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
dump("###################################### BrowserElementCopyPaste.js loaded\n");
|
||||
|
||||
let CopyPasteAssistent = {
|
||||
COMMAND_MAP: {
|
||||
'cut': 'cmd_cut',
|
||||
'copy': 'cmd_copyAndCollapseToEnd',
|
||||
'paste': 'cmd_paste',
|
||||
'selectall': 'cmd_selectAll'
|
||||
},
|
||||
|
||||
init: function() {
|
||||
addEventListener('mozcaretstatechanged',
|
||||
this._caretStateChangedHandler.bind(this),
|
||||
/* useCapture = */ true,
|
||||
/* wantsUntrusted = */ false);
|
||||
addMessageListener('browser-element-api:call', this._browserAPIHandler.bind(this));
|
||||
},
|
||||
|
||||
_browserAPIHandler: function(e) {
|
||||
switch (e.data.msg_name) {
|
||||
case 'copypaste-do-command':
|
||||
if (this._isCommandEnabled(e.data.command)) {
|
||||
docShell.doCommand(COMMAND_MAP[e.data.command]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_isCommandEnabled: function(cmd) {
|
||||
let command = this.COMMAND_MAP[cmd];
|
||||
if (!command) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return docShell.isCommandEnabled(command);
|
||||
},
|
||||
|
||||
_caretStateChangedHandler: function(e) {
|
||||
e.stopPropagation();
|
||||
|
||||
let boundingClientRect = e.boundingClientRect;
|
||||
let canPaste = this._isCommandEnabled("paste");
|
||||
let zoomFactor = content.innerWidth == 0 ? 1 : content.screen.width / content.innerWidth;
|
||||
|
||||
let detail = {
|
||||
rect: {
|
||||
width: boundingClientRect ? boundingClientRect.width : 0,
|
||||
height: boundingClientRect ? boundingClientRect.height : 0,
|
||||
top: boundingClientRect ? boundingClientRect.top : 0,
|
||||
bottom: boundingClientRect ? boundingClientRect.bottom : 0,
|
||||
left: boundingClientRect ? boundingClientRect.left : 0,
|
||||
right: boundingClientRect ? boundingClientRect.right : 0,
|
||||
},
|
||||
commands: {
|
||||
canSelectAll: this._isCommandEnabled("selectall"),
|
||||
canCut: this._isCommandEnabled("cut"),
|
||||
canCopy: this._isCommandEnabled("copy"),
|
||||
canPaste: this._isCommandEnabled("paste"),
|
||||
},
|
||||
zoomFactor: zoomFactor,
|
||||
reason: e.reason,
|
||||
collapsed: e.collapsed,
|
||||
caretVisible: e.caretVisible,
|
||||
selectionVisible: e.selectionVisible
|
||||
};
|
||||
|
||||
// Get correct geometry information if we have nested iframe.
|
||||
let currentWindow = e.target.defaultView;
|
||||
while (currentWindow.realFrameElement) {
|
||||
let currentRect = currentWindow.realFrameElement.getBoundingClientRect();
|
||||
detail.rect.top += currentRect.top;
|
||||
detail.rect.bottom += currentRect.top;
|
||||
detail.rect.left += currentRect.left;
|
||||
detail.rect.right += currentRect.left;
|
||||
currentWindow = currentWindow.realFrameElement.ownerDocument.defaultView;
|
||||
}
|
||||
|
||||
sendAsyncMsg('caretstatechanged', detail);
|
||||
},
|
||||
};
|
||||
|
||||
CopyPasteAssistent.init();
|
|
@ -87,6 +87,7 @@ function BrowserElementParent() {
|
|||
|
||||
Services.obs.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
|
||||
Services.obs.addObserver(this, 'copypaste-docommand', /* ownsWeak = */ true);
|
||||
Services.obs.addObserver(this, 'ask-children-to-execute-copypaste-command', /* ownsWeak = */ true);
|
||||
}
|
||||
|
||||
BrowserElementParent.prototype = {
|
||||
|
@ -203,6 +204,7 @@ BrowserElementParent.prototype = {
|
|||
"got-set-input-method-active": this._gotDOMRequestResult,
|
||||
"selectionstatechanged": this._handleSelectionStateChanged,
|
||||
"scrollviewchange": this._handleScrollViewChange,
|
||||
"caretstatechanged": this._handleCaretStateChanged,
|
||||
};
|
||||
|
||||
let mmSecuritySensitiveCalls = {
|
||||
|
@ -438,6 +440,34 @@ BrowserElementParent.prototype = {
|
|||
this._frameElement.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
// Called when state of accessible caret in child has changed.
|
||||
// The fields of data is as following:
|
||||
// - rect: Contains bounding rectangle of selection, Include width, height,
|
||||
// top, bottom, left and right.
|
||||
// - commands: Describe what commands can be executed in child. Include canSelectAll,
|
||||
// canCut, canCopy and canPaste. For example: if we want to check if cut
|
||||
// command is available, using following code, if (data.commands.canCut) {}.
|
||||
// - zoomFactor: Current zoom factor in child frame.
|
||||
// - reason: The reason causes the state changed. Include "visibilitychange",
|
||||
// "updateposition", "longpressonemptycontent", "taponcaret", "presscaret",
|
||||
// "releasecaret".
|
||||
// - collapsed: Indicate current selection is collapsed or not.
|
||||
// - caretVisible: Indicate the caret visiibility.
|
||||
// - selectionVisible: Indicate current selection is visible or not.
|
||||
_handleCaretStateChanged: function(data) {
|
||||
let evt = this._createEvent('caretstatechanged', data.json,
|
||||
/* cancelable = */ false);
|
||||
|
||||
let self = this;
|
||||
function sendDoCommandMsg(cmd) {
|
||||
let data = { command: cmd };
|
||||
self._sendAsyncMsg('copypaste-do-command', data);
|
||||
}
|
||||
Cu.exportFunction(sendDoCommandMsg, evt.detail, { defineAs: 'sendDoCommandMsg' });
|
||||
|
||||
this._frameElement.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
_handleScrollViewChange: function(data) {
|
||||
let evt = this._createEvent("scrollviewchange", data.json,
|
||||
/* cancelable = */ false);
|
||||
|
@ -979,6 +1009,11 @@ BrowserElementParent.prototype = {
|
|||
this._sendAsyncMsg('do-command', { command: data });
|
||||
}
|
||||
break;
|
||||
case 'ask-children-to-execute-copypaste-command':
|
||||
if (this._isAlive() && this._frameElement == subject.wrappedJSObject) {
|
||||
this._sendAsyncMsg('copypaste-do-command', { command: data });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug('Unknown topic: ' + topic);
|
||||
break;
|
||||
|
|
|
@ -65,6 +65,10 @@ const browserElementTestHelpers = {
|
|||
this._setPref('selectioncaret.enabled', value);
|
||||
},
|
||||
|
||||
setAccessibleCaretEnabledPref: function(value) {
|
||||
this._setPref('layout.accessiblecaret.enabled', value);
|
||||
},
|
||||
|
||||
getOOPByDefaultPref: function() {
|
||||
return this._getBoolPref("dom.ipc.browser_frames.oop_by_default");
|
||||
},
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("untriaged");
|
||||
SimpleTest.requestLongerTimeout(2); // slow on android
|
||||
browserElementTestHelpers.setEnabledPref(true);
|
||||
browserElementTestHelpers.setSelectionChangeEnabledPref(true);
|
||||
browserElementTestHelpers.setSelectionChangeEnabledPref(false);
|
||||
browserElementTestHelpers.setAccessibleCaretEnabledPref(true);
|
||||
browserElementTestHelpers.addPermission();
|
||||
const { Services } = SpecialPowers.Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
|
@ -21,6 +23,7 @@ var defaultData;
|
|||
var pasteData;
|
||||
var focusScript;
|
||||
var createEmbededFrame = false;
|
||||
var testSelectionChange = false;
|
||||
|
||||
function copyToClipboard(str) {
|
||||
gTextarea.value = str;
|
||||
|
@ -89,6 +92,14 @@ function doCommand(cmd) {
|
|||
'copypaste-docommand', cmd);
|
||||
}
|
||||
|
||||
function rerunTest() {
|
||||
// clean up and run test again.
|
||||
document.body.removeChild(iframeOuter);
|
||||
document.body.removeChild(gTextarea);
|
||||
state = 0;
|
||||
runTest();
|
||||
}
|
||||
|
||||
function dispatchTest(e) {
|
||||
iframeInner.addEventListener("mozbrowserloadend", function onloadend2(e) {
|
||||
iframeInner.removeEventListener("mozbrowserloadend", onloadend2);
|
||||
|
@ -160,15 +171,23 @@ function dispatchTest(e) {
|
|||
break;
|
||||
default:
|
||||
if (createEmbededFrame || browserElementTestHelpers.getOOPByDefaultPref()) {
|
||||
SimpleTest.finish();
|
||||
if (testSelectionChange) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
} else {
|
||||
testSelectionChange = true;
|
||||
createEmbededFrame = false;
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{'set':
|
||||
[['selectioncaret.enabled', true],
|
||||
['layout.accessiblecaret.enabled', false]]},
|
||||
function() {
|
||||
rerunTest();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
createEmbededFrame = true;
|
||||
|
||||
// clean up and run test again.
|
||||
document.body.removeChild(iframeOuter);
|
||||
document.body.removeChild(gTextarea);
|
||||
state = 0;
|
||||
runTest();
|
||||
rerunTest();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -183,14 +202,17 @@ function isChildProcess() {
|
|||
function testSelectAll(e) {
|
||||
// Skip mozbrowser test if we're at child process.
|
||||
if (!isChildProcess()) {
|
||||
iframeOuter.addEventListener("mozbrowserselectionstatechanged", function selectchangeforselectall(e) {
|
||||
if (e.detail.states.indexOf('selectall') == 0) {
|
||||
iframeOuter.removeEventListener("mozbrowserselectionstatechanged", selectchangeforselectall, true);
|
||||
let eventName = testSelectionChange ? "mozbrowserselectionstatechanged" : "mozbrowsercaretstatechanged";
|
||||
iframeOuter.addEventListener(eventName, function selectchangeforselectall(e) {
|
||||
if (!e.detail.states || e.detail.states.indexOf('selectall') == 0) {
|
||||
iframeOuter.removeEventListener(eventName, selectchangeforselectall, true);
|
||||
ok(true, "got mozbrowserselectionstatechanged event." + stateMeaning);
|
||||
ok(e.detail, "event.detail is not null." + stateMeaning);
|
||||
ok(e.detail.width != 0, "event.detail.width is not zero" + stateMeaning);
|
||||
ok(e.detail.height != 0, "event.detail.height is not zero" + stateMeaning);
|
||||
ok(e.detail.states, "event.detail.state " + e.detail.states);
|
||||
if (testSelectionChange) {
|
||||
ok(e.detail.states, "event.detail.state " + e.detail.states);
|
||||
}
|
||||
SimpleTest.executeSoon(function() { testCopy1(e); });
|
||||
}
|
||||
}, true);
|
||||
|
|
|
@ -170,6 +170,7 @@ class WebGLContext
|
|||
friend class WebGLExtensionCompressedTexturePVRTC;
|
||||
friend class WebGLExtensionCompressedTextureS3TC;
|
||||
friend class WebGLExtensionDepthTexture;
|
||||
friend class WebGLExtensionDisjointTimerQuery;
|
||||
friend class WebGLExtensionDrawBuffers;
|
||||
friend class WebGLExtensionLoseContext;
|
||||
friend class WebGLExtensionVertexArray;
|
||||
|
@ -1601,6 +1602,7 @@ public:
|
|||
friend class WebGLSampler;
|
||||
friend class WebGLShader;
|
||||
friend class WebGLSync;
|
||||
friend class WebGLTimerQuery;
|
||||
friend class WebGLTransformFeedback;
|
||||
friend class WebGLUniformLocation;
|
||||
friend class WebGLVertexArray;
|
||||
|
|
|
@ -36,6 +36,7 @@ WebGLContext::GetExtensionString(WebGLExtensionID ext)
|
|||
WEBGL_EXTENSION_IDENTIFIER(EXT_shader_texture_lod)
|
||||
WEBGL_EXTENSION_IDENTIFIER(EXT_sRGB)
|
||||
WEBGL_EXTENSION_IDENTIFIER(EXT_texture_filter_anisotropic)
|
||||
WEBGL_EXTENSION_IDENTIFIER(EXT_disjoint_timer_query)
|
||||
WEBGL_EXTENSION_IDENTIFIER(OES_element_index_uint)
|
||||
WEBGL_EXTENSION_IDENTIFIER(OES_standard_derivatives)
|
||||
WEBGL_EXTENSION_IDENTIFIER(OES_texture_float)
|
||||
|
@ -179,13 +180,13 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
|
|||
if (Preferences::GetBool("webgl.enable-draft-extensions", false) ||
|
||||
IsWebGL2())
|
||||
{
|
||||
/* None for now.
|
||||
switch (ext) {
|
||||
case WebGLExtensionID::EXT_disjoint_timer_query:
|
||||
return WebGLExtensionDisjointTimerQuery::IsSupported(this);
|
||||
default:
|
||||
// For warnings-as-errors.
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -312,6 +313,9 @@ WebGLContext::EnableExtension(WebGLExtensionID ext)
|
|||
case WebGLExtensionID::EXT_color_buffer_half_float:
|
||||
obj = new WebGLExtensionColorBufferHalfFloat(this);
|
||||
break;
|
||||
case WebGLExtensionID::EXT_disjoint_timer_query:
|
||||
obj = new WebGLExtensionDisjointTimerQuery(this);
|
||||
break;
|
||||
case WebGLExtensionID::EXT_frag_depth:
|
||||
obj = new WebGLExtensionFragDepth(this);
|
||||
break;
|
||||
|
|
|
@ -177,6 +177,21 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
|||
}
|
||||
}
|
||||
|
||||
if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
|
||||
if (pname == LOCAL_GL_TIMESTAMP_EXT) {
|
||||
GLuint64 iv = 0;
|
||||
gl->fGetInteger64v(pname, (GLint64*) &iv);
|
||||
return JS::NumberValue(uint64_t(iv));
|
||||
} else if (pname == LOCAL_GL_GPU_DISJOINT_EXT) {
|
||||
// When disjoint isn't supported, leave as false.
|
||||
realGLboolean disjoint = 0;
|
||||
if (gl->IsExtensionSupported(gl::GLContext::EXT_disjoint_timer_query)) {
|
||||
gl->fGetBooleanv(pname, &disjoint);
|
||||
}
|
||||
return JS::BooleanValue(bool(disjoint));
|
||||
}
|
||||
}
|
||||
|
||||
if (IsWebGL2()) {
|
||||
switch (pname) {
|
||||
case LOCAL_GL_MAX_SAMPLES:
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLExtensions.h"
|
||||
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "GLContext.h"
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLTimerQuery.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
WebGLExtensionDisjointTimerQuery::WebGLExtensionDisjointTimerQuery(WebGLContext* webgl)
|
||||
: WebGLExtensionBase(webgl)
|
||||
, mActiveQuery(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
|
||||
}
|
||||
|
||||
WebGLExtensionDisjointTimerQuery::~WebGLExtensionDisjointTimerQuery()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<WebGLTimerQuery>
|
||||
WebGLExtensionDisjointTimerQuery::CreateQueryEXT()
|
||||
{
|
||||
if (mIsLost)
|
||||
return nullptr;
|
||||
|
||||
nsRefPtr<WebGLTimerQuery> query = WebGLTimerQuery::Create(mContext);
|
||||
return query.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLExtensionDisjointTimerQuery::DeleteQueryEXT(WebGLTimerQuery* query)
|
||||
{
|
||||
if (mIsLost)
|
||||
return;
|
||||
|
||||
if (!mContext->ValidateObject("deleteQueryEXT", query))
|
||||
return;
|
||||
|
||||
query->RequestDelete();
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLExtensionDisjointTimerQuery::IsQueryEXT(WebGLTimerQuery* query)
|
||||
{
|
||||
if (!query)
|
||||
return false;
|
||||
|
||||
if (!mContext->ValidateObjectAllowDeleted("isQueryEXT", query))
|
||||
return false;
|
||||
|
||||
if (query->IsDeleted())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLExtensionDisjointTimerQuery::BeginQueryEXT(GLenum target,
|
||||
WebGLTimerQuery* query)
|
||||
{
|
||||
if (mIsLost)
|
||||
return;
|
||||
|
||||
if (!mContext->ValidateObject("beginQueryEXT", query))
|
||||
return;
|
||||
|
||||
if (query->HasEverBeenBound() && query->Target() != target) {
|
||||
mContext->ErrorInvalidOperation("beginQueryEXT: Query is already bound"
|
||||
" to a different target.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (target != LOCAL_GL_TIME_ELAPSED_EXT) {
|
||||
mContext->ErrorInvalidEnumInfo("beginQueryEXT: Can only begin on target"
|
||||
" TIME_ELAPSED_EXT.", target);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mActiveQuery) {
|
||||
mContext->ErrorInvalidOperation("beginQueryEXT: A query is already"
|
||||
" active.");
|
||||
return;
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
gl::GLContext* gl = mContext->GL();
|
||||
gl->fBeginQuery(target, query->GLName());
|
||||
query->BindTo(LOCAL_GL_TIME_ELAPSED_EXT);
|
||||
mActiveQuery = query;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLExtensionDisjointTimerQuery::EndQueryEXT(GLenum target)
|
||||
{
|
||||
if (mIsLost)
|
||||
return;
|
||||
|
||||
if (target != LOCAL_GL_TIME_ELAPSED_EXT) {
|
||||
mContext->ErrorInvalidEnumInfo("endQueryEXT: Can only end on"
|
||||
" TIME_ELAPSED_EXT.", target);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mActiveQuery) {
|
||||
mContext->ErrorInvalidOperation("endQueryEXT: A query is not active.");
|
||||
return;
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->GL()->fEndQuery(target);
|
||||
mActiveQuery = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLExtensionDisjointTimerQuery::QueryCounterEXT(WebGLTimerQuery* query,
|
||||
GLenum target)
|
||||
{
|
||||
if (mIsLost)
|
||||
return;
|
||||
|
||||
if (!mContext->ValidateObject("queryCounterEXT", query))
|
||||
return;
|
||||
|
||||
if (target != LOCAL_GL_TIMESTAMP_EXT) {
|
||||
mContext->ErrorInvalidEnumInfo("queryCounterEXT: requires"
|
||||
" TIMESTAMP_EXT.", target);
|
||||
return;
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->GL()->fQueryCounter(query->GLName(), target);
|
||||
query->BindTo(LOCAL_GL_TIMESTAMP_EXT);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLExtensionDisjointTimerQuery::GetQueryEXT(JSContext* cx, GLenum target,
|
||||
GLenum pname,
|
||||
JS::MutableHandle<JS::Value> retval)
|
||||
{
|
||||
if (mIsLost)
|
||||
return;
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
switch (pname) {
|
||||
case LOCAL_GL_CURRENT_QUERY_EXT: {
|
||||
if (target != LOCAL_GL_TIME_ELAPSED_EXT) {
|
||||
mContext->ErrorInvalidEnumInfo("getQueryEXT: Invalid query target.",
|
||||
target);
|
||||
return;
|
||||
}
|
||||
if (mActiveQuery) {
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
dom::GetOrCreateDOMReflector(cx, mActiveQuery.get(), &v);
|
||||
retval.set(v);
|
||||
} else {
|
||||
retval.set(JS::NullValue());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LOCAL_GL_QUERY_COUNTER_BITS_EXT: {
|
||||
if (target != LOCAL_GL_TIME_ELAPSED_EXT &&
|
||||
target != LOCAL_GL_TIMESTAMP_EXT) {
|
||||
mContext->ErrorInvalidEnumInfo("getQueryEXT: Invalid query target.",
|
||||
target);
|
||||
return;
|
||||
}
|
||||
GLint bits = 0;
|
||||
mContext->GL()->fGetQueryiv(target, pname, &bits);
|
||||
retval.set(JS::Int32Value(int32_t(bits)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mContext->ErrorInvalidEnumInfo("getQueryEXT: Invalid query property.",
|
||||
pname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLExtensionDisjointTimerQuery::GetQueryObjectEXT(JSContext* cx,
|
||||
WebGLTimerQuery* query,
|
||||
GLenum pname,
|
||||
JS::MutableHandle<JS::Value> retval)
|
||||
{
|
||||
if (mIsLost)
|
||||
return;
|
||||
|
||||
if (!mContext->ValidateObject("getQueryObjectEXT", query))
|
||||
return;
|
||||
|
||||
if (query == mActiveQuery.get()) {
|
||||
mContext->ErrorInvalidOperation("getQueryObjectEXT: Query must not be"
|
||||
" active.");
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
// XXX: Note that the query result *may change* within the same task!
|
||||
// This does not follow the specification, which states that all calls
|
||||
// checking query results must return the same value until the event loop
|
||||
// is empty.
|
||||
switch (pname) {
|
||||
case LOCAL_GL_QUERY_RESULT_EXT: {
|
||||
GLuint64 result = 0;
|
||||
mContext->GL()->fGetQueryObjectui64v(query->GLName(),
|
||||
LOCAL_GL_QUERY_RESULT_EXT,
|
||||
&result);
|
||||
retval.set(JS::NumberValue(result));
|
||||
break;
|
||||
}
|
||||
case LOCAL_GL_QUERY_RESULT_AVAILABLE_EXT: {
|
||||
GLuint avail = 0;
|
||||
mContext->GL()->fGetQueryObjectuiv(query->GLName(),
|
||||
LOCAL_GL_QUERY_RESULT_AVAILABLE_EXT,
|
||||
&avail);
|
||||
retval.set(JS::BooleanValue(bool(avail)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mContext->ErrorInvalidEnumInfo("getQueryObjectEXT: Invalid query"
|
||||
" property.", pname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLExtensionDisjointTimerQuery::IsSupported(const WebGLContext* webgl)
|
||||
{
|
||||
webgl->MakeContextCurrent();
|
||||
gl::GLContext* gl = webgl->GL();
|
||||
return gl->IsSupported(gl::GLFeature::query_objects) &&
|
||||
gl->IsSupported(gl::GLFeature::get_query_object_i64v) &&
|
||||
gl->IsSupported(gl::GLFeature::query_counter); // provides GL_TIMESTAMP
|
||||
}
|
||||
|
||||
|
||||
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionDisjointTimerQuery)
|
||||
|
||||
} // namespace mozilla
|
|
@ -16,6 +16,8 @@ namespace mozilla {
|
|||
|
||||
class WebGLContext;
|
||||
class WebGLShader;
|
||||
class WebGLQuery;
|
||||
class WebGLTimerQuery;
|
||||
class WebGLVertexArray;
|
||||
|
||||
class WebGLExtensionBase
|
||||
|
@ -329,6 +331,36 @@ public:
|
|||
DECL_WEBGL_EXTENSION_GOOP
|
||||
};
|
||||
|
||||
class WebGLExtensionDisjointTimerQuery
|
||||
: public WebGLExtensionBase
|
||||
{
|
||||
public:
|
||||
explicit WebGLExtensionDisjointTimerQuery(WebGLContext* webgl);
|
||||
virtual ~WebGLExtensionDisjointTimerQuery();
|
||||
|
||||
already_AddRefed<WebGLTimerQuery> CreateQueryEXT();
|
||||
void DeleteQueryEXT(WebGLTimerQuery* query);
|
||||
bool IsQueryEXT(WebGLTimerQuery* query);
|
||||
void BeginQueryEXT(GLenum target, WebGLTimerQuery* query);
|
||||
void EndQueryEXT(GLenum target);
|
||||
void QueryCounterEXT(WebGLTimerQuery* query, GLenum target);
|
||||
void GetQueryEXT(JSContext *cx, GLenum target, GLenum pname,
|
||||
JS::MutableHandle<JS::Value> retval);
|
||||
void GetQueryObjectEXT(JSContext *cx, WebGLTimerQuery* query,
|
||||
GLenum pname,
|
||||
JS::MutableHandle<JS::Value> retval);
|
||||
|
||||
static bool IsSupported(const WebGLContext*);
|
||||
|
||||
DECL_WEBGL_EXTENSION_GOOP
|
||||
|
||||
private:
|
||||
/**
|
||||
* An active TIME_ELAPSED query participating in a begin/end block.
|
||||
*/
|
||||
WebGLRefPtr<WebGLTimerQuery> mActiveQuery;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // WEBGL_EXTENSIONS_H_
|
||||
|
|
|
@ -454,4 +454,10 @@ STRONG_GLENUM_BEGIN(BufferBinding)
|
|||
STRONG_GLENUM_VALUE(TRANSFORM_FEEDBACK_BUFFER), // 0x8C8E
|
||||
STRONG_GLENUM_END(BufferBinding)
|
||||
|
||||
STRONG_GLENUM_BEGIN(QueryBinding)
|
||||
STRONG_GLENUM_VALUE(NONE),
|
||||
STRONG_GLENUM_VALUE(TIME_ELAPSED_EXT),
|
||||
STRONG_GLENUM_VALUE(TIMESTAMP_EXT),
|
||||
STRONG_GLENUM_END(QueryBinding)
|
||||
|
||||
#endif // WEBGL_STRONG_TYPES_H_
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLTimerQuery.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "WebGLContext.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
JSObject*
|
||||
WebGLTimerQuery::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return dom::WebGLTimerQueryBinding::Wrap(cx, this, aGivenProto);
|
||||
}
|
||||
|
||||
WebGLTimerQuery::WebGLTimerQuery(WebGLContext* webgl, GLuint aName)
|
||||
: WebGLBindableName<QueryBinding>(aName)
|
||||
, WebGLContextBoundObject(webgl)
|
||||
{
|
||||
}
|
||||
|
||||
WebGLTimerQuery*
|
||||
WebGLTimerQuery::Create(WebGLContext* webgl)
|
||||
{
|
||||
GLuint name = 0;
|
||||
webgl->MakeContextCurrent();
|
||||
webgl->gl->fGenQueries(1, &name);
|
||||
return new WebGLTimerQuery(webgl, name);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTimerQuery::Delete()
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
mContext->gl->fDeleteQueries(1, &mGLName);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTimerQuery)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTimerQuery, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTimerQuery, Release)
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef WEBGL_TIMER_QUERY_H_
|
||||
#define WEBGL_TIMER_QUERY_H_
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "WebGLObjectModel.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLTimerQuery final
|
||||
: public nsWrapperCache
|
||||
, public WebGLBindableName<QueryBinding>
|
||||
, public WebGLRefCountedObject<WebGLTimerQuery>
|
||||
, public WebGLContextBoundObject
|
||||
{
|
||||
public:
|
||||
static WebGLTimerQuery* Create(WebGLContext* webgl);
|
||||
|
||||
// WebGLRefCountedObject
|
||||
void Delete();
|
||||
|
||||
// nsWrapperCache
|
||||
WebGLContext* GetParentObject() const {
|
||||
return Context();
|
||||
}
|
||||
|
||||
// NS
|
||||
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTimerQuery)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTimerQuery)
|
||||
|
||||
private:
|
||||
explicit WebGLTimerQuery(WebGLContext* webgl, GLuint aName);
|
||||
~WebGLTimerQuery() {
|
||||
DeleteOnce();
|
||||
}
|
||||
|
||||
friend class WebGLExtensionDisjointTimerQuery;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // WEBGL_TIMER_QUERY_H_
|
|
@ -151,6 +151,7 @@ enum class WebGLExtensionID : uint8_t {
|
|||
EXT_sRGB,
|
||||
EXT_shader_texture_lod,
|
||||
EXT_texture_filter_anisotropic,
|
||||
EXT_disjoint_timer_query,
|
||||
OES_element_index_uint,
|
||||
OES_standard_derivatives,
|
||||
OES_texture_float,
|
||||
|
|
|
@ -93,6 +93,7 @@ UNIFIED_SOURCES += [
|
|||
'WebGLExtensionDebugRendererInfo.cpp',
|
||||
'WebGLExtensionDebugShaders.cpp',
|
||||
'WebGLExtensionDepthTexture.cpp',
|
||||
'WebGLExtensionDisjointTimerQuery.cpp',
|
||||
'WebGLExtensionDrawBuffers.cpp',
|
||||
'WebGLExtensionElementIndexUint.cpp',
|
||||
'WebGLExtensionFragDepth.cpp',
|
||||
|
@ -120,6 +121,7 @@ UNIFIED_SOURCES += [
|
|||
'WebGLSync.cpp',
|
||||
'WebGLTexelConversions.cpp',
|
||||
'WebGLTexture.cpp',
|
||||
'WebGLTimerQuery.cpp',
|
||||
'WebGLTransformFeedback.cpp',
|
||||
'WebGLUniformLocation.cpp',
|
||||
'WebGLValidateStrings.cpp',
|
||||
|
|
|
@ -30,6 +30,7 @@ skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests
|
|||
# We haven't cleaned up the Try results yet, but let's get this on the books first.
|
||||
[webgl-mochitest/test_webgl_conformance.html]
|
||||
skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
|
||||
[webgl-mochitest/test_webgl_disjoint_timer_query.html]
|
||||
[webgl-mochitest/test_webgl_request_context.html]
|
||||
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
|
||||
[webgl-mochitest/test_webgl_request_mismatch.html]
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<title>WebGL test: Test EXT_disjoint_timer_query.</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
<script src="webgl-util.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="c"></canvas>
|
||||
|
||||
<script>
|
||||
|
||||
function doTest() {
|
||||
var gl = WebGLUtil.getWebGL('c', true);
|
||||
var ext = gl.getExtension('EXT_disjoint_timer_query');
|
||||
if (!ext) {
|
||||
ok(true, "EXT_disjoint_timer_query may be unsupported.");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
ok(!ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT),
|
||||
"No query is active initially.");
|
||||
|
||||
var elapsedQuery = ext.createQueryEXT();
|
||||
ok(elapsedQuery, "Query creation works.");
|
||||
ok(ext.isQueryEXT(elapsedQuery), "New query is valid after creation.");
|
||||
|
||||
ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, elapsedQuery);
|
||||
is(ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT), elapsedQuery,
|
||||
"Query is active after beginQueryEXT.");
|
||||
ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
|
||||
gl.flush();
|
||||
|
||||
ok(!ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.CURRENT_QUERY_EXT),
|
||||
"Query is inactive after endQueryEXT.");
|
||||
ok(ext.getQueryObjectEXT(elapsedQuery, ext.QUERY_RESULT_AVAILABLE_EXT),
|
||||
"Time elapsed query is available immediately after flush.");
|
||||
|
||||
ext.deleteQueryEXT(elapsedQuery);
|
||||
ok(!ext.isQueryEXT(elapsedQuery), "Query is no longer valid after deletion.");
|
||||
|
||||
var timestampQuery = ext.createQueryEXT();
|
||||
ext.queryCounterEXT(timestampQuery, ext.TIMESTAMP_EXT);
|
||||
gl.flush();
|
||||
ok(ext.getQueryObjectEXT(timestampQuery, ext.QUERY_RESULT_AVAILABLE_EXT),
|
||||
"Timestamp query should be available immediately after flush.");
|
||||
|
||||
ok(ext.getQueryEXT(ext.TIMESTAMP_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30,
|
||||
"Timestamp must be at least 30 bits to hold at least 1 second of timing.");
|
||||
ok(ext.getQueryEXT(ext.TIME_ELAPSED_EXT, ext.QUERY_COUNTER_BITS_EXT) >= 30,
|
||||
"Time elapsed must be at least 30 bits to hold at least 1 second of timing.");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [['webgl.enable-draft-extensions', true]]}, doTest);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -20,9 +20,6 @@
|
|||
#include "TabChild.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "mozilla/a11y/DocAccessibleChild.h"
|
||||
#endif
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ProcessHangMonitorIPC.h"
|
||||
|
@ -857,22 +854,6 @@ ContentChild::InitXPCOM()
|
|||
InitOnContentProcessCreated();
|
||||
}
|
||||
|
||||
a11y::PDocAccessibleChild*
|
||||
ContentChild::AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&)
|
||||
{
|
||||
MOZ_ASSERT(false, "should never call this!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPDocAccessibleChild(a11y::PDocAccessibleChild* aChild)
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
PMemoryReportRequestChild*
|
||||
ContentChild::AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
|
||||
const bool &aAnonymize,
|
||||
|
|
|
@ -446,8 +446,6 @@ public:
|
|||
const ContentParentId& aCpID,
|
||||
const bool& aIsForApp,
|
||||
const bool& aIsForBrowser) override;
|
||||
virtual PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) override;
|
||||
virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) override;
|
||||
|
||||
void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
|
||||
|
||||
|
|
|
@ -32,10 +32,6 @@
|
|||
#include "IHistory.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "mozIApplication.h"
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "mozilla/a11y/DocAccessibleParent.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#endif
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/docshell/OfflineCacheUpdateParent.h"
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
|
@ -3155,42 +3151,6 @@ ContentParent::Observe(nsISupports* aSubject,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
a11y::PDocAccessibleParent*
|
||||
ContentParent::AllocPDocAccessibleParent(PDocAccessibleParent* aParent, const uint64_t&)
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
return new a11y::DocAccessibleParent();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPDocAccessibleParent(PDocAccessibleParent* aParent)
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
delete static_cast<a11y::DocAccessibleParent*>(aParent);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc, PDocAccessibleParent* aParentDoc, const uint64_t& aParentID)
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
auto doc = static_cast<a11y::DocAccessibleParent*>(aDoc);
|
||||
if (aParentDoc) {
|
||||
MOZ_ASSERT(aParentID);
|
||||
auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
|
||||
return parentDoc->AddChildDoc(doc, aParentID);
|
||||
} else {
|
||||
MOZ_ASSERT(!aParentID);
|
||||
a11y::DocManager::RemoteDocAdded(doc);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
PGMPServiceParent*
|
||||
ContentParent::AllocPGMPServiceParent(mozilla::ipc::Transport* aTransport,
|
||||
base::ProcessId aOtherProcess)
|
||||
|
|
|
@ -845,11 +845,6 @@ private:
|
|||
int32_t* aSliceRefCnt,
|
||||
bool* aResult) override;
|
||||
|
||||
virtual PDocAccessibleParent* AllocPDocAccessibleParent(PDocAccessibleParent*, const uint64_t&) override;
|
||||
virtual bool DeallocPDocAccessibleParent(PDocAccessibleParent*) override;
|
||||
virtual bool RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
|
||||
PDocAccessibleParent* aParentDoc, const uint64_t& aParentID) override;
|
||||
|
||||
virtual PWebrtcGlobalParent* AllocPWebrtcGlobalParent() override;
|
||||
virtual bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent *aActor) override;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ include protocol PBlob;
|
|||
include protocol PColorPicker;
|
||||
include protocol PContent;
|
||||
include protocol PContentBridge;
|
||||
include protocol PDocAccessible;
|
||||
include protocol PDocumentRenderer;
|
||||
include protocol PFilePicker;
|
||||
include protocol PIndexedDBPermissionRequest;
|
||||
|
@ -98,6 +99,7 @@ prio(normal upto urgent) sync protocol PBrowser
|
|||
manager PContent or PContentBridge;
|
||||
|
||||
manages PColorPicker;
|
||||
manages PDocAccessible;
|
||||
manages PDocumentRenderer;
|
||||
manages PFilePicker;
|
||||
manages PIndexedDBPermissionRequest;
|
||||
|
@ -115,6 +117,14 @@ both:
|
|||
PRenderFrame();
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Tell the parent process a new accessible document has been created.
|
||||
* aParentDoc is the accessible document it was created in if any, and
|
||||
* aParentAcc is the id of the accessible in that document the new document
|
||||
* is a child of.
|
||||
*/
|
||||
PDocAccessible(nullable PDocAccessible aParentDoc, uint64_t aParentAcc);
|
||||
|
||||
/*
|
||||
* Creates a new remoted nsIWidget connection for windowed plugins
|
||||
* in e10s mode. This is always initiated from the child in response
|
||||
|
|
|
@ -15,7 +15,6 @@ include protocol PContentBridge;
|
|||
include protocol PContentPermissionRequest;
|
||||
include protocol PCycleCollectWithLogs;
|
||||
include protocol PCrashReporter;
|
||||
include protocol PDocAccessible;
|
||||
include protocol PPSMContentDownloader;
|
||||
include protocol PExternalHelperApp;
|
||||
include protocol PDeviceStorageRequest;
|
||||
|
@ -422,7 +421,6 @@ prio(normal upto urgent) sync protocol PContent
|
|||
manages PContentPermissionRequest;
|
||||
manages PCrashReporter;
|
||||
manages PCycleCollectWithLogs;
|
||||
manages PDocAccessible;
|
||||
manages PDeviceStorageRequest;
|
||||
manages PFileSystemRequest;
|
||||
manages PPSMContentDownloader;
|
||||
|
@ -654,14 +652,6 @@ child:
|
|||
*/
|
||||
GamepadUpdate(GamepadChangeEvent aGamepadEvent);
|
||||
parent:
|
||||
/**
|
||||
* Tell the parent process a new accessible document has been created.
|
||||
* aParentDoc is the accessible document it was created in if any, and
|
||||
* aParentAcc is the id of the accessible in that document the new document
|
||||
* is a child of.
|
||||
*/
|
||||
PDocAccessible(nullable PDocAccessible aParentDoc, uint64_t aParentAcc);
|
||||
|
||||
/**
|
||||
* Tell the content process some attributes of itself. This is
|
||||
* among the first information queried by content processes after
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
#include "TabChild.h"
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "mozilla/a11y/DocAccessibleChild.h"
|
||||
#endif
|
||||
#include "Layers.h"
|
||||
#include "ContentChild.h"
|
||||
#include "TabParent.h"
|
||||
|
@ -202,6 +205,28 @@ NS_INTERFACE_MAP_END
|
|||
NS_IMPL_CYCLE_COLLECTING_ADDREF(TabChildBase)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(TabChildBase)
|
||||
|
||||
// For the root frame, Screen and ParentLayer pixels are interchangeable.
|
||||
// nsViewportInfo stores zoom values as CSSToScreenScale (because it's a
|
||||
// data structure specific to the root frame), while FrameMetrics and
|
||||
// ZoomConstraints store zoom values as CSSToParentLayerScale (because they
|
||||
// are not specific to the root frame). We define convenience functions for
|
||||
// converting between the two. As the name suggests, they should only be used
|
||||
// when dealing with the root frame!
|
||||
CSSToScreenScale ConvertScaleForRoot(CSSToParentLayerScale aScale)
|
||||
{
|
||||
return ViewTargetAs<ScreenPixel>(aScale, PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||
}
|
||||
CSSToParentLayerScale ConvertScaleForRoot(CSSToScreenScale aScale)
|
||||
{
|
||||
return ViewTargetAs<ParentLayerPixel>(aScale, PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||
}
|
||||
|
||||
// Calculate the scale needed to fit the given viewport into the given display.
|
||||
CSSToScreenScale CalculateIntrinsicScale(const ScreenIntSize& aDisplaySize, const CSSSize& aViewportSize)
|
||||
{
|
||||
return MaxScaleRatio(ScreenSize(aDisplaySize), aViewportSize);
|
||||
}
|
||||
|
||||
void
|
||||
TabChildBase::InitializeRootMetrics()
|
||||
{
|
||||
|
@ -212,7 +237,8 @@ TabChildBase::InitializeRootMetrics()
|
|||
mLastRootMetrics.SetCompositionBounds(ParentLayerRect(
|
||||
ParentLayerPoint(),
|
||||
ParentLayerSize(ViewAs<ParentLayerPixel>(mInnerSize, PixelCastJustification::ScreenIsParentLayerForRoot))));
|
||||
mLastRootMetrics.SetZoom(CSSToParentLayerScale2D(mLastRootMetrics.CalculateIntrinsicScale()));
|
||||
mLastRootMetrics.SetZoom(CSSToParentLayerScale2D(
|
||||
ConvertScaleForRoot(CalculateIntrinsicScale(mInnerSize, kDefaultViewportSize))));
|
||||
mLastRootMetrics.SetDevPixelsPerCSSPixel(WebWidget()->GetDefaultScale());
|
||||
// We use ParentLayerToLayerScale(1) below in order to turn the
|
||||
// async zoom amount into the gecko zoom amount.
|
||||
|
@ -264,20 +290,6 @@ TabChildBase::GetPageSize(nsCOMPtr<nsIDocument> aDocument, const CSSSize& aViewp
|
|||
std::max(htmlHeight, bodyHeight));
|
||||
}
|
||||
|
||||
// For the root frame, Screen and ParentLayer pixels are interchangeable.
|
||||
// nsViewportInfo stores zoom values as CSSToScreenScale (because it's a
|
||||
// data structure specific to the root frame), while FrameMetrics and
|
||||
// ZoomConstraints store zoom values as CSSToParentLayerScale (because they
|
||||
// are not specific to the root frame). We define convenience functions for
|
||||
// converting between the two. As the name suggests, they should only be used
|
||||
// when dealing with the root frame!
|
||||
CSSToScreenScale ConvertScaleForRoot(CSSToParentLayerScale aScale) {
|
||||
return ViewTargetAs<ScreenPixel>(aScale, PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||
}
|
||||
CSSToParentLayerScale ConvertScaleForRoot(CSSToScreenScale aScale) {
|
||||
return ViewTargetAs<ParentLayerPixel>(aScale, PixelCastJustification::ScreenIsParentLayerForRoot);
|
||||
}
|
||||
|
||||
bool
|
||||
TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
|
||||
{
|
||||
|
@ -383,10 +395,9 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
|
|||
// In all of these cases, we maintain how much actual content is visible
|
||||
// within the screen width. Note that "actual content" may be different with
|
||||
// respect to CSS pixels because of the CSS viewport size changing.
|
||||
float oldIntrinsicScale =
|
||||
std::max(oldScreenSize.width / oldBrowserSize.width,
|
||||
oldScreenSize.height / oldBrowserSize.height);
|
||||
metrics.ZoomBy(metrics.CalculateIntrinsicScale().scale / oldIntrinsicScale);
|
||||
CSSToScreenScale oldIntrinsicScale = CalculateIntrinsicScale(oldScreenSize, oldBrowserSize);
|
||||
CSSToScreenScale newIntrinsicScale = CalculateIntrinsicScale(mInnerSize, viewport);
|
||||
metrics.ZoomBy(newIntrinsicScale.scale / oldIntrinsicScale.scale);
|
||||
|
||||
// Changing the zoom when we're not doing a first paint will get ignored
|
||||
// by AsyncPanZoomController and causes a blurry flash.
|
||||
|
@ -399,7 +410,7 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
|
|||
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
||||
// it to the intrinsic scale.
|
||||
if (viewportInfo.GetDefaultZoom().scale < 0.01f) {
|
||||
viewportInfo.SetDefaultZoom(ConvertScaleForRoot(metrics.CalculateIntrinsicScale()));
|
||||
viewportInfo.SetDefaultZoom(newIntrinsicScale);
|
||||
}
|
||||
|
||||
CSSToScreenScale defaultZoom = viewportInfo.GetDefaultZoom();
|
||||
|
@ -2572,6 +2583,22 @@ TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event)
|
|||
return true;
|
||||
}
|
||||
|
||||
a11y::PDocAccessibleChild*
|
||||
TabChild::AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&)
|
||||
{
|
||||
MOZ_ASSERT(false, "should never call this!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::DeallocPDocAccessibleChild(a11y::PDocAccessibleChild* aChild)
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
delete static_cast<mozilla::a11y::DocAccessibleChild*>(aChild);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
PDocumentRendererChild*
|
||||
TabChild::AllocPDocumentRendererChild(const nsRect& documentRect,
|
||||
const mozilla::gfx::Matrix& transform,
|
||||
|
|
|
@ -391,6 +391,10 @@ public:
|
|||
|
||||
virtual bool RecvSwappedWithOtherRemoteLoader() override;
|
||||
|
||||
virtual PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*,
|
||||
const uint64_t&)
|
||||
override;
|
||||
virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) override;
|
||||
virtual PDocumentRendererChild*
|
||||
AllocPDocumentRendererChild(const nsRect& documentRect, const gfx::Matrix& transform,
|
||||
const nsString& bgcolor,
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
#include "AppProcessChecker.h"
|
||||
#include "mozIApplication.h"
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "mozilla/a11y/DocAccessibleParent.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#endif
|
||||
#include "mozilla/BrowserElementParent.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
|
@ -1107,6 +1111,45 @@ TabParent::SetDocShell(nsIDocShell *aDocShell)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
a11y::PDocAccessibleParent*
|
||||
TabParent::AllocPDocAccessibleParent(PDocAccessibleParent* aParent,
|
||||
const uint64_t&)
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
return new a11y::DocAccessibleParent();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::DeallocPDocAccessibleParent(PDocAccessibleParent* aParent)
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
delete static_cast<a11y::DocAccessibleParent*>(aParent);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
|
||||
PDocAccessibleParent* aParentDoc,
|
||||
const uint64_t& aParentID)
|
||||
{
|
||||
#ifdef ACCESSIBILITY
|
||||
auto doc = static_cast<a11y::DocAccessibleParent*>(aDoc);
|
||||
if (aParentDoc) {
|
||||
MOZ_ASSERT(aParentID);
|
||||
auto parentDoc = static_cast<a11y::DocAccessibleParent*>(aParentDoc);
|
||||
return parentDoc->AddChildDoc(doc, aParentID);
|
||||
} else {
|
||||
MOZ_ASSERT(!aParentID);
|
||||
a11y::DocManager::RemoteDocAdded(doc);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
PDocumentRendererParent*
|
||||
TabParent::AllocPDocumentRendererParent(const nsRect& documentRect,
|
||||
const gfx::Matrix& transform,
|
||||
|
|
|
@ -247,6 +247,14 @@ public:
|
|||
AllocPColorPickerParent(const nsString& aTitle, const nsString& aInitialColor) override;
|
||||
virtual bool DeallocPColorPickerParent(PColorPickerParent* aColorPicker) override;
|
||||
|
||||
virtual PDocAccessibleParent*
|
||||
AllocPDocAccessibleParent(PDocAccessibleParent*, const uint64_t&) override;
|
||||
virtual bool DeallocPDocAccessibleParent(PDocAccessibleParent*) override;
|
||||
virtual bool
|
||||
RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
|
||||
PDocAccessibleParent* aParentDoc,
|
||||
const uint64_t& aParentID) override;
|
||||
|
||||
void LoadURL(nsIURI* aURI);
|
||||
// XXX/cjones: it's not clear what we gain by hiding these
|
||||
// message-sending functions under a layer of indirection and
|
||||
|
|
|
@ -7,6 +7,7 @@ toolkit.jar:
|
|||
content/global/remote-test-ipc.js (remote-test.js)
|
||||
content/global/BrowserElementChild.js (../browser-element/BrowserElementChild.js)
|
||||
content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
|
||||
content/global/BrowserElementCopyPaste.js (../browser-element/BrowserElementCopyPaste.js)
|
||||
content/global/BrowserElementPanning.js (../browser-element/BrowserElementPanning.js)
|
||||
* content/global/BrowserElementPanningAPZDisabled.js (../browser-element/BrowserElementPanningAPZDisabled.js)
|
||||
content/global/manifestMessages.js (manifestMessages.js)
|
||||
|
|
|
@ -103,6 +103,7 @@ const BrowserElementIsPreloaded = true;
|
|||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js", global);
|
||||
}
|
||||
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js", global);
|
||||
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js", global);
|
||||
|
||||
Services.io.getProtocolHandler("app");
|
||||
|
|
|
@ -32,6 +32,7 @@ outlineitem = outline item
|
|||
pagetab = tab
|
||||
propertypage = property page
|
||||
graphic = graphic
|
||||
switch = switch
|
||||
pushbutton = button
|
||||
checkbutton = check button
|
||||
radiobutton = radio button
|
||||
|
@ -127,6 +128,8 @@ jumpAction = jumped
|
|||
pressAction = pressed
|
||||
checkAction = checked
|
||||
uncheckAction = unchecked
|
||||
onAction = on
|
||||
offAction = off
|
||||
selectAction = selected
|
||||
unselectAction = unselected
|
||||
openAction = opened
|
||||
|
@ -151,7 +154,9 @@ tabReload = reloading
|
|||
|
||||
# Object states
|
||||
stateChecked = checked
|
||||
stateOn = on
|
||||
stateNotChecked = not checked
|
||||
stateOff = off
|
||||
statePressed = pressed
|
||||
# No string for a not pressed toggle button
|
||||
stateExpanded = expanded
|
||||
|
|
|
@ -124,6 +124,8 @@ using dom::OwningBooleanOrMediaTrackConstraints;
|
|||
using dom::SupportedAudioConstraints;
|
||||
using dom::SupportedVideoConstraints;
|
||||
|
||||
static Atomic<bool> sInShutdown;
|
||||
|
||||
static bool
|
||||
HostInDomain(const nsCString &aHost, const nsCString &aPattern)
|
||||
{
|
||||
|
@ -946,7 +948,7 @@ public:
|
|||
nsRefPtr<nsDOMUserMediaStream> trackunion =
|
||||
nsDOMUserMediaStream::CreateTrackUnionStream(window, mListener,
|
||||
mAudioSource, mVideoSource);
|
||||
if (!trackunion) {
|
||||
if (!trackunion || sInShutdown) {
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
|
||||
LOG(("Returning error for getUserMedia() - no stream"));
|
||||
|
||||
|
@ -954,7 +956,8 @@ public:
|
|||
if (window) {
|
||||
nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
|
||||
NS_LITERAL_STRING("InternalError"),
|
||||
NS_LITERAL_STRING("No stream."));
|
||||
sInShutdown ? NS_LITERAL_STRING("In shutdown") :
|
||||
NS_LITERAL_STRING("No stream."));
|
||||
onFailure->OnError(error);
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -1009,7 +1012,7 @@ public:
|
|||
// because that can take a while.
|
||||
// Pass ownership of trackunion to the MediaOperationTask
|
||||
// to ensure it's kept alive until the MediaOperationTask runs (at least).
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
MediaManager::PostTask(FROM_HERE,
|
||||
new MediaOperationTask(MEDIA_START, mListener, trackunion,
|
||||
tracksAvailableCallback,
|
||||
mAudioSource, mVideoSource, false, mWindowID,
|
||||
|
@ -1612,7 +1615,7 @@ MediaManager::Get() {
|
|||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(sSingleton, "xpcom-shutdown", false);
|
||||
obs->AddObserver(sSingleton, "xpcom-will-shutdown", false);
|
||||
obs->AddObserver(sSingleton, "getUserMedia:response:allow", false);
|
||||
obs->AddObserver(sSingleton, "getUserMedia:response:deny", false);
|
||||
obs->AddObserver(sSingleton, "getUserMedia:revoke", false);
|
||||
|
@ -1644,12 +1647,17 @@ MediaManager::GetInstance()
|
|||
}
|
||||
|
||||
/* static */
|
||||
MessageLoop*
|
||||
MediaManager::GetMessageLoop()
|
||||
void
|
||||
MediaManager::PostTask(const tracked_objects::Location& from_here, Task* task)
|
||||
{
|
||||
if (sInShutdown) {
|
||||
// Can't safely delete task here since it may have items with specific
|
||||
// thread-release requirements.
|
||||
return;
|
||||
}
|
||||
NS_ASSERTION(Get(), "MediaManager singleton?");
|
||||
NS_ASSERTION(Get()->mMediaThread, "No thread yet");
|
||||
return Get()->mMediaThread->message_loop();
|
||||
Get()->mMediaThread->message_loop()->PostTask(from_here, task);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
|
@ -1783,6 +1791,9 @@ MediaManager::GetUserMedia(
|
|||
task = new GetUserMediaTask(c, onSuccess.forget(),
|
||||
onFailure.forget(), windowID, listener, mPrefs);
|
||||
}
|
||||
if (sInShutdown) {
|
||||
return task->Denied(NS_LITERAL_STRING("In shutdown"));
|
||||
}
|
||||
|
||||
nsIURI* docURI = aWindow->GetDocumentURI();
|
||||
|
||||
|
@ -1889,7 +1900,7 @@ MediaManager::GetUserMedia(
|
|||
// XXX No full support for picture in Desktop yet (needs proper UI)
|
||||
if (privileged ||
|
||||
(fake && !Preferences::GetBool("media.navigator.permission.fake"))) {
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE, task.forget());
|
||||
MediaManager::PostTask(FROM_HERE, task.forget());
|
||||
} else {
|
||||
bool isHTTPS = false;
|
||||
if (docURI) {
|
||||
|
@ -1974,6 +1985,7 @@ MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
|
|||
|
||||
NS_ENSURE_TRUE(aOnFailure, NS_ERROR_NULL_POINTER);
|
||||
NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
|
||||
NS_ENSURE_TRUE(!sInShutdown, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
|
||||
|
@ -1994,7 +2006,7 @@ MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
|
|||
nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
|
||||
inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
|
||||
}
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
MediaManager::PostTask(FROM_HERE,
|
||||
new GetUserMediaDevicesTask(
|
||||
aConstraints, onSuccess.forget(), onFailure.forget(),
|
||||
(aInnerWindowID ? aInnerWindowID : aWindow->WindowID()),
|
||||
|
@ -2027,6 +2039,7 @@ MediaManager::GetBackend(uint64_t aWindowId)
|
|||
// This IS called off main-thread.
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mBackend) {
|
||||
MOZ_RELEASE_ASSERT(!sInShutdown); // we should never create a new backend in shutdown
|
||||
#if defined(MOZ_WEBRTC)
|
||||
mBackend = new MediaEngineWebRTC(mPrefs);
|
||||
#else
|
||||
|
@ -2202,8 +2215,10 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
LOG(("%s: %dx%d @%dfps (min %d)", __FUNCTION__,
|
||||
mPrefs.mWidth, mPrefs.mHeight, mPrefs.mFPS, mPrefs.mMinFPS));
|
||||
}
|
||||
} else if (!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
obs->RemoveObserver(this, "xpcom-shutdown");
|
||||
} else if (!strcmp(aTopic, "xpcom-will-shutdown")) {
|
||||
sInShutdown = true;
|
||||
|
||||
obs->RemoveObserver(this, "xpcom-will-shutdown");
|
||||
obs->RemoveObserver(this, "getUserMedia:response:allow");
|
||||
obs->RemoveObserver(this, "getUserMedia:response:deny");
|
||||
obs->RemoveObserver(this, "getUserMedia:revoke");
|
||||
|
@ -2216,22 +2231,43 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
prefs->RemoveObserver("media.navigator.video.default_minfps", this);
|
||||
}
|
||||
|
||||
// Close off any remaining active windows.
|
||||
GetActiveWindows()->Clear();
|
||||
mActiveCallbacks.Clear();
|
||||
mCallIds.Clear();
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mBackend) {
|
||||
mBackend->Shutdown(); // ok to invoke multiple times
|
||||
}
|
||||
}
|
||||
|
||||
// Because mMediaThread is not an nsThread, we must dispatch to it so it can
|
||||
// clean up BackgroundChild. Continue stopping thread once this is done.
|
||||
|
||||
class ShutdownTask : public Task
|
||||
{
|
||||
public:
|
||||
explicit ShutdownTask(nsRunnable* aReply) : mReply(aReply) {}
|
||||
ShutdownTask(TemporaryRef<MediaEngine> aBackend,
|
||||
nsRunnable* aReply)
|
||||
: mReply(aReply)
|
||||
, mBackend(aBackend) {}
|
||||
private:
|
||||
virtual void
|
||||
Run()
|
||||
{
|
||||
LOG(("MediaManager Thread Shutdown"));
|
||||
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
||||
mozilla::ipc::BackgroundChild::CloseForCurrentThread();
|
||||
NS_DispatchToMainThread(mReply);
|
||||
// must explicitly do this before dispatching the reply, since the reply may kill us with Stop()
|
||||
mBackend = nullptr; // last reference, will invoke Shutdown() again
|
||||
|
||||
if (NS_FAILED(NS_DispatchToMainThread(mReply))) {
|
||||
LOG(("Will leak thread: DispatchToMainthread of reply runnable failed in MediaManager shutdown"));
|
||||
}
|
||||
}
|
||||
nsRefPtr<nsRunnable> mReply;
|
||||
RefPtr<MediaEngine> mBackend;
|
||||
};
|
||||
|
||||
// Post ShutdownTask to execute on mMediaThread and pass in a lambda
|
||||
|
@ -2241,20 +2277,25 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
// This is safe since this is guaranteed to be here since sSingleton isn't
|
||||
// cleared until the lambda function clears it.
|
||||
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE, new ShutdownTask(
|
||||
media::NewRunnableFrom([this]() mutable {
|
||||
// Close off any remaining active windows.
|
||||
// note that this == sSingleton
|
||||
nsRefPtr<MediaManager> that(sSingleton);
|
||||
// Release the backend (and call Shutdown()) from within the MediaManager thread
|
||||
RefPtr<MediaEngine> temp;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
GetActiveWindows()->Clear();
|
||||
mActiveCallbacks.Clear();
|
||||
mCallIds.Clear();
|
||||
LOG(("Releasing MediaManager singleton and thread"));
|
||||
// Note: won't be released immediately as the Observer has a ref to us
|
||||
sSingleton = nullptr;
|
||||
temp = mBackend.forget();
|
||||
}
|
||||
// Don't use MediaManager::PostTask() because we're sInShutdown=true here!
|
||||
mMediaThread->message_loop()->PostTask(FROM_HERE, new ShutdownTask(
|
||||
temp.forget(),
|
||||
media::NewRunnableFrom([this, that]() mutable {
|
||||
LOG(("MediaManager shutdown lambda running, releasing MediaManager singleton and thread"));
|
||||
if (mMediaThread) {
|
||||
mMediaThread->Stop();
|
||||
}
|
||||
mBackend = nullptr;
|
||||
// we hold a ref to 'that' which is the same as sSingleton
|
||||
sSingleton = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
})));
|
||||
return NS_OK;
|
||||
|
@ -2299,8 +2340,11 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
}
|
||||
}
|
||||
|
||||
if (sInShutdown) {
|
||||
return task->Denied(NS_LITERAL_STRING("In shutdown"));
|
||||
}
|
||||
// Reuse the same thread to save memory.
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE, task.forget());
|
||||
MediaManager::PostTask(FROM_HERE, task.forget());
|
||||
return NS_OK;
|
||||
|
||||
} else if (!strcmp(aTopic, "getUserMedia:response:deny")) {
|
||||
|
@ -2498,8 +2542,7 @@ MediaManager::SanitizeDeviceIds(int64_t aSinceWhen)
|
|||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
LOG(("%s: sinceWhen = %llu", __FUNCTION__, aSinceWhen));
|
||||
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
new SanitizeDeviceIdsTask(aSinceWhen));
|
||||
MediaManager::PostTask(FROM_HERE, new SanitizeDeviceIdsTask(aSinceWhen));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2616,12 +2659,10 @@ GetUserMediaCallbackMediaStreamListener::AudioConfig(bool aEchoOn,
|
|||
{
|
||||
if (mAudioSource) {
|
||||
#ifdef MOZ_WEBRTC
|
||||
mMediaThread->message_loop()->PostTask(FROM_HERE,
|
||||
MediaManager::PostTask(FROM_HERE,
|
||||
NewRunnableMethod(mAudioSource.get(), &MediaEngineSource::Config,
|
||||
aEchoOn, aEcho, aAgcOn, aAGC, aNoiseOn,
|
||||
aNoise, aPlayoutDelay));
|
||||
#else
|
||||
unused << mMediaThread;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -2634,7 +2675,7 @@ GetUserMediaCallbackMediaStreamListener::Invalidate()
|
|||
// thread.
|
||||
// Pass a ref to us (which is threadsafe) so it can query us for the
|
||||
// source stream info.
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
MediaManager::PostTask(FROM_HERE,
|
||||
new MediaOperationTask(MEDIA_STOP,
|
||||
this, nullptr, nullptr,
|
||||
mAudioSource, mVideoSource,
|
||||
|
@ -2652,7 +2693,7 @@ GetUserMediaCallbackMediaStreamListener::StopScreenWindowSharing()
|
|||
mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Application ||
|
||||
mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Window)) {
|
||||
// Stop the whole stream if there's no audio; just the video track if we have both
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
MediaManager::PostTask(FROM_HERE,
|
||||
new MediaOperationTask(mAudioSource ? MEDIA_STOP_TRACK : MEDIA_STOP,
|
||||
this, nullptr, nullptr,
|
||||
nullptr, mVideoSource,
|
||||
|
@ -2670,7 +2711,7 @@ GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aID, bool aIsAudio)
|
|||
{
|
||||
// XXX to support multiple tracks of a type in a stream, this should key off
|
||||
// the TrackID and not just the type
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
MediaManager::PostTask(FROM_HERE,
|
||||
new MediaOperationTask(MEDIA_STOP_TRACK,
|
||||
this, nullptr, nullptr,
|
||||
aIsAudio ? mAudioSource : nullptr,
|
||||
|
@ -2696,7 +2737,7 @@ void
|
|||
GetUserMediaCallbackMediaStreamListener::NotifyDirectListeners(MediaStreamGraph* aGraph,
|
||||
bool aHasListeners)
|
||||
{
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
MediaManager::PostTask(FROM_HERE,
|
||||
new MediaOperationTask(MEDIA_DIRECT_LISTENERS,
|
||||
this, nullptr, nullptr,
|
||||
mAudioSource, mVideoSource,
|
||||
|
|
|
@ -71,6 +71,7 @@ public:
|
|||
|
||||
~GetUserMediaCallbackMediaStreamListener()
|
||||
{
|
||||
unused << mMediaThread;
|
||||
// It's OK to release mStream on any thread; they have thread-safe
|
||||
// refcounts.
|
||||
}
|
||||
|
@ -514,7 +515,7 @@ public:
|
|||
// from MediaManager thread.
|
||||
static MediaManager* Get();
|
||||
static MediaManager* GetIfExists();
|
||||
static MessageLoop* GetMessageLoop();
|
||||
static void PostTask(const tracked_objects::Location& from_here, Task* task);
|
||||
#ifdef DEBUG
|
||||
static bool IsInMediaThread();
|
||||
#endif
|
||||
|
|
|
@ -67,7 +67,7 @@ GMPChild::~GMPChild()
|
|||
|
||||
static bool
|
||||
GetFileBase(const std::string& aPluginPath,
|
||||
#if defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
nsCOMPtr<nsIFile>& aLibDirectory,
|
||||
#endif
|
||||
nsCOMPtr<nsIFile>& aFileBase,
|
||||
|
@ -81,7 +81,7 @@ GetFileBase(const std::string& aPluginPath,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
if (NS_FAILED(aFileBase->Clone(getter_AddRefs(aLibDirectory)))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -107,13 +107,13 @@ GetFileBase(const std::string& aPluginPath,
|
|||
|
||||
static bool
|
||||
GetPluginFile(const std::string& aPluginPath,
|
||||
#if defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
nsCOMPtr<nsIFile>& aLibDirectory,
|
||||
#endif
|
||||
nsCOMPtr<nsIFile>& aLibFile)
|
||||
{
|
||||
nsAutoString baseName;
|
||||
#ifdef XP_MACOSX
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
GetFileBase(aPluginPath, aLibDirectory, aLibFile, baseName);
|
||||
#else
|
||||
GetFileBase(aPluginPath, aLibFile, baseName);
|
||||
|
@ -592,7 +592,7 @@ GetPluginVoucherFile(const std::string& aPluginPath,
|
|||
nsCOMPtr<nsIFile>& aOutVoucherFile)
|
||||
{
|
||||
nsAutoString baseName;
|
||||
#if defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
nsCOMPtr<nsIFile> libDir;
|
||||
GetFileBase(aPluginPath, aOutVoucherFile, libDir, baseName);
|
||||
#else
|
||||
|
|
|
@ -80,7 +80,7 @@ public:
|
|||
|
||||
virtual void Shutdown() override;
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
virtual void SetSandboxInfo(MacSandboxInfo* aSandboxInfo) override;
|
||||
#endif
|
||||
|
||||
|
@ -275,7 +275,7 @@ GMPLoaderImpl::Shutdown()
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
void
|
||||
GMPLoaderImpl::SetSandboxInfo(MacSandboxInfo* aSandboxInfo)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <stdint.h>
|
||||
#include "gmp-entrypoints.h"
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
#include "mozilla/Sandbox.h"
|
||||
#endif
|
||||
|
||||
|
@ -21,7 +21,7 @@ class SandboxStarter {
|
|||
public:
|
||||
virtual ~SandboxStarter() {}
|
||||
virtual bool Start(const char* aLibPath) = 0;
|
||||
#if defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
// On OS X we need to set Mac-specific sandbox info just before we start the
|
||||
// sandbox, which we don't yet know when the GMPLoader and SandboxStarter
|
||||
// objects are created.
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
// plugin library.
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
// On OS X we need to set Mac-specific sandbox info just before we start the
|
||||
// sandbox, which we don't yet know when the GMPLoader and SandboxStarter
|
||||
// objects are created.
|
||||
|
|
|
@ -64,6 +64,8 @@ public:
|
|||
virtual void EnumerateAudioDevices(dom::MediaSourceEnum,
|
||||
nsTArray<nsRefPtr<MediaEngineAudioSource> >*) = 0;
|
||||
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~MediaEngine() {}
|
||||
};
|
||||
|
@ -81,6 +83,8 @@ public:
|
|||
|
||||
virtual ~MediaEngineSource() {}
|
||||
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
/* Populate the human readable name of this device in the nsAString */
|
||||
virtual void GetName(nsAString&) = 0;
|
||||
|
||||
|
@ -245,6 +249,7 @@ public:
|
|||
/* This call reserves but does not start the device. */
|
||||
virtual nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
|
||||
const MediaEnginePrefs &aPrefs) = 0;
|
||||
|
||||
protected:
|
||||
explicit MediaEngineAudioSource(MediaEngineState aState)
|
||||
: MediaEngineSource(aState) {}
|
||||
|
|
|
@ -61,6 +61,8 @@ public:
|
|||
uint32_t GetBestFitnessDistance(
|
||||
const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets) override;
|
||||
|
||||
virtual void Shutdown() override {};
|
||||
|
||||
protected:
|
||||
struct CapabilityCandidate {
|
||||
explicit CapabilityCandidate(uint8_t index, uint32_t distance = 0)
|
||||
|
|
|
@ -36,6 +36,8 @@ class MediaEngineDefaultVideoSource : public nsITimerCallback,
|
|||
public:
|
||||
MediaEngineDefaultVideoSource();
|
||||
|
||||
virtual void Shutdown() override {};
|
||||
|
||||
virtual void GetName(nsAString&) override;
|
||||
virtual void GetUUID(nsAString&) override;
|
||||
|
||||
|
@ -104,6 +106,8 @@ class MediaEngineDefaultAudioSource : public nsITimerCallback,
|
|||
public:
|
||||
MediaEngineDefaultAudioSource();
|
||||
|
||||
virtual void Shutdown() override {};
|
||||
|
||||
virtual void GetName(nsAString&) override;
|
||||
virtual void GetUUID(nsAString&) override;
|
||||
|
||||
|
@ -158,15 +162,23 @@ public:
|
|||
{}
|
||||
|
||||
virtual void EnumerateVideoDevices(dom::MediaSourceEnum,
|
||||
nsTArray<nsRefPtr<MediaEngineVideoSource> >*);
|
||||
nsTArray<nsRefPtr<MediaEngineVideoSource> >*) override;
|
||||
virtual void EnumerateAudioDevices(dom::MediaSourceEnum,
|
||||
nsTArray<nsRefPtr<MediaEngineAudioSource> >*);
|
||||
nsTArray<nsRefPtr<MediaEngineAudioSource> >*) override;
|
||||
virtual void Shutdown() override {
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
mVSources.Clear();
|
||||
mASources.Clear();
|
||||
};
|
||||
|
||||
protected:
|
||||
bool mHasFakeTracks;
|
||||
|
||||
private:
|
||||
~MediaEngineDefault() {}
|
||||
~MediaEngineDefault() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
Mutex mMutex;
|
||||
// protected with mMutex:
|
||||
|
|
|
@ -18,6 +18,7 @@ class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventList
|
|||
NS_DECL_NSITIMERCALLBACK
|
||||
MediaEngineTabVideoSource();
|
||||
|
||||
virtual void Shutdown() override {};
|
||||
virtual void GetName(nsAString_internal&) override;
|
||||
virtual void GetUUID(nsAString_internal&) override;
|
||||
virtual nsresult Allocate(const dom::MediaTrackConstraints &,
|
||||
|
|
|
@ -274,10 +274,9 @@ MediaEngineWebRTC::EnumerateVideoDevices(dom::MediaSourceEnum aMediaSource,
|
|||
}
|
||||
}
|
||||
|
||||
if (mHasTabVideoSource || dom::MediaSourceEnum::Browser == aMediaSource)
|
||||
if (mHasTabVideoSource || dom::MediaSourceEnum::Browser == aMediaSource) {
|
||||
aVSources->AppendElement(new MediaEngineTabVideoSource());
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -372,15 +371,43 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
|
|||
}
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
ClearVideoSource (const nsAString&, // unused
|
||||
MediaEngineVideoSource* aData,
|
||||
void *userArg)
|
||||
{
|
||||
if (aData) {
|
||||
aData->Shutdown();
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
ClearAudioSource (const nsAString&, // unused
|
||||
MediaEngineWebRTCAudioSource* aData,
|
||||
void *userArg)
|
||||
{
|
||||
if (aData) {
|
||||
aData->Shutdown();
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTC::Shutdown()
|
||||
{
|
||||
// This is likely paranoia
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
// Clear callbacks before we go away since the engines may outlive us
|
||||
LOG(("%s", __FUNCTION__));
|
||||
// Shutdown all the sources, since we may have dangling references to the
|
||||
// sources in nsDOMUserMediaStreams waiting for GC/CC
|
||||
mVideoSources.EnumerateRead(ClearVideoSource, nullptr);
|
||||
mAudioSources.EnumerateRead(ClearAudioSource, nullptr);
|
||||
mVideoSources.Clear();
|
||||
mAudioSources.Clear();
|
||||
|
||||
// Clear callbacks before we go away since the engines may outlive us
|
||||
if (mVideoEngine) {
|
||||
mVideoEngine->SetTraceCallback(nullptr);
|
||||
webrtc::VideoEngine::Delete(mVideoEngine);
|
||||
|
|
|
@ -109,19 +109,20 @@ public:
|
|||
|
||||
void Refresh(int aIndex);
|
||||
|
||||
virtual void Shutdown() override;
|
||||
|
||||
protected:
|
||||
~MediaEngineWebRTCVideoSource() { Shutdown(); }
|
||||
|
||||
private:
|
||||
// Initialize the needed Video engine interfaces.
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Engine variables.
|
||||
webrtc::VideoEngine* mVideoEngine; // Weak reference, don't free.
|
||||
webrtc::ViEBase* mViEBase;
|
||||
webrtc::ViECapture* mViECapture;
|
||||
webrtc::ViERender* mViERender;
|
||||
ScopedCustomReleasePtr<webrtc::ViEBase> mViEBase;
|
||||
ScopedCustomReleasePtr<webrtc::ViECapture> mViECapture;
|
||||
ScopedCustomReleasePtr<webrtc::ViERender> mViERender;
|
||||
|
||||
int mMinFps; // Min rate we want to accept
|
||||
dom::MediaSourceEnum mMediaSource; // source of media (camera | application | screen)
|
||||
|
@ -195,12 +196,13 @@ public:
|
|||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
virtual void Shutdown() override;
|
||||
|
||||
protected:
|
||||
~MediaEngineWebRTCAudioSource() { Shutdown(); }
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
webrtc::VoiceEngine* mVoiceEngine;
|
||||
ScopedCustomReleasePtr<webrtc::VoEBase> mVoEBase;
|
||||
|
@ -239,12 +241,12 @@ public:
|
|||
|
||||
// Clients should ensure to clean-up sources video/audio sources
|
||||
// before invoking Shutdown on this class.
|
||||
void Shutdown();
|
||||
void Shutdown() override;
|
||||
|
||||
virtual void EnumerateVideoDevices(dom::MediaSourceEnum,
|
||||
nsTArray<nsRefPtr<MediaEngineVideoSource> >*);
|
||||
nsTArray<nsRefPtr<MediaEngineVideoSource>>*) override;
|
||||
virtual void EnumerateAudioDevices(dom::MediaSourceEnum,
|
||||
nsTArray<nsRefPtr<MediaEngineAudioSource> >*);
|
||||
nsTArray<nsRefPtr<MediaEngineAudioSource>>*) override;
|
||||
private:
|
||||
~MediaEngineWebRTC() {
|
||||
Shutdown();
|
||||
|
|
|
@ -478,11 +478,12 @@ MediaEngineWebRTCAudioSource::Shutdown()
|
|||
{
|
||||
if (!mInitDone) {
|
||||
// duplicate these here in case we failed during Init()
|
||||
if (mChannel != -1) {
|
||||
if (mChannel != -1 && mVoENetwork) {
|
||||
mVoENetwork->DeRegisterExternalTransport(mChannel);
|
||||
}
|
||||
|
||||
delete mNullTransport;
|
||||
mNullTransport = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -514,6 +515,7 @@ MediaEngineWebRTCAudioSource::Shutdown()
|
|||
}
|
||||
|
||||
delete mNullTransport;
|
||||
mNullTransport = nullptr;
|
||||
|
||||
mVoEProcessing = nullptr;
|
||||
mVoENetwork = nullptr;
|
||||
|
|
|
@ -266,7 +266,7 @@ MediaEngineWebRTCVideoSource::Deallocate()
|
|||
// another thread anywhere else, b) ViEInputManager::DestroyCaptureDevice() grabs
|
||||
// an exclusive object lock and deletes it in a critical section, so all in all
|
||||
// this should be safe threadwise.
|
||||
NS_DispatchToMainThread(WrapRunnable(mViECapture,
|
||||
NS_DispatchToMainThread(WrapRunnable(mViECapture.get(),
|
||||
&webrtc::ViECapture::ReleaseCaptureDevice,
|
||||
mCaptureIndex),
|
||||
NS_DISPATCH_SYNC);
|
||||
|
@ -422,9 +422,10 @@ MediaEngineWebRTCVideoSource::Shutdown()
|
|||
if (mState == kAllocated || mState == kStopped) {
|
||||
Deallocate();
|
||||
}
|
||||
mViECapture->Release();
|
||||
mViERender->Release();
|
||||
mViEBase->Release();
|
||||
mViECapture = nullptr;
|
||||
mViERender = nullptr;
|
||||
mViEBase = nullptr;
|
||||
|
||||
mState = kReleased;
|
||||
mInitDone = false;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PNecko;
|
||||
include protocol PBackground;
|
||||
include protocol PBlob;
|
||||
include InputStreamParams;
|
||||
|
||||
|
@ -37,7 +38,7 @@ namespace net {
|
|||
//-------------------------------------------------------------------
|
||||
protocol PUDPSocket
|
||||
{
|
||||
manager PNecko;
|
||||
manager PNecko or PBackground;
|
||||
|
||||
parent:
|
||||
Bind(UDPAddressInfo addressInfo, bool addressReuse, bool loopback);
|
||||
|
|
|
@ -318,8 +318,10 @@ UDPSocket::Send(const StringOrBlobOrArrayBufferOrArrayBufferView& aData,
|
|||
nsCString remoteAddress;
|
||||
if (aRemoteAddress.WasPassed()) {
|
||||
remoteAddress = NS_ConvertUTF16toUTF8(aRemoteAddress.Value());
|
||||
UDPSOCKET_LOG(("%s: Send to %s", __FUNCTION__, remoteAddress.get()));
|
||||
} else if (!mRemoteAddress.IsVoid()) {
|
||||
remoteAddress = mRemoteAddress;
|
||||
UDPSOCKET_LOG(("%s: Send to %s", __FUNCTION__, remoteAddress.get()));
|
||||
} else {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return false;
|
||||
|
@ -413,6 +415,7 @@ UDPSocket::InitLocal(const nsAString& aLocalAddress,
|
|||
PRNetAddr prAddr;
|
||||
PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr);
|
||||
PR_StringToNetAddr(NS_ConvertUTF16toUTF8(aLocalAddress).BeginReading(), &prAddr);
|
||||
UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, NS_ConvertUTF16toUTF8(aLocalAddress).get(), aLocalPort));
|
||||
|
||||
mozilla::net::NetAddr addr;
|
||||
PRNetAddrToNetAddr(&prAddr, &addr);
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
|
||||
struct JSContext;
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
//
|
||||
// set NSPR_LOG_MODULES=UDPSocket:5
|
||||
//
|
||||
extern PRLogModuleInfo *gUDPSocketLog;
|
||||
#endif
|
||||
#define UDPSOCKET_LOG(args) PR_LOG(gUDPSocketLog, PR_LOG_DEBUG, args)
|
||||
#define UDPSOCKET_LOG_ENABLED() PR_LOG_TEST(gUDPSocketLog, PR_LOG_DEBUG)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
|
|
@ -9,9 +9,23 @@
|
|||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||
|
||||
using mozilla::net::gNeckoChild;
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
//
|
||||
// set NSPR_LOG_MODULES=UDPSocket:5
|
||||
//
|
||||
extern PRLogModuleInfo *gUDPSocketLog;
|
||||
#endif
|
||||
#define UDPSOCKET_LOG(args) PR_LOG(gUDPSocketLog, PR_LOG_DEBUG, args)
|
||||
#define UDPSOCKET_LOG_ENABLED() PR_LOG_TEST(gUDPSocketLog, PR_LOG_DEBUG)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -54,7 +68,8 @@ NS_IMETHODIMP_(MozExternalRefCountType) UDPSocketChild::Release(void)
|
|||
}
|
||||
|
||||
UDPSocketChild::UDPSocketChild()
|
||||
:mLocalPort(0)
|
||||
:mBackgroundManager(nullptr)
|
||||
,mLocalPort(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -62,8 +77,96 @@ UDPSocketChild::~UDPSocketChild()
|
|||
{
|
||||
}
|
||||
|
||||
class UDPSocketBackgroundChildCallback final :
|
||||
public nsIIPCBackgroundChildCreateCallback
|
||||
{
|
||||
bool* mDone;
|
||||
|
||||
public:
|
||||
explicit UDPSocketBackgroundChildCallback(bool* aDone)
|
||||
: mDone(aDone)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(mDone);
|
||||
MOZ_ASSERT(!*mDone);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
private:
|
||||
~UDPSocketBackgroundChildCallback()
|
||||
{ }
|
||||
|
||||
virtual void
|
||||
ActorCreated(PBackgroundChild* aActor) override
|
||||
{
|
||||
*mDone = true;
|
||||
}
|
||||
|
||||
virtual void
|
||||
ActorFailed() override
|
||||
{
|
||||
*mDone = true;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(UDPSocketBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
|
||||
|
||||
nsresult
|
||||
UDPSocketChild::CreatePBackgroundSpinUntilDone()
|
||||
{
|
||||
using mozilla::ipc::BackgroundChild;
|
||||
|
||||
// Spinning the event loop in MainThread would be dangerous
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
|
||||
|
||||
bool done = false;
|
||||
nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
|
||||
new UDPSocketBackgroundChildCallback(&done);
|
||||
|
||||
if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsIThread* thread = NS_GetCurrentThread();
|
||||
while (!done) {
|
||||
if (NS_WARN_IF(!NS_ProcessNextEvent(thread, true /* aMayWait */))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIUDPSocketChild Methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
UDPSocketChild::SetBackgroundSpinsEvents()
|
||||
{
|
||||
using mozilla::ipc::BackgroundChild;
|
||||
|
||||
PBackgroundChild* existingBackgroundChild =
|
||||
BackgroundChild::GetForCurrentThread();
|
||||
// If it's not spun up yet, block until it is, and retry
|
||||
if (!existingBackgroundChild) {
|
||||
nsresult rv = CreatePBackgroundSpinUntilDone();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
existingBackgroundChild =
|
||||
BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(existingBackgroundChild);
|
||||
}
|
||||
// By now PBackground is guaranteed to be/have-been up
|
||||
mBackgroundManager = existingBackgroundChild;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
|
||||
nsIPrincipal* aPrincipal,
|
||||
|
@ -72,13 +175,22 @@ UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
|
|||
bool aAddressReuse,
|
||||
bool aLoopback)
|
||||
{
|
||||
UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
|
||||
|
||||
NS_ENSURE_ARG(aSocket);
|
||||
|
||||
mSocket = aSocket;
|
||||
AddIPDLReference();
|
||||
|
||||
gNeckoChild->SendPUDPSocketConstructor(this, IPC::Principal(aPrincipal),
|
||||
mFilterName);
|
||||
if (mBackgroundManager) {
|
||||
// If we want to support a passed-in principal here we'd need to
|
||||
// convert it to a PrincipalInfo
|
||||
MOZ_ASSERT(!aPrincipal);
|
||||
mBackgroundManager->SendPUDPSocketConstructor(this, void_t(), mFilterName);
|
||||
} else {
|
||||
gNeckoChild->SendPUDPSocketConstructor(this, IPC::Principal(aPrincipal),
|
||||
mFilterName);
|
||||
}
|
||||
|
||||
SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback);
|
||||
return NS_OK;
|
||||
|
@ -99,6 +211,7 @@ UDPSocketChild::Send(const nsACString& aHost,
|
|||
{
|
||||
NS_ENSURE_ARG(aData);
|
||||
|
||||
UDPSOCKET_LOG(("%s: %s:%u - %u bytes", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort, aByteLength));
|
||||
return SendDataInternal(UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)),
|
||||
aData, aByteLength);
|
||||
}
|
||||
|
@ -114,6 +227,7 @@ UDPSocketChild::SendWithAddr(nsINetAddr* aAddr,
|
|||
NetAddr addr;
|
||||
aAddr->GetNetAddr(&addr);
|
||||
|
||||
UDPSOCKET_LOG(("%s: %u bytes", __FUNCTION__, aByteLength));
|
||||
return SendDataInternal(UDPSocketAddr(addr), aData, aByteLength);
|
||||
}
|
||||
|
||||
|
@ -125,6 +239,7 @@ UDPSocketChild::SendWithAddress(const NetAddr* aAddr,
|
|||
NS_ENSURE_ARG(aAddr);
|
||||
NS_ENSURE_ARG(aData);
|
||||
|
||||
UDPSOCKET_LOG(("%s: %u bytes", __FUNCTION__, aByteLength));
|
||||
return SendDataInternal(UDPSocketAddr(*aAddr), aData, aByteLength);
|
||||
}
|
||||
|
||||
|
@ -161,6 +276,7 @@ UDPSocketChild::SendBinaryStream(const nsACString& aHost,
|
|||
|
||||
MOZ_ASSERT(fds.IsEmpty());
|
||||
|
||||
UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
|
||||
SendOutgoingData(UDPData(stream), UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)));
|
||||
|
||||
return NS_OK;
|
||||
|
@ -223,6 +339,7 @@ UDPSocketChild::RecvCallbackOpened(const UDPAddressInfo& aAddressInfo)
|
|||
mLocalAddress = aAddressInfo.addr();
|
||||
mLocalPort = aAddressInfo.port();
|
||||
|
||||
UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, mLocalAddress.get(), mLocalPort));
|
||||
nsresult rv = mSocket->CallListenerOpened();
|
||||
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
|
@ -242,6 +359,8 @@ bool
|
|||
UDPSocketChild::RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
|
||||
InfallibleTArray<uint8_t>&& aData)
|
||||
{
|
||||
UDPSOCKET_LOG(("%s: %s:%u length %u", __FUNCTION__,
|
||||
aAddressInfo.addr().get(), aAddressInfo.port(), aData.Length()));
|
||||
nsresult rv = mSocket->CallListenerReceivedData(aAddressInfo.addr(), aAddressInfo.port(),
|
||||
aData.Elements(), aData.Length());
|
||||
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
|
@ -254,6 +373,7 @@ UDPSocketChild::RecvCallbackError(const nsCString& aMessage,
|
|||
const nsCString& aFilename,
|
||||
const uint32_t& aLineNumber)
|
||||
{
|
||||
UDPSOCKET_LOG(("%s: %s:%s:%u", __FUNCTION__, aMessage.get(), aFilename.get(), aLineNumber));
|
||||
nsresult rv = mSocket->CallListenerError(aMessage, aFilename, aLineNumber);
|
||||
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ public:
|
|||
UDPSocketChild();
|
||||
virtual ~UDPSocketChild();
|
||||
|
||||
nsresult CreatePBackgroundSpinUntilDone();
|
||||
|
||||
virtual bool RecvCallbackOpened(const UDPAddressInfo& aAddressInfo) override;
|
||||
virtual bool RecvCallbackClosed() override;
|
||||
virtual bool RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
|
||||
|
@ -55,6 +57,7 @@ private:
|
|||
const uint8_t* aData,
|
||||
const uint32_t aByteLength);
|
||||
|
||||
mozilla::ipc::PBackgroundChild* mBackgroundManager;
|
||||
uint16_t mLocalPort;
|
||||
nsCString mLocalAddress;
|
||||
nsCString mFilterName;
|
||||
|
|
|
@ -20,14 +20,34 @@
|
|||
#include "mozilla/dom/TabParent.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
//
|
||||
// set NSPR_LOG_MODULES=UDPSocket:5
|
||||
//
|
||||
extern PRLogModuleInfo *gUDPSocketLog;
|
||||
#endif
|
||||
#define UDPSOCKET_LOG(args) PR_LOG(gUDPSocketLog, PR_LOG_DEBUG, args)
|
||||
#define UDPSOCKET_LOG_ENABLED() PR_LOG_TEST(gUDPSocketLog, PR_LOG_DEBUG)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
|
||||
|
||||
UDPSocketParent::UDPSocketParent()
|
||||
: mIPCOpen(true)
|
||||
UDPSocketParent::UDPSocketParent(PBackgroundParent* aManager)
|
||||
: mBackgroundManager(aManager)
|
||||
, mNeckoManager(nullptr)
|
||||
, mIPCOpen(true)
|
||||
{
|
||||
mObserver = new mozilla::net::OfflineObserver(this);
|
||||
}
|
||||
|
||||
UDPSocketParent::UDPSocketParent(PNeckoParent* aManager)
|
||||
: mBackgroundManager(nullptr)
|
||||
, mNeckoManager(aManager)
|
||||
, mIPCOpen(true)
|
||||
{
|
||||
mObserver = new mozilla::net::OfflineObserver(this);
|
||||
}
|
||||
|
@ -78,12 +98,22 @@ bool
|
|||
UDPSocketParent::Init(const IPC::Principal& aPrincipal,
|
||||
const nsACString& aFilter)
|
||||
{
|
||||
MOZ_ASSERT_IF(mBackgroundManager, !aPrincipal);
|
||||
// will be used once we move all UDPSocket to PBackground, or
|
||||
// if we add in Principal checking for mtransport
|
||||
unused << mBackgroundManager;
|
||||
|
||||
mPrincipal = aPrincipal;
|
||||
if (net::UsingNeckoIPCSecurity() &&
|
||||
mPrincipal &&
|
||||
!ContentParent::IgnoreIPCPrincipal()) {
|
||||
if (!AssertAppPrincipal(Manager()->Manager(), mPrincipal)) {
|
||||
return false;
|
||||
if (mNeckoManager) {
|
||||
if (!AssertAppPrincipal(mNeckoManager->Manager(), mPrincipal)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// PBackground is (for now) using a STUN filter for verification
|
||||
// it's not being used for DoS
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
|
@ -121,7 +151,7 @@ UDPSocketParent::Init(const IPC::Principal& aPrincipal,
|
|||
}
|
||||
// We don't have browser actors in xpcshell, and hence can't run automated
|
||||
// tests without this loophole.
|
||||
if (net::UsingNeckoIPCSecurity() && !mFilter &&
|
||||
if (net::UsingNeckoIPCSecurity() && !mFilter &&
|
||||
(!mPrincipal || ContentParent::IgnoreIPCPrincipal())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -134,6 +164,8 @@ bool
|
|||
UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
|
||||
const bool& aAddressReuse, const bool& aLoopback)
|
||||
{
|
||||
UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port()));
|
||||
|
||||
if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback))) {
|
||||
FireInternalError(__LINE__);
|
||||
return true;
|
||||
|
@ -154,6 +186,7 @@ UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
|
|||
return true;
|
||||
}
|
||||
|
||||
UDPSOCKET_LOG(("%s: SendCallbackOpened: %s:%u", __FUNCTION__, addr.get(), port));
|
||||
mozilla::unused << SendCallbackOpened(UDPAddressInfo(addr, port));
|
||||
|
||||
return true;
|
||||
|
@ -165,6 +198,8 @@ UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, nsCString(aHost).get(), aPort));
|
||||
|
||||
nsCOMPtr<nsIUDPSocket> sock =
|
||||
do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
|
||||
|
||||
|
@ -398,6 +433,7 @@ UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage
|
|||
|
||||
const char* buffer = data.get();
|
||||
uint32_t len = data.Length();
|
||||
UDPSOCKET_LOG(("%s: %s:%u, length %u", __FUNCTION__, ip.get(), port, len));
|
||||
|
||||
if (mFilter) {
|
||||
bool allowed;
|
||||
|
@ -409,6 +445,9 @@ UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage
|
|||
&allowed);
|
||||
// Receiving unallowed data, drop.
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
|
||||
if (!allowed) {
|
||||
UDPSOCKET_LOG(("%s: not allowed", __FUNCTION__));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
class PNeckoParent;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
class UDPSocketParent : public mozilla::net::PUDPSocketParent
|
||||
|
@ -25,7 +29,8 @@ public:
|
|||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIUDPSOCKETLISTENER
|
||||
|
||||
UDPSocketParent();
|
||||
explicit UDPSocketParent(PBackgroundParent* aManager);
|
||||
explicit UDPSocketParent(PNeckoParent* aManager);
|
||||
|
||||
bool Init(const IPC::Principal& aPrincipal, const nsACString& aFilter);
|
||||
|
||||
|
@ -54,6 +59,10 @@ private:
|
|||
|
||||
void FireInternalError(uint32_t aLineNo);
|
||||
|
||||
// One of these will be null and the other non-null.
|
||||
PBackgroundParent* mBackgroundManager;
|
||||
PNeckoParent* mNeckoManager;
|
||||
|
||||
bool mIPCOpen;
|
||||
nsCOMPtr<nsIUDPSocket> mSocket;
|
||||
nsCOMPtr<nsIUDPSocketFilter> mFilter;
|
||||
|
|
|
@ -19,13 +19,16 @@ union NetAddr;
|
|||
native NetAddr(mozilla::net::NetAddr);
|
||||
[ptr] native NetAddrPtr(mozilla::net::NetAddr);
|
||||
|
||||
[scriptable, uuid(dd636fc5-05a0-401c-832f-2c07f3477c60)]
|
||||
[scriptable, uuid(481f15ce-224a-40b6-9927-7effbc326776)]
|
||||
interface nsIUDPSocketChild : nsISupports
|
||||
{
|
||||
readonly attribute unsigned short localPort;
|
||||
readonly attribute AUTF8String localAddress;
|
||||
attribute AUTF8String filterName;
|
||||
|
||||
// Allow hosting this over PBackground instead of PNecko
|
||||
[noscript] void setBackgroundSpinsEvents();
|
||||
|
||||
// Tell the chrome process to bind the UDP socket to a given local host and port
|
||||
void bind(in nsIUDPSocketInternal socket, in nsIPrincipal principal,
|
||||
in AUTF8String host, in unsigned short port,
|
||||
|
|
|
@ -1954,7 +1954,7 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
|||
return NPERR_GENERIC_ERROR;
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) || (MOZ_WIDGET_GTK == 2) || defined(MOZ_WIDGET_QT)
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
case NPNVnetscapeWindow: {
|
||||
if (!npp || !npp->ndata)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
|
|
@ -481,7 +481,8 @@ PluginModuleChromeParent::LoadModule(const char* aFilePath, uint32_t aPluginId,
|
|||
}
|
||||
#endif
|
||||
|
||||
nsAutoPtr<PluginModuleChromeParent> parent(new PluginModuleChromeParent(aFilePath, aPluginId));
|
||||
nsAutoPtr<PluginModuleChromeParent> parent(new PluginModuleChromeParent(aFilePath, aPluginId,
|
||||
sandboxLevel));
|
||||
UniquePtr<LaunchCompleteTask> onLaunchedRunnable(new LaunchedTask(parent));
|
||||
parent->mSubprocess->SetCallRunnableImmediately(!parent->mIsStartingAsync);
|
||||
TimeStamp launchStart = TimeStamp::Now();
|
||||
|
@ -564,9 +565,11 @@ PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#if defined(XP_WIN) && defined(_X86_)
|
||||
// Protected mode only applies to Windows and only to x86.
|
||||
if (!mIsBlocklisted && mIsFlashPlugin &&
|
||||
Preferences::GetBool("dom.ipc.plugins.flash.disable-protected-mode", false)) {
|
||||
(Preferences::GetBool("dom.ipc.plugins.flash.disable-protected-mode", false) ||
|
||||
mSandboxLevel >= 2)) {
|
||||
SendDisableFlashProtectedMode();
|
||||
}
|
||||
#endif
|
||||
|
@ -662,7 +665,9 @@ PluginModuleContentParent::~PluginModuleContentParent()
|
|||
|
||||
bool PluginModuleChromeParent::sInstantiated = false;
|
||||
|
||||
PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId)
|
||||
PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
|
||||
uint32_t aPluginId,
|
||||
int32_t aSandboxLevel)
|
||||
: PluginModuleParent(true)
|
||||
, mSubprocess(new PluginProcessParent(aFilePath))
|
||||
, mPluginId(aPluginId)
|
||||
|
@ -674,6 +679,7 @@ PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32
|
|||
, mHangUIParent(nullptr)
|
||||
, mHangUIEnabled(true)
|
||||
, mIsTimerReset(true)
|
||||
, mSandboxLevel(aSandboxLevel)
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
, mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
|
||||
, mCrashReporter(nullptr)
|
||||
|
|
|
@ -443,7 +443,8 @@ private:
|
|||
virtual void ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
// aFilePath is UTF8, not native!
|
||||
explicit PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId);
|
||||
explicit PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId,
|
||||
int32_t aSandboxLevel);
|
||||
|
||||
CrashReporterParent* CrashReporter();
|
||||
|
||||
|
@ -483,6 +484,7 @@ private:
|
|||
PluginHangUIParent *mHangUIParent;
|
||||
bool mHangUIEnabled;
|
||||
bool mIsTimerReset;
|
||||
int32_t mSandboxLevel;
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
/**
|
||||
* This mutex protects the crash reporter when the Plugin Hang UI event
|
||||
|
|
|
@ -76,7 +76,7 @@ AddSandboxAllowedFiles(int32_t aSandboxLevel,
|
|||
vector<std::wstring>& aAllowedFilesRead,
|
||||
vector<std::wstring>& aAllowedFilesReadWrite)
|
||||
{
|
||||
if (aSandboxLevel < 3) {
|
||||
if (aSandboxLevel < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -87,16 +87,26 @@ AddSandboxAllowedFiles(int32_t aSandboxLevel,
|
|||
return;
|
||||
}
|
||||
|
||||
AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR);
|
||||
AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR,
|
||||
NS_LITERAL_STRING("\\*"));
|
||||
// Higher than level 2 currently removes the users own rights.
|
||||
if (aSandboxLevel > 2) {
|
||||
AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR);
|
||||
AddSandboxAllowedFile(aAllowedFilesRead, dirSvc, NS_WIN_HOME_DIR,
|
||||
NS_LITERAL_STRING("\\*"));
|
||||
}
|
||||
|
||||
// Level 2 and above is now using low integrity, so we need to give write
|
||||
// access to the Flash directories.
|
||||
AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_WIN_APPDATA_DIR,
|
||||
NS_LITERAL_STRING("\\Macromedia\\Flash Player\\*"));
|
||||
AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_WIN_APPDATA_DIR,
|
||||
NS_LITERAL_STRING("\\Adobe\\Flash Player\\*"));
|
||||
|
||||
#if defined(_X86_)
|
||||
// Write access to the Temp directory should only be needed for 32-bit as
|
||||
// it is used to turn off protected mode, which only applies to x86.
|
||||
AddSandboxAllowedFile(aAllowedFilesReadWrite, dirSvc, NS_OS_TEMP_DIR,
|
||||
NS_LITERAL_STRING("\\*"));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
enum CaretChangedReason {
|
||||
"visibilitychange",
|
||||
"updateposition",
|
||||
"longpressonemptycontent",
|
||||
"taponcaret",
|
||||
"presscaret",
|
||||
"releasecaret"
|
||||
};
|
||||
|
||||
dictionary CaretStateChangedEventInit : EventInit {
|
||||
boolean collapsed = true;
|
||||
DOMRectReadOnly? boundingClientRect = null;
|
||||
CaretChangedReason reason = "visibilitychange";
|
||||
boolean caretVisible = false;
|
||||
boolean selectionVisible = false;
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional CaretStateChangedEventInit eventInit),
|
||||
ChromeOnly]
|
||||
interface CaretStateChangedEvent : Event {
|
||||
readonly attribute boolean collapsed;
|
||||
readonly attribute DOMRectReadOnly? boundingClientRect;
|
||||
readonly attribute CaretChangedReason reason;
|
||||
readonly attribute boolean caretVisible;
|
||||
readonly attribute boolean selectionVisible;
|
||||
};
|
|
@ -8,7 +8,6 @@
|
|||
*/
|
||||
|
||||
typedef long long GLint64; // Should this be int64?
|
||||
typedef unsigned long long GLuint64; // Should this be uint64?
|
||||
|
||||
[Pref="webgl.enable-prototype-webgl2"]
|
||||
interface WebGLQuery {
|
||||
|
|
|
@ -28,6 +28,7 @@ typedef long long GLsizeiptr;
|
|||
typedef octet GLubyte; /* 'octet' should be an unsigned 8 bit type. */
|
||||
typedef unsigned short GLushort;
|
||||
typedef unsigned long GLuint;
|
||||
typedef unsigned long long GLuint64;
|
||||
typedef unrestricted float GLfloat;
|
||||
typedef unrestricted float GLclampf;
|
||||
|
||||
|
@ -975,3 +976,29 @@ interface WebGLExtensionBlendMinMax {
|
|||
const GLenum MIN_EXT = 0x8007;
|
||||
const GLenum MAX_EXT = 0x8008;
|
||||
};
|
||||
|
||||
// FIXME: Spec interface name is WebGLTimerQueryEXT.
|
||||
[NoInterfaceObject]
|
||||
interface WebGLTimerQuery {
|
||||
};
|
||||
|
||||
// FIXME: Spec interface name is EXT_disjoint_timer_query.
|
||||
[NoInterfaceObject]
|
||||
interface WebGLExtensionDisjointTimerQuery {
|
||||
const GLenum QUERY_COUNTER_BITS_EXT = 0x8864;
|
||||
const GLenum CURRENT_QUERY_EXT = 0x8865;
|
||||
const GLenum QUERY_RESULT_EXT = 0x8866;
|
||||
const GLenum QUERY_RESULT_AVAILABLE_EXT = 0x8867;
|
||||
const GLenum TIME_ELAPSED_EXT = 0x88BF;
|
||||
const GLenum TIMESTAMP_EXT = 0x8E28;
|
||||
const GLenum GPU_DISJOINT_EXT = 0x8FBB;
|
||||
|
||||
WebGLTimerQuery? createQueryEXT();
|
||||
void deleteQueryEXT(WebGLTimerQuery? query);
|
||||
[WebGLHandlesContextLoss] boolean isQueryEXT(WebGLTimerQuery? query);
|
||||
void beginQueryEXT(GLenum target, WebGLTimerQuery? query);
|
||||
void endQueryEXT(GLenum target);
|
||||
void queryCounterEXT(WebGLTimerQuery? query, GLenum target);
|
||||
any getQueryEXT(GLenum target, GLenum pname);
|
||||
any getQueryObjectEXT(WebGLTimerQuery? query, GLenum pname);
|
||||
};
|
||||
|
|
|
@ -727,6 +727,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
|
|||
'CameraConfigurationEvent.webidl',
|
||||
'CameraFacesDetectedEvent.webidl',
|
||||
'CameraStateChangeEvent.webidl',
|
||||
'CaretStateChangedEvent.webidl',
|
||||
'CFStateChangeEvent.webidl',
|
||||
'CloseEvent.webidl',
|
||||
'CSSFontFaceLoadEvent.webidl',
|
||||
|
|
|
@ -393,6 +393,8 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoMicroTask mt;
|
||||
|
||||
nsAutoCString uriSpec;
|
||||
aBindingDocURI->GetSpec(uriSpec);
|
||||
|
||||
|
|
|
@ -293,6 +293,8 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement, JSAddonId* aAd
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoMicroTask mt;
|
||||
|
||||
// We are going to run script via JS::Call, so we need a script entry point,
|
||||
// but as this is XBL related it does not appear in the HTML spec.
|
||||
dom::AutoEntryScript aes(global, "XBL <constructor>/<destructor> invocation");
|
||||
|
|
|
@ -3537,7 +3537,9 @@ XULDocument::ExecuteScript(nsXULPrototypeScript *aScript)
|
|||
JS::HandleScript scriptObject = aScript->GetScriptObject();
|
||||
NS_ENSURE_TRUE(scriptObject, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Execute the precompiled script with the given version.
|
||||
// Execute the precompiled script with the given version
|
||||
nsAutoMicroTask mt;
|
||||
|
||||
// We're about to run script via JS::CloneAndExecuteScript, so we need an
|
||||
// AutoEntryScript. This is Gecko specific and not in any spec.
|
||||
AutoEntryScript aes(mScriptGlobalObject, "precompiled XUL <script> element");
|
||||
|
|
|
@ -526,10 +526,69 @@ DrawTargetD2D1::FillGlyphs(ScaledFont *aFont,
|
|||
AutoDWriteGlyphRun autoRun;
|
||||
DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun);
|
||||
|
||||
bool needsRepushedLayers = false;
|
||||
if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && mFormat != SurfaceFormat::B8G8R8X8) {
|
||||
D2D1_RECT_F rect;
|
||||
bool isAligned;
|
||||
needsRepushedLayers = mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
|
||||
|
||||
// If we have a complex clip in our stack and we have a transparent
|
||||
// background, and subpixel AA is permitted, we need to repush our layer
|
||||
// stack limited by the glyph run bounds initializing our layers for
|
||||
// subpixel AA.
|
||||
if (needsRepushedLayers) {
|
||||
mDC->GetGlyphRunWorldBounds(D2D1::Point2F(), &autoRun,
|
||||
DWRITE_MEASURING_MODE_NATURAL, &rect);
|
||||
rect.left = std::floor(rect.left);
|
||||
rect.right = std::ceil(rect.right);
|
||||
rect.top = std::floor(rect.top);
|
||||
rect.bottom = std::ceil(rect.bottom);
|
||||
|
||||
PopAllClips();
|
||||
|
||||
if (!mTransform.IsRectilinear()) {
|
||||
// We must limit the pixels we touch to the -user space- bounds of
|
||||
// the glyphs being drawn. In order not to get transparent pixels
|
||||
// copied up in our pushed layer stack.
|
||||
D2D1_RECT_F userRect;
|
||||
mDC->SetTransform(D2D1::IdentityMatrix());
|
||||
mDC->GetGlyphRunWorldBounds(D2D1::Point2F(), &autoRun,
|
||||
DWRITE_MEASURING_MODE_NATURAL, &userRect);
|
||||
|
||||
RefPtr<ID2D1PathGeometry> path;
|
||||
D2DFactory()->CreatePathGeometry(byRef(path));
|
||||
RefPtr<ID2D1GeometrySink> sink;
|
||||
path->Open(byRef(sink));
|
||||
sink->BeginFigure(D2D1::Point2F(userRect.left, userRect.top), D2D1_FIGURE_BEGIN_FILLED);
|
||||
sink->AddLine(D2D1::Point2F(userRect.right, userRect.top));
|
||||
sink->AddLine(D2D1::Point2F(userRect.right, userRect.bottom));
|
||||
sink->AddLine(D2D1::Point2F(userRect.left, userRect.bottom));
|
||||
sink->EndFigure(D2D1_FIGURE_END_CLOSED);
|
||||
sink->Close();
|
||||
|
||||
mDC->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), path, D2D1_ANTIALIAS_MODE_ALIASED,
|
||||
D2DMatrix(mTransform), 1.0f, nullptr,
|
||||
D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND |
|
||||
D2D1_LAYER_OPTIONS1_IGNORE_ALPHA), nullptr);
|
||||
}
|
||||
|
||||
PushClipsToDC(mDC, true, rect);
|
||||
mDC->SetTransform(D2DMatrix(mTransform));
|
||||
}
|
||||
}
|
||||
|
||||
if (brush) {
|
||||
mDC->DrawGlyphRun(D2D1::Point2F(), &autoRun, brush);
|
||||
}
|
||||
|
||||
if (needsRepushedLayers) {
|
||||
PopClipsFromDC(mDC);
|
||||
|
||||
if (!mTransform.IsRectilinear()) {
|
||||
mDC->PopLayer();
|
||||
}
|
||||
}
|
||||
|
||||
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
|
||||
}
|
||||
|
||||
|
@ -1261,7 +1320,7 @@ DrawTargetD2D1::PushAllClips()
|
|||
}
|
||||
|
||||
void
|
||||
DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC)
|
||||
DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC, bool aForceIgnoreAlpha, const D2D1_RECT_F& aMaxRect)
|
||||
{
|
||||
mDC->SetTransform(D2D1::IdentityMatrix());
|
||||
mTransformDirty = true;
|
||||
|
@ -1269,7 +1328,7 @@ DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC)
|
|||
for (std::vector<PushedClip>::iterator iter = mPushedClips.begin();
|
||||
iter != mPushedClips.end(); iter++) {
|
||||
if (iter->mPath) {
|
||||
PushD2DLayer(aDC, iter->mPath->mGeometry, iter->mTransform);
|
||||
PushD2DLayer(aDC, iter->mPath->mGeometry, iter->mTransform, aForceIgnoreAlpha, aMaxRect);
|
||||
} else {
|
||||
mDC->PushAxisAlignedClip(iter->mBounds, iter->mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
|
||||
}
|
||||
|
@ -1493,15 +1552,16 @@ DrawTargetD2D1::OptimizeSourceSurface(SourceSurface* aSurface) const
|
|||
}
|
||||
|
||||
void
|
||||
DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform)
|
||||
DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform,
|
||||
bool aForceIgnoreAlpha, const D2D1_RECT_F& aMaxRect)
|
||||
{
|
||||
D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE;
|
||||
|
||||
if (aDC->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE) {
|
||||
if (aDC->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE || aForceIgnoreAlpha) {
|
||||
options = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
|
||||
}
|
||||
|
||||
mDC->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), aGeometry,
|
||||
mDC->PushLayer(D2D1::LayerParameters1(aMaxRect, aGeometry,
|
||||
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform,
|
||||
1.0, nullptr, options), nullptr);
|
||||
}
|
||||
|
|
|
@ -179,14 +179,15 @@ private:
|
|||
|
||||
void PopAllClips();
|
||||
void PushAllClips();
|
||||
void PushClipsToDC(ID2D1DeviceContext *aDC);
|
||||
void PushClipsToDC(ID2D1DeviceContext *aDC, bool aForceIgnoreAlpha = false, const D2D1_RECT_F& aMaxRect = D2D1::InfiniteRect());
|
||||
void PopClipsFromDC(ID2D1DeviceContext *aDC);
|
||||
|
||||
TemporaryRef<ID2D1Brush> CreateTransparentBlackBrush();
|
||||
TemporaryRef<ID2D1SolidColorBrush> GetSolidColorBrush(const D2D_COLOR_F& aColor);
|
||||
TemporaryRef<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
|
||||
|
||||
void PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform);
|
||||
void PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform,
|
||||
bool aForceIgnoreAlpha = false, const D2D1_RECT_F& aLayerRect = D2D1::InfiniteRect());
|
||||
|
||||
IntSize mSize;
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ static const char *sExtensionNames[] = {
|
|||
"GL_ANGLE_instanced_arrays",
|
||||
"GL_ANGLE_texture_compression_dxt3",
|
||||
"GL_ANGLE_texture_compression_dxt5",
|
||||
"GL_ANGLE_timer_query",
|
||||
"GL_APPLE_client_storage",
|
||||
"GL_APPLE_texture_range",
|
||||
"GL_APPLE_vertex_array_object",
|
||||
|
@ -97,6 +98,7 @@ static const char *sExtensionNames[] = {
|
|||
"GL_ARB_texture_rectangle",
|
||||
"GL_ARB_texture_storage",
|
||||
"GL_ARB_texture_swizzle",
|
||||
"GL_ARB_timer_query",
|
||||
"GL_ARB_transform_feedback2",
|
||||
"GL_ARB_uniform_buffer_object",
|
||||
"GL_ARB_vertex_array_object",
|
||||
|
@ -105,6 +107,7 @@ static const char *sExtensionNames[] = {
|
|||
"GL_EXT_color_buffer_float",
|
||||
"GL_EXT_color_buffer_half_float",
|
||||
"GL_EXT_copy_texture",
|
||||
"GL_EXT_disjoint_timer_query",
|
||||
"GL_EXT_draw_buffers",
|
||||
"GL_EXT_draw_buffers2",
|
||||
"GL_EXT_draw_instanced",
|
||||
|
@ -129,6 +132,7 @@ static const char *sExtensionNames[] = {
|
|||
"GL_EXT_texture_format_BGRA8888",
|
||||
"GL_EXT_texture_sRGB",
|
||||
"GL_EXT_texture_storage",
|
||||
"GL_EXT_timer_query",
|
||||
"GL_EXT_transform_feedback",
|
||||
"GL_EXT_unpack_subimage",
|
||||
"GL_IMG_read_format",
|
||||
|
@ -1043,6 +1047,26 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
}
|
||||
}
|
||||
|
||||
if (IsSupported(GLFeature::query_counter)) {
|
||||
SymLoadStruct coreSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fQueryCounter, { "QueryCounter", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
SymLoadStruct extSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fQueryCounter, { "QueryCounterEXT", "QueryCounterANGLE", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::query_counter);
|
||||
|
||||
if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
|
||||
NS_ERROR("GL supports query counters without supplying its functions.");
|
||||
|
||||
MarkUnsupported(GLFeature::query_counter);
|
||||
ClearSymbols(coreSymbols);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSupported(GLFeature::query_objects)) {
|
||||
SymLoadStruct coreSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQuery", nullptr } },
|
||||
|
@ -1056,13 +1080,13 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
};
|
||||
|
||||
SymLoadStruct extSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQueryEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueriesEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueriesEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQueryEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryivEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuivEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fIsQuery, { "IsQueryEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fBeginQuery, { "BeginQueryEXT", "BeginQueryANGLE", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGenQueries, { "GenQueriesEXT", "GenQueriesANGLE", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fDeleteQueries, { "DeleteQueriesEXT", "DeleteQueriesANGLE", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fEndQuery, { "EndQueryEXT", "EndQueryANGLE", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryiv, { "GetQueryivEXT", "GetQueryivANGLE", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryObjectuiv, { "GetQueryObjectuivEXT", "GetQueryObjectuivANGLE", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fIsQuery, { "IsQueryEXT", "IsQueryANGLE", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
|
@ -1072,6 +1096,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
NS_ERROR("GL supports query objects without supplying its functions.");
|
||||
|
||||
MarkUnsupported(GLFeature::query_objects);
|
||||
MarkUnsupported(GLFeature::get_query_object_i64v);
|
||||
MarkUnsupported(GLFeature::get_query_object_iv);
|
||||
MarkUnsupported(GLFeature::occlusion_query);
|
||||
MarkUnsupported(GLFeature::occlusion_query_boolean);
|
||||
|
@ -1080,6 +1105,29 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
}
|
||||
}
|
||||
|
||||
if (IsSupported(GLFeature::get_query_object_i64v)) {
|
||||
SymLoadStruct coreSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, { "GetQueryObjecti64v", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, { "GetQueryObjectui64v", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
SymLoadStruct extSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryObjecti64v, { "GetQueryObjecti64vEXT", "GetQueryObjecti64vANGLE", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryObjectui64v, { "GetQueryObjectui64vEXT", "GetQueryObjectui64vANGLE", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
bool useCore = IsFeatureProvidedByCoreSymbols(GLFeature::get_query_object_i64v);
|
||||
if (!LoadSymbols(useCore ? coreSymbols : extSymbols, trygl, prefix)) {
|
||||
NS_ERROR("GL supports 64 bit query object getters without supplying its functions.");
|
||||
|
||||
MarkUnsupported(GLFeature::get_query_object_i64v);
|
||||
MarkUnsupported(GLFeature::query_counter);
|
||||
ClearSymbols(coreSymbols);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSupported(GLFeature::get_query_object_iv)) {
|
||||
SymLoadStruct coreSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectiv", nullptr } },
|
||||
|
@ -1087,7 +1135,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
};
|
||||
|
||||
SymLoadStruct extSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectivEXT", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fGetQueryObjectiv, { "GetQueryObjectivEXT", "GetQueryObjectivANGLE", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ enum class GLFeature {
|
|||
framebuffer_object,
|
||||
get_integer_indexed,
|
||||
get_integer64_indexed,
|
||||
get_query_object_i64v,
|
||||
get_query_object_iv,
|
||||
get_string_indexed,
|
||||
gpu_shader4,
|
||||
|
@ -110,7 +111,9 @@ enum class GLFeature {
|
|||
occlusion_query_boolean,
|
||||
occlusion_query2,
|
||||
packed_depth_stencil,
|
||||
query_counter,
|
||||
query_objects,
|
||||
query_time_elapsed,
|
||||
read_buffer,
|
||||
renderbuffer_color_float,
|
||||
renderbuffer_color_half_float,
|
||||
|
@ -364,6 +367,7 @@ public:
|
|||
ANGLE_instanced_arrays,
|
||||
ANGLE_texture_compression_dxt3,
|
||||
ANGLE_texture_compression_dxt5,
|
||||
ANGLE_timer_query,
|
||||
APPLE_client_storage,
|
||||
APPLE_texture_range,
|
||||
APPLE_vertex_array_object,
|
||||
|
@ -391,6 +395,7 @@ public:
|
|||
ARB_texture_rectangle,
|
||||
ARB_texture_storage,
|
||||
ARB_texture_swizzle,
|
||||
ARB_timer_query,
|
||||
ARB_transform_feedback2,
|
||||
ARB_uniform_buffer_object,
|
||||
ARB_vertex_array_object,
|
||||
|
@ -399,6 +404,7 @@ public:
|
|||
EXT_color_buffer_float,
|
||||
EXT_color_buffer_half_float,
|
||||
EXT_copy_texture,
|
||||
EXT_disjoint_timer_query,
|
||||
EXT_draw_buffers,
|
||||
EXT_draw_buffers2,
|
||||
EXT_draw_instanced,
|
||||
|
@ -423,6 +429,7 @@ public:
|
|||
EXT_texture_format_BGRA8888,
|
||||
EXT_texture_sRGB,
|
||||
EXT_texture_storage,
|
||||
EXT_timer_query,
|
||||
EXT_transform_feedback,
|
||||
EXT_unpack_subimage,
|
||||
IMG_read_format,
|
||||
|
@ -2617,6 +2624,22 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Package XXX_query_counter
|
||||
/**
|
||||
* XXX_query_counter:
|
||||
* - depends on XXX_query_objects
|
||||
* - provide all followed entry points
|
||||
* - provide GL_TIMESTAMP
|
||||
*/
|
||||
public:
|
||||
void fQueryCounter(GLuint id, GLenum target) {
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fQueryCounter);
|
||||
mSymbols.fQueryCounter(id, target);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Package XXX_query_objects
|
||||
|
@ -2671,6 +2694,28 @@ public:
|
|||
return retval;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Package XXX_get_query_object_i64v
|
||||
/**
|
||||
* XXX_get_query_object_i64v:
|
||||
* - depends on XXX_query_objects
|
||||
* - provide the followed entry point
|
||||
*/
|
||||
public:
|
||||
void fGetQueryObjecti64v(GLuint id, GLenum pname, GLint64* params) {
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fGetQueryObjecti64v);
|
||||
mSymbols.fGetQueryObjecti64v(id, pname, params);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64* params) {
|
||||
BEFORE_GL_CALL;
|
||||
ASSERT_SYMBOL_PRESENT(fGetQueryObjectui64v);
|
||||
mSymbols.fGetQueryObjectui64v(id, pname, params);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Package XXX_get_query_object_iv
|
||||
|
|
|
@ -260,6 +260,18 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
|||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"get_query_object_i64v",
|
||||
GLVersion::GL3_3,
|
||||
GLESVersion::NONE,
|
||||
GLContext::ARB_timer_query,
|
||||
{
|
||||
GLContext::ANGLE_timer_query,
|
||||
GLContext::EXT_disjoint_timer_query,
|
||||
GLContext::EXT_timer_query,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"get_query_object_iv",
|
||||
GLVersion::GL2,
|
||||
|
@ -392,21 +404,48 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
|||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"query_counter",
|
||||
GLVersion::GL3_3,
|
||||
GLESVersion::NONE,
|
||||
GLContext::ARB_timer_query,
|
||||
{
|
||||
GLContext::ANGLE_timer_query,
|
||||
GLContext::EXT_disjoint_timer_query,
|
||||
// EXT_timer_query does NOT support GL_TIMESTAMP retrieval with
|
||||
// QueryCounter.
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"query_objects",
|
||||
GLVersion::GL2,
|
||||
GLESVersion::ES3,
|
||||
GLContext::Extension_None,
|
||||
{
|
||||
GLContext::ANGLE_timer_query,
|
||||
GLContext::EXT_disjoint_timer_query,
|
||||
GLContext::EXT_occlusion_query_boolean,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
/*
|
||||
* XXX_query_objects only provide entry points commonly supported by
|
||||
* ARB_occlusion_query (added in OpenGL 2.0) and EXT_occlusion_query_boolean
|
||||
* (added in OpenGL ES 3.0)
|
||||
* ARB_occlusion_query (added in OpenGL 2.0), EXT_occlusion_query_boolean
|
||||
* (added in OpenGL ES 3.0), and ARB_timer_query (added in OpenGL 3.3)
|
||||
*/
|
||||
},
|
||||
{
|
||||
"query_time_elapsed",
|
||||
GLVersion::GL3_3,
|
||||
GLESVersion::NONE,
|
||||
GLContext::ARB_timer_query,
|
||||
{
|
||||
GLContext::ANGLE_timer_query,
|
||||
GLContext::EXT_disjoint_timer_query,
|
||||
GLContext::EXT_timer_query,
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"read_buffer",
|
||||
GLVersion::GL2,
|
||||
|
|
|
@ -145,6 +145,12 @@ struct GLContextSymbols
|
|||
PFNGLGETQUERYOBJECTIVPROC fGetQueryObjectiv;
|
||||
typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint* params);
|
||||
PFNGLGETQUERYOBJECTUIVPROC fGetQueryObjectuiv;
|
||||
typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64* params);
|
||||
PFNGLGETQUERYOBJECTI64VPROC fGetQueryObjecti64v;
|
||||
typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64* params);
|
||||
PFNGLGETQUERYOBJECTUI64VPROC fGetQueryObjectui64v;
|
||||
typedef void (GLAPIENTRY * PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target);
|
||||
PFNGLQUERYCOUNTERPROC fQueryCounter;
|
||||
typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
|
||||
PFNGLTEXPARAMETERIPROC fTexParameteri;
|
||||
typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint* param);
|
||||
|
|
|
@ -175,15 +175,6 @@ public:
|
|||
return scrollableRect;
|
||||
}
|
||||
|
||||
// Return the scale factor needed to fit the viewport
|
||||
// into its composition bounds.
|
||||
CSSToParentLayerScale CalculateIntrinsicScale() const
|
||||
{
|
||||
return CSSToParentLayerScale(
|
||||
std::max(mCompositionBounds.width / mViewport.width,
|
||||
mCompositionBounds.height / mViewport.height));
|
||||
}
|
||||
|
||||
CSSSize CalculateCompositedSizeInCssPixels() const
|
||||
{
|
||||
return mCompositionBounds.Size() / GetZoom();
|
||||
|
|
|
@ -574,12 +574,26 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
|||
result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
|
||||
break;
|
||||
} case SCROLLWHEEL_INPUT: {
|
||||
FlushRepaintsToClearScreenToGeckoTransform();
|
||||
|
||||
ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput();
|
||||
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(wheelInput.mOrigin,
|
||||
&hitResult);
|
||||
if (apzc) {
|
||||
MOZ_ASSERT(hitResult == HitLayer || hitResult == HitDispatchToContentRegion);
|
||||
|
||||
// For wheel events, the call to ReceiveInputEvent below may result in
|
||||
// scrolling, which changes the async transform. However, the event we
|
||||
// want to pass to gecko should be the pre-scroll event coordinates,
|
||||
// transformed into the gecko space. (pre-scroll because the mouse
|
||||
// cursor is stationary during wheel scrolling, unlike touchmove
|
||||
// events). Also, since we just flushed the pending repaints the
|
||||
// transform to gecko space is a no-op so we can just skip it.
|
||||
MOZ_ASSERT(
|
||||
(GetScreenToApzcTransform(apzc) * GetApzcToGeckoTransform(apzc))
|
||||
.NudgeToIntegersFixedEpsilon()
|
||||
.IsIdentity());
|
||||
|
||||
result = mInputQueue->ReceiveInputEvent(
|
||||
apzc,
|
||||
/* aTargetConfirmed = */ hitResult == HitLayer,
|
||||
|
@ -587,10 +601,6 @@ APZCTreeManager::ReceiveInputEvent(InputData& aEvent,
|
|||
|
||||
// Update the out-parameters so they are what the caller expects.
|
||||
apzc->GetGuid(aOutTargetGuid);
|
||||
Matrix4x4 transformToGecko = GetScreenToApzcTransform(apzc)
|
||||
* GetApzcToGeckoTransform(apzc);
|
||||
wheelInput.mOrigin =
|
||||
TransformTo<ScreenPixel>(transformToGecko, wheelInput.mOrigin);
|
||||
}
|
||||
break;
|
||||
} case PANGESTURE_INPUT: {
|
||||
|
@ -668,17 +678,7 @@ APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
|
|||
return apzc.forget();
|
||||
}
|
||||
|
||||
{ // In this block we flush repaint requests for the entire APZ tree. We need to do this
|
||||
// at the start of an input block for a number of reasons. One of the reasons is so that
|
||||
// after we untransform the event into gecko space, it doesn't end up under something
|
||||
// else. Another reason is that if we hit-test this event and end up on a layer's
|
||||
// dispatch-to-content region we cannot be sure we actually got the correct layer. We
|
||||
// have to fall back to the gecko hit-test to handle this case, but we can't untransform
|
||||
// the event we send to gecko because we don't know the layer to untransform with
|
||||
// respect to.
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
FlushRepaintsRecursively(mRootNode);
|
||||
}
|
||||
FlushRepaintsToClearScreenToGeckoTransform();
|
||||
|
||||
apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, aOutHitResult);
|
||||
for (size_t i = 1; i < aEvent.mTouches.Length(); i++) {
|
||||
|
@ -770,6 +770,12 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
|||
Matrix4x4 transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock);
|
||||
Matrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock);
|
||||
Matrix4x4 outTransform = transformToApzc * transformToGecko;
|
||||
if (aInput.mType == MultiTouchInput::MULTITOUCH_START) {
|
||||
// For touch-start events we should have flushed all pending repaints
|
||||
// above as part of the GetTouchInputBlockAPZC call, and so we expect
|
||||
// the apzc-to-gecko transform to be empty.
|
||||
MOZ_ASSERT(outTransform.NudgeToIntegersFixedEpsilon().IsIdentity());
|
||||
}
|
||||
for (size_t i = 0; i < aInput.mTouches.Length(); i++) {
|
||||
SingleTouchData& touchData = aInput.mTouches[i];
|
||||
touchData.mScreenPoint = TransformTo<ScreenPixel>(
|
||||
|
@ -1057,6 +1063,32 @@ APZCTreeManager::UpdateZoomConstraintsRecursively(HitTestingTreeNode* aNode,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::FlushRepaintsToClearScreenToGeckoTransform()
|
||||
{
|
||||
// As the name implies, we flush repaint requests for the entire APZ tree in
|
||||
// order to clear the screen-to-gecko transform (aka the "untransform" applied
|
||||
// to incoming input events before they can be passed on to Gecko).
|
||||
//
|
||||
// The primary reason we do this is to avoid the problem where input events,
|
||||
// after being untransformed, end up hit-testing differently in Gecko. This
|
||||
// might happen in cases where the input event lands on content that is async-
|
||||
// scrolled into view, but Gecko still thinks it is out of view given the
|
||||
// visible area of a scrollframe.
|
||||
//
|
||||
// Another reason we want to clear the untransform is that if our APZ hit-test
|
||||
// hits a dispatch-to-content region then that's an ambiguous result and we
|
||||
// need to ask Gecko what actually got hit. In order to do this we need to
|
||||
// untransform the input event into Gecko space - but to do that we need to
|
||||
// know which APZC got hit! This leads to a circular dependency; the only way
|
||||
// to get out of it is to make sure that the untransform for all the possible
|
||||
// matched APZCs is the same. It is simplest to ensure that by flushing the
|
||||
// pending repaint requests, which makes all of the untransforms empty (and
|
||||
// therefore equal).
|
||||
MonitorAutoLock lock(mTreeLock);
|
||||
FlushRepaintsRecursively(mRootNode);
|
||||
}
|
||||
|
||||
void
|
||||
APZCTreeManager::FlushRepaintsRecursively(HitTestingTreeNode* aNode)
|
||||
{
|
||||
|
|
|
@ -429,6 +429,7 @@ private:
|
|||
void UpdateWheelTransaction(WidgetInputEvent& aEvent);
|
||||
void UpdateZoomConstraintsRecursively(HitTestingTreeNode* aNode,
|
||||
const ZoomConstraints& aConstraints);
|
||||
void FlushRepaintsToClearScreenToGeckoTransform();
|
||||
void FlushRepaintsRecursively(HitTestingTreeNode* aNode);
|
||||
|
||||
already_AddRefed<HitTestingTreeNode> RecycleOrCreateNode(TreeBuildingState& aState,
|
||||
|
|
|
@ -1505,6 +1505,7 @@ AsyncPanZoomController::AllowScrollHandoffInWheelTransaction() const
|
|||
nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEvent)
|
||||
{
|
||||
LayoutDevicePoint delta = GetScrollWheelDelta(aEvent);
|
||||
APZC_LOG("%p got a scroll-wheel with delta %s\n", this, Stringify(delta).c_str());
|
||||
|
||||
if ((delta.x || delta.y) &&
|
||||
!CanScrollWithWheel(delta) &&
|
||||
|
|
|
@ -125,16 +125,15 @@ void Axis::StartTouch(ParentLayerCoord aPos, uint32_t aTimestampMs) {
|
|||
|
||||
bool Axis::AdjustDisplacement(ParentLayerCoord aDisplacement,
|
||||
/* ParentLayerCoord */ float& aDisplacementOut,
|
||||
/* ParentLayerCoord */ float&
|
||||
aOverscrollAmountOut,
|
||||
bool forceOverscroll /* = false */)
|
||||
/* ParentLayerCoord */ float& aOverscrollAmountOut,
|
||||
bool aForceOverscroll /* = false */)
|
||||
{
|
||||
if (mAxisLocked) {
|
||||
aOverscrollAmountOut = 0;
|
||||
aDisplacementOut = 0;
|
||||
return false;
|
||||
}
|
||||
if (forceOverscroll) {
|
||||
if (aForceOverscroll) {
|
||||
aOverscrollAmountOut = aDisplacement;
|
||||
aDisplacementOut = 0;
|
||||
return false;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче