mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-10 22:09:32 +00:00
Merge m-c and birch.
This commit is contained in:
commit
b6a943bbd8
@ -468,6 +468,10 @@ var Output = {
|
||||
Utils.win.navigator.vibrate(aDetails.pattern);
|
||||
},
|
||||
|
||||
Braille: function Braille(aDetails, aBrowser) {
|
||||
Logger.debug('Braille output: ' + aDetails.text);
|
||||
},
|
||||
|
||||
_adjustBounds: function(aJsonBounds, aBrowser) {
|
||||
let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
|
||||
aJsonBounds.right - aJsonBounds.left,
|
||||
|
@ -16,11 +16,11 @@ ACCESSFU_FILES := \
|
||||
EventManager.jsm \
|
||||
jar.mn \
|
||||
Makefile.in \
|
||||
OutputGenerator.jsm \
|
||||
Presentation.jsm \
|
||||
TouchAdapter.jsm \
|
||||
TraversalRules.jsm \
|
||||
Utils.jsm \
|
||||
UtteranceGenerator.jsm \
|
||||
$(NULL)
|
||||
|
||||
ACCESSFU_DEST = $(FINAL_TARGET)/modules/accessibility
|
||||
|
@ -14,9 +14,14 @@ const INCLUDE_NAME = 0x02;
|
||||
const INCLUDE_CUSTOM = 0x04;
|
||||
const NAME_FROM_SUBTREE_RULE = 0x08;
|
||||
|
||||
const UTTERANCE_DESC_FIRST = 0;
|
||||
const OUTPUT_DESC_FIRST = 0;
|
||||
const OUTPUT_DESC_LAST = 1;
|
||||
|
||||
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
|
||||
'resource://gre/modules/accessibility/Utils.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'PrefCache',
|
||||
'resource://gre/modules/accessibility/Utils.jsm');
|
||||
|
||||
let gUtteranceOrder = new PrefCache('accessibility.accessfu.utterance');
|
||||
|
||||
@ -24,44 +29,12 @@ var gStringBundle = Cc['@mozilla.org/intl/stringbundle;1'].
|
||||
getService(Ci.nsIStringBundleService).
|
||||
createBundle('chrome://global/locale/AccessFu.properties');
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['UtteranceGenerator'];
|
||||
this.EXPORTED_SYMBOLS = ['UtteranceGenerator', 'BrailleGenerator'];
|
||||
|
||||
|
||||
/**
|
||||
* Generates speech utterances from objects, actions and state changes.
|
||||
* An utterance is an array of strings.
|
||||
*
|
||||
* It should not be assumed that flattening an utterance array would create a
|
||||
* gramatically correct sentence. For example, {@link genForObject} might
|
||||
* return: ['graphic', 'Welcome to my home page'].
|
||||
* Each string element in an utterance should be gramatically correct in itself.
|
||||
* Another example from {@link genForObject}: ['list item 2 of 5', 'Alabama'].
|
||||
*
|
||||
* An utterance is ordered from the least to the most important. Speaking the
|
||||
* last string usually makes sense, but speaking the first often won't.
|
||||
* For example {@link genForAction} might return ['button', 'clicked'] for a
|
||||
* clicked event. Speaking only 'clicked' makes sense. Speaking 'button' does
|
||||
* not.
|
||||
*/
|
||||
this.UtteranceGenerator = {
|
||||
gActionMap: {
|
||||
jump: 'jumpAction',
|
||||
press: 'pressAction',
|
||||
check: 'checkAction',
|
||||
uncheck: 'uncheckAction',
|
||||
select: 'selectAction',
|
||||
open: 'openAction',
|
||||
close: 'closeAction',
|
||||
switch: 'switchAction',
|
||||
click: 'clickAction',
|
||||
collapse: 'collapseAction',
|
||||
expand: 'expandAction',
|
||||
activate: 'activateAction',
|
||||
cycle: 'cycleAction'
|
||||
},
|
||||
this.OutputGenerator = {
|
||||
|
||||
/**
|
||||
* Generates an utterance for a PivotContext.
|
||||
* Generates output for a PivotContext.
|
||||
* @param {PivotContext} aContext object that generates and caches
|
||||
* context information for a given accessible and its relationship with
|
||||
* another accessible.
|
||||
@ -70,43 +43,44 @@ this.UtteranceGenerator = {
|
||||
* starting from the accessible's ancestry or accessible's subtree.
|
||||
*/
|
||||
genForContext: function genForContext(aContext) {
|
||||
let utterance = [];
|
||||
let addUtterance = function addUtterance(aAccessible) {
|
||||
utterance.push.apply(utterance,
|
||||
UtteranceGenerator.genForObject(aAccessible));
|
||||
let output = [];
|
||||
let self = this;
|
||||
let addOutput = function addOutput(aAccessible) {
|
||||
output.push.apply(output, self.genForObject(aAccessible));
|
||||
};
|
||||
let ignoreSubtree = function ignoreSubtree(aAccessible) {
|
||||
let roleString = Utils.AccRetrieval.getStringRole(aAccessible.role);
|
||||
let nameRule = UtteranceGenerator.roleRuleMap[roleString] || 0;
|
||||
let nameRule = self.roleRuleMap[roleString] || 0;
|
||||
// Ignore subtree if the name is explicit and the role's name rule is the
|
||||
// NAME_FROM_SUBTREE_RULE.
|
||||
return (nameRule & NAME_FROM_SUBTREE_RULE) &&
|
||||
(Utils.getAttributes(aAccessible)['explicit-name'] === 'true');
|
||||
};
|
||||
let utteranceOrder = gUtteranceOrder.value || UTTERANCE_DESC_FIRST;
|
||||
let outputOrder = typeof gUtteranceOrder.value == 'number' ?
|
||||
gUtteranceOrder.value : this.defaultOutputOrder;
|
||||
let contextStart = this._getContextStart(aContext);
|
||||
|
||||
if (utteranceOrder === UTTERANCE_DESC_FIRST) {
|
||||
aContext.newAncestry.forEach(addUtterance);
|
||||
addUtterance(aContext.accessible);
|
||||
[addUtterance(node) for
|
||||
if (outputOrder === OUTPUT_DESC_FIRST) {
|
||||
contextStart.forEach(addOutput);
|
||||
addOutput(aContext.accessible);
|
||||
[addOutput(node) for
|
||||
(node of aContext.subtreeGenerator(true, ignoreSubtree))];
|
||||
} else {
|
||||
[addUtterance(node) for
|
||||
[addOutput(node) for
|
||||
(node of aContext.subtreeGenerator(false, ignoreSubtree))];
|
||||
addUtterance(aContext.accessible);
|
||||
aContext.newAncestry.reverse().forEach(addUtterance);
|
||||
addOutput(aContext.accessible);
|
||||
contextStart.reverse().forEach(addOutput);
|
||||
}
|
||||
|
||||
// Clean up the white space.
|
||||
let trimmed;
|
||||
utterance = [trimmed for (word of utterance) if (trimmed = word.trim())];
|
||||
|
||||
return utterance;
|
||||
output = [trimmed for (word of output) if (trimmed = word.trim())];
|
||||
return output;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Generates an utterance for an object.
|
||||
* Generates output for an object.
|
||||
* @param {nsIAccessible} aAccessible accessible object to generate utterance
|
||||
* for.
|
||||
* @return {Array} Two string array. The first string describes the object
|
||||
@ -116,9 +90,8 @@ this.UtteranceGenerator = {
|
||||
*/
|
||||
genForObject: function genForObject(aAccessible) {
|
||||
let roleString = Utils.AccRetrieval.getStringRole(aAccessible.role);
|
||||
|
||||
let func = this.objectUtteranceFunctions[roleString] ||
|
||||
this.objectUtteranceFunctions.defaultFunc;
|
||||
let func = this.objectOutputFunctions[roleString.replace(' ', '')] ||
|
||||
this.objectOutputFunctions.defaultFunc;
|
||||
|
||||
let flags = this.roleRuleMap[roleString] || 0;
|
||||
|
||||
@ -134,68 +107,61 @@ this.UtteranceGenerator = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Generates an utterance for an action performed.
|
||||
* TODO: May become more verbose in the future.
|
||||
* Generates output for an action performed.
|
||||
* @param {nsIAccessible} aAccessible accessible object that the action was
|
||||
* invoked in.
|
||||
* @param {string} aActionName the name of the action, one of the keys in
|
||||
* {@link gActionMap}.
|
||||
* @return {Array} A one string array with the action.
|
||||
*/
|
||||
genForAction: function genForAction(aObject, aActionName) {
|
||||
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
|
||||
},
|
||||
genForAction: function genForAction(aObject, aActionName) {},
|
||||
|
||||
/**
|
||||
* Generates an utterance for an announcement. Basically attempts to localize
|
||||
* Generates output for an announcement. Basically attempts to localize
|
||||
* the announcement string.
|
||||
* @param {string} aAnnouncement unlocalized announcement.
|
||||
* @return {Array} A one string array with the announcement.
|
||||
*/
|
||||
genForAnnouncement: function genForAnnouncement(aAnnouncement) {
|
||||
try {
|
||||
return [gStringBundle.GetStringFromName(aAnnouncement)];
|
||||
} catch (x) {
|
||||
return [aAnnouncement];
|
||||
}
|
||||
},
|
||||
genForAnnouncement: function genForAnnouncement(aAnnouncement) {},
|
||||
|
||||
/**
|
||||
* Generates an utterance for a tab state change.
|
||||
* Generates output for a tab state change.
|
||||
* @param {nsIAccessible} aAccessible accessible object of the tab's attached
|
||||
* document.
|
||||
* @param {string} aTabState the tab state name, see
|
||||
* {@link Presenter.tabStateChanged}.
|
||||
* @return {Array} The tab state utterace.
|
||||
*/
|
||||
genForTabStateChange: function genForTabStateChange(aObject, aTabState) {
|
||||
switch (aTabState) {
|
||||
case 'newtab':
|
||||
return [gStringBundle.GetStringFromName('tabNew')];
|
||||
case 'loading':
|
||||
return [gStringBundle.GetStringFromName('tabLoading')];
|
||||
case 'loaded':
|
||||
return [aObject.name || '',
|
||||
gStringBundle.GetStringFromName('tabLoaded')];
|
||||
case 'loadstopped':
|
||||
return [gStringBundle.GetStringFromName('tabLoadStopped')];
|
||||
case 'reload':
|
||||
return [gStringBundle.GetStringFromName('tabReload')];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
},
|
||||
genForTabStateChange: function genForTabStateChange(aObject, aTabState) {},
|
||||
|
||||
/**
|
||||
* Generates an utterance for announcing entering and leaving editing mode.
|
||||
* Generates output for announcing entering and leaving editing mode.
|
||||
* @param {aIsEditing} boolean true if we are in editing mode
|
||||
* @return {Array} The mode utterance
|
||||
*/
|
||||
genForEditingMode: function genForEditingMode(aIsEditing) {
|
||||
return [gStringBundle.GetStringFromName(
|
||||
aIsEditing ? 'editingMode' : 'navigationMode')];
|
||||
genForEditingMode: function genForEditingMode(aIsEditing) {},
|
||||
|
||||
_getContextStart: function getContextStart(aContext) {},
|
||||
|
||||
_addName: function _addName(aOutput, aAccessible, aFlags) {
|
||||
let name;
|
||||
if (Utils.getAttributes(aAccessible)['explicit-name'] === 'true' ||
|
||||
(aFlags & INCLUDE_NAME)) {
|
||||
name = aAccessible.name;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
let outputOrder = typeof gUtteranceOrder.value == 'number' ?
|
||||
gUtteranceOrder.value : this.defaultOutputOrder;
|
||||
aOutput[outputOrder === OUTPUT_DESC_FIRST ?
|
||||
'push' : 'unshift'](name);
|
||||
}
|
||||
},
|
||||
|
||||
_getLocalizedRole: function _getLocalizedRole(aRoleStr) {},
|
||||
|
||||
_getLocalizedStates: function _getLocalizedStates(aStates) {},
|
||||
|
||||
roleRuleMap: {
|
||||
'menubar': INCLUDE_DESC,
|
||||
'scrollbar': INCLUDE_DESC,
|
||||
@ -268,35 +234,119 @@ this.UtteranceGenerator = {
|
||||
'listbox': INCLUDE_DESC,
|
||||
'definitionlist': INCLUDE_DESC | INCLUDE_NAME},
|
||||
|
||||
objectUtteranceFunctions: {
|
||||
defaultFunc: function defaultFunc(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
let utterance = [];
|
||||
objectOutputFunctions: {
|
||||
_generateBaseOutput: function _generateBaseOutput(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
let output = [];
|
||||
|
||||
if (aFlags & INCLUDE_DESC) {
|
||||
let desc = this._getLocalizedStates(aStates);
|
||||
let roleStr = this._getLocalizedRole(aRoleStr);
|
||||
if (roleStr)
|
||||
desc.push(roleStr);
|
||||
utterance.push(desc.join(' '));
|
||||
output.push(desc.join(' '));
|
||||
}
|
||||
|
||||
this._addName(utterance, aAccessible, aFlags);
|
||||
this._addName(output, aAccessible, aFlags);
|
||||
|
||||
return utterance;
|
||||
return output;
|
||||
},
|
||||
|
||||
entry: function entry(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
let utterance = [];
|
||||
let output = [];
|
||||
let desc = this._getLocalizedStates(aStates);
|
||||
desc.push(this._getLocalizedRole(
|
||||
(aStates.ext & Ci.nsIAccessibleStates.EXT_STATE_MULTI_LINE) ?
|
||||
'textarea' : 'entry'));
|
||||
|
||||
utterance.push(desc.join(' '));
|
||||
output.push(desc.join(' '));
|
||||
|
||||
this._addName(utterance, aAccessible, aFlags);
|
||||
this._addName(output, aAccessible, aFlags);
|
||||
|
||||
return utterance;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates speech utterances from objects, actions and state changes.
|
||||
* An utterance is an array of strings.
|
||||
*
|
||||
* It should not be assumed that flattening an utterance array would create a
|
||||
* gramatically correct sentence. For example, {@link genForObject} might
|
||||
* return: ['graphic', 'Welcome to my home page'].
|
||||
* Each string element in an utterance should be gramatically correct in itself.
|
||||
* Another example from {@link genForObject}: ['list item 2 of 5', 'Alabama'].
|
||||
*
|
||||
* An utterance is ordered from the least to the most important. Speaking the
|
||||
* last string usually makes sense, but speaking the first often won't.
|
||||
* For example {@link genForAction} might return ['button', 'clicked'] for a
|
||||
* clicked event. Speaking only 'clicked' makes sense. Speaking 'button' does
|
||||
* not.
|
||||
*/
|
||||
this.UtteranceGenerator = {
|
||||
__proto__: OutputGenerator,
|
||||
|
||||
defaultOutputOrder: OUTPUT_DESC_FIRST,
|
||||
|
||||
gActionMap: {
|
||||
jump: 'jumpAction',
|
||||
press: 'pressAction',
|
||||
check: 'checkAction',
|
||||
uncheck: 'uncheckAction',
|
||||
select: 'selectAction',
|
||||
open: 'openAction',
|
||||
close: 'closeAction',
|
||||
switch: 'switchAction',
|
||||
click: 'clickAction',
|
||||
collapse: 'collapseAction',
|
||||
expand: 'expandAction',
|
||||
activate: 'activateAction',
|
||||
cycle: 'cycleAction'
|
||||
},
|
||||
|
||||
//TODO: May become more verbose in the future.
|
||||
genForAction: function genForAction(aObject, aActionName) {
|
||||
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
|
||||
},
|
||||
|
||||
genForAnnouncement: function genForAnnouncement(aAnnouncement) {
|
||||
try {
|
||||
return [gStringBundle.GetStringFromName(aAnnouncement)];
|
||||
} catch (x) {
|
||||
return [aAnnouncement];
|
||||
}
|
||||
},
|
||||
|
||||
genForTabStateChange: function genForTabStateChange(aObject, aTabState) {
|
||||
switch (aTabState) {
|
||||
case 'newtab':
|
||||
return [gStringBundle.GetStringFromName('tabNew')];
|
||||
case 'loading':
|
||||
return [gStringBundle.GetStringFromName('tabLoading')];
|
||||
case 'loaded':
|
||||
return [aObject.name || '',
|
||||
gStringBundle.GetStringFromName('tabLoaded')];
|
||||
case 'loadstopped':
|
||||
return [gStringBundle.GetStringFromName('tabLoadStopped')];
|
||||
case 'reload':
|
||||
return [gStringBundle.GetStringFromName('tabReload')];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
genForEditingMode: function genForEditingMode(aIsEditing) {
|
||||
return [gStringBundle.GetStringFromName(
|
||||
aIsEditing ? 'editingMode' : 'navigationMode')];
|
||||
},
|
||||
|
||||
objectOutputFunctions: {
|
||||
defaultFunc: function defaultFunc(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
return OutputGenerator.objectOutputFunctions._generateBaseOutput.apply(this, arguments);
|
||||
},
|
||||
|
||||
entry: function entry(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
return OutputGenerator.objectOutputFunctions.entry.apply(this, arguments);
|
||||
},
|
||||
|
||||
heading: function heading(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
@ -338,25 +388,15 @@ this.UtteranceGenerator = {
|
||||
application: function application(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
// Don't utter location of applications, it gets tiring.
|
||||
if (aAccessible.name != aAccessible.DOMNode.location)
|
||||
return this.objectUtteranceFunctions.defaultFunc.apply(this,
|
||||
return this.objectOutputFunctions.defaultFunc.apply(this,
|
||||
[aAccessible, aRoleStr, aStates, aFlags]);
|
||||
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
_addName: function _addName(utterance, aAccessible, aFlags) {
|
||||
let name;
|
||||
if (Utils.getAttributes(aAccessible)['explicit-name'] === 'true' ||
|
||||
(aFlags & INCLUDE_NAME)) {
|
||||
name = aAccessible.name;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
let utteranceOrder = gUtteranceOrder.value || UTTERANCE_DESC_FIRST;
|
||||
utterance[utteranceOrder === UTTERANCE_DESC_FIRST ?
|
||||
'push' : 'unshift'](name);
|
||||
}
|
||||
_getContextStart: function _getContextStart(aContext) {
|
||||
return aContext.newAncestry;
|
||||
},
|
||||
|
||||
_getLocalizedRole: function _getLocalizedRole(aRoleStr) {
|
||||
@ -419,3 +459,118 @@ this.UtteranceGenerator = {
|
||||
return utterance;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.BrailleGenerator = {
|
||||
__proto__: OutputGenerator,
|
||||
|
||||
defaultOutputOrder: OUTPUT_DESC_LAST,
|
||||
|
||||
objectOutputFunctions: {
|
||||
defaultFunc: function defaultFunc(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
let braille = OutputGenerator.objectOutputFunctions._generateBaseOutput.apply(this, arguments);
|
||||
|
||||
if (aAccessible.indexInParent === 1 &&
|
||||
aAccessible.parent.role == Ci.nsIAccessibleRole.ROLE_LISTITEM &&
|
||||
aAccessible.previousSibling.role == Ci.nsIAccessibleRole.ROLE_STATICTEXT) {
|
||||
if (aAccessible.parent.parent && aAccessible.parent.parent.DOMNode &&
|
||||
aAccessible.parent.parent.DOMNode.nodeName == 'UL') {
|
||||
braille.unshift('*');
|
||||
} else {
|
||||
braille.unshift(aAccessible.previousSibling.name);
|
||||
}
|
||||
}
|
||||
|
||||
return braille;
|
||||
},
|
||||
|
||||
listitem: function listitem(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
let braille = [];
|
||||
|
||||
this._addName(braille, aAccessible, aFlags);
|
||||
|
||||
return braille;
|
||||
},
|
||||
|
||||
statictext: function statictext(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
// Since we customize the list bullet's output, we add the static
|
||||
// text from the first node in each listitem, so skip it here.
|
||||
if (aAccessible.parent.role == Ci.nsIAccessibleRole.ROLE_LISTITEM) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||
},
|
||||
|
||||
_useStateNotRole: function _useStateNotRole(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
let braille = [];
|
||||
|
||||
let desc = this._getLocalizedStates(aStates);
|
||||
braille.push(desc.join(' '));
|
||||
|
||||
this._addName(braille, aAccessible, aFlags);
|
||||
|
||||
return braille;
|
||||
},
|
||||
|
||||
checkbutton: function checkbutton(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||
},
|
||||
|
||||
radiobutton: function radiobutton(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||
},
|
||||
|
||||
togglebutton: function radiobutton(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
return this.objectOutputFunctions._useStateNotRole.apply(this, arguments);
|
||||
},
|
||||
|
||||
entry: function entry(aAccessible, aRoleStr, aStates, aFlags) {
|
||||
return OutputGenerator.objectOutputFunctions.entry.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
_getContextStart: function _getContextStart(aContext) {
|
||||
if (aContext.accessible.parent.role == Ci.nsIAccessibleRole.ROLE_LINK) {
|
||||
return [aContext.accessible.parent];
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
|
||||
_getLocalizedRole: function _getLocalizedRole(aRoleStr) {
|
||||
try {
|
||||
return gStringBundle.GetStringFromName(aRoleStr.replace(' ', '') + 'Abbr');
|
||||
} catch (x) {
|
||||
try {
|
||||
return gStringBundle.GetStringFromName(aRoleStr.replace(' ', ''));
|
||||
} catch (y) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_getLocalizedStates: function _getLocalizedStates(aStates) {
|
||||
let stateBraille = [];
|
||||
|
||||
let getCheckedState = function getCheckedState() {
|
||||
let resultMarker = [];
|
||||
let state = aStates.base;
|
||||
let fill = !!(state & Ci.nsIAccessibleStates.STATE_CHECKED) ||
|
||||
!!(state & Ci.nsIAccessibleStates.STATE_PRESSED);
|
||||
|
||||
resultMarker.push('(');
|
||||
resultMarker.push(fill ? 'x' : ' ');
|
||||
resultMarker.push(')');
|
||||
|
||||
return resultMarker.join('');
|
||||
};
|
||||
|
||||
if (aStates.base & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
|
||||
stateBraille.push(getCheckedState());
|
||||
}
|
||||
|
||||
return stateBraille;
|
||||
}
|
||||
|
||||
};
|
@ -9,8 +9,17 @@ const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
||||
Cu.import('resource://gre/modules/accessibility/UtteranceGenerator.jsm');
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
|
||||
'resource://gre/modules/accessibility/Utils.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
|
||||
'resource://gre/modules/accessibility/Utils.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'PivotContext',
|
||||
'resource://gre/modules/accessibility/Utils.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'UtteranceGenerator',
|
||||
'resource://gre/modules/accessibility/OutputGenerator.jsm');
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'BrailleGenerator',
|
||||
'resource://gre/modules/accessibility/OutputGenerator.jsm');
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['Presentation'];
|
||||
|
||||
@ -219,6 +228,15 @@ AndroidPresenter.prototype = {
|
||||
|
||||
let state = Utils.getStates(aContext.accessible)[0];
|
||||
|
||||
let brailleText = '';
|
||||
if (Utils.AndroidSdkVersion >= 16) {
|
||||
if (!this._braillePresenter) {
|
||||
this._braillePresenter = new BraillePresenter();
|
||||
}
|
||||
brailleText = this._braillePresenter.pivotChanged(aContext, aReason).
|
||||
details.text;
|
||||
}
|
||||
|
||||
androidEvents.push({eventType: (isExploreByTouch) ?
|
||||
this.ANDROID_VIEW_HOVER_ENTER : focusEventType,
|
||||
text: UtteranceGenerator.genForContext(aContext),
|
||||
@ -227,7 +245,8 @@ AndroidPresenter.prototype = {
|
||||
checkable: !!(state &
|
||||
Ci.nsIAccessibleStates.STATE_CHECKABLE),
|
||||
checked: !!(state &
|
||||
Ci.nsIAccessibleStates.STATE_CHECKED)});
|
||||
Ci.nsIAccessibleStates.STATE_CHECKED),
|
||||
brailleText: brailleText});
|
||||
|
||||
|
||||
return {
|
||||
@ -367,6 +386,29 @@ HapticPresenter.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A braille presenter
|
||||
*/
|
||||
|
||||
this.BraillePresenter = function BraillePresenter() {};
|
||||
|
||||
BraillePresenter.prototype = {
|
||||
__proto__: Presenter.prototype,
|
||||
|
||||
type: 'Braille',
|
||||
|
||||
pivotChanged: function BraillePresenter_pivotChanged(aContext, aReason) {
|
||||
if (!aContext.accessible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let text = BrailleGenerator.genForContext(aContext);
|
||||
|
||||
return { type: this.type, details: {text: text.join(' ')} };
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Presentation = {
|
||||
get presenters() {
|
||||
delete this.presenters;
|
||||
|
@ -13,10 +13,11 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MOCHITEST_A11Y_FILES =\
|
||||
jsatcommon.js \
|
||||
utterance.js \
|
||||
output.js \
|
||||
test_alive.html \
|
||||
test_explicit_names.html \
|
||||
test_utterance_order.html \
|
||||
test_braille.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
80
accessible/tests/mochitest/jsat/output.js
Normal file
80
accessible/tests/mochitest/jsat/output.js
Normal file
@ -0,0 +1,80 @@
|
||||
const Cu = Components.utils;
|
||||
const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance";
|
||||
|
||||
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
||||
Cu.import("resource://gre/modules/accessibility/OutputGenerator.jsm", this);
|
||||
|
||||
/**
|
||||
* Test context output generation.
|
||||
*
|
||||
* @param expected {Array} expected output.
|
||||
* @param aAccOrElmOrID identifier to get an accessible to test.
|
||||
* @param aOldAccOrElmOrID optional identifier to get an accessible relative to
|
||||
* the |aAccOrElmOrID|.
|
||||
* @param aGenerator the output generator to use when generating accessible
|
||||
* output
|
||||
*
|
||||
* Note: if |aOldAccOrElmOrID| is not provided, the |aAccOrElmOrID| must be
|
||||
* scoped to the "root" element in markup.
|
||||
*/
|
||||
function testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aGenerator) {
|
||||
aOldAccOrElmOrID = aOldAccOrElmOrID || "root";
|
||||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
var oldAccessible = getAccessible(aOldAccOrElmOrID);
|
||||
var context = new PivotContext(accessible, oldAccessible);
|
||||
var output = aGenerator.genForContext(context);
|
||||
isDeeply(output, expected,
|
||||
"Context output is correct for " + aAccOrElmOrID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test object output generated array that includes names.
|
||||
* Note: test ignores outputs without the name.
|
||||
*
|
||||
* @param aAccOrElmOrID identifier to get an accessible to test.
|
||||
* @param aGenerator the output generator to use when generating accessible
|
||||
* output
|
||||
*/
|
||||
function testObjectOutput(aAccOrElmOrID, aGenerator) {
|
||||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
var output = aGenerator.genForObject(accessible);
|
||||
var outputOrder;
|
||||
try {
|
||||
outputOrder = SpecialPowers.getIntPref(PREF_UTTERANCE_ORDER);
|
||||
} catch (ex) {
|
||||
// PREF_UTTERANCE_ORDER not set.
|
||||
outputOrder = 0;
|
||||
}
|
||||
var expectedNameIndex = outputOrder === 0 ? output.length - 1 : 0;
|
||||
var nameIndex = output.indexOf(accessible.name);
|
||||
|
||||
if (nameIndex > -1) {
|
||||
ok(output.indexOf(accessible.name) === expectedNameIndex,
|
||||
"Object output is correct for " + aAccOrElmOrID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test object and context output for an accessible.
|
||||
*
|
||||
* @param expected {Array} expected output.
|
||||
* @param aAccOrElmOrID identifier to get an accessible to test.
|
||||
* @param aOldAccOrElmOrID optional identifier to get an accessible relative to
|
||||
* the |aAccOrElmOrID|.
|
||||
* @param aOutputKind the type of output
|
||||
*/
|
||||
function testOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, aOutputKind) {
|
||||
var generator;
|
||||
if (aOutputKind === 1) {
|
||||
generator = UtteranceGenerator;
|
||||
} else {
|
||||
generator = BrailleGenerator;
|
||||
}
|
||||
testContextOutput(expected, aAccOrElmOrID, aOldAccOrElmOrID, generator);
|
||||
// Just need to test object output for individual
|
||||
// accOrElmOrID.
|
||||
if (aOldAccOrElmOrID) {
|
||||
return;
|
||||
}
|
||||
testObjectOutput(aAccOrElmOrID, generator);
|
||||
}
|
114
accessible/tests/mochitest/jsat/test_braille.html
Normal file
114
accessible/tests/mochitest/jsat/test_braille.html
Normal file
@ -0,0 +1,114 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=876475
|
||||
-->
|
||||
<head>
|
||||
<title>[AccessFu] braille generation test</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="./output.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
||||
function doTest() {
|
||||
// Test the following accOrElmOrID (with optional old accOrElmOrID).
|
||||
// Note: each accOrElmOrID entry maps to a unique object braille
|
||||
// generator function within the BrailleGenerator.
|
||||
var tests = [{
|
||||
accOrElmOrID: "link",
|
||||
expected: [["lnk", "Link"], ["Link", "lnk"]]
|
||||
},{
|
||||
accOrElmOrID: "button",
|
||||
expected: [["btn", "I am a button"], ["I am a button", "btn"]]
|
||||
},{
|
||||
accOrElmOrID: "password_input",
|
||||
expected: [["passwdtxt", "Secret Password"], ["Secret Password", "passwdtxt"]]
|
||||
},{
|
||||
accOrElmOrID: "checkbox_unchecked",
|
||||
expected: [["( )", "checkboxtext"], ["checkboxtext", "( )"]]
|
||||
},{
|
||||
accOrElmOrID: "checkbox_checked",
|
||||
expected: [["(x)", "some more checkbox text"], ["some more checkbox text", "(x)"]]
|
||||
},{
|
||||
accOrElmOrID: "radio_unselected",
|
||||
expected: [["( )", "any old radio button"], ["any old radio button", "( )"]]
|
||||
},{
|
||||
accOrElmOrID: "radio_selected",
|
||||
expected: [["(x)", "a unique radio button"], ["a unique radio button", "(x)"]]
|
||||
},{
|
||||
accOrElmOrID: "togglebutton_notpressed",
|
||||
expected: [["( )", "I ain't pressed"], ["I ain't pressed", "( )"]]
|
||||
},{
|
||||
accOrElmOrID: "togglebutton_pressed",
|
||||
expected: [["(x)", "I am pressed!"], ["I am pressed!", "(x)"]]
|
||||
},{
|
||||
accOrElmOrID: "ul_li_one",
|
||||
expected: [["*", "ul item 1"], ["*", "ul item 1"]]
|
||||
},{
|
||||
accOrElmOrID: "ol_li_one",
|
||||
expected: [["1.", "ol item 1"], ["1.", "ol item 1"]]
|
||||
},{
|
||||
accOrElmOrID: "textarea",
|
||||
expected: [["txtarea", "Here lies treasure."], ["Here lies treasure.", "txtarea"]]
|
||||
}];
|
||||
|
||||
// Test all possible braille order preference values.
|
||||
tests.forEach(function run(test) {
|
||||
var brailleOrderValues = [0, 1];
|
||||
brailleOrderValues.forEach(
|
||||
function testBrailleOrder(brailleOrder) {
|
||||
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, brailleOrder);
|
||||
var expected = test.expected[brailleOrder];
|
||||
testOutput(expected, test.accOrElmOrID, test.oldAccOrElmOrID, 2);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// If there was an original utterance order preference, revert to it.
|
||||
SpecialPowers.clearUserPref(PREF_UTTERANCE_ORDER);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<a href="example.com" id="link">Link</a>
|
||||
<button id="button">I am a button</button>
|
||||
<label for="password_input">Secret Password</label><input id="password_input" type="password"></input>
|
||||
<label for="checkbox_unchecked">checkboxtext</label><input id="checkbox_unchecked" type="checkbox"></input>
|
||||
<label for="checkbox_checked">some more checkbox text</label><input id="checkbox_checked" type="checkbox" checked></input>
|
||||
<label for="radio_unselected">any old radio button</label><input id="radio_unselected" type="radio"></input>
|
||||
<label for="radio_selected">a unique radio button</label><input id="radio_selected" type="radio" checked></input>
|
||||
<div id="togglebutton_notpressed" aria-pressed="false" role="button" tabindex="-1">I ain't pressed</div>
|
||||
<div id="togglebutton_pressed" aria-pressed="true" role="button" tabindex="-1">I am pressed!</div>
|
||||
<ol id="ordered_list">
|
||||
<li id="ol_li_one">ol item 1</li>
|
||||
<li id="ol_li_two">ol item 2</li>
|
||||
<li id="ol_li_three">ol item 3</li>
|
||||
<li id="ol_li_three">ol item 4</li>
|
||||
</ol>
|
||||
<ul id="unordered_list">
|
||||
<li id="ul_li_one">ul item 1</li>
|
||||
<li id="ul_li_two">ul item 2</li>
|
||||
<li id="ul_li_three">ul item 3</li>
|
||||
<li id="ul_li_three">ul item 4</li>
|
||||
</ul>
|
||||
<textarea id="textarea" cols="80" rows="5">
|
||||
Here lies treasure.
|
||||
</textarea>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -9,7 +9,7 @@
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="utterance.js"></script>
|
||||
src="output.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
||||
function doTest() {
|
||||
@ -87,11 +87,14 @@
|
||||
"Plums"]
|
||||
}];
|
||||
|
||||
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, 0);
|
||||
|
||||
// Test various explicit names vs the utterance generated from subtrees.
|
||||
tests.forEach(function run(test) {
|
||||
testUtterance(test.expected, test.accOrElmOrID, test.oldAccOrElmOrID);
|
||||
testOutput(test.expected, test.accOrElmOrID, test.oldAccOrElmOrID, 1);
|
||||
});
|
||||
|
||||
SpecialPowers.clearUserPref(PREF_UTTERANCE_ORDER);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="./utterance.js"></script>
|
||||
src="./output.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
||||
function doTest() {
|
||||
@ -120,7 +120,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
|
||||
function testUtteranceOrder(utteranceOrder) {
|
||||
SpecialPowers.setIntPref(PREF_UTTERANCE_ORDER, utteranceOrder);
|
||||
var expected = test.expected[utteranceOrder];
|
||||
testUtterance(expected, test.accOrElmOrID, test.oldAccOrElmOrID);
|
||||
testOutput(expected, test.accOrElmOrID, test.oldAccOrElmOrID, 1);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -1,70 +0,0 @@
|
||||
const Cu = Components.utils;
|
||||
const PREF_UTTERANCE_ORDER = "accessibility.accessfu.utterance";
|
||||
|
||||
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
|
||||
Cu.import("resource://gre/modules/accessibility/UtteranceGenerator.jsm",
|
||||
this);
|
||||
|
||||
/**
|
||||
* Test context utterance generation.
|
||||
*
|
||||
* @param expected {Array} expected utterance.
|
||||
* @param aAccOrElmOrID identifier to get an accessible to test.
|
||||
* @param aOldAccOrElmOrID optional identifier to get an accessible relative to
|
||||
* the |aAccOrElmOrID|.
|
||||
*
|
||||
* Note: if |aOldAccOrElmOrID| is not provided, the |aAccOrElmOrID| must be
|
||||
* scoped to the "root" element in markup.
|
||||
*/
|
||||
function testContextUtterance(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
|
||||
aOldAccOrElmOrID = aOldAccOrElmOrID || "root";
|
||||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
var oldAccessible = getAccessible(aOldAccOrElmOrID);
|
||||
var context = new PivotContext(accessible, oldAccessible);
|
||||
var utterance = UtteranceGenerator.genForContext(context);
|
||||
isDeeply(utterance, expected,
|
||||
"Context utterance is correct for " + aAccOrElmOrID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test object utterance generated array that includes names.
|
||||
* Note: test ignores utterances without the name.
|
||||
*
|
||||
* @param aAccOrElmOrID identifier to get an accessible to test.
|
||||
*/
|
||||
function testObjectUtterance(aAccOrElmOrID) {
|
||||
var accessible = getAccessible(aAccOrElmOrID);
|
||||
var utterance = UtteranceGenerator.genForObject(accessible);
|
||||
var utteranceOrder;
|
||||
try {
|
||||
utteranceOrder = SpecialPowers.getIntPref(PREF_UTTERANCE_ORDER);
|
||||
} catch (ex) {
|
||||
// PREF_UTTERANCE_ORDER not set.
|
||||
utteranceOrder = 0;
|
||||
}
|
||||
var expectedNameIndex = utteranceOrder === 0 ? utterance.length - 1 : 0;
|
||||
var nameIndex = utterance.indexOf(accessible.name);
|
||||
|
||||
if (nameIndex > -1) {
|
||||
ok(utterance.indexOf(accessible.name) === expectedNameIndex,
|
||||
"Object utterance is correct for " + aAccOrElmOrID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test object and context utterance for an accessible.
|
||||
*
|
||||
* @param expected {Array} expected utterance.
|
||||
* @param aAccOrElmOrID identifier to get an accessible to test.
|
||||
* @param aOldAccOrElmOrID optional identifier to get an accessible relative to
|
||||
* the |aAccOrElmOrID|.
|
||||
*/
|
||||
function testUtterance(expected, aAccOrElmOrID, aOldAccOrElmOrID) {
|
||||
testContextUtterance(expected, aAccOrElmOrID, aOldAccOrElmOrID);
|
||||
// Just need to test object utterance for individual
|
||||
// accOrElmOrID.
|
||||
if (aOldAccOrElmOrID) {
|
||||
return;
|
||||
}
|
||||
testObjectUtterance(aAccOrElmOrID);
|
||||
}
|
@ -341,7 +341,7 @@ Section "-Application" APP_IDX
|
||||
${AddDisabledDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" \
|
||||
"${AppRegName} Document" ""
|
||||
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
|
||||
"true"
|
||||
"delete"
|
||||
|
||||
; For pre win8, the following keys should only be set if we can write to HKLM.
|
||||
; For post win8, the keys below get set in both HKLM and HKCU.
|
||||
|
@ -412,7 +412,7 @@ FunctionEnd
|
||||
"${AppRegName} HTML Document" ""
|
||||
|
||||
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" \
|
||||
"true"
|
||||
"delete"
|
||||
Call RegisterCEH
|
||||
|
||||
; An empty string is used for the 4th & 5th params because the following
|
||||
@ -650,7 +650,7 @@ FunctionEnd
|
||||
${IsHandlerForInstallDir} "FirefoxURL" $R9
|
||||
${If} "$R9" == "true"
|
||||
${AddDisabledDDEHandlerValues} "FirefoxURL" "$2" "$8,1" \
|
||||
"${AppRegName} URL" "true"
|
||||
"${AppRegName} URL" "delete"
|
||||
${EndIf}
|
||||
|
||||
; An empty string is used for the 4th & 5th params because the following
|
||||
|
@ -126,7 +126,7 @@
|
||||
* rectBrowserToClient
|
||||
* Converts a rect (left, top, right, bottom).
|
||||
*
|
||||
* @param aMessage - message manager message
|
||||
* @param aRect - rect to convert
|
||||
* @param aIgnoreScroll ignore root frame scroll.
|
||||
* @param aIgnoreScale ignore current scale factor.
|
||||
* @return { left:, top:, right:, bottom: }
|
||||
|
@ -10,9 +10,9 @@
|
||||
<html:div flex="1" class="selection-overlay-inner window-width window-height" anonid="selection-overlay-inner">
|
||||
<xul:stack>
|
||||
<html:div anonid="selection-overlay-debug" class="window-width window-height"/>
|
||||
<xul:toolbarbutton id="selectionhandle-mark1" label="^" left="10" top="10" hidden="true"/>
|
||||
<xul:toolbarbutton id="selectionhandle-mark2" label="^" left="10" top="10" hidden="true"/>
|
||||
<xul:toolbarbutton id="selectionhandle-mark3" label="^" left="10" top="10" hidden="true"/>
|
||||
<xul:toolbarbutton anonid="selectionhandle-mark1" class="selectionhandle" label="^" left="10" top="10" hidden="true"/>
|
||||
<xul:toolbarbutton anonid="selectionhandle-mark2" class="selectionhandle" label="^" left="10" top="10" hidden="true"/>
|
||||
<xul:toolbarbutton anonid="selectionhandle-mark3" class="selectionhandle" label="^" left="10" top="10" hidden="true"/>
|
||||
</xul:stack>
|
||||
</html:div>
|
||||
</content>
|
||||
@ -62,18 +62,11 @@
|
||||
</getter>
|
||||
</property>
|
||||
|
||||
<method name="init">
|
||||
<method name="getMarker">
|
||||
<parameter name="aMarkerId"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
this.enabled = true;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="shutdown">
|
||||
<body>
|
||||
<![CDATA[
|
||||
this.enabled = false;
|
||||
return document.getAnonymousElementByAttribute(this, "anonid", aMarkerId);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
@ -109,6 +109,8 @@ let ScriptContexts = {};
|
||||
["OfflineApps", "chrome://browser/content/helperui/OfflineApps.js"],
|
||||
["SelectHelperUI", "chrome://browser/content/helperui/SelectHelperUI.js"],
|
||||
["SelectionHelperUI", "chrome://browser/content/helperui/SelectionHelperUI.js"],
|
||||
["SelectionPrototype", "chrome://browser/content/library/SelectionPrototype.js"],
|
||||
["ChromeSelectionHandler", "chrome://browser/content/helperui/ChromeSelectionHandler.js"],
|
||||
["AnimatedZoom", "chrome://browser/content/AnimatedZoom.js"],
|
||||
["CommandUpdater", "chrome://browser/content/commandUtil.js"],
|
||||
["ContextCommands", "chrome://browser/content/ContextCommands.js"],
|
||||
|
@ -783,21 +783,35 @@ var BrowserUI = {
|
||||
onEvent: function(aEventName) {}
|
||||
},
|
||||
|
||||
_urlbarClicked: function _urlbarClicked() {
|
||||
_urlbarClicked: function _urlbarClicked(aEvent) {
|
||||
let touchEvent = aEvent.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH;
|
||||
|
||||
// If the urlbar is not already focused, focus it and select the contents.
|
||||
if (Elements.urlbarState.getAttribute("mode") != "edit")
|
||||
if (Elements.urlbarState.getAttribute("mode") != "edit") {
|
||||
this._editURI(true);
|
||||
if (touchEvent) {
|
||||
SelectionHelperUI.attachEditSession(ChromeSelectionHandler,
|
||||
aEvent.clientX, aEvent.clientY);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// tap caret handling
|
||||
if (touchEvent) {
|
||||
SelectionHelperUI.attachToCaret(ChromeSelectionHandler,
|
||||
aEvent.clientX, aEvent.clientY);
|
||||
}
|
||||
},
|
||||
|
||||
_editURI: function _editURI(aShouldDismiss) {
|
||||
this._clearURIFormatting();
|
||||
this._edit.focus();
|
||||
this._edit.select();
|
||||
|
||||
Elements.urlbarState.setAttribute("mode", "edit");
|
||||
StartUI.show();
|
||||
if (aShouldDismiss)
|
||||
if (aShouldDismiss) {
|
||||
ContextUI.dismissTabs();
|
||||
}
|
||||
},
|
||||
|
||||
formatURI: function formatURI() {
|
||||
|
@ -89,7 +89,8 @@ setting[type="menulist"] {
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-multi");
|
||||
}
|
||||
|
||||
#selection-overlay {
|
||||
#chrome-selection-overlay,
|
||||
#content-selection-overlay {
|
||||
-moz-binding: url("chrome://browser/content/bindings/selectionoverlay.xml#selection-binding");
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ var Browser = {
|
||||
messageManager.loadFrameScript("chrome://browser/content/Util.js", true);
|
||||
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/Content.js", true);
|
||||
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/FormHelper.js", true);
|
||||
messageManager.loadFrameScript("chrome://browser/content/library/SelectionPrototype.js", true);
|
||||
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/SelectionHandler.js", true);
|
||||
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/ContextMenuHandler.js", true);
|
||||
messageManager.loadFrameScript("chrome://browser/content/contenthandlers/FindHandler.js", true);
|
||||
|
@ -235,7 +235,11 @@
|
||||
<deck id="browsers" flex="1" observes="bcast_preciseInput"/>
|
||||
<box id="vertical-scroller" class="scroller" orient="vertical" end="0" top="0"/>
|
||||
<box id="horizontal-scroller" class="scroller" orient="horizontal" left="0" bottom="0"/>
|
||||
</stack>
|
||||
|
||||
<!-- Content touch selection overlay -->
|
||||
<!-- onclick addresses dom bug 835175 -->
|
||||
<box onclick="false" class="selection-overlay-hidden" id="content-selection-overlay"/>
|
||||
</stack>
|
||||
</vbox>
|
||||
|
||||
<!-- popup for content navigator helper -->
|
||||
@ -360,9 +364,9 @@
|
||||
</toolbar>
|
||||
</appbar>
|
||||
|
||||
<!-- Selection overlay - this should be below any content that can have selectable text -->
|
||||
<!-- onclick addresses dom bug 835175, str in bug 832957 -->
|
||||
<box onclick="false" class="selection-overlay-hidden" id="selection-overlay"/>
|
||||
<!-- Chrome touch selection overlay -->
|
||||
<!-- onclick addresses dom bug 835175 -->
|
||||
<box onclick="false" class="selection-overlay-hidden" id="chrome-selection-overlay"/>
|
||||
|
||||
<autoscroller class="autoscroller" id="autoscrollerid"/>
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
364
browser/metro/base/content/helperui/ChromeSelectionHandler.js
Normal file
364
browser/metro/base/content/helperui/ChromeSelectionHandler.js
Normal file
@ -0,0 +1,364 @@
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* Selection handler for chrome text inputs
|
||||
*/
|
||||
|
||||
const kCaretMode = 1;
|
||||
const kSelectionMode = 2;
|
||||
|
||||
var ChromeSelectionHandler = {
|
||||
_mode: kSelectionMode,
|
||||
|
||||
/*************************************************
|
||||
* Messaging wrapper
|
||||
*/
|
||||
|
||||
sendAsync: function sendAsync(aMsg, aJson) {
|
||||
SelectionHelperUI.receiveMessage({
|
||||
name: aMsg,
|
||||
json: aJson
|
||||
});
|
||||
},
|
||||
|
||||
/*************************************************
|
||||
* Browser event handlers
|
||||
*/
|
||||
|
||||
/*
|
||||
* General selection start method for both caret and selection mode.
|
||||
*/
|
||||
_onSelectionAttach: function _onSelectionAttach(aJson) {
|
||||
this._domWinUtils = Util.getWindowUtils(window);
|
||||
this._contentWindow = window;
|
||||
this._targetElement = this._domWinUtils.elementFromPoint(aJson.xPos, aJson.yPos, true, false);
|
||||
|
||||
this._targetIsEditable = this._targetElement instanceof Components.interfaces.nsIDOMXULTextBoxElement;
|
||||
if (!this._targetIsEditable) {
|
||||
this._onFail("not an editable?");
|
||||
return;
|
||||
}
|
||||
|
||||
let selection = this._getSelection();
|
||||
if (!selection) {
|
||||
this._onFail("no selection.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selection.isCollapsed) {
|
||||
this._mode = kSelectionMode;
|
||||
this._updateSelectionUI("start", true, true);
|
||||
} else {
|
||||
this._mode = kCaretMode;
|
||||
this._updateSelectionUI("caret", false, false, true);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/*
|
||||
* Selection monocle start move event handler
|
||||
*/
|
||||
_onSelectionMoveStart: function _onSelectionMoveStart(aMsg) {
|
||||
if (!this.targetIsEditable) {
|
||||
this._onFail("_onSelectionMoveStart with bad targetElement.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._selectionMoveActive) {
|
||||
this._onFail("mouse is already down on drag start?");
|
||||
return;
|
||||
}
|
||||
|
||||
// We bail if things get out of sync here implying we missed a message.
|
||||
this._selectionMoveActive = true;
|
||||
|
||||
if (this._targetIsEditable) {
|
||||
// If we're coming out of an out-of-bounds scroll, the node the user is
|
||||
// trying to drag may be hidden (the monocle will be pegged to the edge
|
||||
// of the edit). Make sure the node the user wants to move is visible
|
||||
// and has focus.
|
||||
this._updateInputFocus(aMsg.change);
|
||||
}
|
||||
|
||||
// Update the position of our selection monocles
|
||||
this._updateSelectionUI("update", true, true);
|
||||
},
|
||||
|
||||
/*
|
||||
* Selection monocle move event handler
|
||||
*/
|
||||
_onSelectionMove: function _onSelectionMove(aMsg) {
|
||||
if (!this.targetIsEditable) {
|
||||
this._onFail("_onSelectionMove with bad targetElement.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._selectionMoveActive) {
|
||||
this._onFail("mouse isn't down for drag move?");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update selection in the doc
|
||||
let pos = null;
|
||||
if (aMsg.change == "start") {
|
||||
pos = aMsg.start;
|
||||
} else {
|
||||
pos = aMsg.end;
|
||||
}
|
||||
this._handleSelectionPoint(aMsg.change, pos, false);
|
||||
},
|
||||
|
||||
/*
|
||||
* Selection monocle move finished event handler
|
||||
*/
|
||||
_onSelectionMoveEnd: function _onSelectionMoveComplete(aMsg) {
|
||||
if (!this.targetIsEditable) {
|
||||
this._onFail("_onSelectionMoveEnd with bad targetElement.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._selectionMoveActive) {
|
||||
this._onFail("mouse isn't down for drag move?");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update selection in the doc
|
||||
let pos = null;
|
||||
if (aMsg.change == "start") {
|
||||
pos = aMsg.start;
|
||||
} else {
|
||||
pos = aMsg.end;
|
||||
}
|
||||
|
||||
this._handleSelectionPoint(aMsg.change, pos, true);
|
||||
this._selectionMoveActive = false;
|
||||
|
||||
// Update the position of our selection monocles
|
||||
this._updateSelectionUI("end", true, true);
|
||||
},
|
||||
|
||||
/*
|
||||
* Switch selection modes. Currently we only support switching
|
||||
* from "caret" to "selection".
|
||||
*/
|
||||
_onSwitchMode: function _onSwitchMode(aMode, aMarker, aX, aY) {
|
||||
if (aMode != "selection") {
|
||||
this._onFail("unsupported mode switch");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanity check to be sure we are initialized
|
||||
if (!this._targetElement) {
|
||||
this._onFail("not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
// Similar to _onSelectionStart - we need to create initial selection
|
||||
// but without the initialization bits.
|
||||
let framePoint = this._clientPointToFramePoint({ xPos: aX, yPos: aY });
|
||||
if (!this._domWinUtils.selectAtPoint(framePoint.xPos, framePoint.yPos,
|
||||
Ci.nsIDOMWindowUtils.SELECT_CHARACTER)) {
|
||||
this._onFail("failed to set selection at point");
|
||||
return;
|
||||
}
|
||||
|
||||
// We bail if things get out of sync here implying we missed a message.
|
||||
this._selectionMoveActive = true;
|
||||
this._mode = kSelectionMode;
|
||||
|
||||
// Update the position of the selection marker that is *not*
|
||||
// being dragged.
|
||||
this._updateSelectionUI("update", aMarker == "end", aMarker == "start");
|
||||
},
|
||||
|
||||
/*
|
||||
* Selection close event handler
|
||||
*
|
||||
* @param aClearSelection requests that selection be cleared.
|
||||
*/
|
||||
_onSelectionClose: function _onSelectionClose(aClearSelection) {
|
||||
if (aClearSelection) {
|
||||
this._clearSelection();
|
||||
}
|
||||
this._closeSelection();
|
||||
},
|
||||
|
||||
/*
|
||||
* Called if for any reason we fail during the selection
|
||||
* process. Cancels the selection.
|
||||
*/
|
||||
_onFail: function _onFail(aDbgMessage) {
|
||||
if (aDbgMessage && aDbgMessage.length > 0)
|
||||
Util.dumpLn(aDbgMessage);
|
||||
this.sendAsync("Content:SelectionFail");
|
||||
this._clearSelection();
|
||||
this._closeSelection();
|
||||
},
|
||||
|
||||
/*
|
||||
* Empty conversion routines to match those in
|
||||
* browser. Called by SelectionHelperUI when
|
||||
* sending and receiving coordinates in messages.
|
||||
*/
|
||||
|
||||
ptClientToBrowser: function ptClientToBrowser(aX, aY, aIgnoreScroll, aIgnoreScale) {
|
||||
return { x: aX, y: aY }
|
||||
},
|
||||
|
||||
rectBrowserToClient: function rectBrowserToClient(aRect, aIgnoreScroll, aIgnoreScale) {
|
||||
return {
|
||||
left: aRect.left,
|
||||
right: aRect.right,
|
||||
top: aRect.top,
|
||||
bottom: aRect.bottom
|
||||
}
|
||||
},
|
||||
|
||||
ptBrowserToClient: function ptBrowserToClient(aX, aY, aIgnoreScroll, aIgnoreScale) {
|
||||
return { x: aX, y: aY }
|
||||
},
|
||||
|
||||
ctobx: function ctobx(aCoord) {
|
||||
return aCoord;
|
||||
},
|
||||
|
||||
ctoby: function ctoby(aCoord) {
|
||||
return aCoord;
|
||||
},
|
||||
|
||||
btocx: function btocx(aCoord) {
|
||||
return aCoord;
|
||||
},
|
||||
|
||||
btocy: function btocy(aCoord) {
|
||||
return aCoord;
|
||||
},
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Selection helpers
|
||||
*/
|
||||
|
||||
/*
|
||||
* _clearSelection
|
||||
*
|
||||
* Clear existing selection if it exists and reset our internla state.
|
||||
*/
|
||||
_clearSelection: function _clearSelection() {
|
||||
let selection = this._getSelection();
|
||||
if (selection) {
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* _closeSelection
|
||||
*
|
||||
* Shuts SelectionHandler down.
|
||||
*/
|
||||
_closeSelection: function _closeSelection() {
|
||||
this._clearTimers();
|
||||
this._cache = null;
|
||||
this._contentWindow = null;
|
||||
this._targetElement = null;
|
||||
this._selectionMoveActive = false;
|
||||
this._domWinUtils = null;
|
||||
this._targetIsEditable = false;
|
||||
this.sendAsync("Content:HandlerShutdown", {});
|
||||
},
|
||||
|
||||
/*************************************************
|
||||
* Events
|
||||
*/
|
||||
|
||||
/*
|
||||
* Scroll + selection advancement timer when the monocle is
|
||||
* outside the bounds of an input control.
|
||||
*/
|
||||
scrollTimerCallback: function scrollTimerCallback() {
|
||||
let result = ChromeSelectionHandler.updateTextEditSelection();
|
||||
// Update monocle position and speed if we've dragged off to one side
|
||||
if (result.trigger) {
|
||||
ChromeSelectionHandler._updateSelectionUI("update", result.start, result.end);
|
||||
}
|
||||
},
|
||||
|
||||
msgHandler: function msgHandler(aMsg, aJson) {
|
||||
if (this._debugEvents && "Browser:SelectionMove" != aMsg) {
|
||||
Util.dumpLn("ChromeSelectionHandler:", aMsg);
|
||||
}
|
||||
switch(aMsg) {
|
||||
case "Browser:SelectionDebug":
|
||||
this._onSelectionDebug(aJson);
|
||||
break;
|
||||
|
||||
case "Browser:SelectionAttach":
|
||||
this._onSelectionAttach(aJson);
|
||||
break;
|
||||
|
||||
case "Browser:CaretAttach":
|
||||
this._onSelectionAttach(aJson);
|
||||
break;
|
||||
|
||||
case "Browser:SelectionClose":
|
||||
this._onSelectionClose(aJson.clearSelection);
|
||||
break;
|
||||
|
||||
case "Browser:SelectionUpdate":
|
||||
this._updateSelectionUI("update",
|
||||
this._mode == kSelectionMode,
|
||||
this._mode == kSelectionMode,
|
||||
this._mode == kCaretMode);
|
||||
break;
|
||||
|
||||
case "Browser:SelectionMoveStart":
|
||||
this._onSelectionMoveStart(aJson);
|
||||
break;
|
||||
|
||||
case "Browser:SelectionMove":
|
||||
this._onSelectionMove(aJson);
|
||||
break;
|
||||
|
||||
case "Browser:SelectionMoveEnd":
|
||||
this._onSelectionMoveEnd(aJson);
|
||||
break;
|
||||
|
||||
case "Browser:CaretUpdate":
|
||||
this._onCaretPositionUpdate(aJson.caret.xPos, aJson.caret.yPos);
|
||||
break;
|
||||
|
||||
case "Browser:CaretMove":
|
||||
this._onCaretMove(aJson.caret.xPos, aJson.caret.yPos);
|
||||
break;
|
||||
|
||||
case "Browser:SelectionSwitchMode":
|
||||
this._onSwitchMode(aJson.newMode, aJson.change, aJson.xPos, aJson.yPos);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/*************************************************
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
_getSelection: function _getSelection() {
|
||||
if (this._targetElement instanceof Ci.nsIDOMXULTextBoxElement) {
|
||||
return this._targetElement
|
||||
.QueryInterface(Components.interfaces.nsIDOMXULTextBoxElement)
|
||||
.editor.selection;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_getSelectController: function _getSelectController() {
|
||||
return this._targetElement
|
||||
.QueryInterface(Components.interfaces.nsIDOMXULTextBoxElement)
|
||||
.editor.selectionController;
|
||||
},
|
||||
};
|
||||
|
||||
ChromeSelectionHandler.__proto__ = new SelectionPrototype();
|
||||
ChromeSelectionHandler.type = 1; // kChromeSelector
|
||||
|
@ -13,14 +13,16 @@
|
||||
* padding top: 6
|
||||
*/
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
|
||||
// Y axis scroll distance that will disable this module and cancel selection
|
||||
const kDisableOnScrollDistance = 25;
|
||||
|
||||
// Drag hysteresis programmed into monocle drag moves
|
||||
const kDragHysteresisDistance = 10;
|
||||
|
||||
// selection layer id returned from SelectionHandlerUI's layerMode.
|
||||
const kChromeLayer = 1;
|
||||
const kContentLayer = 2;
|
||||
|
||||
/*
|
||||
* Markers
|
||||
*/
|
||||
@ -91,7 +93,7 @@ function Marker(aParent, aTag, aElementId, xPos, yPos) {
|
||||
this._xPos = xPos;
|
||||
this._yPos = yPos;
|
||||
this._selectionHelperUI = aParent;
|
||||
this._element = document.getElementById(aElementId);
|
||||
this._element = aParent.overlay.getMarker(aElementId);
|
||||
this._elementId = aElementId;
|
||||
// These get picked in input.js and receives drag input
|
||||
this._element.customDragger = new MarkerDragger(this);
|
||||
@ -282,7 +284,14 @@ var SelectionHelperUI = {
|
||||
},
|
||||
|
||||
get overlay() {
|
||||
return document.getElementById("selection-overlay");
|
||||
return document.getElementById(this.layerMode == kChromeLayer ?
|
||||
"chrome-selection-overlay" : "content-selection-overlay");
|
||||
},
|
||||
|
||||
get layerMode() {
|
||||
if (this._msgTarget && this._msgTarget instanceof SelectionPrototype)
|
||||
return kChromeLayer;
|
||||
return kContentLayer;
|
||||
},
|
||||
|
||||
/*
|
||||
@ -375,13 +384,13 @@ var SelectionHelperUI = {
|
||||
* Attempts to select underlying text at a point and begins editing
|
||||
* the section.
|
||||
*
|
||||
* @param aContent - Browser object
|
||||
* @param aMsgTarget - Browser or chrome message target
|
||||
* @param aX, aY - Browser relative client coordinates.
|
||||
*/
|
||||
openEditSession: function openEditSession(aBrowser, aX, aY) {
|
||||
if (!aBrowser || this.isActive)
|
||||
openEditSession: function openEditSession(aMsgTarget, aX, aY) {
|
||||
if (!aMsgTarget || this.isActive)
|
||||
return;
|
||||
this._init(aBrowser);
|
||||
this._init(aMsgTarget);
|
||||
this._setupDebugOptions();
|
||||
|
||||
// Send this over to SelectionHandler in content, they'll message us
|
||||
@ -398,13 +407,13 @@ var SelectionHelperUI = {
|
||||
*
|
||||
* Attaches to existing selection and begins editing.
|
||||
*
|
||||
* @param aBrowser - Browser object
|
||||
* @param aMsgTarget - Browser or chrome message target
|
||||
* @param aX, aY - Browser relative client coordinates.
|
||||
*/
|
||||
attachEditSession: function attachEditSession(aBrowser, aX, aY) {
|
||||
if (!aBrowser || this.isActive)
|
||||
attachEditSession: function attachEditSession(aMsgTarget, aX, aY) {
|
||||
if (!aMsgTarget || this.isActive)
|
||||
return;
|
||||
this._init(aBrowser);
|
||||
this._init(aMsgTarget);
|
||||
this._setupDebugOptions();
|
||||
|
||||
// Send this over to SelectionHandler in content, they'll message us
|
||||
@ -427,13 +436,13 @@ var SelectionHelperUI = {
|
||||
* Once the user starts a drag, the caret marker is hidden, and
|
||||
* the start and end markers take over.
|
||||
*
|
||||
* @param aBrowser - Browser object
|
||||
* @param aMsgTarget - Browser or chrome message target
|
||||
* @param aX, aY - Browser relative client coordinates of the tap
|
||||
* that initiated the session.
|
||||
*/
|
||||
attachToCaret: function attachToCaret(aBrowser, aX, aY) {
|
||||
attachToCaret: function attachToCaret(aMsgTarget, aX, aY) {
|
||||
if (!this.isActive) {
|
||||
this._init(aBrowser);
|
||||
this._init(aMsgTarget);
|
||||
this._setupDebugOptions();
|
||||
} else {
|
||||
this._hideMonocles();
|
||||
@ -507,8 +516,6 @@ var SelectionHelperUI = {
|
||||
window.addEventListener("touchstart", this, true);
|
||||
window.addEventListener("touchend", this, true);
|
||||
window.addEventListener("touchmove", this, true);
|
||||
window.addEventListener("MozContextUIShow", this, true);
|
||||
window.addEventListener("MozContextUIDismiss", this, true);
|
||||
window.addEventListener("MozPrecisePointer", this, true);
|
||||
window.addEventListener("MozDeckOffsetChanging", this, true);
|
||||
window.addEventListener("MozDeckOffsetChanged", this, true);
|
||||
@ -517,6 +524,8 @@ var SelectionHelperUI = {
|
||||
Elements.browsers.addEventListener("SizeChanged", this, true);
|
||||
Elements.browsers.addEventListener("ZoomChanged", this, true);
|
||||
|
||||
Elements.navbar.addEventListener("transitionend", this, true);
|
||||
|
||||
this.overlay.enabled = true;
|
||||
},
|
||||
|
||||
@ -533,8 +542,6 @@ var SelectionHelperUI = {
|
||||
window.removeEventListener("touchstart", this, true);
|
||||
window.removeEventListener("touchend", this, true);
|
||||
window.removeEventListener("touchmove", this, true);
|
||||
window.removeEventListener("MozContextUIShow", this, true);
|
||||
window.removeEventListener("MozContextUIDismiss", this, true);
|
||||
window.removeEventListener("MozPrecisePointer", this, true);
|
||||
window.removeEventListener("MozDeckOffsetChanging", this, true);
|
||||
window.removeEventListener("MozDeckOffsetChanged", this, true);
|
||||
@ -543,6 +550,8 @@ var SelectionHelperUI = {
|
||||
Elements.browsers.removeEventListener("SizeChanged", this, true);
|
||||
Elements.browsers.removeEventListener("ZoomChanged", this, true);
|
||||
|
||||
Elements.navbar.removeEventListener("transitionend", this, true);
|
||||
|
||||
this._shutdownAllMarkers();
|
||||
|
||||
this._selectionMarkIds = [];
|
||||
@ -622,9 +631,6 @@ var SelectionHelperUI = {
|
||||
* tap that initiates the change.
|
||||
*/
|
||||
_transitionFromSelectionToCaret: function _transitionFromSelectionToCaret(aClientX, aClientY) {
|
||||
// clear existing selection and shutdown SelectionHandler
|
||||
this.closeEditSession(true);
|
||||
|
||||
// Reset some of our state
|
||||
this._activeSelectionRect = null;
|
||||
|
||||
@ -691,7 +697,11 @@ var SelectionHelperUI = {
|
||||
Util.dumpLn("SelectionHelperUI sendAsyncMessage could not send", aMsg);
|
||||
return;
|
||||
}
|
||||
this._msgTarget.messageManager.sendAsyncMessage(aMsg, aJson);
|
||||
if (this._msgTarget && this._msgTarget instanceof SelectionPrototype) {
|
||||
this._msgTarget.msgHandler(aMsg, aJson);
|
||||
} else {
|
||||
this._msgTarget.messageManager.sendAsyncMessage(aMsg, aJson);
|
||||
}
|
||||
},
|
||||
|
||||
_checkForActiveDrag: function _checkForActiveDrag() {
|
||||
@ -714,8 +724,7 @@ var SelectionHelperUI = {
|
||||
* @param aX, aY - browser relative client coordinates
|
||||
*/
|
||||
_setCaretPositionAtPoint: function _setCaretPositionAtPoint(aX, aY) {
|
||||
let json = this._getMarkerBaseMessage();
|
||||
json.change = "caret";
|
||||
let json = this._getMarkerBaseMessage("caret");
|
||||
json.caret.xPos = aX;
|
||||
json.caret.yPos = aY;
|
||||
this._sendAsyncMessage("Browser:CaretUpdate", json);
|
||||
@ -743,7 +752,7 @@ var SelectionHelperUI = {
|
||||
/*
|
||||
* _setupMonocleIdArray
|
||||
*
|
||||
* Helper for initing the array of monocle ids.
|
||||
* Helper for initing the array of monocle anon ids.
|
||||
*/
|
||||
_setupMonocleIdArray: function _setupMonocleIdArray() {
|
||||
this._selectionMarkIds = ["selectionhandle-mark1",
|
||||
@ -763,6 +772,15 @@ var SelectionHelperUI = {
|
||||
}
|
||||
},
|
||||
|
||||
_showMonocles: function _showMonocles(aSelection) {
|
||||
if (!aSelection) {
|
||||
this.caretMark.show();
|
||||
} else {
|
||||
this.endMark.show();
|
||||
this.startMark.show();
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Event handlers for document events
|
||||
*/
|
||||
@ -820,8 +838,15 @@ var SelectionHelperUI = {
|
||||
// since we always get a single tap before a double, and double tap
|
||||
// copies selected text.
|
||||
if (selectionTap) {
|
||||
aEvent.stopPropagation();
|
||||
aEvent.preventDefault();
|
||||
if (!this._targetIsEditable) {
|
||||
this.closeEditSession(false);
|
||||
return;
|
||||
}
|
||||
// Attach to the newly placed caret position
|
||||
this._sendAsyncMessage("Browser:CaretAttach", {
|
||||
xPos: aEvent.clientX,
|
||||
yPos: aEvent.clientY
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -846,13 +871,6 @@ var SelectionHelperUI = {
|
||||
this._sendAsyncMessage("Browser:SelectionUpdate", {});
|
||||
},
|
||||
|
||||
_onContextUIVisibilityEvent: function _onContextUIVisibilityEvent(aType) {
|
||||
// Manage display of monocles when the context ui is displayed.
|
||||
if (!this.isActive)
|
||||
return;
|
||||
this.overlay.hidden = (aType == "MozContextUIShow");
|
||||
},
|
||||
|
||||
/*
|
||||
* _onDeckOffsetChanging - fired by ContentAreaObserver before the browser
|
||||
* deck is shifted for form input access in response to a soft keyboard
|
||||
@ -873,6 +891,24 @@ var SelectionHelperUI = {
|
||||
this.attachToCaret(null, this._lastPoint.xPos, this._lastPoint.yPos);
|
||||
},
|
||||
|
||||
/*
|
||||
* Detects when the nav bar hides or shows, so we can enable
|
||||
* selection at the appropriate location once the transition is
|
||||
* complete, or shutdown selection down when the nav bar is hidden.
|
||||
*/
|
||||
_onNavBarTransitionEvent: function _onNavBarTransitionEvent(aEvent) {
|
||||
if (this.layerMode == kContentLayer) {
|
||||
return;
|
||||
}
|
||||
if (aEvent.propertyName == "bottom" && !Elements.navbar.isShowing) {
|
||||
this.closeEditSession(false);
|
||||
return;
|
||||
}
|
||||
if (aEvent.propertyName == "bottom" && Elements.navbar.isShowing) {
|
||||
this._sendAsyncMessage("Browser:SelectionUpdate", {});
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Event handlers for message manager
|
||||
*/
|
||||
@ -897,17 +933,15 @@ var SelectionHelperUI = {
|
||||
_onSelectionRangeChange: function _onSelectionRangeChange(json) {
|
||||
let haveSelectionRect = true;
|
||||
|
||||
// start and end contain client coordinates.
|
||||
if (json.updateStart) {
|
||||
this.startMark.position(this._msgTarget.btocx(json.start.xPos, true),
|
||||
this._msgTarget.btocy(json.start.yPos, true));
|
||||
this.startMark.show();
|
||||
}
|
||||
if (json.updateEnd) {
|
||||
this.endMark.position(this._msgTarget.btocx(json.end.xPos, true),
|
||||
this._msgTarget.btocy(json.end.yPos, true));
|
||||
this.endMark.show();
|
||||
}
|
||||
|
||||
if (json.updateCaret) {
|
||||
// If selectionRangeFound is set SelectionHelper found a range we can
|
||||
// attach to. If not, there's no text in the control, and hence no caret
|
||||
@ -926,6 +960,12 @@ var SelectionHelperUI = {
|
||||
this._activeSelectionRect = Util.getCleanRect();
|
||||
this._targetElementRect =
|
||||
this._msgTarget.rectBrowserToClient(json.element, true);
|
||||
|
||||
// Ifd this is the end of a selection move show the appropriate
|
||||
// monocle images. src=(start, update, end, caret)
|
||||
if (json.src == "start" || json.src == "end") {
|
||||
this._showMonocles(true);
|
||||
}
|
||||
},
|
||||
|
||||
_onSelectionFail: function _onSelectionFail() {
|
||||
@ -1008,11 +1048,6 @@ var SelectionHelperUI = {
|
||||
this.closeEditSession(true);
|
||||
break;
|
||||
|
||||
case "MozContextUIShow":
|
||||
case "MozContextUIDismiss":
|
||||
this._onContextUIVisibilityEvent(aEvent.type);
|
||||
break;
|
||||
|
||||
case "MozDeckOffsetChanging":
|
||||
this._onDeckOffsetChanging(aEvent);
|
||||
break;
|
||||
@ -1020,6 +1055,10 @@ var SelectionHelperUI = {
|
||||
case "MozDeckOffsetChanged":
|
||||
this._onDeckOffsetChanged(aEvent);
|
||||
break;
|
||||
|
||||
case "transitionend":
|
||||
this._onNavBarTransitionEvent(aEvent);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1052,8 +1091,9 @@ var SelectionHelperUI = {
|
||||
* Callbacks from markers
|
||||
*/
|
||||
|
||||
_getMarkerBaseMessage: function _getMarkerBaseMessage() {
|
||||
_getMarkerBaseMessage: function _getMarkerBaseMessage(aMarkerTag) {
|
||||
return {
|
||||
change: aMarkerTag,
|
||||
start: {
|
||||
xPos: this._msgTarget.ctobx(this.startMark.xPos, true),
|
||||
yPos: this._msgTarget.ctoby(this.startMark.yPos, true)
|
||||
@ -1070,8 +1110,7 @@ var SelectionHelperUI = {
|
||||
},
|
||||
|
||||
markerDragStart: function markerDragStart(aMarker) {
|
||||
let json = this._getMarkerBaseMessage();
|
||||
json.change = aMarker.tag;
|
||||
let json = this._getMarkerBaseMessage(aMarker.tag);
|
||||
if (aMarker.tag == "caret") {
|
||||
this._sendAsyncMessage("Browser:CaretMove", json);
|
||||
return;
|
||||
@ -1080,8 +1119,7 @@ var SelectionHelperUI = {
|
||||
},
|
||||
|
||||
markerDragStop: function markerDragStop(aMarker) {
|
||||
let json = this._getMarkerBaseMessage();
|
||||
json.change = aMarker.tag;
|
||||
let json = this._getMarkerBaseMessage(aMarker.tag);
|
||||
if (aMarker.tag == "caret") {
|
||||
this._sendAsyncMessage("Browser:CaretUpdate", json);
|
||||
return;
|
||||
@ -1102,8 +1140,11 @@ var SelectionHelperUI = {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
let json = this._getMarkerBaseMessage();
|
||||
json.change = aMarker.tag;
|
||||
|
||||
// We'll re-display these after the drag is complete.
|
||||
this._hideMonocles();
|
||||
|
||||
let json = this._getMarkerBaseMessage(aMarker.tag);
|
||||
this._sendAsyncMessage("Browser:SelectionMove", json);
|
||||
return true;
|
||||
},
|
||||
|
940
browser/metro/base/content/library/SelectionPrototype.js
Normal file
940
browser/metro/base/content/library/SelectionPrototype.js
Normal file
@ -0,0 +1,940 @@
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* SelectionPrototype - common base class used by both chrome and content selection logic.
|
||||
*/
|
||||
|
||||
// selection node parameters for various apis
|
||||
const kSelectionNodeAnchor = 1;
|
||||
const kSelectionNodeFocus = 2;
|
||||
|
||||
// selection type property constants
|
||||
const kChromeSelector = 1;
|
||||
const kContentSelector = 2;
|
||||
|
||||
dump("### SelectionPrototype.js loaded\n");
|
||||
|
||||
/*
|
||||
http://mxr.mozilla.org/mozilla-central/source/docshell/base/nsIDocShell.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/content/base/public/nsISelectionDisplay.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/content/base/public/nsISelectionListener.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/content/base/public/nsISelectionPrivate.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/content/base/public/nsISelectionController.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/content/base/public/nsISelection.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMDocument.idl#372
|
||||
rangeCount
|
||||
getRangeAt
|
||||
containsNode
|
||||
http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html
|
||||
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/range/nsIDOMRange.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMDocument.idl#80
|
||||
content.document.createRange()
|
||||
getBoundingClientRect
|
||||
isPointInRange
|
||||
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMNode.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/base/nsIDOMWindowUtils.idl
|
||||
setSelectionAtPoint
|
||||
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMElement.idl
|
||||
getClientRect
|
||||
http://mxr.mozilla.org/mozilla-central/source/layout/generic/nsFrameSelection.h
|
||||
http://mxr.mozilla.org/mozilla-central/source/editor/idl/nsIEditor.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/base/nsIFocusManager.idl
|
||||
http://mxr.mozilla.org/mozilla-central/source/toolkit/content/widgets/textbox.xml
|
||||
http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/xul/nsIDOMXULTextboxElement.idl
|
||||
mEditor
|
||||
*/
|
||||
|
||||
var SelectionPrototype = function() { }
|
||||
|
||||
SelectionPrototype.prototype = {
|
||||
_debugEvents: false,
|
||||
_cache: {},
|
||||
_targetElement: null,
|
||||
_targetIsEditable: true,
|
||||
_contentOffset: { x: 0, y: 0 },
|
||||
_contentWindow: null,
|
||||
_debugOptions: { dumpRanges: false, displayRanges: false },
|
||||
_domWinUtils: null,
|
||||
_selectionMoveActive: false,
|
||||
_snap: false,
|
||||
_type: 0,
|
||||
|
||||
/*************************************************
|
||||
* Properties
|
||||
*/
|
||||
|
||||
get isActive() {
|
||||
return !!this._targetElement;
|
||||
},
|
||||
|
||||
get targetIsEditable() {
|
||||
return this._targetIsEditable || false;
|
||||
},
|
||||
|
||||
/*
|
||||
* snap - enable or disable word snap for the active marker when a
|
||||
* SelectionMoveEnd event is received. Typically you would disable
|
||||
* snap when zoom is < 1.0 for precision selection. defaults to off.
|
||||
*/
|
||||
get snap() {
|
||||
return this._snap;
|
||||
},
|
||||
|
||||
set snap(aValue) {
|
||||
this._snap = aValue;
|
||||
},
|
||||
|
||||
/*
|
||||
* type - returns a constant indicating which module we're
|
||||
* loaded into - chrome or content.
|
||||
*/
|
||||
set type(aValue) {
|
||||
this._type = aValue;
|
||||
},
|
||||
|
||||
get type() {
|
||||
return this._type;
|
||||
},
|
||||
|
||||
/*************************************************
|
||||
* Messaging wrapper
|
||||
*/
|
||||
|
||||
/*
|
||||
* sendAsync
|
||||
*
|
||||
* Wrapper over sendAsyncMessage in content, waps direct invocation on
|
||||
* SelectionHelperUI in chrome. Should be overriden by objects that inherit
|
||||
* our behavior.
|
||||
*/
|
||||
sendAsync: function sendAsync(aMsg, aJson) {
|
||||
Util.dumpLn("Base sendAsync called on SelectionPrototype. This is a no-op.");
|
||||
},
|
||||
|
||||
/*************************************************
|
||||
* Common browser event handlers
|
||||
*/
|
||||
|
||||
/*
|
||||
* _onCaretPositionUpdate - sets the current caret location based on
|
||||
* a client coordinates. Messages back with updated monocle position
|
||||
* information.
|
||||
*
|
||||
* @param aX, aY drag location in client coordinates.
|
||||
*/
|
||||
_onCaretPositionUpdate: function _onCaretPositionUpdate(aX, aY) {
|
||||
this._onCaretMove(aX, aY);
|
||||
|
||||
// Update the position of our selection monocles
|
||||
this._updateSelectionUI("caret", false, false, true);
|
||||
},
|
||||
|
||||
/*
|
||||
* _onCaretMove - updates the current caret location based on a client
|
||||
* coordinates.
|
||||
*
|
||||
* @param aX, aY drag location in client coordinates.
|
||||
*/
|
||||
_onCaretMove: function _onCaretMove(aX, aY) {
|
||||
if (!this._targetIsEditable) {
|
||||
this._onFail("Unexpected, caret position isn't supported with non-inputs.");
|
||||
return;
|
||||
}
|
||||
|
||||
// SelectionHelperUI sends text input tap coordinates and a caret move
|
||||
// event at the start of a monocle drag. caretPositionFromPoint isn't
|
||||
// going to give us correct info if the coord is outside the edit bounds,
|
||||
// so restrict the coordinates before we call cpfp.
|
||||
let containedCoords = this._restrictCoordinateToEditBounds(aX, aY);
|
||||
let cp = this._contentWindow.document.caretPositionFromPoint(containedCoords.xPos,
|
||||
containedCoords.yPos);
|
||||
let input = cp.offsetNode;
|
||||
let offset = cp.offset;
|
||||
input.selectionStart = input.selectionEnd = offset;
|
||||
},
|
||||
|
||||
/*
|
||||
* Turning on or off various debug features.
|
||||
*/
|
||||
_onSelectionDebug: function _onSelectionDebug(aMsg) {
|
||||
this._debugOptions = aMsg;
|
||||
this._debugEvents = aMsg.dumpEvents;
|
||||
},
|
||||
|
||||
/*************************************************
|
||||
* Selection api
|
||||
*/
|
||||
|
||||
/*
|
||||
* _updateSelectionUI
|
||||
*
|
||||
* Informs SelectionHelperUI about selection marker position
|
||||
* so that our selection monocles can be positioned properly.
|
||||
*
|
||||
* @param aSrcMsg string the message type that triggered this update.
|
||||
* @param aUpdateStart bool update start marker position
|
||||
* @param aUpdateEnd bool update end marker position
|
||||
* @param aUpdateCaret bool update caret marker position, can be
|
||||
* undefined, defaults to false.
|
||||
*/
|
||||
_updateSelectionUI: function _updateSelectionUI(aSrcMsg, aUpdateStart, aUpdateEnd,
|
||||
aUpdateCaret) {
|
||||
let selection = this._getSelection();
|
||||
|
||||
// If the range didn't have any text, let's bail
|
||||
if (!selection) {
|
||||
this._onFail("no selection was present");
|
||||
return;
|
||||
}
|
||||
|
||||
// Updates this._cache content selection position data which we send over
|
||||
// to SelectionHelperUI. Note updateUIMarkerRects will fail if there isn't
|
||||
// any selection in the page. This can happen when we start a monocle drag
|
||||
// but haven't dragged enough to create selection. Just return.
|
||||
try {
|
||||
this._updateUIMarkerRects(selection);
|
||||
} catch (ex) {
|
||||
Util.dumpLn("_updateUIMarkerRects:", ex.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this._cache.src = aSrcMsg;
|
||||
this._cache.updateStart = aUpdateStart;
|
||||
this._cache.updateEnd = aUpdateEnd;
|
||||
this._cache.updateCaret = aUpdateCaret || false;
|
||||
this._cache.targetIsEditable = this._targetIsEditable;
|
||||
|
||||
// Get monocles positioned correctly
|
||||
this.sendAsync("Content:SelectionRange", this._cache);
|
||||
},
|
||||
|
||||
/*
|
||||
* _handleSelectionPoint(aMarker, aPoint, aEndOfSelection)
|
||||
*
|
||||
* After a monocle moves to a new point in the document, determines
|
||||
* what the target is and acts on its selection accordingly. If the
|
||||
* monocle is within the bounds of the target, adds or subtracts selection
|
||||
* at the monocle coordinates appropriately and then merges selection ranges
|
||||
* into a single continuous selection. If the monocle is outside the bounds
|
||||
* of the target and the underlying target is editable, uses the selection
|
||||
* controller to advance selection and visibility within the control.
|
||||
*/
|
||||
_handleSelectionPoint: function _handleSelectionPoint(aMarker, aClientPoint,
|
||||
aEndOfSelection) {
|
||||
let selection = this._getSelection();
|
||||
|
||||
let clientPoint = { xPos: aClientPoint.xPos, yPos: aClientPoint.yPos };
|
||||
|
||||
if (selection.rangeCount == 0) {
|
||||
this._onFail("selection.rangeCount == 0");
|
||||
return;
|
||||
}
|
||||
|
||||
// We expect continuous selection ranges.
|
||||
if (selection.rangeCount > 1) {
|
||||
this._setContinuousSelection();
|
||||
}
|
||||
|
||||
// Adjust our y position up such that we are sending coordinates on
|
||||
// the text line vs. below it where the monocle is positioned.
|
||||
let halfLineHeight = this._queryHalfLineHeight(aMarker, selection);
|
||||
clientPoint.yPos -= halfLineHeight;
|
||||
|
||||
// Modify selection based on monocle movement
|
||||
if (this._targetIsEditable) {
|
||||
this._adjustEditableSelection(aMarker, clientPoint, aEndOfSelection);
|
||||
} else {
|
||||
this._adjustSelectionAtPoint(aMarker, clientPoint, aEndOfSelection);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* _handleSelectionPoint helper methods
|
||||
*/
|
||||
|
||||
/*
|
||||
* _adjustEditableSelection
|
||||
*
|
||||
* Based on a monocle marker and position, adds or subtracts from the
|
||||
* existing selection in editable controls. Handles auto-scroll as well.
|
||||
*
|
||||
* @param the marker currently being manipulated
|
||||
* @param aAdjustedClientPoint client point adjusted for line height.
|
||||
* @param aEndOfSelection indicates if this is the end of a selection
|
||||
* move, in which case we may want to snap to the end of a word or
|
||||
* sentence.
|
||||
*/
|
||||
_adjustEditableSelection: function _adjustEditableSelection(aMarker,
|
||||
aAdjustedClientPoint,
|
||||
aEndOfSelection) {
|
||||
// Test to see if we need to handle auto-scroll in cases where the
|
||||
// monocle is outside the bounds of the control. This also handles
|
||||
// adjusting selection if out-of-bounds is true.
|
||||
let result = this.updateTextEditSelection(aAdjustedClientPoint);
|
||||
|
||||
// If result.trigger is true, the monocle is outside the bounds of the
|
||||
// control.
|
||||
if (result.trigger) {
|
||||
// _handleSelectionPoint is triggered by input movement, so if we've
|
||||
// tested positive for out-of-bounds scrolling here, we need to set a
|
||||
// recurring timer to keep the expected selection behavior going as
|
||||
// long as the user keeps the monocle out of bounds.
|
||||
this._setTextEditUpdateInterval(result.speed);
|
||||
|
||||
// Smooth the selection
|
||||
this._setContinuousSelection();
|
||||
|
||||
// Update the other monocle's position if we've dragged off to one side
|
||||
this._updateSelectionUI("update", result.start, result.end);
|
||||
} else {
|
||||
// If we aren't out-of-bounds, clear the scroll timer if it exists.
|
||||
this._clearTimers();
|
||||
|
||||
// Restrict the client point to the interior of the control.
|
||||
let constrainedPoint =
|
||||
this._constrainPointWithinControl(aAdjustedClientPoint);
|
||||
|
||||
// For textareas we fall back on the selectAtPoint logic due to various
|
||||
// issues with caretPositionFromPoint (bug 882149).
|
||||
if (Util.isMultilineInput(this._targetElement)) {
|
||||
this._adjustSelectionAtPoint(aMarker, constrainedPoint, aEndOfSelection);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add or subtract selection
|
||||
let cp =
|
||||
this._contentWindow.document.caretPositionFromPoint(constrainedPoint.xPos,
|
||||
constrainedPoint.yPos);
|
||||
if (!cp || (cp.offsetNode != this._targetElement &&
|
||||
this._contentWindow.document.getBindingParent(cp.offsetNode) != this._targetElement)) {
|
||||
return;
|
||||
}
|
||||
if (aMarker == "start") {
|
||||
this._targetElement.selectionStart = cp.offset;
|
||||
} else {
|
||||
this._targetElement.selectionEnd = cp.offset;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* _adjustSelectionAtPoint
|
||||
*
|
||||
* Based on a monocle marker and position, adds or subtracts from the
|
||||
* existing selection at a point.
|
||||
*
|
||||
* Note: we are trying to move away from this api due to the overhead.
|
||||
*
|
||||
* @param the marker currently being manipulated
|
||||
* @param aClientPoint the point designating the new start or end
|
||||
* position for the selection.
|
||||
* @param aEndOfSelection indicates if this is the end of a selection
|
||||
* move, in which case we may want to snap to the end of a word or
|
||||
* sentence.
|
||||
*/
|
||||
_adjustSelectionAtPoint: function _adjustSelectionAtPoint(aMarker, aClientPoint,
|
||||
aEndOfSelection) {
|
||||
// Make a copy of the existing range, we may need to reset it.
|
||||
this._backupRangeList();
|
||||
|
||||
// shrinkSelectionFromPoint takes sub-frame relative coordinates.
|
||||
let framePoint = this._clientPointToFramePoint(aClientPoint);
|
||||
|
||||
// Tests to see if the user is trying to shrink the selection, and if so
|
||||
// collapses it down to the appropriate side such that our calls below
|
||||
// will reset the selection to the proper range.
|
||||
let shrunk = this._shrinkSelectionFromPoint(aMarker, framePoint);
|
||||
|
||||
let selectResult = false;
|
||||
try {
|
||||
// If we're at the end of a selection (touchend) snap to the word.
|
||||
let type = ((aEndOfSelection && this._snap) ?
|
||||
Ci.nsIDOMWindowUtils.SELECT_WORD :
|
||||
Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
|
||||
|
||||
// Select a character at the point.
|
||||
selectResult =
|
||||
this._domWinUtils.selectAtPoint(framePoint.xPos,
|
||||
framePoint.yPos,
|
||||
type);
|
||||
} catch (ex) {
|
||||
}
|
||||
|
||||
// If selectAtPoint failed (which can happen if there's nothing to select)
|
||||
// reset our range back before we shrunk it.
|
||||
if (!selectResult) {
|
||||
this._restoreRangeList();
|
||||
}
|
||||
|
||||
this._freeRangeList();
|
||||
|
||||
// Smooth over the selection between all existing ranges.
|
||||
this._setContinuousSelection();
|
||||
|
||||
// Update the other monocle's position. We do this because the dragging
|
||||
// monocle may reset the static monocle to a new position if the dragging
|
||||
// monocle drags ahead or behind the other.
|
||||
this._updateSelectionUI("update", aMarker == "end", aMarker == "start");
|
||||
},
|
||||
|
||||
/*
|
||||
* _backupRangeList, _restoreRangeList, and _freeRangeList
|
||||
*
|
||||
* Utilities that manage a cloned copy of the existing selection.
|
||||
*/
|
||||
|
||||
_backupRangeList: function _backupRangeList() {
|
||||
this._rangeBackup = new Array();
|
||||
for (let idx = 0; idx < this._getSelection().rangeCount; idx++) {
|
||||
this._rangeBackup.push(this._getSelection().getRangeAt(idx).cloneRange());
|
||||
}
|
||||
},
|
||||
|
||||
_restoreRangeList: function _restoreRangeList() {
|
||||
if (this._rangeBackup == null)
|
||||
return;
|
||||
for (let idx = 0; idx < this._rangeBackup.length; idx++) {
|
||||
this._getSelection().addRange(this._rangeBackup[idx]);
|
||||
}
|
||||
this._freeRangeList();
|
||||
},
|
||||
|
||||
_freeRangeList: function _restoreRangeList() {
|
||||
this._rangeBackup = null;
|
||||
},
|
||||
|
||||
/*
|
||||
* Constrains a selection point within a text input control bounds.
|
||||
*
|
||||
* @param aPoint - client coordinate point
|
||||
* @param aMargin - added inner margin to respect, defaults to 0.
|
||||
* @param aOffset - amount to push the resulting point inward, defaults to 0.
|
||||
* @return new constrained point struct
|
||||
*/
|
||||
_constrainPointWithinControl: function _cpwc(aPoint, aMargin, aOffset) {
|
||||
let margin = aMargin || 0;
|
||||
let offset = aOffset || 0;
|
||||
let bounds = this._getTargetBrowserRect();
|
||||
let point = { xPos: aPoint.xPos, yPos: aPoint.yPos };
|
||||
if (point.xPos <= (bounds.left + margin))
|
||||
point.xPos = bounds.left + offset;
|
||||
if (point.xPos >= (bounds.right - margin))
|
||||
point.xPos = bounds.right - offset;
|
||||
if (point.yPos <= (bounds.top + margin))
|
||||
point.yPos = bounds.top + offset;
|
||||
if (point.yPos >= (bounds.bottom - margin))
|
||||
point.yPos = bounds.bottom - offset;
|
||||
return point;
|
||||
},
|
||||
|
||||
/*
|
||||
* _pointOrientationToRect(aPoint, aRect)
|
||||
*
|
||||
* Returns a table representing which sides of target aPoint is offset
|
||||
* from: { left: offset, top: offset, right: offset, bottom: offset }
|
||||
* Works on client coordinates.
|
||||
*/
|
||||
_pointOrientationToRect: function _pointOrientationToRect(aPoint) {
|
||||
let bounds = this._getTargetBrowserRect();
|
||||
let result = { left: 0, right: 0, top: 0, bottom: 0 };
|
||||
if (aPoint.xPos <= bounds.left)
|
||||
result.left = bounds.left - aPoint.xPos;
|
||||
if (aPoint.xPos >= bounds.right)
|
||||
result.right = aPoint.xPos - bounds.right;
|
||||
if (aPoint.yPos <= bounds.top)
|
||||
result.top = bounds.top - aPoint.yPos;
|
||||
if (aPoint.yPos >= bounds.bottom)
|
||||
result.bottom = aPoint.yPos - bounds.bottom;
|
||||
return result;
|
||||
},
|
||||
|
||||
/*
|
||||
* updateTextEditSelection(aPoint, aClientPoint)
|
||||
*
|
||||
* Checks to see if the monocle point is outside the bounds of the target
|
||||
* edit. If so, use the selection controller to select and scroll the edit
|
||||
* appropriately.
|
||||
*
|
||||
* @param aClientPoint raw pointer position
|
||||
* @return { speed: 0.0 -> 1.0,
|
||||
* trigger: true/false if out of bounds,
|
||||
* start: true/false if updated position,
|
||||
* end: true/false if updated position }
|
||||
*/
|
||||
updateTextEditSelection: function updateTextEditSelection(aClientPoint) {
|
||||
if (aClientPoint == undefined) {
|
||||
aClientPoint = this._rawSelectionPoint;
|
||||
}
|
||||
this._rawSelectionPoint = aClientPoint;
|
||||
|
||||
let orientation = this._pointOrientationToRect(aClientPoint);
|
||||
let result = { speed: 1, trigger: false, start: false, end: false };
|
||||
let ml = Util.isMultilineInput(this._targetElement);
|
||||
|
||||
// This could be improved such that we only select to the beginning of
|
||||
// the line when dragging left but not up.
|
||||
if (orientation.left || (ml && orientation.top)) {
|
||||
this._addEditSelection(kSelectionNodeAnchor);
|
||||
result.speed = orientation.left + orientation.top;
|
||||
result.trigger = true;
|
||||
result.end = true;
|
||||
} else if (orientation.right || (ml && orientation.bottom)) {
|
||||
this._addEditSelection(kSelectionNodeFocus);
|
||||
result.speed = orientation.right + orientation.bottom;
|
||||
result.trigger = true;
|
||||
result.start = true;
|
||||
}
|
||||
|
||||
// 'speed' is just total pixels offset, so clamp it to something
|
||||
// reasonable callers can work with.
|
||||
if (result.speed > 100)
|
||||
result.speed = 100;
|
||||
if (result.speed < 1)
|
||||
result.speed = 1;
|
||||
result.speed /= 100;
|
||||
return result;
|
||||
},
|
||||
|
||||
_setTextEditUpdateInterval: function _setTextEditUpdateInterval(aSpeedValue) {
|
||||
let timeout = (75 - (aSpeedValue * 75));
|
||||
if (!this._scrollTimer)
|
||||
this._scrollTimer = new Util.Timeout();
|
||||
this._scrollTimer.interval(timeout, this.scrollTimerCallback);
|
||||
},
|
||||
|
||||
_clearTimers: function _clearTimers() {
|
||||
if (this._scrollTimer) {
|
||||
this._scrollTimer.clear();
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* _addEditSelection - selection control call wrapper for text inputs.
|
||||
* Adds selection on the anchor or focus side of selection in a text
|
||||
* input. Scrolls the location into view as well.
|
||||
*
|
||||
* @param const selection node identifier
|
||||
*/
|
||||
_addEditSelection: function _addEditSelection(aLocation) {
|
||||
let selCtrl = this._getSelectController();
|
||||
try {
|
||||
if (aLocation == kSelectionNodeAnchor) {
|
||||
let start = Math.max(this._targetElement.selectionStart - 1, 0);
|
||||
this._targetElement.setSelectionRange(start, this._targetElement.selectionEnd,
|
||||
"backward");
|
||||
} else {
|
||||
let end = Math.min(this._targetElement.selectionEnd + 1,
|
||||
this._targetElement.textLength);
|
||||
this._targetElement.setSelectionRange(this._targetElement.selectionStart,
|
||||
end,
|
||||
"forward");
|
||||
}
|
||||
selCtrl.scrollSelectionIntoView(Ci.nsISelectionController.SELECTION_NORMAL,
|
||||
Ci.nsISelectionController.SELECTION_FOCUS_REGION,
|
||||
Ci.nsISelectionController.SCROLL_SYNCHRONOUS);
|
||||
} catch (ex) { Util.dumpLn(ex);}
|
||||
},
|
||||
|
||||
_updateInputFocus: function _updateInputFocus(aMarker) {
|
||||
try {
|
||||
let selCtrl = this._getSelectController();
|
||||
this._targetElement.setSelectionRange(this._targetElement.selectionStart,
|
||||
this._targetElement.selectionEnd,
|
||||
aMarker == "start" ?
|
||||
"backward" : "forward");
|
||||
selCtrl.scrollSelectionIntoView(Ci.nsISelectionController.SELECTION_NORMAL,
|
||||
Ci.nsISelectionController.SELECTION_FOCUS_REGION,
|
||||
Ci.nsISelectionController.SCROLL_SYNCHRONOUS);
|
||||
} catch (ex) {}
|
||||
},
|
||||
|
||||
/*
|
||||
* _queryHalfLineHeight(aMarker, aSelection)
|
||||
*
|
||||
* Y offset applied to the coordinates of the selection position we send
|
||||
* to dom utils. The selection marker sits below text, but we want the
|
||||
* selection position to be on the text above the monocle. Since text
|
||||
* height can vary across the entire selection range, we need the correct
|
||||
* height based on the line the marker in question is moving on.
|
||||
*/
|
||||
_queryHalfLineHeight: function _queryHalfLineHeight(aMarker, aSelection) {
|
||||
let rects = aSelection.getRangeAt(0).getClientRects();
|
||||
if (!rects.length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We are assuming here that these rects are ordered correctly.
|
||||
// From looking at the range code it appears they will be.
|
||||
let height = 0;
|
||||
if (aMarker == "start") {
|
||||
// height of the first rect corresponding to the start marker:
|
||||
height = rects[0].bottom - rects[0].top;
|
||||
} else {
|
||||
// height of the last rect corresponding to the end marker:
|
||||
let len = rects.length - 1;
|
||||
height = rects[len].bottom - rects[len].top;
|
||||
}
|
||||
return height / 2;
|
||||
},
|
||||
|
||||
/*
|
||||
* _setContinuousSelection()
|
||||
*
|
||||
* Smooths a selection with multiple ranges into a single
|
||||
* continuous range.
|
||||
*/
|
||||
_setContinuousSelection: function _setContinuousSelection() {
|
||||
let selection = this._getSelection();
|
||||
try {
|
||||
if (selection.rangeCount > 1) {
|
||||
let startRange = selection.getRangeAt(0);
|
||||
if (this. _debugOptions.displayRanges) {
|
||||
let clientRect = startRange.getBoundingClientRect();
|
||||
this._setDebugRect(clientRect, "red", false);
|
||||
}
|
||||
let newStartNode = null;
|
||||
let newStartOffset = 0;
|
||||
let newEndNode = null;
|
||||
let newEndOffset = 0;
|
||||
for (let idx = 1; idx < selection.rangeCount; idx++) {
|
||||
let range = selection.getRangeAt(idx);
|
||||
switch (startRange.compareBoundaryPoints(Ci.nsIDOMRange.START_TO_START, range)) {
|
||||
case -1: // startRange is before
|
||||
newStartNode = startRange.startContainer;
|
||||
newStartOffset = startRange.startOffset;
|
||||
break;
|
||||
case 0: // startRange is equal
|
||||
newStartNode = startRange.startContainer;
|
||||
newStartOffset = startRange.startOffset;
|
||||
break;
|
||||
case 1: // startRange is after
|
||||
newStartNode = range.startContainer;
|
||||
newStartOffset = range.startOffset;
|
||||
break;
|
||||
}
|
||||
switch (startRange.compareBoundaryPoints(Ci.nsIDOMRange.END_TO_END, range)) {
|
||||
case -1: // startRange is before
|
||||
newEndNode = range.endContainer;
|
||||
newEndOffset = range.endOffset;
|
||||
break;
|
||||
case 0: // startRange is equal
|
||||
newEndNode = range.endContainer;
|
||||
newEndOffset = range.endOffset;
|
||||
break;
|
||||
case 1: // startRange is after
|
||||
newEndNode = startRange.endContainer;
|
||||
newEndOffset = startRange.endOffset;
|
||||
break;
|
||||
}
|
||||
if (this. _debugOptions.displayRanges) {
|
||||
let clientRect = range.getBoundingClientRect();
|
||||
this._setDebugRect(clientRect, "orange", false);
|
||||
}
|
||||
}
|
||||
let range = content.document.createRange();
|
||||
range.setStart(newStartNode, newStartOffset);
|
||||
range.setEnd(newEndNode, newEndOffset);
|
||||
selection.addRange(range);
|
||||
}
|
||||
} catch (ex) {
|
||||
Util.dumpLn("exception while modifying selection:", ex.message);
|
||||
this._onFail("_handleSelectionPoint failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/*
|
||||
* _shrinkSelectionFromPoint(aMarker, aFramePoint)
|
||||
*
|
||||
* Tests to see if aFramePoint intersects the current selection and if so,
|
||||
* collapses selection down to the opposite start or end point leaving a
|
||||
* character of selection at the collapse point.
|
||||
*
|
||||
* @param aMarker the marker that is being relocated. ("start" or "end")
|
||||
* @param aFramePoint position of the marker.
|
||||
*/
|
||||
_shrinkSelectionFromPoint: function _shrinkSelectionFromPoint(aMarker, aFramePoint) {
|
||||
let result = false;
|
||||
try {
|
||||
let selection = this._getSelection();
|
||||
for (let range = 0; range < selection.rangeCount; range++) {
|
||||
// relative to frame
|
||||
let rects = selection.getRangeAt(range).getClientRects();
|
||||
for (let idx = 0; idx < rects.length; idx++) {
|
||||
// Util.dumpLn("[" + idx + "]", aFramePoint.xPos, aFramePoint.yPos, rects[idx].left,
|
||||
// rects[idx].top, rects[idx].right, rects[idx].bottom);
|
||||
if (Util.pointWithinDOMRect(aFramePoint.xPos, aFramePoint.yPos, rects[idx])) {
|
||||
result = true;
|
||||
if (aMarker == "start") {
|
||||
selection.collapseToEnd();
|
||||
} else {
|
||||
selection.collapseToStart();
|
||||
}
|
||||
// collapseToStart and collapseToEnd leave an empty range in the
|
||||
// selection at the collapse point. Therefore we need to add some
|
||||
// selection such that the selection added by selectAtPoint and
|
||||
// the current empty range will get merged properly when we smooth
|
||||
// the selection ranges out.
|
||||
let selCtrl = this._getSelectController();
|
||||
// Expand the collapsed range such that it occupies a little space.
|
||||
if (aMarker == "start") {
|
||||
// State: focus = anchor (collapseToEnd does this)
|
||||
selCtrl.characterMove(false, true);
|
||||
// State: focus = (anchor - 1)
|
||||
selection.collapseToStart();
|
||||
// State: focus = anchor and both are -1 from the original offset
|
||||
selCtrl.characterMove(true, true);
|
||||
// State: focus = anchor + 1, both have been moved back one char
|
||||
} else {
|
||||
selCtrl.characterMove(true, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
Util.dumpLn("error shrinking selection:", ex.message);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/*
|
||||
* _updateUIMarkerRects(aSelection)
|
||||
*
|
||||
* Extracts the rects of the current selection, clips them to any text
|
||||
* input bounds, and stores them in the cache table we send over to
|
||||
* SelectionHelperUI.
|
||||
*/
|
||||
_updateUIMarkerRects: function _updateUIMarkerRects(aSelection) {
|
||||
this._cache = this._extractUIRects(aSelection.getRangeAt(0));
|
||||
if (this. _debugOptions.dumpRanges) {
|
||||
Util.dumpLn("start:", "(" + this._cache.start.xPos + "," +
|
||||
this._cache.start.yPos + ")");
|
||||
Util.dumpLn("end:", "(" + this._cache.end.xPos + "," +
|
||||
this._cache.end.yPos + ")");
|
||||
Util.dumpLn("caret:", "(" + this._cache.caret.xPos + "," +
|
||||
this._cache.caret.yPos + ")");
|
||||
}
|
||||
this._restrictSelectionRectToEditBounds();
|
||||
},
|
||||
|
||||
/*
|
||||
* _extractUIRects - Extracts selection and target element information
|
||||
* used by SelectionHelperUI. Returns client relative coordinates.
|
||||
*
|
||||
* @return table containing various ui rects and information
|
||||
*/
|
||||
_extractUIRects: function _extractUIRects(aRange) {
|
||||
let seldata = {
|
||||
start: {}, end: {}, caret: {},
|
||||
selection: { left: 0, top: 0, right: 0, bottom: 0 },
|
||||
element: { left: 0, top: 0, right: 0, bottom: 0 }
|
||||
};
|
||||
|
||||
// When in an iframe, aRange coordinates are relative to the frame origin.
|
||||
let rects = aRange.getClientRects();
|
||||
|
||||
if (rects && rects.length) {
|
||||
let startSet = false;
|
||||
for (let idx = 0; idx < rects.length; idx++) {
|
||||
if (this. _debugOptions.dumpRanges) Util.dumpDOMRect(idx, rects[idx]);
|
||||
if (!startSet && !Util.isEmptyDOMRect(rects[idx])) {
|
||||
seldata.start.xPos = rects[idx].left + this._contentOffset.x;
|
||||
seldata.start.yPos = rects[idx].bottom + this._contentOffset.y;
|
||||
seldata.caret = seldata.start;
|
||||
startSet = true;
|
||||
if (this. _debugOptions.dumpRanges) Util.dumpLn("start set");
|
||||
}
|
||||
if (!Util.isEmptyDOMRect(rects[idx])) {
|
||||
seldata.end.xPos = rects[idx].right + this._contentOffset.x;
|
||||
seldata.end.yPos = rects[idx].bottom + this._contentOffset.y;
|
||||
if (this. _debugOptions.dumpRanges) Util.dumpLn("end set");
|
||||
}
|
||||
}
|
||||
|
||||
// Store the client rect of selection
|
||||
let r = aRange.getBoundingClientRect();
|
||||
seldata.selection.left = r.left + this._contentOffset.x;
|
||||
seldata.selection.top = r.top + this._contentOffset.y;
|
||||
seldata.selection.right = r.right + this._contentOffset.x;
|
||||
seldata.selection.bottom = r.bottom + this._contentOffset.y;
|
||||
}
|
||||
|
||||
// Store the client rect of target element
|
||||
r = this._getTargetClientRect();
|
||||
seldata.element.left = r.left + this._contentOffset.x;
|
||||
seldata.element.top = r.top + this._contentOffset.y;
|
||||
seldata.element.right = r.right + this._contentOffset.x;
|
||||
seldata.element.bottom = r.bottom + this._contentOffset.y;
|
||||
|
||||
// If we don't have a range we can attach to let SelectionHelperUI know.
|
||||
seldata.selectionRangeFound = !!rects.length;
|
||||
|
||||
return seldata;
|
||||
},
|
||||
|
||||
/*
|
||||
* Selection bounds will fall outside the bound of a control if the control
|
||||
* can scroll. Clip UI cache data to the bounds of the target so monocles
|
||||
* don't draw outside the control.
|
||||
*/
|
||||
_restrictSelectionRectToEditBounds: function _restrictSelectionRectToEditBounds() {
|
||||
if (!this._targetIsEditable)
|
||||
return;
|
||||
|
||||
let bounds = this._getTargetBrowserRect();
|
||||
if (this._cache.start.xPos < bounds.left)
|
||||
this._cache.start.xPos = bounds.left;
|
||||
if (this._cache.end.xPos < bounds.left)
|
||||
this._cache.end.xPos = bounds.left;
|
||||
if (this._cache.caret.xPos < bounds.left)
|
||||
this._cache.caret.xPos = bounds.left;
|
||||
if (this._cache.start.xPos > bounds.right)
|
||||
this._cache.start.xPos = bounds.right;
|
||||
if (this._cache.end.xPos > bounds.right)
|
||||
this._cache.end.xPos = bounds.right;
|
||||
if (this._cache.caret.xPos > bounds.right)
|
||||
this._cache.caret.xPos = bounds.right;
|
||||
|
||||
if (this._cache.start.yPos < bounds.top)
|
||||
this._cache.start.yPos = bounds.top;
|
||||
if (this._cache.end.yPos < bounds.top)
|
||||
this._cache.end.yPos = bounds.top;
|
||||
if (this._cache.caret.yPos < bounds.top)
|
||||
this._cache.caret.yPos = bounds.top;
|
||||
if (this._cache.start.yPos > bounds.bottom)
|
||||
this._cache.start.yPos = bounds.bottom;
|
||||
if (this._cache.end.yPos > bounds.bottom)
|
||||
this._cache.end.yPos = bounds.bottom;
|
||||
if (this._cache.caret.yPos > bounds.bottom)
|
||||
this._cache.caret.yPos = bounds.bottom;
|
||||
},
|
||||
|
||||
_restrictCoordinateToEditBounds: function _restrictCoordinateToEditBounds(aX, aY) {
|
||||
let result = {
|
||||
xPos: aX,
|
||||
yPos: aY
|
||||
};
|
||||
if (!this._targetIsEditable)
|
||||
return result;
|
||||
let bounds = this._getTargetBrowserRect();
|
||||
if (aX <= bounds.left)
|
||||
result.xPos = bounds.left + 1;
|
||||
if (aX >= bounds.right)
|
||||
result.xPos = bounds.right - 1;
|
||||
if (aY <= bounds.top)
|
||||
result.yPos = bounds.top + 1;
|
||||
if (aY >= bounds.bottom)
|
||||
result.yPos = bounds.bottom - 1;
|
||||
return result;
|
||||
},
|
||||
|
||||
/*************************************************
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
/*
|
||||
* Returns bounds of the element relative to the inner sub frame it sits
|
||||
* in.
|
||||
*/
|
||||
_getTargetClientRect: function _getTargetClientRect() {
|
||||
return this._targetElement.getBoundingClientRect();
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns bounds of the element relative to the top level browser.
|
||||
*/
|
||||
_getTargetBrowserRect: function _getTargetBrowserRect() {
|
||||
let client = this._getTargetClientRect();
|
||||
return {
|
||||
left: client.left + this._contentOffset.x,
|
||||
top: client.top + this._contentOffset.y,
|
||||
right: client.right + this._contentOffset.x,
|
||||
bottom: client.bottom + this._contentOffset.y
|
||||
};
|
||||
},
|
||||
|
||||
_clientPointToFramePoint: function _clientPointToFramePoint(aClientPoint) {
|
||||
let point = {
|
||||
xPos: aClientPoint.xPos - this._contentOffset.x,
|
||||
yPos: aClientPoint.yPos - this._contentOffset.y
|
||||
};
|
||||
return point;
|
||||
},
|
||||
|
||||
/*************************************************
|
||||
* Debug routines
|
||||
*/
|
||||
|
||||
_debugDumpSelection: function _debugDumpSelection(aNote, aSel) {
|
||||
Util.dumpLn("--" + aNote + "--");
|
||||
Util.dumpLn("anchor:", aSel.anchorNode, aSel.anchorOffset);
|
||||
Util.dumpLn("focus:", aSel.focusNode, aSel.focusOffset);
|
||||
},
|
||||
|
||||
_debugDumpChildNodes: function _dumpChildNodes(aNode, aSpacing) {
|
||||
for (let idx = 0; idx < aNode.childNodes.length; idx++) {
|
||||
let node = aNode.childNodes.item(idx);
|
||||
for (let spaceIdx = 0; spaceIdx < aSpacing; spaceIdx++) dump(" ");
|
||||
Util.dumpLn("[" + idx + "]", node);
|
||||
this._debugDumpChildNodes(node, aSpacing + 1);
|
||||
}
|
||||
},
|
||||
|
||||
_setDebugElementRect: function _setDebugElementRect(e, aScrollOffset, aColor) {
|
||||
try {
|
||||
if (e == null) {
|
||||
Util.dumpLn("_setDebugElementRect(): passed in null element");
|
||||
return;
|
||||
}
|
||||
if (e.offsetWidth == 0 || e.offsetHeight== 0) {
|
||||
Util.dumpLn("_setDebugElementRect(): passed in flat rect");
|
||||
return;
|
||||
}
|
||||
// e.offset values are positioned relative to the view.
|
||||
this.sendAsync("Content:SelectionDebugRect",
|
||||
{ left:e.offsetLeft - aScrollOffset.x,
|
||||
top:e.offsetTop - aScrollOffset.y,
|
||||
right:e.offsetLeft + e.offsetWidth - aScrollOffset.x,
|
||||
bottom:e.offsetTop + e.offsetHeight - aScrollOffset.y,
|
||||
color:aColor, id: e.id });
|
||||
} catch(ex) {
|
||||
Util.dumpLn("_setDebugElementRect():", ex.message);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Adds a debug rect to the selection overlay, useful in identifying
|
||||
* locations for points and rects. Params are in client coordinates.
|
||||
*
|
||||
* Example:
|
||||
* let rect = { left: aPoint.xPos - 1, top: aPoint.yPos - 1,
|
||||
* right: aPoint.xPos + 1, bottom: aPoint.yPos + 1 };
|
||||
* this._setDebugRect(rect, "red");
|
||||
*
|
||||
* In SelectionHelperUI, you'll need to turn on displayDebugLayer
|
||||
* in init().
|
||||
*/
|
||||
_setDebugRect: function _setDebugRect(aRect, aColor, aFill, aId) {
|
||||
this.sendAsync("Content:SelectionDebugRect",
|
||||
{ left:aRect.left, top:aRect.top,
|
||||
right:aRect.right, bottom:aRect.bottom,
|
||||
color:aColor, fill: aFill, id: aId });
|
||||
},
|
||||
|
||||
/*
|
||||
* Adds a small debug rect at the point specified. Params are in
|
||||
* client coordinates.
|
||||
*
|
||||
* In SelectionHelperUI, you'll need to turn on displayDebugLayer
|
||||
* in init().
|
||||
*/
|
||||
_setDebugPoint: function _setDebugPoint(aX, aY, aColor) {
|
||||
let rect = { left: aX - 2, top: aY - 2,
|
||||
right: aX + 2, bottom: aY + 2 };
|
||||
this._setDebugRect(rect, aColor, true);
|
||||
},
|
||||
};
|
@ -42,6 +42,7 @@ chrome.jar:
|
||||
content/helperui/OfflineApps.js (content/helperui/OfflineApps.js)
|
||||
content/helperui/SelectHelperUI.js (content/helperui/SelectHelperUI.js)
|
||||
content/helperui/SelectionHelperUI.js (content/helperui/SelectionHelperUI.js)
|
||||
content/helperui/ChromeSelectionHandler.js (content/helperui/ChromeSelectionHandler.js)
|
||||
content/helperui/FormHelperUI.js (content/helperui/FormHelperUI.js)
|
||||
content/helperui/FindHelperUI.js (content/helperui/FindHelperUI.js)
|
||||
content/helperui/ItemPinHelper.js (content/helperui/ItemPinHelper.js)
|
||||
@ -55,6 +56,8 @@ chrome.jar:
|
||||
content/contenthandlers/ConsoleAPIObserver.js (content/contenthandlers/ConsoleAPIObserver.js)
|
||||
content/contenthandlers/Content.js (content/contenthandlers/Content.js)
|
||||
|
||||
content/library/SelectionPrototype.js (content/library/SelectionPrototype.js)
|
||||
|
||||
content/ContentAreaObserver.js (content/ContentAreaObserver.js)
|
||||
content/BrowserTouchHandler.js (content/BrowserTouchHandler.js)
|
||||
* content/WebProgress.js (content/WebProgress.js)
|
||||
|
@ -53,6 +53,7 @@ BROWSER_TESTS += \
|
||||
browser_selection_frame_textarea.html \
|
||||
browser_selection_frame_inputs.js \
|
||||
browser_selection_frame_inputs.html \
|
||||
browser_selection_urlbar.js \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
@ -64,7 +64,7 @@ gTests.push({
|
||||
gTextArea.selectionStart = gTextArea.selectionEnd = 0;
|
||||
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 195, 80);
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 220, 80);
|
||||
yield promise;
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
@ -97,7 +97,7 @@ gTests.push({
|
||||
gTextArea.selectionStart = gTextArea.selectionEnd = 0;
|
||||
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 195, 80);
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 220, 80);
|
||||
yield promise;
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
@ -178,7 +178,7 @@ gTests.push({
|
||||
yield scrollPromise;
|
||||
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 195, 80);
|
||||
sendContextMenuClickToElement(gWindow, gFrame, 220, 80);
|
||||
yield promise;
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
|
@ -0,0 +1,78 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
let gWindow = null;
|
||||
var gFrame = null;
|
||||
|
||||
const kMarkerOffsetY = 12;
|
||||
const kCommonWaitMs = 5000;
|
||||
const kCommonPollMs = 100;
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// text area tests
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
gTests.push({
|
||||
desc: "normalize browser",
|
||||
run: function test() {
|
||||
InputSourceHelper.isPrecise = false;
|
||||
InputSourceHelper.fireUpdate();
|
||||
|
||||
info(chromeRoot + "res/textblock01.html");
|
||||
yield addTab(chromeRoot + "res/textblock01.html");
|
||||
|
||||
yield waitForCondition(function () {
|
||||
return !StartUI.isStartPageVisible;
|
||||
});
|
||||
|
||||
yield hideContextUI();
|
||||
},
|
||||
});
|
||||
|
||||
gTests.push({
|
||||
desc: "nav bar display",
|
||||
run: function test() {
|
||||
gWindow = window;
|
||||
|
||||
yield showNavBar();
|
||||
|
||||
let edit = document.getElementById("urlbar-edit");
|
||||
|
||||
sendElementTap(window, edit, 100, 10);
|
||||
|
||||
ok(SelectionHelperUI.isSelectionUIVisible, "selection ui active");
|
||||
|
||||
sendElementTap(window, edit, 70, 10);
|
||||
|
||||
ok(SelectionHelperUI.isCaretUIVisible, "caret ui active");
|
||||
|
||||
// to the right
|
||||
let xpos = SelectionHelperUI.caretMark.xPos;
|
||||
let ypos = SelectionHelperUI.caretMark.yPos + 10;
|
||||
var touchdrag = new TouchDragAndHold();
|
||||
yield touchdrag.start(gWindow, xpos, ypos, 800, ypos);
|
||||
yield waitForCondition(function () {
|
||||
return getTrimmedSelection(edit).toString() ==
|
||||
"mochitests/content/metro/browser/metro/base/tests/mochitest/res/textblock01.html";
|
||||
}, kCommonWaitMs, kCommonPollMs);
|
||||
touchdrag.end();
|
||||
yield waitForMs(100);
|
||||
|
||||
ok(SelectionHelperUI.isSelectionUIVisible, "selection ui active");
|
||||
|
||||
// taps on the urlbar-edit leak a ClientRect property on the window
|
||||
delete window.r;
|
||||
},
|
||||
});
|
||||
|
||||
function test() {
|
||||
if (!isLandscapeMode()) {
|
||||
todo(false, "browser_selection_tests need landscape mode to run.");
|
||||
return;
|
||||
}
|
||||
runTests();
|
||||
}
|
@ -118,15 +118,24 @@ function showNotification()
|
||||
function getSelection(aElement) {
|
||||
if (!aElement)
|
||||
return null;
|
||||
// editable element
|
||||
|
||||
// chrome text edit
|
||||
if (aElement instanceof Ci.nsIDOMXULTextBoxElement) {
|
||||
return aElement.QueryInterface(Components.interfaces.nsIDOMXULTextBoxElement)
|
||||
.editor.selection;
|
||||
}
|
||||
|
||||
// editable content element
|
||||
if (aElement instanceof Ci.nsIDOMNSEditableElement) {
|
||||
return aElement.QueryInterface(Ci.nsIDOMNSEditableElement)
|
||||
.editor.selection;
|
||||
.editor.selection;
|
||||
}
|
||||
|
||||
// document or window
|
||||
if (aElement instanceof HTMLDocument || aElement instanceof Window) {
|
||||
return aElement.getSelection();
|
||||
}
|
||||
|
||||
// browser
|
||||
return aElement.contentWindow.getSelection();
|
||||
};
|
||||
@ -177,7 +186,7 @@ function hideContextUI()
|
||||
|
||||
function showNavBar()
|
||||
{
|
||||
let promise = waitForEvent(Elements.tray, "transitionend");
|
||||
let promise = waitForEvent(Elements.navbar, "transitionend");
|
||||
if (!ContextUI.isVisible) {
|
||||
ContextUI.displayNavbar();
|
||||
return promise;
|
||||
@ -577,6 +586,14 @@ function sendTap(aWindow, aX, aY) {
|
||||
}, aWindow);
|
||||
}
|
||||
|
||||
function sendElementTap(aWindow, aElement, aX, aY) {
|
||||
let rect = aElement.getBoundingClientRect();
|
||||
EventUtils.synthesizeMouseAtPoint(rect.left + aX, rect.top + aY, {
|
||||
clickCount: 1,
|
||||
inputSource: Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH
|
||||
}, aWindow);
|
||||
}
|
||||
|
||||
/*
|
||||
* sendTouchDrag - sends a touch series composed of a touchstart,
|
||||
* touchmove, and touchend w3c event.
|
||||
|
@ -201,6 +201,23 @@ documenttab[selected] .documenttab-selection {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#tabs-controls {
|
||||
margin-top: @metro_spacing_small@;
|
||||
-moz-box-align: start;
|
||||
-moz-box-orient: vertical;
|
||||
padding: 0 @metro_spacing_small@;
|
||||
}
|
||||
|
||||
#tabs-controls toolbarbutton {
|
||||
margin: @toolbar_vertical_spacing@ @toolbar_horizontal_spacing@;
|
||||
}
|
||||
|
||||
#newtab-button {
|
||||
list-style-image: url("images/newtab-default.png");
|
||||
}
|
||||
|
||||
/* Selection overlay and monocles ----------------------------------------------- */
|
||||
|
||||
#page,
|
||||
.selection-overlay {
|
||||
-moz-stack-sizing: ignore;
|
||||
@ -218,19 +235,13 @@ documenttab[selected] .documenttab-selection {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#tabs-controls {
|
||||
margin-top: @metro_spacing_small@;
|
||||
-moz-box-align: start;
|
||||
-moz-box-orient: vertical;
|
||||
padding: 0 @metro_spacing_small@;
|
||||
}
|
||||
|
||||
#tabs-controls toolbarbutton {
|
||||
margin: @toolbar_vertical_spacing@ @toolbar_horizontal_spacing@;
|
||||
}
|
||||
|
||||
#newtab-button {
|
||||
list-style-image: url("images/newtab-default.png");
|
||||
.selectionhandle {
|
||||
list-style-image: url("chrome://browser/skin/images/selection-monocle.png");
|
||||
border: 0px solid gray;
|
||||
padding: 0px;
|
||||
margin-top: -30px;
|
||||
margin-left: -18px;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* Toolbar ------------------------------------------------------------------ */
|
||||
@ -1007,19 +1018,6 @@ setting[type="radio"] > vbox {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Text selection handles */
|
||||
|
||||
#selectionhandle-mark1,
|
||||
#selectionhandle-mark2,
|
||||
#selectionhandle-mark3 {
|
||||
list-style-image: url("chrome://browser/skin/images/selection-monocle.png");
|
||||
border: 0px solid gray;
|
||||
padding: 0px;
|
||||
margin-top: -30px;
|
||||
margin-left: -18px;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* :::::: autoscroll popup ::::: */
|
||||
|
||||
.autoscroller {
|
||||
|
@ -2076,7 +2076,7 @@ nsScriptSecurityManager::old_doGetObjectPrincipal(JS::Handle<JSObject*> aObj,
|
||||
|
||||
jsClass = js::GetObjectClass(obj);
|
||||
|
||||
if (jsClass == &js::CallClass) {
|
||||
if (js::IsCallObject(obj)) {
|
||||
obj = js::GetObjectParentMaybeScope(obj);
|
||||
|
||||
if (!obj)
|
||||
|
@ -33,7 +33,7 @@ is(blob.type, "null", "Blob type should be stringified");
|
||||
|
||||
blob = Blob([], {type: undefined});
|
||||
ok(blob, "Blob should exist");
|
||||
is(blob.type, "undefined", "Blob type should be stringified");
|
||||
is(blob.type, "", "Blob type should be treated as missing");
|
||||
|
||||
try {
|
||||
blob = Blob([]);
|
||||
|
@ -889,7 +889,7 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
||||
}
|
||||
|
||||
void
|
||||
MediaStreamGraphImpl::PrepareUpdatesToMainThreadState()
|
||||
MediaStreamGraphImpl::PrepareUpdatesToMainThreadState(bool aFinalUpdate)
|
||||
{
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
|
||||
@ -906,7 +906,14 @@ MediaStreamGraphImpl::PrepareUpdatesToMainThreadState()
|
||||
}
|
||||
mUpdateRunnables.MoveElementsFrom(mPendingUpdateRunnables);
|
||||
|
||||
EnsureStableStateEventPosted();
|
||||
// Don't send the message to the main thread if it's not going to have
|
||||
// any work to do.
|
||||
if (aFinalUpdate ||
|
||||
!mUpdateRunnables.IsEmpty() ||
|
||||
!mCurrentTaskMessageQueue.IsEmpty() ||
|
||||
!mStreamUpdates.IsEmpty()) {
|
||||
EnsureStableStateEventPosted();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -1099,7 +1106,7 @@ MediaStreamGraphImpl::RunThread()
|
||||
// Wait indefinitely when we've processed enough non-realtime ticks.
|
||||
// We'll be woken up when the graph shuts down.
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
PrepareUpdatesToMainThreadState();
|
||||
PrepareUpdatesToMainThreadState(true);
|
||||
mWaitState = WAITSTATE_WAITING_INDEFINITELY;
|
||||
mMonitor.Wait(PR_INTERVAL_NO_TIMEOUT);
|
||||
}
|
||||
@ -1112,8 +1119,10 @@ MediaStreamGraphImpl::RunThread()
|
||||
// iteration.
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
PrepareUpdatesToMainThreadState();
|
||||
if (mForceShutDown || (IsEmpty() && mMessageQueue.IsEmpty())) {
|
||||
bool finalUpdate = (mForceShutDown ||
|
||||
(IsEmpty() && mMessageQueue.IsEmpty()));
|
||||
PrepareUpdatesToMainThreadState(finalUpdate);
|
||||
if (finalUpdate) {
|
||||
// Enter shutdown mode. The stable-state handler will detect this
|
||||
// and complete shutdown. Destroy any streams immediately.
|
||||
LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p waiting for main thread cleanup", this));
|
||||
|
@ -189,7 +189,7 @@ public:
|
||||
* Generate messages to the main thread to update it for all state changes.
|
||||
* mMonitor must be held.
|
||||
*/
|
||||
void PrepareUpdatesToMainThreadState();
|
||||
void PrepareUpdatesToMainThreadState(bool aFinalUpdate);
|
||||
// The following methods are the various stages of RunThread processing.
|
||||
/**
|
||||
* Compute a new current time for the graph and advance all on-graph-thread
|
||||
|
@ -53,12 +53,54 @@ ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, aErrorNumber);
|
||||
JS_ReportErrorNumberVA(aCx, GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumberVA(aCx, GetErrorMessage, nullptr,
|
||||
static_cast<const unsigned>(aErrorNumber), ap);
|
||||
va_end(ap);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowInvalidMethodThis(JSContext* aCx, const JS::CallArgs& aArgs,
|
||||
const char* aInterfaceName)
|
||||
{
|
||||
NS_ConvertASCIItoUTF16 ifaceName(aInterfaceName);
|
||||
// This should only be called for DOM methods, which are JSNative-backed
|
||||
// functions, so we can assume that JS_ValueToFunction and
|
||||
// JS_GetFunctionDisplayId will both return non-null and that
|
||||
// JS_GetStringCharsZ returns non-null.
|
||||
JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, aArgs.calleev()));
|
||||
MOZ_ASSERT(func);
|
||||
JS::Rooted<JSString*> funcName(aCx, JS_GetFunctionDisplayId(func));
|
||||
MOZ_ASSERT(funcName);
|
||||
JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
|
||||
static_cast<const unsigned>(MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE),
|
||||
JS_GetStringCharsZ(aCx, funcName),
|
||||
ifaceName.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowInvalidGetterThis(JSContext* aCx, const char* aInterfaceName)
|
||||
{
|
||||
// Sadly for getters we have no way to get the name of the property.
|
||||
NS_ConvertASCIItoUTF16 ifaceName(aInterfaceName);
|
||||
JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
|
||||
static_cast<const unsigned>(MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE),
|
||||
ifaceName.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowInvalidSetterThis(JSContext* aCx, const char* aInterfaceName)
|
||||
{
|
||||
// Sadly for setters we have no way to get the name of the property.
|
||||
NS_ConvertASCIItoUTF16 ifaceName(aInterfaceName);
|
||||
JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr,
|
||||
static_cast<const unsigned>(MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE),
|
||||
ifaceName.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
struct ErrorResult::Message {
|
||||
@ -1826,7 +1868,7 @@ GetWindowForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||
}
|
||||
|
||||
if (!domImplVal.isObject()) {
|
||||
ThrowErrorMessage(cx, MSG_NOT_OBJECT);
|
||||
ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Value");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,13 @@ UnwrapArg(JSContext* cx, jsval v, Interface** ppArg,
|
||||
|
||||
bool
|
||||
ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...);
|
||||
bool
|
||||
ThrowInvalidMethodThis(JSContext* aCx, const JS::CallArgs& aArgs,
|
||||
const char* aInterfaceName);
|
||||
bool
|
||||
ThrowInvalidGetterThis(JSContext* aCx, const char* aInterfaceName);
|
||||
bool
|
||||
ThrowInvalidSetterThis(JSContext* aCx, const char* aInterfaceName);
|
||||
|
||||
template<bool mainThread>
|
||||
inline bool
|
||||
@ -805,7 +812,7 @@ HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
|
||||
template<bool Fatal>
|
||||
inline bool
|
||||
EnumValueNotFound(JSContext* cx, const jschar* chars, size_t length,
|
||||
const char* type)
|
||||
const char* type, const char* sourceDescription)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -813,7 +820,7 @@ EnumValueNotFound(JSContext* cx, const jschar* chars, size_t length,
|
||||
template<>
|
||||
inline bool
|
||||
EnumValueNotFound<false>(JSContext* cx, const jschar* chars, size_t length,
|
||||
const char* type)
|
||||
const char* type, const char* sourceDescription)
|
||||
{
|
||||
// TODO: Log a warning to the console.
|
||||
return true;
|
||||
@ -822,18 +829,19 @@ EnumValueNotFound<false>(JSContext* cx, const jschar* chars, size_t length,
|
||||
template<>
|
||||
inline bool
|
||||
EnumValueNotFound<true>(JSContext* cx, const jschar* chars, size_t length,
|
||||
const char* type)
|
||||
const char* type, const char* sourceDescription)
|
||||
{
|
||||
NS_LossyConvertUTF16toASCII deflated(static_cast<const PRUnichar*>(chars),
|
||||
length);
|
||||
return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, deflated.get(), type);
|
||||
return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
|
||||
deflated.get(), type);
|
||||
}
|
||||
|
||||
|
||||
template<bool InvalidValueFatal>
|
||||
inline int
|
||||
FindEnumStringIndex(JSContext* cx, JS::Value v, const EnumEntry* values,
|
||||
const char* type, bool* ok)
|
||||
const char* type, const char* sourceDescription, bool* ok)
|
||||
{
|
||||
// JS_StringEqualsAscii is slow as molasses, so don't use it here.
|
||||
JSString* str = JS_ValueToString(cx, v);
|
||||
@ -869,7 +877,8 @@ FindEnumStringIndex(JSContext* cx, JS::Value v, const EnumEntry* values,
|
||||
}
|
||||
}
|
||||
|
||||
*ok = EnumValueNotFound<InvalidValueFatal>(cx, chars, length, type);
|
||||
*ok = EnumValueNotFound<InvalidValueFatal>(cx, chars, length, type,
|
||||
sourceDescription);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/dom/CallbackInterface.h"
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -20,7 +21,8 @@ CallbackInterface::GetCallableProperty(JSContext* cx, const char* aPropName,
|
||||
}
|
||||
if (!aCallable.isObject() ||
|
||||
!JS_ObjectIsCallable(cx, &aCallable.toObject())) {
|
||||
ThrowErrorMessage(cx, MSG_NOT_CALLABLE);
|
||||
nsPrintfCString description("Property '%s'", aPropName);
|
||||
ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2377,11 +2377,12 @@ class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
|
||||
As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
|
||||
"""
|
||||
def __init__(self, descriptor, source, target, exceptionCode,
|
||||
isCallbackReturnValue):
|
||||
isCallbackReturnValue, sourceDescription):
|
||||
CastableObjectUnwrapper.__init__(
|
||||
self, descriptor, source, target,
|
||||
'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");\n'
|
||||
'%s' % (descriptor.name, exceptionCode),
|
||||
'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
|
||||
'%s' % (sourceDescription, descriptor.interface.identifier.name,
|
||||
exceptionCode),
|
||||
exceptionCode,
|
||||
isCallbackReturnValue)
|
||||
|
||||
@ -2393,11 +2394,12 @@ class CallbackObjectUnwrapper:
|
||||
|target| is an nsCOMPtr of the appropriate type in which we store the result.
|
||||
"""
|
||||
def __init__(self, descriptor, source, target, exceptionCode,
|
||||
codeOnFailure=None):
|
||||
sourceDescription, codeOnFailure=None):
|
||||
if codeOnFailure is None:
|
||||
codeOnFailure = (
|
||||
'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");\n'
|
||||
'%s' % (descriptor.name, exceptionCode))
|
||||
'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
|
||||
'%s' % (sourceDescription, descriptor.interface.identifier.name,
|
||||
exceptionCode))
|
||||
self.descriptor = descriptor
|
||||
self.substitution = { "nativeType" : descriptor.nativeType,
|
||||
"source" : source,
|
||||
@ -2521,7 +2523,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
exceptionCode=None,
|
||||
lenientFloatCode=None,
|
||||
allowTreatNonCallableAsNull=False,
|
||||
isCallbackReturnValue=False):
|
||||
isCallbackReturnValue=False,
|
||||
sourceDescription="value"):
|
||||
"""
|
||||
Get a template for converting a JS value to a native object based on the
|
||||
given type and descriptor. If failureCode is given, then we're actually
|
||||
@ -2574,6 +2577,11 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
implementing auto-wrapping of JS-implemented return values from a
|
||||
JS-implemented interface.
|
||||
|
||||
sourceDescription is a description of what this JS value represents, to be
|
||||
used in error reporting. Callers should assume that it might get placed in
|
||||
the middle of a sentence. If it ends up at the beginning of a sentence, its
|
||||
first character will be automatically uppercased.
|
||||
|
||||
The return value from this function is a JSToNativeConversionInfo.
|
||||
"""
|
||||
# If we have a defaultValue then we're not actually optional for
|
||||
@ -2596,23 +2604,35 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
# if body.
|
||||
exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode))
|
||||
|
||||
# Unfortunately, .capitalize() on a string will lowercase things inside the
|
||||
# string, which we do not want.
|
||||
def firstCap(string):
|
||||
return string[0].upper() + string[1:]
|
||||
|
||||
# Helper functions for dealing with failures due to the JS value being the
|
||||
# wrong type of value
|
||||
def onFailureNotAnObject(failureCode):
|
||||
return CGWrapper(CGGeneric(
|
||||
return CGWrapper(
|
||||
CGGeneric(
|
||||
failureCode or
|
||||
('ThrowErrorMessage(cx, MSG_NOT_OBJECT);\n'
|
||||
'%s' % exceptionCode)), post="\n")
|
||||
('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
|
||||
'%s' % (firstCap(sourceDescription), exceptionCode))),
|
||||
post="\n")
|
||||
def onFailureBadType(failureCode, typeName):
|
||||
return CGWrapper(CGGeneric(
|
||||
return CGWrapper(
|
||||
CGGeneric(
|
||||
failureCode or
|
||||
('ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");\n'
|
||||
'%s' % (typeName, exceptionCode))), post="\n")
|
||||
('ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n'
|
||||
'%s' % (firstCap(sourceDescription), typeName,
|
||||
exceptionCode))),
|
||||
post="\n")
|
||||
def onFailureNotCallable(failureCode):
|
||||
return CGWrapper(CGGeneric(
|
||||
return CGWrapper(
|
||||
CGGeneric(
|
||||
failureCode or
|
||||
('ThrowErrorMessage(cx, MSG_NOT_CALLABLE);\n'
|
||||
'%s' % exceptionCode)), post="\n")
|
||||
('ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "%s");\n'
|
||||
'%s' % (firstCap(sourceDescription), exceptionCode))),
|
||||
post="\n")
|
||||
|
||||
# A helper function for handling default values. Takes a template
|
||||
# body and the C++ code to set the default value and wraps the
|
||||
@ -2699,8 +2719,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
assert not isEnforceRange and not isClamp
|
||||
|
||||
if failureCode is None:
|
||||
notSequence = ("ThrowErrorMessage(cx, MSG_NOT_SEQUENCE);\n"
|
||||
"%s" % exceptionCode)
|
||||
notSequence = ('ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "%s");\n'
|
||||
"%s" % (firstCap(sourceDescription), exceptionCode))
|
||||
else:
|
||||
notSequence = failureCode
|
||||
|
||||
@ -2731,10 +2751,13 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
else:
|
||||
sequenceClass = "AutoSequence"
|
||||
|
||||
# XXXbz we can't include the index in the the sourceDescription, because
|
||||
# we don't really have a way to pass one in dynamically at runtime...
|
||||
elementInfo = getJSToNativeConversionInfo(
|
||||
elementType, descriptorProvider, isMember="Sequence",
|
||||
exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode,
|
||||
isCallbackReturnValue=isCallbackReturnValue)
|
||||
isCallbackReturnValue=isCallbackReturnValue,
|
||||
sourceDescription="element of %s" % sourceDescription)
|
||||
if elementInfo.dealWithOptional:
|
||||
raise TypeError("Shouldn't have optional things in sequences")
|
||||
if elementInfo.holderType is not None:
|
||||
@ -2944,9 +2967,10 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
"%s\n"
|
||||
"}\n"
|
||||
"if (!done) {\n"
|
||||
" ThrowErrorMessage(cx, MSG_NOT_IN_UNION, \"%s\");\n"
|
||||
' ThrowErrorMessage(cx, MSG_NOT_IN_UNION, "%s", "%s");\n'
|
||||
"%s\n"
|
||||
"}" % (exceptionCodeIndented.define(),
|
||||
firstCap(sourceDescription),
|
||||
", ".join(names),
|
||||
exceptionCodeIndented.define()))
|
||||
templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}")
|
||||
@ -3087,6 +3111,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
"callbackObj",
|
||||
"${declName}",
|
||||
exceptionCode,
|
||||
firstCap(sourceDescription),
|
||||
codeOnFailure=failureCode))
|
||||
templateBody += (
|
||||
"{ // Scope for callbackObj\n"
|
||||
@ -3106,7 +3131,8 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
"&${val}.toObject()",
|
||||
"${declName}",
|
||||
exceptionCode,
|
||||
isCallbackReturnValue))
|
||||
isCallbackReturnValue,
|
||||
firstCap(sourceDescription)))
|
||||
elif descriptor.workers:
|
||||
return handleJSObjectType(type, isMember, failureCode)
|
||||
else:
|
||||
@ -3143,10 +3169,11 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
# And store our tmp, before it goes out of scope.
|
||||
templateBody += "${declName} = tmp;"
|
||||
|
||||
# Just pass failureCode, not onFailureBadType, here, so we'll report the
|
||||
# thing as not an object as opposed to not implementing whatever our
|
||||
# interface is.
|
||||
templateBody = wrapObjectTemplate(templateBody, type,
|
||||
"${declName} = nullptr",
|
||||
onFailureBadType(failureCode,
|
||||
descriptor.interface.identifier.name).define())
|
||||
"${declName} = nullptr", failureCode)
|
||||
|
||||
declType = CGGeneric(declType)
|
||||
if holderType is not None:
|
||||
@ -3326,7 +3353,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
template = (
|
||||
"{\n"
|
||||
" bool ok;\n"
|
||||
" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
|
||||
' int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, "%(enumtype)s", "%(sourceDescription)s", &ok);\n'
|
||||
" if (!ok) {\n"
|
||||
"%(exceptionCode)s\n"
|
||||
" }\n"
|
||||
@ -3338,6 +3365,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
"handleInvalidEnumValueCode" : handleInvalidEnumValueCode,
|
||||
"exceptionCode" : CGIndenter(exceptionCodeIndented).define(),
|
||||
"enumLoc" : enumLoc,
|
||||
"sourceDescription" : firstCap(sourceDescription)
|
||||
})
|
||||
|
||||
setNull = "${declName}.SetNull();"
|
||||
@ -3479,9 +3507,10 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
else:
|
||||
template = ""
|
||||
|
||||
template += ("if (!${declName}.Init(cx, %s)) {\n"
|
||||
template += ('if (!${declName}.Init(cx, %s, "%s")) {\n'
|
||||
"%s\n"
|
||||
"}" % (val, exceptionCodeIndented.define()))
|
||||
"}" % (val, firstCap(sourceDescription),
|
||||
exceptionCodeIndented.define()))
|
||||
|
||||
# Dictionary arguments that might contain traceable things need to get
|
||||
# traced
|
||||
@ -3511,8 +3540,8 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
dateVal = "${declName}"
|
||||
|
||||
if failureCode is None:
|
||||
notDate = ("ThrowErrorMessage(cx, MSG_NOT_DATE);\n"
|
||||
"%s" % exceptionCode)
|
||||
notDate = ('ThrowErrorMessage(cx, MSG_NOT_DATE, "%s");\n'
|
||||
"%s" % (firstCap(sourceDescription), exceptionCode))
|
||||
else:
|
||||
notDate = failureCode
|
||||
|
||||
@ -3572,8 +3601,9 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
if lenientFloatCode is not None:
|
||||
nonFiniteCode = CGIndenter(CGGeneric(lenientFloatCode)).define()
|
||||
else:
|
||||
nonFiniteCode = (" ThrowErrorMessage(cx, MSG_NOT_FINITE);\n"
|
||||
"%s" % exceptionCodeIndented.define())
|
||||
nonFiniteCode = (' ThrowErrorMessage(cx, MSG_NOT_FINITE, "%s");\n'
|
||||
"%s" % (firstCap(sourceDescription),
|
||||
exceptionCodeIndented.define()))
|
||||
template += (" else if (!mozilla::IsFinite(%s)) {\n"
|
||||
" // Note: mozilla::IsFinite will do the right thing\n"
|
||||
" // when passed a non-finite float too.\n"
|
||||
@ -3721,12 +3751,19 @@ class CGArgumentConverter(CGThing):
|
||||
A class that takes an IDL argument object and its index in the
|
||||
argument list and generates code to unwrap the argument to the
|
||||
right native type.
|
||||
|
||||
argDescription is a description of the argument for error-reporting
|
||||
purposes. Callers should assume that it might get placed in the middle of a
|
||||
sentence. If it ends up at the beginning of a sentence, its first character
|
||||
will be automatically uppercased.
|
||||
"""
|
||||
def __init__(self, argument, index, descriptorProvider,
|
||||
argDescription,
|
||||
invalidEnumValueFatal=True, lenientFloatCode=None,
|
||||
allowTreatNonCallableAsNull=False):
|
||||
CGThing.__init__(self)
|
||||
self.argument = argument
|
||||
self.argDescription = argDescription
|
||||
assert(not argument.defaultValue or argument.optional)
|
||||
|
||||
replacer = {
|
||||
@ -3771,7 +3808,8 @@ class CGArgumentConverter(CGThing):
|
||||
isClamp=self.argument.clamp,
|
||||
lenientFloatCode=self.lenientFloatCode,
|
||||
isMember="Variadic" if self.argument.variadic else False,
|
||||
allowTreatNonCallableAsNull=self.allowTreatNonCallableAsNull)
|
||||
allowTreatNonCallableAsNull=self.allowTreatNonCallableAsNull,
|
||||
sourceDescription=self.argDescription)
|
||||
|
||||
if not self.argument.variadic:
|
||||
return instantiateJSToNativeConversion(
|
||||
@ -4577,7 +4615,17 @@ if (global.Failed()) {
|
||||
# Pass in our thisVal
|
||||
argsPre.append("args.thisv()")
|
||||
|
||||
ourName = "%s.%s" % (descriptor.interface.identifier.name,
|
||||
idlNode.identifier.name)
|
||||
if idlNode.isMethod():
|
||||
argDescription = "argument %(index)d of " + ourName
|
||||
elif setter:
|
||||
argDescription = "value being assigned to %s" % ourName
|
||||
else:
|
||||
assert self.argCount == 0
|
||||
|
||||
cgThings.extend([CGArgumentConverter(arguments[i], i, self.descriptor,
|
||||
argDescription % { "index": i + 1 },
|
||||
invalidEnumValueFatal=not setter,
|
||||
allowTreatNonCallableAsNull=setter,
|
||||
lenientFloatCode=lenientFloatCode) for
|
||||
@ -4710,7 +4758,8 @@ class CGMethodCall(CGThing):
|
||||
isConstructor=False):
|
||||
CGThing.__init__(self)
|
||||
|
||||
methodName = '"%s.%s"' % (descriptor.interface.identifier.name, method.identifier.name)
|
||||
methodName = "%s.%s" % (descriptor.interface.identifier.name, method.identifier.name)
|
||||
argDesc = "argument %d of " + methodName
|
||||
|
||||
def requiredArgCount(signature):
|
||||
arguments = signature[1]
|
||||
@ -4742,7 +4791,7 @@ class CGMethodCall(CGThing):
|
||||
if requiredArgs > 0:
|
||||
code = (
|
||||
"if (args.length() < %d) {\n"
|
||||
" return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n"
|
||||
' return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "%s");\n'
|
||||
"}" % (requiredArgs, methodName))
|
||||
self.cgRoot.prepend(
|
||||
CGWrapper(CGIndenter(CGGeneric(code)), pre="\n", post="\n"))
|
||||
@ -4830,7 +4879,8 @@ class CGMethodCall(CGThing):
|
||||
# they all have the same types up to that point; just use
|
||||
# possibleSignatures[0]
|
||||
caseBody = [ CGArgumentConverter(possibleSignatures[0][1][i],
|
||||
i, descriptor) for i in
|
||||
i, descriptor,
|
||||
argDesc % (i + 1)) for i in
|
||||
range(0, distinguishingIndex) ]
|
||||
|
||||
# Select the right overload from our set.
|
||||
@ -4867,7 +4917,8 @@ class CGMethodCall(CGThing):
|
||||
getJSToNativeConversionInfo(type, descriptor,
|
||||
failureCode=failureCode,
|
||||
isDefinitelyObject=isDefinitelyObject,
|
||||
isNullOrUndefined=isNullOrUndefined),
|
||||
isNullOrUndefined=isNullOrUndefined,
|
||||
sourceDescription=(argDesc % (distinguishingIndex + 1))),
|
||||
{
|
||||
"declName" : "arg%d" % distinguishingIndex,
|
||||
"holderName" : ("arg%d" % distinguishingIndex) + "_holder",
|
||||
@ -4991,8 +5042,8 @@ class CGMethodCall(CGThing):
|
||||
# Just throw; we have no idea what we're supposed to
|
||||
# do with this.
|
||||
caseBody.append(CGGeneric(
|
||||
'return ThrowErrorMessage(cx, MSG_INVALID_ARG, "%s", "%s");'
|
||||
% (str(distinguishingIndex), str(argCount))))
|
||||
'return ThrowErrorMessage(cx, MSG_OVERLOAD_RESOLUTION_FAILED, "%d", "%d", "%s");'
|
||||
% (distinguishingIndex+1, argCount, methodName)))
|
||||
|
||||
argCountCases.append(CGCase(str(argCount),
|
||||
CGList(caseBody, "\n")))
|
||||
@ -5004,7 +5055,7 @@ class CGMethodCall(CGThing):
|
||||
overloadCGThings.append(
|
||||
CGSwitch("argcount",
|
||||
argCountCases,
|
||||
CGGeneric("return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n" % methodName)))
|
||||
CGGeneric('return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "%s");\n' % methodName)))
|
||||
overloadCGThings.append(
|
||||
CGGeneric('MOZ_NOT_REACHED("We have an always-returning default case");\n'
|
||||
'return false;'))
|
||||
@ -5070,7 +5121,7 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod):
|
||||
CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args)
|
||||
|
||||
if unwrapFailureCode is None:
|
||||
self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % self.descriptor.name
|
||||
self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");' % descriptor.interface.identifier.name
|
||||
else:
|
||||
self.unwrapFailureCode = unwrapFailureCode
|
||||
self.getThisObj = getThisObj
|
||||
@ -5133,7 +5184,12 @@ class CGGenericMethod(CGAbstractBindingMethod):
|
||||
def __init__(self, descriptor):
|
||||
args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
|
||||
Argument('JS::Value*', 'vp')]
|
||||
CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod', args)
|
||||
unwrapFailureCode = (
|
||||
'return ThrowInvalidMethodThis(cx, args, \"%s\");' %
|
||||
descriptor.interface.identifier.name)
|
||||
CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod',
|
||||
args,
|
||||
unwrapFailureCode=unwrapFailureCode)
|
||||
|
||||
def generate_code(self):
|
||||
return CGIndenter(CGGeneric(
|
||||
@ -5265,7 +5321,9 @@ class CGGenericGetter(CGAbstractBindingMethod):
|
||||
"return true;")
|
||||
else:
|
||||
name = "genericGetter"
|
||||
unwrapFailureCode = None
|
||||
unwrapFailureCode = (
|
||||
'return ThrowInvalidGetterThis(cx, "%s");' %
|
||||
descriptor.interface.identifier.name)
|
||||
CGAbstractBindingMethod.__init__(self, descriptor, name, args,
|
||||
unwrapFailureCode)
|
||||
|
||||
@ -5343,7 +5401,10 @@ class CGGenericSetter(CGAbstractBindingMethod):
|
||||
"return true;")
|
||||
else:
|
||||
name = "genericSetter"
|
||||
unwrapFailureCode = None
|
||||
unwrapFailureCode = (
|
||||
'return ThrowInvalidSetterThis(cx, "%s");' %
|
||||
descriptor.interface.identifier.name)
|
||||
|
||||
CGAbstractBindingMethod.__init__(self, descriptor, name, args,
|
||||
unwrapFailureCode)
|
||||
|
||||
@ -5425,10 +5486,10 @@ if (!JS_GetProperty(cx, obj, "%s", v.address())) {
|
||||
}
|
||||
|
||||
if (!v.isObject()) {
|
||||
return ThrowErrorMessage(cx, MSG_NOT_OBJECT);
|
||||
return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s.%s");
|
||||
}
|
||||
|
||||
return JS_SetProperty(cx, &v.toObject(), "%s", args.handleAt(0).address());""" % (attrName, forwardToAttrName))).define()
|
||||
return JS_SetProperty(cx, &v.toObject(), "%s", args.handleAt(0).address());""" % (attrName, self.descriptor.interface.identifier.name, attrName, forwardToAttrName))).define()
|
||||
|
||||
def memberIsCreator(member):
|
||||
return member.getExtendedAttribute("Creator") is not None
|
||||
@ -5670,6 +5731,8 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
|
||||
type = type.inner.inner
|
||||
else:
|
||||
type = type.inner
|
||||
# We don't use the returned template here, so it's OK to just pass no
|
||||
# sourceDescription.
|
||||
elementInfo = getJSToNativeConversionInfo(type, descriptorProvider,
|
||||
isMember="Sequence")
|
||||
typeName = CGTemplatedType("Sequence", elementInfo.declType,
|
||||
@ -5742,7 +5805,7 @@ def getUnionAccessorSignatureType(type, descriptorProvider):
|
||||
typeName = CGTemplatedType("Nullable", typeName, isReference=True)
|
||||
return typeName
|
||||
|
||||
def getUnionTypeTemplateVars(type, descriptorProvider):
|
||||
def getUnionTypeTemplateVars(unionType, type, descriptorProvider):
|
||||
# For dictionaries and sequences we need to pass None as the failureCode
|
||||
# for getJSToNativeConversionInfo.
|
||||
# Also, for dictionaries we would need to handle conversion of
|
||||
@ -5767,7 +5830,8 @@ return true;"""
|
||||
}""" % name) + tryNextCode
|
||||
conversionInfo = getJSToNativeConversionInfo(
|
||||
type, descriptorProvider, failureCode=tryNextCode,
|
||||
isDefinitelyObject=True)
|
||||
isDefinitelyObject=True,
|
||||
sourceDescription="member of %s" % unionType)
|
||||
|
||||
# This is ugly, but UnionMember needs to call a constructor with no
|
||||
# arguments so the type can't be const.
|
||||
@ -5819,7 +5883,7 @@ class CGUnionStruct(CGThing):
|
||||
self.type = type.unroll()
|
||||
self.descriptorProvider = descriptorProvider
|
||||
self.templateVars = map(
|
||||
lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
|
||||
lambda t: getUnionTypeTemplateVars(self.type, t, self.descriptorProvider),
|
||||
self.type.flatMemberTypes)
|
||||
|
||||
|
||||
@ -5989,7 +6053,7 @@ class CGUnionConversionStruct(CGThing):
|
||||
return true;
|
||||
}""")
|
||||
|
||||
templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
|
||||
templateVars = map(lambda t: getUnionTypeTemplateVars(self.type, t, self.descriptorProvider),
|
||||
self.type.flatMemberTypes)
|
||||
structName = self.type.__str__()
|
||||
|
||||
@ -6639,9 +6703,12 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
||||
if operation.isSetter() or operation.isCreator():
|
||||
# arguments[0] is the index or name of the item that we're setting.
|
||||
argument = arguments[1]
|
||||
info = getJSToNativeConversionInfo(argument.type, descriptor,
|
||||
treatNullAs=argument.treatNullAs,
|
||||
treatUndefinedAs=argument.treatUndefinedAs)
|
||||
info = getJSToNativeConversionInfo(
|
||||
argument.type, descriptor,
|
||||
treatNullAs=argument.treatNullAs,
|
||||
treatUndefinedAs=argument.treatUndefinedAs,
|
||||
sourceDescription=("value being assigned to %s setter" %
|
||||
descriptor.interface.identifier.name))
|
||||
templateValues = {
|
||||
"declName": argument.identifier.name,
|
||||
"holderName": argument.identifier.name + "_holder",
|
||||
@ -7666,11 +7733,15 @@ class CGDictionary(CGThing):
|
||||
self.needToInitIds = not self.workers and len(dictionary.members) > 0
|
||||
self.memberInfo = [
|
||||
(member,
|
||||
getJSToNativeConversionInfo(member.type,
|
||||
descriptorProvider,
|
||||
isMember="Dictionary",
|
||||
isOptional=(not member.defaultValue),
|
||||
defaultValue=member.defaultValue))
|
||||
getJSToNativeConversionInfo(
|
||||
member.type,
|
||||
descriptorProvider,
|
||||
isMember="Dictionary",
|
||||
isOptional=(not member.defaultValue),
|
||||
defaultValue=member.defaultValue,
|
||||
sourceDescription=("'%s' member of %s" %
|
||||
(member.identifier.name,
|
||||
dictionary.identifier.name))))
|
||||
for member in dictionary.members ]
|
||||
self.structs = self.getStructs()
|
||||
|
||||
@ -7710,7 +7781,7 @@ class CGDictionary(CGThing):
|
||||
else:
|
||||
body += (
|
||||
"if (!IsConvertibleToDictionary(cx, val)) {\n"
|
||||
" return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY);\n"
|
||||
" return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription);\n"
|
||||
"}\n"
|
||||
"\n")
|
||||
|
||||
@ -7718,7 +7789,6 @@ class CGDictionary(CGThing):
|
||||
for m in self.memberInfo]
|
||||
if memberInits:
|
||||
body += (
|
||||
"JSBool found;\n"
|
||||
"JS::Rooted<JS::Value> temp(cx);\n"
|
||||
"bool isNull = val.isNullOrUndefined();\n")
|
||||
body += "\n\n".join(memberInits) + "\n"
|
||||
@ -7728,6 +7798,7 @@ class CGDictionary(CGThing):
|
||||
return ClassMethod("Init", "bool", [
|
||||
Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JS::Value>', 'val'),
|
||||
Argument('const char*', 'sourceDescription', default='"Value"')
|
||||
], body=body)
|
||||
|
||||
def initFromJSONMethod(self):
|
||||
@ -7900,48 +7971,35 @@ class CGDictionary(CGThing):
|
||||
if conversionInfo.dealWithOptional:
|
||||
replacements["declName"] = "(" + replacements["declName"] + ".Value())"
|
||||
if member.defaultValue:
|
||||
replacements["haveValue"] = "found"
|
||||
replacements["haveValue"] = "!temp.isUndefined()"
|
||||
|
||||
# NOTE: jsids are per-runtime, so don't use them in workers
|
||||
if self.workers:
|
||||
propName = member.identifier.name
|
||||
propCheck = ('JS_HasProperty(cx, &val.toObject(), "%s", &found)' %
|
||||
propName)
|
||||
propGet = ('JS_GetProperty(cx, &val.toObject(), "%s", temp.address())' %
|
||||
propName)
|
||||
else:
|
||||
propId = self.makeIdName(member.identifier.name);
|
||||
propCheck = ("JS_HasPropertyById(cx, &val.toObject(), %s, &found)" %
|
||||
propId)
|
||||
propGet = ("JS_GetPropertyById(cx, &val.toObject(), %s, temp.address())" %
|
||||
propId)
|
||||
|
||||
conversionReplacements = {
|
||||
"prop": self.makeMemberName(member.identifier.name),
|
||||
"convert": string.Template(conversionInfo.template).substitute(replacements),
|
||||
"propCheck": propCheck,
|
||||
"propGet": propGet
|
||||
}
|
||||
conversion = ("if (isNull) {\n"
|
||||
" found = false;\n"
|
||||
"} else if (!${propCheck}) {\n"
|
||||
" temp.setUndefined();\n"
|
||||
"} else if (!${propGet}) {\n"
|
||||
" return false;\n"
|
||||
"}\n")
|
||||
if member.defaultValue:
|
||||
conversion += (
|
||||
"if (found) {\n"
|
||||
" if (!${propGet}) {\n"
|
||||
" return false;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"${convert}")
|
||||
else:
|
||||
conversion += (
|
||||
"if (found) {\n"
|
||||
"if (!temp.isUndefined()) {\n"
|
||||
" ${prop}.Construct();\n"
|
||||
" if (!${propGet}) {\n"
|
||||
" return false;\n"
|
||||
" }\n"
|
||||
"${convert}\n"
|
||||
"}")
|
||||
conversionReplacements["convert"] = CGIndenter(
|
||||
@ -9539,7 +9597,9 @@ class CallbackMember(CGNativeMember):
|
||||
getJSToNativeConversionInfo(self.retvalType,
|
||||
self.descriptorProvider,
|
||||
exceptionCode=self.exceptionCode,
|
||||
isCallbackReturnValue=isCallbackReturnValue),
|
||||
isCallbackReturnValue=isCallbackReturnValue,
|
||||
# XXXbz we should try to do better here
|
||||
sourceDescription="return value"),
|
||||
replacements)
|
||||
assignRetval = string.Template(
|
||||
self.getRetvalInfo(self.retvalType,
|
||||
@ -9993,3 +10053,4 @@ struct PrototypeIDMap;
|
||||
|
||||
# Done.
|
||||
return curr
|
||||
|
||||
|
@ -19,24 +19,28 @@
|
||||
* be replaced with a string value when the error is reported.
|
||||
*/
|
||||
|
||||
MSG_DEF(MSG_INVALID_ENUM_VALUE, 2, "Value '{0}' is not a valid value for enumeration {1}.")
|
||||
MSG_DEF(MSG_INVALID_ENUM_VALUE, 3, "{0} '{1}' is not a valid value for enumeration {2}.")
|
||||
MSG_DEF(MSG_MISSING_ARGUMENTS, 1, "Not enough arguments to {0}.")
|
||||
MSG_DEF(MSG_NOT_OBJECT, 0, "Value is not an object.")
|
||||
MSG_DEF(MSG_NOT_CALLABLE, 0, "Value is not callable.")
|
||||
MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 1, "Value does not implement interface {0}.")
|
||||
MSG_DEF(MSG_NOT_IN_UNION, 1, "Value could not be converted to any of: {0}.")
|
||||
MSG_DEF(MSG_NOT_OBJECT, 1, "{0} is not an object.")
|
||||
MSG_DEF(MSG_NOT_CALLABLE, 1, "{0} is not callable.")
|
||||
MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 2, "{0} does not implement interface {1}.")
|
||||
MSG_DEF(MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 2, "{0} called on an object that does not implement interface {1}.")
|
||||
MSG_DEF(MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1, "getter called on an object that does not implement interface {0}.")
|
||||
MSG_DEF(MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1, "setter called on an object that does not implement interface {0}.")
|
||||
MSG_DEF(MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1, "\"this\" object does not implement interface {0}.")
|
||||
MSG_DEF(MSG_NOT_IN_UNION, 2, "{0} could not be converted to any of: {1}.")
|
||||
MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, "Illegal constructor.")
|
||||
MSG_DEF(MSG_NO_PROPERTY_SETTER, 1, "{0} doesn't have an indexed property setter.")
|
||||
MSG_DEF(MSG_ENFORCE_RANGE_NON_FINITE, 1, "Non-finite value is out of range for {0}.")
|
||||
MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 1, "Value is out of range for {0}.")
|
||||
MSG_DEF(MSG_NOT_SEQUENCE, 0, "Value can not be converted to a sequence.")
|
||||
MSG_DEF(MSG_NOT_DICTIONARY, 0, "Value can not be converted to a dictionary.")
|
||||
MSG_DEF(MSG_INVALID_ARG, 2, "Argument {0} is not valid for any of the {1}-argument overloads.")
|
||||
MSG_DEF(MSG_NOT_SEQUENCE, 1, "{0} can't be converted to a sequence.")
|
||||
MSG_DEF(MSG_NOT_DICTIONARY, 1, "{0} can't be converted to a dictionary.")
|
||||
MSG_DEF(MSG_OVERLOAD_RESOLUTION_FAILED, 3, "Argument {0} is not valid for any of the {1}-argument overloads of {2}.")
|
||||
MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, "Global is not a native object.")
|
||||
MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, "The given encoding '{0}' is not supported.")
|
||||
MSG_DEF(MSG_DOM_ENCODING_NOT_UTF, 0, "The encoding must be utf-8, utf-16, or utf-16be.")
|
||||
MSG_DEF(MSG_NOT_FINITE, 0, "Floating-point value is not finite.")
|
||||
MSG_DEF(MSG_NOT_FINITE, 1, "{0} is not a finite floating-point value.")
|
||||
MSG_DEF(MSG_INVALID_VERSION, 0, "0 (Zero) is not a valid database version.")
|
||||
MSG_DEF(MSG_INVALID_BYTESTRING, 2, "Cannot convert string to ByteString because the character"
|
||||
" at index {0} has value {1} which is greater than 255.")
|
||||
MSG_DEF(MSG_NOT_DATE, 0, "Value is not a date.")
|
||||
MSG_DEF(MSG_NOT_DATE, 1, "{0} is not a date.")
|
||||
|
@ -538,13 +538,6 @@ TabParent::SetDocShell(nsIDocShell *aDocShell)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabParent::GetTooltipText(nsAString & aTooltipText)
|
||||
{
|
||||
aTooltipText.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PDocumentRendererParent*
|
||||
TabParent::AllocPDocumentRenderer(const nsRect& documentRect,
|
||||
const gfxMatrix& transform,
|
||||
|
@ -133,3 +133,11 @@ quicknav_RadioButton = Radio buttons
|
||||
quicknav_Separator = Separators
|
||||
quicknav_Table = Tables
|
||||
quicknav_Checkbox = Check boxes
|
||||
|
||||
# Shortened role names for braille
|
||||
linkAbbr = lnk
|
||||
pushbuttonAbbr = btn
|
||||
passwordtextAbbr = passwdtxt
|
||||
imagemapAbbr = imgmap
|
||||
figureAbbr = fig
|
||||
textareaAbbr = txtarea
|
||||
|
@ -206,8 +206,9 @@ URL::CreateObjectURL(const WorkerGlobalObject& aGlobal, JSObject* aBlob,
|
||||
if (!blob) {
|
||||
SetDOMStringToNull(aResult);
|
||||
|
||||
NS_NAMED_LITERAL_STRING(argStr, "Argument 1 of URL.createObjectURL");
|
||||
NS_NAMED_LITERAL_STRING(blobStr, "Blob");
|
||||
aRv.ThrowTypeError(MSG_DOES_NOT_IMPLEMENT_INTERFACE, &blobStr);
|
||||
aRv.ThrowTypeError(MSG_DOES_NOT_IMPLEMENT_INTERFACE, &argStr, &blobStr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,10 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
@ -568,14 +572,25 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (mWorkAroundDriverBugs &&
|
||||
mVendor == VendorIntel) {
|
||||
// see bug 737182 for 2D textures, bug 684882 for cube map textures.
|
||||
mMaxTextureSize = std::min(mMaxTextureSize, 4096);
|
||||
mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 512);
|
||||
// for good measure, we align renderbuffers on what we do for 2D textures
|
||||
mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);
|
||||
mNeedsTextureSizeChecks = true;
|
||||
if (mWorkAroundDriverBugs) {
|
||||
if (mVendor == VendorIntel) {
|
||||
// see bug 737182 for 2D textures, bug 684882 for cube map textures.
|
||||
mMaxTextureSize = std::min(mMaxTextureSize, 4096);
|
||||
mMaxCubeMapTextureSize = std::min(mMaxCubeMapTextureSize, 512);
|
||||
// for good measure, we align renderbuffers on what we do for 2D textures
|
||||
mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);
|
||||
mNeedsTextureSizeChecks = true;
|
||||
} else if (mVendor == VendorNVIDIA) {
|
||||
SInt32 major, minor;
|
||||
OSErr err1 = ::Gestalt(gestaltSystemVersionMajor, &major);
|
||||
OSErr err2 = ::Gestalt(gestaltSystemVersionMinor, &minor);
|
||||
|
||||
if (err1 != noErr || err2 != noErr ||
|
||||
major < 10 || (major == 10 && minor < 8)) {
|
||||
mMaxTextureSize = std::min(mMaxTextureSize, 4096);
|
||||
mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_X11
|
||||
|
@ -314,8 +314,8 @@ SharedSurface_GLTexture::Create(GLContext* prodGL,
|
||||
const gfxIntSize& size,
|
||||
bool hasAlpha)
|
||||
{
|
||||
MOZ_ASSERT(prodGL && consGL);
|
||||
MOZ_ASSERT(prodGL->SharesWith(consGL));
|
||||
MOZ_ASSERT(prodGL);
|
||||
MOZ_ASSERT(!consGL || prodGL->SharesWith(consGL));
|
||||
|
||||
prodGL->MakeCurrent();
|
||||
GLuint tex = prodGL->CreateTextureForOffscreen(formats, size);
|
||||
@ -386,6 +386,7 @@ SharedSurface_GLTexture::SetConsumerGL(GLContext* consGL)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(consGL);
|
||||
MOZ_ASSERT(mGL->SharesWith(consGL));
|
||||
mConsGL = consGL;
|
||||
}
|
||||
|
||||
|
@ -555,7 +555,7 @@ private:
|
||||
gfx::IntSize mSize;
|
||||
GLuint mTextureHandle;
|
||||
GLenum mGLFormat;
|
||||
gl::GLContext* mGL;
|
||||
nsRefPtr<gl::GLContext> mGL;
|
||||
};
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
|
@ -8,31 +8,12 @@
|
||||
#define Iterator_inl_h_
|
||||
|
||||
#include "jsiter.h"
|
||||
|
||||
inline bool
|
||||
JSObject::isPropertyIterator() const
|
||||
{
|
||||
return hasClass(&js::PropertyIteratorObject::class_);
|
||||
}
|
||||
|
||||
inline js::PropertyIteratorObject &
|
||||
JSObject::asPropertyIterator()
|
||||
{
|
||||
JS_ASSERT(isPropertyIterator());
|
||||
return *static_cast<js::PropertyIteratorObject *>(this);
|
||||
}
|
||||
|
||||
inline const js::PropertyIteratorObject &
|
||||
JSObject::asPropertyIterator() const
|
||||
{
|
||||
JS_ASSERT(isPropertyIterator());
|
||||
return *static_cast<const js::PropertyIteratorObject *>(this);
|
||||
}
|
||||
#include "vm/ObjectImpl-inl.h"
|
||||
|
||||
js::NativeIterator *
|
||||
js::PropertyIteratorObject::getNativeIterator() const
|
||||
{
|
||||
JS_ASSERT(isPropertyIterator());
|
||||
JS_ASSERT(is<PropertyIteratorObject>());
|
||||
return static_cast<js::NativeIterator *>(getPrivate());
|
||||
}
|
||||
|
||||
|
@ -849,9 +849,11 @@ HashableValue::mark(JSTracer *trc) const
|
||||
|
||||
/*** MapIterator *********************************************************************************/
|
||||
|
||||
class js::MapIteratorObject : public JSObject
|
||||
class MapIteratorObject : public JSObject
|
||||
{
|
||||
public:
|
||||
static Class class_;
|
||||
|
||||
enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
|
||||
static const JSFunctionSpec methods[];
|
||||
static MapIteratorObject *create(JSContext *cx, HandleObject mapobj, ValueMap *data,
|
||||
@ -866,14 +868,7 @@ class js::MapIteratorObject : public JSObject
|
||||
static JSBool next(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
||||
inline js::MapIteratorObject &
|
||||
JSObject::asMapIterator()
|
||||
{
|
||||
JS_ASSERT(isMapIterator());
|
||||
return *static_cast<js::MapIteratorObject *>(this);
|
||||
}
|
||||
|
||||
Class js::MapIteratorClass = {
|
||||
Class MapIteratorObject::class_ = {
|
||||
"Map Iterator",
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount),
|
||||
@ -913,7 +908,7 @@ GlobalObject::initMapIteratorProto(JSContext *cx, Handle<GlobalObject *> global)
|
||||
if (!base)
|
||||
return false;
|
||||
Rooted<JSObject*> proto(cx,
|
||||
NewObjectWithGivenProto(cx, &MapIteratorClass, base, global));
|
||||
NewObjectWithGivenProto(cx, &MapIteratorObject::class_, base, global));
|
||||
if (!proto)
|
||||
return false;
|
||||
proto->setSlot(MapIteratorObject::RangeSlot, PrivateValue(NULL));
|
||||
@ -936,7 +931,7 @@ MapIteratorObject::create(JSContext *cx, HandleObject mapobj, ValueMap *data,
|
||||
if (!range)
|
||||
return NULL;
|
||||
|
||||
JSObject *iterobj = NewObjectWithGivenProto(cx, &MapIteratorClass, proto, global);
|
||||
JSObject *iterobj = NewObjectWithGivenProto(cx, &class_, proto, global);
|
||||
if (!iterobj) {
|
||||
js_delete(range);
|
||||
return NULL;
|
||||
@ -950,19 +945,19 @@ MapIteratorObject::create(JSContext *cx, HandleObject mapobj, ValueMap *data,
|
||||
void
|
||||
MapIteratorObject::finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
fop->delete_(obj->asMapIterator().range());
|
||||
fop->delete_(obj->as<MapIteratorObject>().range());
|
||||
}
|
||||
|
||||
bool
|
||||
MapIteratorObject::is(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().hasClass(&MapIteratorClass);
|
||||
return v.isObject() && v.toObject().hasClass(&class_);
|
||||
}
|
||||
|
||||
bool
|
||||
MapIteratorObject::next_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
MapIteratorObject &thisobj = args.thisv().toObject().asMapIterator();
|
||||
MapIteratorObject &thisobj = args.thisv().toObject().as<MapIteratorObject>();
|
||||
ValueMap::Range *range = thisobj.range();
|
||||
if (!range)
|
||||
return js_ThrowStopIteration(cx);
|
||||
@ -1433,9 +1428,11 @@ js_InitMapClass(JSContext *cx, HandleObject obj)
|
||||
|
||||
/*** SetIterator *********************************************************************************/
|
||||
|
||||
class js::SetIteratorObject : public JSObject
|
||||
class SetIteratorObject : public JSObject
|
||||
{
|
||||
public:
|
||||
static Class class_;
|
||||
|
||||
enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
|
||||
static const JSFunctionSpec methods[];
|
||||
static SetIteratorObject *create(JSContext *cx, HandleObject setobj, ValueSet *data,
|
||||
@ -1450,14 +1447,7 @@ class js::SetIteratorObject : public JSObject
|
||||
static JSBool next(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
||||
inline js::SetIteratorObject &
|
||||
JSObject::asSetIterator()
|
||||
{
|
||||
JS_ASSERT(isSetIterator());
|
||||
return *static_cast<js::SetIteratorObject *>(this);
|
||||
}
|
||||
|
||||
Class js::SetIteratorClass = {
|
||||
Class SetIteratorObject::class_ = {
|
||||
"Set Iterator",
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount),
|
||||
@ -1496,7 +1486,7 @@ GlobalObject::initSetIteratorProto(JSContext *cx, Handle<GlobalObject*> global)
|
||||
JSObject *base = global->getOrCreateIteratorPrototype(cx);
|
||||
if (!base)
|
||||
return false;
|
||||
RootedObject proto(cx, NewObjectWithGivenProto(cx, &SetIteratorClass, base, global));
|
||||
RootedObject proto(cx, NewObjectWithGivenProto(cx, &SetIteratorObject::class_, base, global));
|
||||
if (!proto)
|
||||
return false;
|
||||
proto->setSlot(SetIteratorObject::RangeSlot, PrivateValue(NULL));
|
||||
@ -1519,7 +1509,7 @@ SetIteratorObject::create(JSContext *cx, HandleObject setobj, ValueSet *data,
|
||||
if (!range)
|
||||
return NULL;
|
||||
|
||||
JSObject *iterobj = NewObjectWithGivenProto(cx, &SetIteratorClass, proto, global);
|
||||
JSObject *iterobj = NewObjectWithGivenProto(cx, &class_, proto, global);
|
||||
if (!iterobj) {
|
||||
js_delete(range);
|
||||
return NULL;
|
||||
@ -1533,19 +1523,19 @@ SetIteratorObject::create(JSContext *cx, HandleObject setobj, ValueSet *data,
|
||||
void
|
||||
SetIteratorObject::finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
fop->delete_(obj->asSetIterator().range());
|
||||
fop->delete_(obj->as<SetIteratorObject>().range());
|
||||
}
|
||||
|
||||
bool
|
||||
SetIteratorObject::is(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().hasClass(&SetIteratorClass);
|
||||
return v.isObject() && v.toObject().is<SetIteratorObject>();
|
||||
}
|
||||
|
||||
bool
|
||||
SetIteratorObject::next_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
SetIteratorObject &thisobj = args.thisv().toObject().asSetIterator();
|
||||
SetIteratorObject &thisobj = args.thisv().toObject().as<SetIteratorObject>();
|
||||
ValueSet::Range *range = thisobj.range();
|
||||
if (!range)
|
||||
return js_ThrowStopIteration(cx);
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
using namespace js;
|
||||
|
||||
Class js::ModuleClass = {
|
||||
Class Module::class_ = {
|
||||
"Module",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
@ -37,10 +37,10 @@ Module::setScript(JSScript *script)
|
||||
Module *
|
||||
Module::create(JSContext *cx, HandleAtom atom)
|
||||
{
|
||||
RootedObject object(cx, NewBuiltinClassInstance(cx, &ModuleClass));
|
||||
RootedObject object(cx, NewBuiltinClassInstance(cx, &class_));
|
||||
if (!object)
|
||||
return NULL;
|
||||
RootedModule module(cx, &object->asModule());
|
||||
RootedModule module(cx, &object->as<Module>());
|
||||
module->setAtom(atom);
|
||||
module->setScript(NULL);
|
||||
return module;
|
||||
|
@ -23,6 +23,8 @@ class Module : public JSObject {
|
||||
return (JSScript *) getReservedSlot(SCRIPT_SLOT).toPrivate();
|
||||
}
|
||||
|
||||
static Class class_;
|
||||
|
||||
private:
|
||||
inline void setAtom(JSAtom *atom);
|
||||
inline void setScript(JSScript *script);
|
||||
|
@ -224,7 +224,7 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
|
||||
/*
|
||||
* Beware, sourceObj may be a (transparent) proxy to a RegExp, so only
|
||||
* use generic (proxyable) operations on sourceObj that do not assume
|
||||
* sourceObj.isRegExp().
|
||||
* sourceObj.is<RegExpObject>().
|
||||
*/
|
||||
RootedObject sourceObj(cx, &sourceValue.toObject());
|
||||
|
||||
@ -306,14 +306,14 @@ CompileRegExpObject(JSContext *cx, RegExpObjectBuilder &builder, CallArgs args)
|
||||
JS_ALWAYS_INLINE bool
|
||||
IsRegExp(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().hasClass(&RegExpClass);
|
||||
return v.isObject() && v.toObject().is<RegExpObject>();
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
regexp_compile_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsRegExp(args.thisv()));
|
||||
RegExpObjectBuilder builder(cx, &args.thisv().toObject().asRegExp());
|
||||
RegExpObjectBuilder builder(cx, &args.thisv().toObject().as<RegExpObject>());
|
||||
return CompileRegExpObject(cx, builder, args);
|
||||
}
|
||||
|
||||
@ -353,7 +353,7 @@ regexp_toString_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsRegExp(args.thisv()));
|
||||
|
||||
JSString *str = args.thisv().toObject().asRegExp().toString(cx);
|
||||
JSString *str = args.thisv().toObject().as<RegExpObject>().toString(cx);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
@ -495,13 +495,13 @@ js_InitRegExpClass(JSContext *cx, HandleObject obj)
|
||||
|
||||
Rooted<GlobalObject*> global(cx, &obj->asGlobal());
|
||||
|
||||
RootedObject proto(cx, global->createBlankPrototype(cx, &RegExpClass));
|
||||
RootedObject proto(cx, global->createBlankPrototype(cx, &RegExpObject::class_));
|
||||
if (!proto)
|
||||
return NULL;
|
||||
proto->setPrivate(NULL);
|
||||
|
||||
HandlePropertyName empty = cx->names().empty;
|
||||
RegExpObjectBuilder builder(cx, &proto->asRegExp());
|
||||
RegExpObjectBuilder builder(cx, &proto->as<RegExpObject>());
|
||||
if (!builder.build(empty, RegExpFlag(0)))
|
||||
return NULL;
|
||||
|
||||
@ -530,7 +530,7 @@ RegExpRunStatus
|
||||
js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string, MatchConduit &matches)
|
||||
{
|
||||
/* Step 1 (b) was performed by CallNonGenericMethod. */
|
||||
Rooted<RegExpObject*> reobj(cx, ®exp->asRegExp());
|
||||
Rooted<RegExpObject*> reobj(cx, ®exp->as<RegExpObject>());
|
||||
|
||||
RegExpGuard re(cx);
|
||||
if (!reobj->getShared(cx, &re))
|
||||
|
@ -108,8 +108,8 @@ MaybeCheckEvalFreeVariables(JSContext *cx, HandleScript evalCaller, HandleObject
|
||||
if (pc.sc->hasDebuggerStatement()) {
|
||||
RootedObject scope(cx, scopeChain);
|
||||
while (scope->isScope() || scope->isDebugScope()) {
|
||||
if (scope->isCall() && !scope->asCall().isForEval()) {
|
||||
RootedScript script(cx, scope->asCall().callee().nonLazyScript());
|
||||
if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
|
||||
RootedScript script(cx, scope->as<CallObject>().callee().nonLazyScript());
|
||||
if (script->argumentsHasVarBinding()) {
|
||||
if (!JSScript::argumentsOptimizationFailed(cx, script))
|
||||
return false;
|
||||
|
@ -811,7 +811,7 @@ ObjectBox::ObjectBox(Module *module, ObjectBox* traceLink)
|
||||
traceLink(traceLink),
|
||||
emitLink(NULL)
|
||||
{
|
||||
JS_ASSERT(object->isModule());
|
||||
JS_ASSERT(object->is<Module>());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "builtin/Module.h"
|
||||
#include "frontend/TokenStream.h"
|
||||
|
||||
namespace js {
|
||||
@ -1360,7 +1360,7 @@ class ObjectBox
|
||||
JSObject *object;
|
||||
|
||||
ObjectBox(JSObject *object, ObjectBox *traceLink);
|
||||
bool isModuleBox() { return object->isModule(); }
|
||||
bool isModuleBox() { return object->is<Module>(); }
|
||||
bool isFunctionBox() { return object->isFunction(); }
|
||||
ModuleBox *asModuleBox();
|
||||
FunctionBox *asFunctionBox();
|
||||
|
@ -4533,7 +4533,7 @@ Parser<ParseHandler>::statement()
|
||||
if (!cond)
|
||||
return null();
|
||||
|
||||
if (tokenStream.peekToken() == TOK_SEMI &&
|
||||
if (tokenStream.peekToken(TSF_OPERAND) == TOK_SEMI &&
|
||||
!report(ParseExtraWarning, false, null(), JSMSG_EMPTY_CONSEQUENT))
|
||||
{
|
||||
return null();
|
||||
|
@ -192,7 +192,7 @@ class ModuleBox : public ObjectBox, public SharedContext
|
||||
ModuleBox(JSContext *cx, ObjectBox *traceListHead, Module *module,
|
||||
ParseContext<FullParseHandler> *pc);
|
||||
ObjectBox *toObjectBox() { return this; }
|
||||
Module *module() const { return &object->asModule(); }
|
||||
Module *module() const { return &object->as<Module>(); }
|
||||
};
|
||||
|
||||
class FunctionBox : public ObjectBox, public SharedContext
|
||||
|
@ -360,7 +360,7 @@ js::Nursery::moveElementsToTenured(JSObject *dst, JSObject *src, AllocKind dstKi
|
||||
}
|
||||
|
||||
/* ArrayBuffer stores byte-length, not Value count. */
|
||||
if (src->isArrayBuffer()) {
|
||||
if (src->is<ArrayBufferObject>()) {
|
||||
size_t nbytes = sizeof(ObjectElements) + srcHeader->initializedLength;
|
||||
if (src->hasDynamicElements()) {
|
||||
dstHeader = static_cast<ObjectElements *>(alloc->malloc_(nbytes));
|
||||
|
@ -186,7 +186,7 @@ DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module)
|
||||
if (!IsTypedArrayBuffer(bufferVal))
|
||||
return LinkFail(cx, "bad ArrayBuffer argument");
|
||||
|
||||
heap = &bufferVal.toObject().asArrayBuffer();
|
||||
heap = &bufferVal.toObject().as<ArrayBufferObject>();
|
||||
|
||||
if (!IsPowerOfTwo(heap->byteLength()) || heap->byteLength() < AsmJSAllocationGranularity)
|
||||
return LinkFail(cx, "ArrayBuffer byteLength must be a power of two greater than or equal to 4096");
|
||||
|
@ -560,7 +560,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||
v = iter.read();
|
||||
JS_ASSERT(v.isObject() || v.isUndefined());
|
||||
if (v.isObject())
|
||||
argsObj = &v.toObject().asArguments();
|
||||
argsObj = &v.toObject().as<ArgumentsObject>();
|
||||
}
|
||||
}
|
||||
IonSpew(IonSpew_BaselineBailouts, " ScopeChain=%p", scopeChain);
|
||||
|
@ -22,7 +22,7 @@ inline void
|
||||
BaselineFrame::pushOnScopeChain(ScopeObject &scope)
|
||||
{
|
||||
JS_ASSERT(*scopeChain() == scope.enclosingScope() ||
|
||||
*scopeChain() == scope.asCall().enclosingScope().asDeclEnv().enclosingScope());
|
||||
*scopeChain() == scope.as<CallObject>().enclosingScope().as<DeclEnvObject>().enclosingScope());
|
||||
scopeChain_ = &scope;
|
||||
}
|
||||
|
||||
@ -72,9 +72,9 @@ BaselineFrame::callObj() const
|
||||
JS_ASSERT(fun()->isHeavyweight());
|
||||
|
||||
JSObject *obj = scopeChain();
|
||||
while (!obj->isCall())
|
||||
while (!obj->is<CallObject>())
|
||||
obj = obj->enclosingScope();
|
||||
return obj->asCall();
|
||||
return obj->as<CallObject>();
|
||||
}
|
||||
|
||||
} // namespace ion
|
||||
|
@ -3532,9 +3532,9 @@ TryAttachGetElemStub(JSContext *cx, HandleScript script, ICGetElem_Fallback *stu
|
||||
RootedObject obj(cx, &lhs.toObject());
|
||||
|
||||
// Check for ArgumentsObj[int] accesses
|
||||
if (obj->isArguments() && rhs.isInt32()) {
|
||||
if (obj->is<ArgumentsObject>() && rhs.isInt32()) {
|
||||
ICGetElem_Arguments::Which which = ICGetElem_Arguments::Normal;
|
||||
if (obj->isStrictArguments())
|
||||
if (obj->is<StrictArgumentsObject>())
|
||||
which = ICGetElem_Arguments::Strict;
|
||||
if (!ArgumentsGetElemStubExists(stub, which)) {
|
||||
IonSpew(IonSpew_BaselineIC, " Generating GetElem(ArgsObj[Int32]) stub");
|
||||
@ -3926,7 +3926,7 @@ ICGetElem_Arguments::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
which_ == ICGetElem_Arguments::Normal);
|
||||
|
||||
bool isStrict = which_ == ICGetElem_Arguments::Strict;
|
||||
Class *clasp = isStrict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
|
||||
Class *clasp = isStrict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_;
|
||||
|
||||
GeneralRegisterSet regs(availableGeneralRegs(2));
|
||||
Register scratchReg = regs.takeAny();
|
||||
@ -5192,11 +5192,11 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj->isArguments() && res.isInt32()) {
|
||||
if (obj->is<ArgumentsObject>() && res.isInt32()) {
|
||||
IonSpew(IonSpew_BaselineIC, " Generating GetProp(ArgsObj.length %s) stub",
|
||||
obj->isStrictArguments() ? "Strict" : "Normal");
|
||||
obj->is<StrictArgumentsObject>() ? "Strict" : "Normal");
|
||||
ICGetProp_ArgumentsLength::Which which = ICGetProp_ArgumentsLength::Normal;
|
||||
if (obj->isStrictArguments())
|
||||
if (obj->is<StrictArgumentsObject>())
|
||||
which = ICGetProp_ArgumentsLength::Strict;
|
||||
ICGetProp_ArgumentsLength::Compiler compiler(cx, which);
|
||||
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
@ -6115,7 +6115,7 @@ ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
which_ == ICGetProp_ArgumentsLength::Normal);
|
||||
|
||||
bool isStrict = which_ == ICGetProp_ArgumentsLength::Strict;
|
||||
Class *clasp = isStrict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
|
||||
Class *clasp = isStrict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_;
|
||||
|
||||
Register scratchReg = R1.scratchReg();
|
||||
|
||||
@ -7834,7 +7834,9 @@ DoIteratorMoreFallback(JSContext *cx, BaselineFrame *frame, ICIteratorMore_Fallb
|
||||
return false;
|
||||
res.setBoolean(cond);
|
||||
|
||||
if (iterValue.toObject().isPropertyIterator() && !stub->hasStub(ICStub::IteratorMore_Native)) {
|
||||
if (iterValue.toObject().is<PropertyIteratorObject>() &&
|
||||
!stub->hasStub(ICStub::IteratorMore_Native))
|
||||
{
|
||||
ICIteratorMore_Native::Compiler compiler(cx);
|
||||
ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
|
||||
if (!newStub)
|
||||
@ -7912,7 +7914,9 @@ DoIteratorNextFallback(JSContext *cx, BaselineFrame *frame, ICIteratorNext_Fallb
|
||||
if (!IteratorNext(cx, iteratorObject, res))
|
||||
return false;
|
||||
|
||||
if (iteratorObject->isPropertyIterator() && !stub->hasStub(ICStub::IteratorNext_Native)) {
|
||||
if (iteratorObject->is<PropertyIteratorObject>() &&
|
||||
!stub->hasStub(ICStub::IteratorNext_Native))
|
||||
{
|
||||
ICIteratorNext_Native::Compiler compiler(cx);
|
||||
ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
|
||||
if (!newStub)
|
||||
|
@ -5974,7 +5974,7 @@ IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bo
|
||||
bool
|
||||
IonBuilder::getStaticName(HandleObject staticObject, HandlePropertyName name, bool *psucceeded)
|
||||
{
|
||||
JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
|
||||
JS_ASSERT(staticObject->isGlobal() || staticObject->is<CallObject>());
|
||||
|
||||
*psucceeded = true;
|
||||
|
||||
@ -6090,7 +6090,7 @@ IonBuilder::setStaticName(HandleObject staticObject, HandlePropertyName name)
|
||||
{
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
JS_ASSERT(staticObject->isGlobal() || staticObject->isCall());
|
||||
JS_ASSERT(staticObject->isGlobal() || staticObject->is<CallObject>());
|
||||
|
||||
MDefinition *value = current->peek(-1);
|
||||
|
||||
@ -8267,9 +8267,9 @@ IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, MutableHandleObject pcall)
|
||||
|
||||
JSObject *environment = script()->function()->environment();
|
||||
while (environment && !environment->isGlobal()) {
|
||||
if (environment->isCall() &&
|
||||
!environment->asCall().isForEval() &&
|
||||
environment->asCall().callee().nonLazyScript() == outerScript)
|
||||
if (environment->is<CallObject>() &&
|
||||
!environment->as<CallObject>().isForEval() &&
|
||||
environment->as<CallObject>().callee().nonLazyScript() == outerScript)
|
||||
{
|
||||
JS_ASSERT(environment->hasSingletonType());
|
||||
pcall.set(environment);
|
||||
@ -8285,7 +8285,9 @@ IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, MutableHandleObject pcall)
|
||||
|
||||
if (script() == outerScript && fp && info().osrPc()) {
|
||||
JSObject *scope = fp.scopeChain();
|
||||
if (scope->isCall() && scope->asCall().callee().nonLazyScript() == outerScript) {
|
||||
if (scope->is<CallObject>() &&
|
||||
scope->as<CallObject>().callee().nonLazyScript() == outerScript)
|
||||
{
|
||||
JS_ASSERT(scope->hasSingletonType());
|
||||
pcall.set(scope);
|
||||
return true;
|
||||
|
@ -555,10 +555,10 @@ IsCacheableNoProperty(JSObject *obj, JSObject *holder, Shape *shape, jsbytecode
|
||||
static bool
|
||||
IsOptimizableArgumentsObjectForLength(JSObject *obj)
|
||||
{
|
||||
if (!obj->isArguments())
|
||||
if (!obj->is<ArgumentsObject>())
|
||||
return false;
|
||||
|
||||
if (obj->asArguments().hasOverriddenLength())
|
||||
if (obj->as<ArgumentsObject>().hasOverriddenLength())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -570,7 +570,7 @@ IsOptimizableArgumentsObjectForGetElem(JSObject *obj, Value idval)
|
||||
if (!IsOptimizableArgumentsObjectForLength(obj))
|
||||
return false;
|
||||
|
||||
ArgumentsObject &argsObj = obj->asArguments();
|
||||
ArgumentsObject &argsObj = obj->as<ArgumentsObject>();
|
||||
|
||||
if (argsObj.isAnyElementDeleted())
|
||||
return false;
|
||||
@ -1252,7 +1252,7 @@ GetPropertyIC::attachTypedArrayLength(JSContext *cx, IonScript *ion, JSObject *o
|
||||
bool
|
||||
GetPropertyIC::attachArgumentsLength(JSContext *cx, IonScript *ion, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isArguments());
|
||||
JS_ASSERT(obj->is<ArgumentsObject>());
|
||||
JS_ASSERT(!idempotent());
|
||||
|
||||
Label failures;
|
||||
@ -1268,8 +1268,8 @@ GetPropertyIC::attachArgumentsLength(JSContext *cx, IonScript *ion, JSObject *ob
|
||||
}
|
||||
JS_ASSERT(object() != tmpReg);
|
||||
|
||||
Class *clasp = obj->isStrictArguments() ? &StrictArgumentsObjectClass
|
||||
: &NormalArgumentsObjectClass;
|
||||
Class *clasp = obj->is<StrictArgumentsObject>() ? &StrictArgumentsObject::class_
|
||||
: &NormalArgumentsObject::class_;
|
||||
|
||||
Label fail;
|
||||
Label pass;
|
||||
@ -1293,7 +1293,7 @@ GetPropertyIC::attachArgumentsLength(JSContext *cx, IonScript *ion, JSObject *ob
|
||||
masm.bind(&failures);
|
||||
attacher.jumpNextStub(masm);
|
||||
|
||||
if (obj->isStrictArguments()) {
|
||||
if (obj->is<StrictArgumentsObject>()) {
|
||||
JS_ASSERT(!hasStrictArgumentsLengthStub_);
|
||||
hasStrictArgumentsLengthStub_ = true;
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj length (strict)");
|
||||
@ -1462,7 +1462,7 @@ GetPropertyIC::update(JSContext *cx, size_t cacheIndex,
|
||||
if (name == cx->names().length &&
|
||||
IsOptimizableArgumentsObjectForLength(obj) &&
|
||||
(cache.output().type() == MIRType_Value || cache.output().type() == MIRType_Int32) &&
|
||||
!cache.hasArgumentsLengthStub(obj->isStrictArguments()))
|
||||
!cache.hasArgumentsLengthStub(obj->is<StrictArgumentsObject>()))
|
||||
{
|
||||
isCacheable = true;
|
||||
if (!cache.attachArgumentsLength(cx, ion, obj))
|
||||
@ -2372,7 +2372,7 @@ GetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, JSObject *o
|
||||
bool
|
||||
GetElementIC::attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isArguments());
|
||||
JS_ASSERT(obj->is<ArgumentsObject>());
|
||||
|
||||
Label failures;
|
||||
MacroAssembler masm(cx);
|
||||
@ -2381,8 +2381,8 @@ GetElementIC::attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *ob
|
||||
Register tmpReg = output().scratchReg().gpr();
|
||||
JS_ASSERT(tmpReg != InvalidReg);
|
||||
|
||||
Class *clasp = obj->isStrictArguments() ? &StrictArgumentsObjectClass
|
||||
: &NormalArgumentsObjectClass;
|
||||
Class *clasp = obj->is<StrictArgumentsObject>() ? &StrictArgumentsObject::class_
|
||||
: &NormalArgumentsObject::class_;
|
||||
|
||||
Label fail;
|
||||
Label pass;
|
||||
@ -2467,7 +2467,7 @@ GetElementIC::attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *ob
|
||||
attacher.jumpNextStub(masm);
|
||||
|
||||
|
||||
if (obj->isStrictArguments()) {
|
||||
if (obj->is<StrictArgumentsObject>()) {
|
||||
JS_ASSERT(!hasStrictArgumentsStub_);
|
||||
hasStrictArgumentsStub_ = true;
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj element (strict)");
|
||||
@ -2507,7 +2507,7 @@ GetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
|
||||
bool attachedStub = false;
|
||||
if (cache.canAttachStub()) {
|
||||
if (IsOptimizableArgumentsObjectForGetElem(obj, idval) &&
|
||||
!cache.hasArgumentsStub(obj->isStrictArguments()) &&
|
||||
!cache.hasArgumentsStub(obj->is<StrictArgumentsObject>()) &&
|
||||
!cache.index().constant() &&
|
||||
(cache.index().reg().hasValue() ||
|
||||
cache.index().reg().type() == MIRType_Int32) &&
|
||||
@ -2734,11 +2734,11 @@ static inline void
|
||||
GenerateScopeChainGuard(MacroAssembler &masm, JSObject *scopeObj,
|
||||
Register scopeObjReg, Shape *shape, Label *failures)
|
||||
{
|
||||
if (scopeObj->isCall()) {
|
||||
if (scopeObj->is<CallObject>()) {
|
||||
// We can skip a guard on the call object if the script's bindings are
|
||||
// guaranteed to be immutable (and thus cannot introduce shadowing
|
||||
// variables).
|
||||
CallObject *callObj = &scopeObj->asCall();
|
||||
CallObject *callObj = &scopeObj->as<CallObject>();
|
||||
if (!callObj->isForEval()) {
|
||||
JSFunction *fun = &callObj->callee();
|
||||
JSScript *script = fun->nonLazyScript();
|
||||
@ -2923,7 +2923,7 @@ IsCacheableNameReadSlot(JSContext *cx, HandleObject scopeChain, HandleObject obj
|
||||
if (!IsCacheableGetPropReadSlot(obj, holder, shape) &&
|
||||
!IsCacheableNoProperty(obj, holder, shape, pc, output))
|
||||
return false;
|
||||
} else if (obj->isCall()) {
|
||||
} else if (obj->is<CallObject>()) {
|
||||
if (!shape->hasDefaultGetter())
|
||||
return false;
|
||||
} else {
|
||||
|
@ -635,7 +635,8 @@ LiveRangeAllocator<VREG>::buildLivenessInfo()
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
CodePosition to = ins->isCall() ? outputOf(*ins) : outputOf(*ins).next();
|
||||
CodePosition to =
|
||||
ins->isCall() ? outputOf(*ins) : outputOf(*ins).next();
|
||||
if (!vregs[temp].getInterval(0)->addRangeAtHead(inputOf(*ins), to))
|
||||
return false;
|
||||
}
|
||||
@ -701,7 +702,8 @@ LiveRangeAllocator<VREG>::buildLivenessInfo()
|
||||
to = use->usedAtStart() ? inputOf(*ins) : outputOf(*ins);
|
||||
}
|
||||
} else {
|
||||
to = (use->usedAtStart() || ins->isCall()) ? inputOf(*ins) : outputOf(*ins);
|
||||
to = (use->usedAtStart() || ins->isCall())
|
||||
? inputOf(*ins) : outputOf(*ins);
|
||||
if (use->isFixedRegister()) {
|
||||
LAllocation reg(AnyRegister::FromCode(use->registerCode()));
|
||||
for (size_t i = 0; i < ins->numDefs(); i++) {
|
||||
|
@ -926,7 +926,7 @@ IonBuilder::inlineRegExpTest(CallInfo &callInfo)
|
||||
return InliningStatus_NotInlined;
|
||||
types::StackTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
Class *clasp = thisTypes ? thisTypes->getKnownClass() : NULL;
|
||||
if (clasp != &RegExpClass)
|
||||
if (clasp != &RegExpObject::class_)
|
||||
return InliningStatus_NotInlined;
|
||||
if (callInfo.getArg(0)->type() != MIRType_String)
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -639,7 +639,7 @@ DebugEpilogue(JSContext *cx, BaselineFrame *frame, JSBool ok)
|
||||
JS_ASSERT_IF(ok, frame->hasReturnValue());
|
||||
DebugScopes::onPopCall(frame, cx);
|
||||
} else if (frame->isStrictEvalFrame()) {
|
||||
JS_ASSERT_IF(frame->hasCallObj(), frame->scopeChain()->asCall().isForEval());
|
||||
JS_ASSERT_IF(frame->hasCallObj(), frame->scopeChain()->as<CallObject>().isForEval());
|
||||
DebugScopes::onPopStrictEvalScope(frame);
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
class DeclEnvObject;
|
||||
class ForkJoinSlice;
|
||||
|
||||
namespace ion {
|
||||
|
@ -580,25 +580,27 @@ class AssemblerX86Shared
|
||||
void cmpEAX(Label *label) { cmpSrc(label); }
|
||||
void bind(Label *label) {
|
||||
JSC::MacroAssembler::Label jsclabel;
|
||||
JSC::X86Assembler::JmpDst dst(masm.label());
|
||||
if (label->used()) {
|
||||
bool more;
|
||||
JSC::X86Assembler::JmpSrc jmp(label->offset());
|
||||
do {
|
||||
JSC::X86Assembler::JmpSrc next;
|
||||
more = masm.nextJump(jmp, &next);
|
||||
masm.linkJump(jmp, masm.label());
|
||||
masm.linkJump(jmp, dst);
|
||||
jmp = next;
|
||||
} while (more);
|
||||
}
|
||||
label->bind(masm.label().offset());
|
||||
label->bind(dst.offset());
|
||||
}
|
||||
void bind(RepatchLabel *label) {
|
||||
JSC::MacroAssembler::Label jsclabel;
|
||||
JSC::X86Assembler::JmpDst dst(masm.label());
|
||||
if (label->used()) {
|
||||
JSC::X86Assembler::JmpSrc jmp(label->offset());
|
||||
masm.linkJump(jmp, masm.label());
|
||||
masm.linkJump(jmp, dst);
|
||||
}
|
||||
label->bind(masm.label().offset());
|
||||
label->bind(dst.offset());
|
||||
}
|
||||
uint32_t currentOffset() {
|
||||
return masm.label().offset();
|
||||
|
1
js/src/jit-test/tests/basic/bug883523.js
Normal file
1
js/src/jit-test/tests/basic/bug883523.js
Normal file
@ -0,0 +1 @@
|
||||
if(1) /a/.test("a"); // should not be a SyntaxError.
|
@ -90,7 +90,7 @@ ExhaustiveTest(const char funcode[])
|
||||
EVAL(funcode, v.address());
|
||||
|
||||
EVAL(CALL_CODES[ArgCount], v.address());
|
||||
Rooted<ArgumentsObject*> argsobj(cx, &JSVAL_TO_OBJECT(v)->asArguments());
|
||||
Rooted<ArgumentsObject*> argsobj(cx, &JSVAL_TO_OBJECT(v)->as<ArgumentsObject>());
|
||||
|
||||
Value elems[MAX_ELEMS];
|
||||
|
||||
|
@ -1792,10 +1792,12 @@ JS_InitStandardClasses(JSContext *cx, JSObject *objArg)
|
||||
}
|
||||
|
||||
#define CLASP(name) (&name##Class)
|
||||
#define OCLASP(name) (&name##Object::class_)
|
||||
#define TYPED_ARRAY_CLASP(type) (&TypedArray::classes[TypedArray::type])
|
||||
#define EAGER_ATOM(name) NAME_OFFSET(name)
|
||||
#define EAGER_CLASS_ATOM(name) NAME_OFFSET(name)
|
||||
#define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
|
||||
#define EAGER_ATOM_AND_OCLASP(name) EAGER_CLASS_ATOM(name), OCLASP(name)
|
||||
|
||||
typedef struct JSStdName {
|
||||
JSClassInitializerOp init;
|
||||
@ -1823,17 +1825,17 @@ static JSStdName standard_class_atoms[] = {
|
||||
{js_InitNumberClass, EAGER_ATOM_AND_CLASP(Number)},
|
||||
{js_InitStringClass, EAGER_ATOM_AND_CLASP(String)},
|
||||
{js_InitExceptionClasses, EAGER_ATOM_AND_CLASP(Error)},
|
||||
{js_InitRegExpClass, EAGER_ATOM_AND_CLASP(RegExp)},
|
||||
{js_InitRegExpClass, EAGER_ATOM_AND_OCLASP(RegExp)},
|
||||
#if JS_HAS_GENERATORS
|
||||
{js_InitIteratorClasses, EAGER_ATOM_AND_CLASP(StopIteration)},
|
||||
#endif
|
||||
{js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBufferObject::protoClass},
|
||||
{js_InitWeakMapClass, EAGER_ATOM_AND_CLASP(WeakMap)},
|
||||
{js_InitMapClass, EAGER_CLASS_ATOM(Map), &js::MapObject::class_},
|
||||
{js_InitSetClass, EAGER_CLASS_ATOM(Set), &js::SetObject::class_},
|
||||
{js_InitMapClass, EAGER_ATOM_AND_OCLASP(Map)},
|
||||
{js_InitSetClass, EAGER_ATOM_AND_OCLASP(Set)},
|
||||
#ifdef ENABLE_PARALLEL_JS
|
||||
{js_InitParallelArrayClass, EAGER_CLASS_ATOM(ParallelArray), &js::ParallelArrayObject::class_},
|
||||
{js_InitParallelArrayClass, EAGER_ATOM_AND_OCLASP(ParallelArray)},
|
||||
#endif
|
||||
{js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)},
|
||||
#if ENABLE_INTL_API
|
||||
@ -1882,7 +1884,7 @@ static JSStdName standard_class_names[] = {
|
||||
{js_InitIteratorClasses, EAGER_CLASS_ATOM(Iterator), &PropertyIteratorObject::class_},
|
||||
|
||||
/* Typed Arrays */
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &ArrayBufferClass},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &ArrayBufferObject::class_},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)},
|
||||
@ -1893,7 +1895,7 @@ static JSStdName standard_class_names[] = {
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8ClampedArray),
|
||||
TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(DataView), &DataViewClass},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(DataView), &DataViewObject::class_},
|
||||
|
||||
{NULL, 0, NULL}
|
||||
};
|
||||
@ -6838,8 +6840,8 @@ JS_ExecuteRegExp(JSContext *cx, JSObject *objArg, JSObject *reobjArg, jschar *ch
|
||||
RegExpStatics *res = obj->asGlobal().getRegExpStatics();
|
||||
|
||||
RootedValue val(cx);
|
||||
if (!ExecuteRegExpLegacy(cx, res, reobj->asRegExp(), NullPtr(), chars, length, indexp, test,
|
||||
&val))
|
||||
if (!ExecuteRegExpLegacy(cx, res, reobj->as<RegExpObject>(), NullPtr(), chars, length, indexp,
|
||||
test, &val))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -6879,8 +6881,8 @@ JS_ExecuteRegExpNoStatics(JSContext *cx, JSObject *objArg, jschar *chars, size_t
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
RootedValue val(cx);
|
||||
if (!ExecuteRegExpLegacy(cx, NULL, obj->asRegExp(), NullPtr(), chars, length, indexp, test,
|
||||
&val))
|
||||
if (!ExecuteRegExpLegacy(cx, NULL, obj->as<RegExpObject>(), NullPtr(), chars, length, indexp,
|
||||
test, &val))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -6903,7 +6905,7 @@ JS_GetRegExpFlags(JSContext *cx, JSObject *objArg)
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
return obj->asRegExp().getFlags();
|
||||
return obj->as<RegExpObject>().getFlags();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSString *)
|
||||
@ -6913,7 +6915,7 @@ JS_GetRegExpSource(JSContext *cx, JSObject *objArg)
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
return obj->asRegExp().getSource();
|
||||
return obj->as<RegExpObject>().getSource();
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -57,8 +57,8 @@ js::GetLengthProperty(JSContext *cx, HandleObject obj, uint32_t *lengthp)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj->isArguments()) {
|
||||
ArgumentsObject &argsobj = obj->asArguments();
|
||||
if (obj->is<ArgumentsObject>()) {
|
||||
ArgumentsObject &argsobj = obj->as<ArgumentsObject>();
|
||||
if (!argsobj.hasOverriddenLength()) {
|
||||
*lengthp = argsobj.initialLength();
|
||||
return true;
|
||||
@ -213,8 +213,8 @@ GetElement(JSContext *cx, HandleObject obj, IndexType index, JSBool *hole, Mutab
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (obj->isArguments()) {
|
||||
if (obj->asArguments().maybeGetElement(uint32_t(index), vp)) {
|
||||
if (obj->is<ArgumentsObject>()) {
|
||||
if (obj->as<ArgumentsObject>().maybeGetElement(uint32_t(index), vp)) {
|
||||
*hole = false;
|
||||
return true;
|
||||
}
|
||||
@ -249,8 +249,8 @@ js::GetElements(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aobj->isArguments()) {
|
||||
ArgumentsObject &argsobj = aobj->asArguments();
|
||||
if (aobj->is<ArgumentsObject>()) {
|
||||
ArgumentsObject &argsobj = aobj->as<ArgumentsObject>();
|
||||
if (!argsobj.hasOverriddenLength()) {
|
||||
if (argsobj.maybeGetElements(0, length, vp))
|
||||
return true;
|
||||
@ -1474,6 +1474,7 @@ typedef bool (*ComparatorNumeric)(const NumericElement &a, const NumericElement
|
||||
bool *lessOrEqualp);
|
||||
|
||||
ComparatorNumeric SortComparatorNumerics[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
ComparatorNumericLeftMinusRight,
|
||||
ComparatorNumericRightMinusLeft
|
||||
@ -1496,13 +1497,17 @@ ComparatorInt32RightMinusLeft(const Value &a, const Value &b, bool *lessOrEqualp
|
||||
typedef bool (*ComparatorInt32)(const Value &a, const Value &b, bool *lessOrEqualp);
|
||||
|
||||
ComparatorInt32 SortComparatorInt32s[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
ComparatorInt32LeftMinusRight,
|
||||
ComparatorInt32RightMinusLeft
|
||||
};
|
||||
|
||||
// Note: Values for this enum must match up with SortComparatorNumerics
|
||||
// and SortComparatorInt32s.
|
||||
enum ComparatorMatchResult {
|
||||
Match_None = 0,
|
||||
Match_Failure = 0,
|
||||
Match_None,
|
||||
Match_LeftMinusRight,
|
||||
Match_RightMinusLeft
|
||||
};
|
||||
@ -1512,7 +1517,7 @@ enum ComparatorMatchResult {
|
||||
* patterns: namely, |return x - y| and |return y - x|.
|
||||
*/
|
||||
ComparatorMatchResult
|
||||
MatchNumericComparator(const Value &v)
|
||||
MatchNumericComparator(JSContext *cx, const Value &v)
|
||||
{
|
||||
if (!v.isObject())
|
||||
return Match_None;
|
||||
@ -1522,10 +1527,13 @@ MatchNumericComparator(const Value &v)
|
||||
return Match_None;
|
||||
|
||||
JSFunction *fun = obj.toFunction();
|
||||
if (!fun->hasScript())
|
||||
if (!fun->isInterpreted())
|
||||
return Match_None;
|
||||
|
||||
JSScript *script = fun->nonLazyScript();
|
||||
JSScript *script = fun->getOrCreateScript(cx);
|
||||
if (!script)
|
||||
return Match_Failure;
|
||||
|
||||
jsbytecode *pc = script->code;
|
||||
|
||||
uint16_t arg0, arg1;
|
||||
@ -1802,7 +1810,9 @@ js::array_sort(JSContext *cx, unsigned argc, Value *vp)
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ComparatorMatchResult comp = MatchNumericComparator(fval);
|
||||
ComparatorMatchResult comp = MatchNumericComparator(cx, fval);
|
||||
if (comp == Match_Failure)
|
||||
return false;
|
||||
|
||||
if (comp != Match_None) {
|
||||
if (allInts) {
|
||||
|
@ -485,7 +485,7 @@ JSStructuredCloneWriter::parseTransferable()
|
||||
JS_ReportError(context(), "Permission denied to access object");
|
||||
return false;
|
||||
}
|
||||
if (!tObj->isArrayBuffer()) {
|
||||
if (!tObj->is<ArrayBufferObject>()) {
|
||||
reportErrorTransferable();
|
||||
return false;
|
||||
}
|
||||
@ -600,7 +600,7 @@ JSStructuredCloneWriter::writeTypedArray(HandleObject arr)
|
||||
bool
|
||||
JSStructuredCloneWriter::writeArrayBuffer(JSHandleObject obj)
|
||||
{
|
||||
ArrayBufferObject &buffer = obj->asArrayBuffer();
|
||||
ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
|
||||
return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, buffer.byteLength()) &&
|
||||
out.writeBytes(buffer.dataPointer(), buffer.byteLength());
|
||||
}
|
||||
@ -681,8 +681,8 @@ JSStructuredCloneWriter::startWrite(const Value &v)
|
||||
if (backref)
|
||||
return true;
|
||||
|
||||
if (obj->isRegExp()) {
|
||||
RegExpObject &reobj = obj->asRegExp();
|
||||
if (obj->is<RegExpObject>()) {
|
||||
RegExpObject &reobj = obj->as<RegExpObject>();
|
||||
return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) &&
|
||||
writeString(SCTAG_STRING, reobj.getSource());
|
||||
} else if (obj->isDate()) {
|
||||
@ -690,7 +690,7 @@ JSStructuredCloneWriter::startWrite(const Value &v)
|
||||
return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d);
|
||||
} else if (obj->isTypedArray()) {
|
||||
return writeTypedArray(obj);
|
||||
} else if (obj->isArrayBuffer() && obj->asArrayBuffer().hasData()) {
|
||||
} else if (obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().hasData()) {
|
||||
return writeArrayBuffer(obj);
|
||||
} else if (obj->isObject() || obj->isArray()) {
|
||||
return traverseObject(obj);
|
||||
@ -947,7 +947,7 @@ JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes, Value *vp)
|
||||
if (!obj)
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
ArrayBufferObject &buffer = obj->asArrayBuffer();
|
||||
ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
|
||||
JS_ASSERT(buffer.byteLength() == nbytes);
|
||||
return in.readArray(buffer.dataPointer(), nbytes);
|
||||
}
|
||||
@ -989,7 +989,7 @@ JSStructuredCloneReader::readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems,
|
||||
if (!obj)
|
||||
return false;
|
||||
vp->setObject(*obj);
|
||||
ArrayBufferObject &buffer = obj->asArrayBuffer();
|
||||
ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
|
||||
JS_ASSERT(buffer.byteLength() == nbytes);
|
||||
|
||||
switch (arrayType) {
|
||||
|
@ -250,6 +250,8 @@ struct EvalCacheHashPolicy
|
||||
|
||||
typedef HashSet<EvalCacheEntry, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
|
||||
|
||||
class PropertyIteratorObject;
|
||||
|
||||
class NativeIterCache
|
||||
{
|
||||
static const size_t SIZE = size_t(1) << 8;
|
||||
|
@ -1265,7 +1265,7 @@ JSAbstractFramePtr::callObject(JSContext *cx)
|
||||
*/
|
||||
while (o) {
|
||||
ScopeObject &scope = o->asDebugScope().scope();
|
||||
if (scope.isCall())
|
||||
if (scope.is<CallObject>())
|
||||
return o;
|
||||
o = o->enclosingScope();
|
||||
}
|
||||
|
@ -353,6 +353,12 @@ js::IsScopeObject(JSObject *obj)
|
||||
return obj->isScope();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::IsCallObject(JSObject *obj)
|
||||
{
|
||||
return obj->is<CallObject>();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
js::GetObjectParentMaybeScope(JSObject *obj)
|
||||
{
|
||||
|
@ -376,8 +376,6 @@ struct Atom {
|
||||
|
||||
} /* namespace shadow */
|
||||
|
||||
extern JS_FRIEND_DATA(js::Class) CallClass;
|
||||
extern JS_FRIEND_DATA(js::Class) DeclEnvClass;
|
||||
extern JS_FRIEND_DATA(js::Class) FunctionClass;
|
||||
extern JS_FRIEND_DATA(js::Class) FunctionProxyClass;
|
||||
extern JS_FRIEND_DATA(js::Class) OuterWindowProxyClass;
|
||||
@ -409,6 +407,9 @@ IsOuterObject(JSObject *obj) {
|
||||
JS_FRIEND_API(bool)
|
||||
IsScopeObject(JSObject *obj);
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
IsCallObject(JSObject *obj);
|
||||
|
||||
inline JSObject *
|
||||
GetObjectParent(JSObject *obj)
|
||||
{
|
||||
|
@ -6141,7 +6141,7 @@ JSCompartment::getNewType(JSContext *cx, Class *clasp, TaggedProto proto_, JSFun
|
||||
if (fun)
|
||||
CheckNewScriptProperties(cx, type, fun);
|
||||
|
||||
if (obj->isRegExp()) {
|
||||
if (obj->is<RegExpObject>()) {
|
||||
AddTypeProperty(cx, type, "source", types::Type::StringType());
|
||||
AddTypeProperty(cx, type, "global", types::Type::BooleanType());
|
||||
AddTypeProperty(cx, type, "ignoreCase", types::Type::BooleanType());
|
||||
|
@ -471,7 +471,7 @@ GetClassForProtoKey(JSProtoKey key)
|
||||
case JSProto_String:
|
||||
return &StringClass;
|
||||
case JSProto_RegExp:
|
||||
return &RegExpClass;
|
||||
return &RegExpObject::class_;
|
||||
|
||||
case JSProto_Int8Array:
|
||||
case JSProto_Uint8Array:
|
||||
@ -485,10 +485,10 @@ GetClassForProtoKey(JSProtoKey key)
|
||||
return &TypedArray::classes[key - JSProto_Int8Array];
|
||||
|
||||
case JSProto_ArrayBuffer:
|
||||
return &ArrayBufferClass;
|
||||
return &ArrayBufferObject::class_;
|
||||
|
||||
case JSProto_DataView:
|
||||
return &DataViewClass;
|
||||
return &DataViewObject::class_;
|
||||
|
||||
case JSProto_ParallelArray:
|
||||
return &ParallelArrayObject::class_;
|
||||
|
@ -389,10 +389,10 @@ NewPropertyIteratorObject(JSContext *cx, unsigned flags)
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(obj->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);
|
||||
return &obj->asPropertyIterator();
|
||||
return &obj->as<PropertyIteratorObject>();
|
||||
}
|
||||
|
||||
return &NewBuiltinClassInstance(cx, &PropertyIteratorObject::class_)->asPropertyIterator();
|
||||
return &NewBuiltinClassInstance(cx, &PropertyIteratorObject::class_)->as<PropertyIteratorObject>();
|
||||
}
|
||||
|
||||
NativeIterator *
|
||||
@ -704,7 +704,7 @@ js::GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleVa
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyIteratorObject *iterobj = &vp.toObject().asPropertyIterator();
|
||||
PropertyIteratorObject *iterobj = &vp.toObject().as<PropertyIteratorObject>();
|
||||
|
||||
/* Cache the iterator object if possible. */
|
||||
if (shapes.length())
|
||||
@ -816,15 +816,15 @@ PropertyIteratorObject::sizeOfMisc(JSMallocSizeOfFun mallocSizeOf) const
|
||||
void
|
||||
PropertyIteratorObject::trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
if (NativeIterator *ni = obj->asPropertyIterator().getNativeIterator())
|
||||
if (NativeIterator *ni = obj->as<PropertyIteratorObject>().getNativeIterator())
|
||||
ni->mark(trc);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyIteratorObject::finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
if (NativeIterator *ni = obj->asPropertyIterator().getNativeIterator()) {
|
||||
obj->asPropertyIterator().setNativeIterator(NULL);
|
||||
if (NativeIterator *ni = obj->as<PropertyIteratorObject>().getNativeIterator()) {
|
||||
obj->as<PropertyIteratorObject>().setNativeIterator(NULL);
|
||||
fop->free_(ni);
|
||||
}
|
||||
}
|
||||
@ -863,7 +863,7 @@ ElementIteratorObject::create(JSContext *cx, Handle<Value> target)
|
||||
RootedObject proto(cx, cx->global()->getOrCreateElementIteratorPrototype(cx));
|
||||
if (!proto)
|
||||
return NULL;
|
||||
RootedObject iterobj(cx, NewObjectWithGivenProto(cx, &ElementIteratorClass, proto, cx->global()));
|
||||
RootedObject iterobj(cx, NewObjectWithGivenProto(cx, &class_, proto, cx->global()));
|
||||
if (iterobj) {
|
||||
iterobj->setReservedSlot(TargetSlot, target);
|
||||
iterobj->setReservedSlot(IndexSlot, Int32Value(0));
|
||||
@ -874,7 +874,7 @@ ElementIteratorObject::create(JSContext *cx, Handle<Value> target)
|
||||
static bool
|
||||
IsElementIterator(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().isElementIterator();
|
||||
return v.isObject() && v.toObject().is<ElementIteratorObject>();
|
||||
}
|
||||
|
||||
JSBool
|
||||
@ -934,7 +934,7 @@ ElementIteratorObject::next_impl(JSContext *cx, CallArgs args)
|
||||
return false;
|
||||
}
|
||||
|
||||
Class js::ElementIteratorClass = {
|
||||
Class ElementIteratorObject::class_ = {
|
||||
"Array Iterator",
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ElementIteratorObject::NumSlots),
|
||||
@ -1002,9 +1002,9 @@ js::CloseIterator(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
cx->iterValue.setMagic(JS_NO_ITER_VALUE);
|
||||
|
||||
if (obj->isPropertyIterator()) {
|
||||
if (obj->is<PropertyIteratorObject>()) {
|
||||
/* Remove enumerators from the active list, which is a stack. */
|
||||
NativeIterator *ni = obj->asPropertyIterator().getNativeIterator();
|
||||
NativeIterator *ni = obj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
|
||||
if (ni->flags & JSITER_ENUMERATE) {
|
||||
ni->unlink();
|
||||
@ -1041,8 +1041,8 @@ js::UnwindIteratorForException(JSContext *cx, HandleObject obj)
|
||||
void
|
||||
js::UnwindIteratorForUncatchableException(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
if (obj->isPropertyIterator()) {
|
||||
NativeIterator *ni = obj->asPropertyIterator().getNativeIterator();
|
||||
if (obj->is<PropertyIteratorObject>()) {
|
||||
NativeIterator *ni = obj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
if (ni->flags & JSITER_ENUMERATE)
|
||||
ni->unlink();
|
||||
}
|
||||
@ -1201,9 +1201,9 @@ js_IteratorMore(JSContext *cx, HandleObject iterobj, MutableHandleValue rval)
|
||||
{
|
||||
/* Fast path for native iterators */
|
||||
NativeIterator *ni = NULL;
|
||||
if (iterobj->isPropertyIterator()) {
|
||||
if (iterobj->is<PropertyIteratorObject>()) {
|
||||
/* Key iterators are handled by fast-paths. */
|
||||
ni = iterobj->asPropertyIterator().getNativeIterator();
|
||||
ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
bool more = ni->props_cursor < ni->props_end;
|
||||
if (ni->isKeyIter() || !more) {
|
||||
rval.setBoolean(more);
|
||||
@ -1260,12 +1260,12 @@ bool
|
||||
js_IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval)
|
||||
{
|
||||
/* Fast path for native iterators */
|
||||
if (iterobj->isPropertyIterator()) {
|
||||
if (iterobj->is<PropertyIteratorObject>()) {
|
||||
/*
|
||||
* Implement next directly as all the methods of the native iterator are
|
||||
* read-only and permanent.
|
||||
*/
|
||||
NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
|
||||
NativeIterator *ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
if (ni->isKeyIter()) {
|
||||
JS_ASSERT(ni->props_cursor < ni->props_end);
|
||||
rval.setString(*ni->current());
|
||||
@ -1769,7 +1769,7 @@ GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
|
||||
return false;
|
||||
ni->init(NULL, NULL, 0 /* flags */, 0, 0);
|
||||
|
||||
iteratorProto->asPropertyIterator().setNativeIterator(ni);
|
||||
iteratorProto->as<PropertyIteratorObject>().setNativeIterator(ni);
|
||||
|
||||
Rooted<JSFunction*> ctor(cx);
|
||||
ctor = global->createConstructor(cx, IteratorConstructor, cx->names().Iterator, 2);
|
||||
@ -1785,7 +1785,7 @@ GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (global->getSlot(ELEMENT_ITERATOR_PROTO).isUndefined()) {
|
||||
Class *cls = &ElementIteratorClass;
|
||||
Class *cls = &ElementIteratorObject::class_;
|
||||
proto = global->createBlankPrototypeInheriting(cx, cls, *iteratorProto);
|
||||
if (!proto || !DefinePropertiesAndBrand(cx, proto, NULL, ElementIteratorObject::methods))
|
||||
return false;
|
||||
|
@ -143,6 +143,8 @@ class PropertyIteratorObject : public JSObject
|
||||
class ElementIteratorObject : public JSObject
|
||||
{
|
||||
public:
|
||||
static Class class_;
|
||||
|
||||
static JSObject *create(JSContext *cx, Handle<Value> target);
|
||||
static const JSFunctionSpec methods[];
|
||||
|
||||
|
@ -1980,7 +1980,7 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
||||
* refcounted JIT code blob for them across compartments instead of just
|
||||
* swapping guts.
|
||||
*/
|
||||
JS_ASSERT(!a->isRegExp() && !b->isRegExp());
|
||||
JS_ASSERT(!a->is<RegExpObject>() && !b->is<RegExpObject>());
|
||||
|
||||
/* Arrays can use their fixed storage for elements. */
|
||||
JS_ASSERT(!a->isArray() && !b->isArray());
|
||||
@ -1989,7 +1989,7 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
|
||||
* Callers should not try to swap ArrayBuffer objects,
|
||||
* these use a different slot representation from other objects.
|
||||
*/
|
||||
JS_ASSERT(!a->isArrayBuffer() && !b->isArrayBuffer());
|
||||
JS_ASSERT(!a->is<ArrayBufferObject>() && !b->is<ArrayBufferObject>());
|
||||
|
||||
/* Trade the guts of the objects. */
|
||||
const size_t size = a->tenuredSizeOfThis();
|
||||
@ -2553,7 +2553,7 @@ JSObject::shrinkSlots(JSContext *cx, HandleObject obj, uint32_t oldCount, uint32
|
||||
* allowing the slots pointer to change may require updating pointers in
|
||||
* the function's active args/vars information.
|
||||
*/
|
||||
if (obj->isCall())
|
||||
if (obj->is<CallObject>())
|
||||
return;
|
||||
|
||||
if (newCount == 0) {
|
||||
@ -3210,7 +3210,7 @@ js_PurgeScopeChainHelper(JSContext *cx, HandleObject objArg, HandleId id)
|
||||
* properties with the same names have been cached or traced. Call objects
|
||||
* may gain such properties via eval introducing new vars; see bug 490364.
|
||||
*/
|
||||
if (obj->isCall()) {
|
||||
if (obj->is<CallObject>()) {
|
||||
while ((obj = obj->enclosingScope()) != NULL) {
|
||||
if (!PurgeProtoChain(cx, obj, id))
|
||||
return false;
|
||||
@ -4311,7 +4311,7 @@ baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receive
|
||||
}
|
||||
} else {
|
||||
/* We should never add properties to lexical blocks. */
|
||||
JS_ASSERT(!obj->isBlock());
|
||||
JS_ASSERT(!obj->is<BlockObject>());
|
||||
|
||||
if (obj->isGlobal() &&
|
||||
(defineHow & DNP_UNQUALIFIED) &&
|
||||
@ -5330,7 +5330,7 @@ JSObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, JS::ObjectsExtraSi
|
||||
#if defined (JS_CPU_X64)
|
||||
// On x64, ArrayBufferObject::prepareForAsmJS switches the
|
||||
// ArrayBufferObject to use mmap'd storage.
|
||||
sizes->elementsAsmJSNonHeap = asArrayBuffer().byteLength();
|
||||
sizes->elementsAsmJSNonHeap = as<ArrayBufferObject>().byteLength();
|
||||
#else
|
||||
sizes->elementsAsmJSHeap = mallocSizeOf(elements);
|
||||
#endif
|
||||
@ -5341,12 +5341,12 @@ JSObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, JS::ObjectsExtraSi
|
||||
|
||||
// Other things may be measured in the future if DMD indicates it is worthwhile.
|
||||
// Note that sizes->private_ is measured elsewhere.
|
||||
if (isArguments()) {
|
||||
sizes->argumentsData = asArguments().sizeOfMisc(mallocSizeOf);
|
||||
if (is<ArgumentsObject>()) {
|
||||
sizes->argumentsData = as<ArgumentsObject>().sizeOfMisc(mallocSizeOf);
|
||||
} else if (isRegExpStatics()) {
|
||||
sizes->regExpStatics = js::SizeOfRegExpStaticsData(this, mallocSizeOf);
|
||||
} else if (isPropertyIterator()) {
|
||||
sizes->propertyIteratorData = asPropertyIterator().sizeOfMisc(mallocSizeOf);
|
||||
} else if (is<PropertyIteratorObject>()) {
|
||||
sizes->propertyIteratorData = as<PropertyIteratorObject>().sizeOfMisc(mallocSizeOf);
|
||||
#ifdef JS_HAS_CTYPES
|
||||
} else {
|
||||
// This must be the last case.
|
||||
|
@ -34,7 +34,6 @@ namespace js {
|
||||
|
||||
class AutoPropDescArrayRooter;
|
||||
class BaseProxyHandler;
|
||||
class CallObject;
|
||||
struct GCMarker;
|
||||
struct NativeIterator;
|
||||
class Nursery;
|
||||
@ -204,59 +203,37 @@ DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded);
|
||||
} /* namespace js::baseops */
|
||||
|
||||
extern Class ArrayClass;
|
||||
extern Class ArrayBufferClass;
|
||||
extern Class BlockClass;
|
||||
extern Class BooleanClass;
|
||||
extern Class CallableObjectClass;
|
||||
extern Class DataViewClass;
|
||||
extern Class DateClass;
|
||||
extern Class ErrorClass;
|
||||
extern Class ElementIteratorClass;
|
||||
extern Class GeneratorClass;
|
||||
extern Class IntlClass;
|
||||
extern Class JSONClass;
|
||||
extern Class MapIteratorClass;
|
||||
extern Class MathClass;
|
||||
extern Class ModuleClass;
|
||||
extern Class NumberClass;
|
||||
extern Class NormalArgumentsObjectClass;
|
||||
extern Class ObjectClass;
|
||||
extern Class ProxyClass;
|
||||
extern Class RegExpClass;
|
||||
extern Class RegExpStaticsClass;
|
||||
extern Class SetIteratorClass;
|
||||
extern Class ScriptSourceClass;
|
||||
extern Class StopIterationClass;
|
||||
extern Class StringClass;
|
||||
extern Class StrictArgumentsObjectClass;
|
||||
extern Class WeakMapClass;
|
||||
extern Class WithClass;
|
||||
|
||||
class ArgumentsObject;
|
||||
class ArrayBufferObject;
|
||||
class BlockObject;
|
||||
class BooleanObject;
|
||||
class ClonedBlockObject;
|
||||
class DataViewObject;
|
||||
class DebugScopeObject;
|
||||
class DeclEnvObject;
|
||||
class ElementIteratorObject;
|
||||
class GlobalObject;
|
||||
class MapObject;
|
||||
class MapIteratorObject;
|
||||
class Module;
|
||||
class NestedScopeObject;
|
||||
class NewObjectCache;
|
||||
class NormalArgumentsObject;
|
||||
class NumberObject;
|
||||
class PropertyIteratorObject;
|
||||
class ScopeObject;
|
||||
class SetObject;
|
||||
class SetIteratorObject;
|
||||
class StaticBlockObject;
|
||||
class StrictArgumentsObject;
|
||||
class StringObject;
|
||||
class RegExpObject;
|
||||
class WithObject;
|
||||
|
||||
} /* namespace js */
|
||||
@ -510,7 +487,7 @@ class JSObject : public js::ObjectImpl
|
||||
*
|
||||
* The scope chain of an object is the link in the search path when a
|
||||
* script does a name lookup on a scope object. For JS internal scope
|
||||
* objects --- Call, DeclEnv and block --- the chain is stored in
|
||||
* objects --- Call, DeclEnv and Block --- the chain is stored in
|
||||
* the first fixed slot of the object, and the object's parent is the
|
||||
* associated global. For other scope objects, the chain is stored in the
|
||||
* object's parent.
|
||||
@ -950,7 +927,7 @@ class JSObject : public js::ObjectImpl
|
||||
* }
|
||||
*
|
||||
* These XObject classes form a hierarchy. For example, for a cloned block
|
||||
* object, the following predicates are true: isClonedBlock, isBlock,
|
||||
* object, the following predicates are true: isClonedBlock, is<BlockObject>,
|
||||
* isNestedScope and isScope. Each of these has a respective class that
|
||||
* derives and adds operations.
|
||||
*
|
||||
@ -967,37 +944,38 @@ class JSObject : public js::ObjectImpl
|
||||
* consider adding the missing XObject class.
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
inline bool is() const { return getClass() == &T::class_; }
|
||||
|
||||
template <class T>
|
||||
T &as() {
|
||||
JS_ASSERT(is<T>());
|
||||
return *static_cast<T *>(this);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T &as() const {
|
||||
JS_ASSERT(is<T>());
|
||||
return *static_cast<const T *>(this);
|
||||
}
|
||||
|
||||
/* Direct subtypes of JSObject: */
|
||||
inline bool isArray() const { return hasClass(&js::ArrayClass); }
|
||||
inline bool isArguments() const { return isNormalArguments() || isStrictArguments(); }
|
||||
inline bool isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); }
|
||||
inline bool isDataView() const { return hasClass(&js::DataViewClass); }
|
||||
inline bool isDate() const { return hasClass(&js::DateClass); }
|
||||
inline bool isElementIterator() const { return hasClass(&js::ElementIteratorClass); }
|
||||
inline bool isError() const { return hasClass(&js::ErrorClass); }
|
||||
inline bool isFunction() const { return hasClass(&js::FunctionClass); }
|
||||
inline bool isGenerator() const { return hasClass(&js::GeneratorClass); }
|
||||
inline bool isGlobal() const;
|
||||
inline bool isMapIterator() const { return hasClass(&js::MapIteratorClass); }
|
||||
inline bool isModule() const { return hasClass(&js::ModuleClass); }
|
||||
inline bool isObject() const { return hasClass(&js::ObjectClass); }
|
||||
inline bool isPrimitive() const { return isNumber() || isString() || isBoolean(); }
|
||||
inline bool isPropertyIterator() const;
|
||||
using js::ObjectImpl::isProxy;
|
||||
inline bool isRegExp() const { return hasClass(&js::RegExpClass); }
|
||||
inline bool isRegExpStatics() const { return hasClass(&js::RegExpStaticsClass); }
|
||||
inline bool isScope() const { return isCall() || isDeclEnv() || isNestedScope(); }
|
||||
inline bool isScriptSource() const { return hasClass(&js::ScriptSourceClass); }
|
||||
inline bool isSetIterator() const { return hasClass(&js::SetIteratorClass); }
|
||||
inline bool isScope() const;
|
||||
inline bool isStopIteration() const { return hasClass(&js::StopIterationClass); }
|
||||
inline bool isTypedArray() const;
|
||||
inline bool isWeakMap() const { return hasClass(&js::WeakMapClass); }
|
||||
|
||||
/* Subtypes of ScopeObject. */
|
||||
inline bool isBlock() const { return hasClass(&js::BlockClass); }
|
||||
inline bool isCall() const { return hasClass(&js::CallClass); }
|
||||
inline bool isDeclEnv() const { return hasClass(&js::DeclEnvClass); }
|
||||
inline bool isNestedScope() const { return isBlock() || isWith(); }
|
||||
inline bool isNestedScope() const;
|
||||
inline bool isWith() const { return hasClass(&js::WithClass); }
|
||||
inline bool isClonedBlock() const;
|
||||
inline bool isStaticBlock() const;
|
||||
@ -1007,44 +985,21 @@ class JSObject : public js::ObjectImpl
|
||||
inline bool isNumber() const { return hasClass(&js::NumberClass); }
|
||||
inline bool isString() const { return hasClass(&js::StringClass); }
|
||||
|
||||
/* Subtypes of ArgumentsObject. */
|
||||
inline bool isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); }
|
||||
inline bool isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); }
|
||||
|
||||
/* Subtypes of Proxy. */
|
||||
inline bool isDebugScope() const;
|
||||
inline bool isWrapper() const;
|
||||
inline bool isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); }
|
||||
inline bool isCrossCompartmentWrapper() const;
|
||||
|
||||
inline js::ArgumentsObject &asArguments();
|
||||
inline js::ArrayBufferObject &asArrayBuffer();
|
||||
inline const js::ArgumentsObject &asArguments() const;
|
||||
inline js::BlockObject &asBlock();
|
||||
inline js::BooleanObject &asBoolean();
|
||||
inline js::CallObject &asCall();
|
||||
inline js::ClonedBlockObject &asClonedBlock();
|
||||
inline js::DataViewObject &asDataView();
|
||||
inline js::DeclEnvObject &asDeclEnv();
|
||||
inline js::DebugScopeObject &asDebugScope();
|
||||
inline js::GlobalObject &asGlobal();
|
||||
inline js::MapObject &asMap();
|
||||
inline js::MapIteratorObject &asMapIterator();
|
||||
js::Module &asModule() {
|
||||
JS_ASSERT(isModule());
|
||||
return *reinterpret_cast<js::Module *>(this);
|
||||
}
|
||||
inline js::NestedScopeObject &asNestedScope();
|
||||
inline js::NormalArgumentsObject &asNormalArguments();
|
||||
inline js::NumberObject &asNumber();
|
||||
inline js::PropertyIteratorObject &asPropertyIterator();
|
||||
inline const js::PropertyIteratorObject &asPropertyIterator() const;
|
||||
inline js::RegExpObject &asRegExp();
|
||||
inline js::ScopeObject &asScope();
|
||||
inline js::SetObject &asSet();
|
||||
inline js::SetIteratorObject &asSetIterator();
|
||||
inline js::ScriptSourceObject &asScriptSource();
|
||||
inline js::StrictArgumentsObject &asStrictArguments();
|
||||
inline js::StaticBlockObject &asStaticBlock();
|
||||
inline js::StringObject &asString();
|
||||
inline js::WithObject &asWith();
|
||||
|
@ -845,8 +845,8 @@ inline bool JSObject::watched() const
|
||||
return lastProperty()->hasObjectFlag(js::BaseShape::WATCHED);
|
||||
}
|
||||
|
||||
inline bool JSObject::isClonedBlock() const { return isBlock() && !!getProto(); }
|
||||
inline bool JSObject::isStaticBlock() const { return isBlock() && !getProto(); }
|
||||
inline bool JSObject::isClonedBlock() const { return is<js::BlockObject>() && !!getProto(); }
|
||||
inline bool JSObject::isStaticBlock() const { return is<js::BlockObject>() && !getProto(); }
|
||||
inline bool JSObject::isTypedArray() const { return IsTypedArrayClass(getClass()); }
|
||||
|
||||
inline js::NumberObject &
|
||||
@ -863,13 +863,6 @@ JSObject::asString()
|
||||
return *static_cast<js::StringObject *>(this);
|
||||
}
|
||||
|
||||
inline js::ScriptSourceObject &
|
||||
JSObject::asScriptSource()
|
||||
{
|
||||
JS_ASSERT(isScriptSource());
|
||||
return *static_cast<js::ScriptSourceObject *>(this);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isDebugScope() const
|
||||
{
|
||||
@ -926,7 +919,7 @@ JSObject::create(JSContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap heap
|
||||
obj->privateRef(shape->numFixedSlots()) = NULL;
|
||||
|
||||
size_t span = shape->slotSpan();
|
||||
if (span && clasp != &js::ArrayBufferClass)
|
||||
if (span && clasp != &js::ArrayBufferObject::class_)
|
||||
obj->initializeSlotRange(0, span);
|
||||
|
||||
return obj;
|
||||
@ -1685,8 +1678,8 @@ ObjectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx)
|
||||
case ESClass_Number: return obj->isNumber();
|
||||
case ESClass_String: return obj->isString();
|
||||
case ESClass_Boolean: return obj->isBoolean();
|
||||
case ESClass_RegExp: return obj->isRegExp();
|
||||
case ESClass_ArrayBuffer: return obj->isArrayBuffer();
|
||||
case ESClass_RegExp: return obj->is<RegExpObject>();
|
||||
case ESClass_ArrayBuffer: return obj->is<ArrayBufferObject>();
|
||||
case ESClass_Date: return obj->isDate();
|
||||
}
|
||||
JS_NOT_REACHED("bad classValue");
|
||||
|
@ -476,8 +476,9 @@ ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes)
|
||||
|
||||
if (!JSVAL_IS_PRIMITIVE(v)) {
|
||||
JSObject *obj = JSVAL_TO_OBJECT(v);
|
||||
if (obj->isBlock()) {
|
||||
char *source = JS_sprintf_append(NULL, "depth %d {", obj->asBlock().stackDepth());
|
||||
if (obj->is<BlockObject>()) {
|
||||
char *source = JS_sprintf_append(NULL, "depth %d {",
|
||||
obj->as<BlockObject>().stackDepth());
|
||||
if (!source)
|
||||
return false;
|
||||
|
||||
@ -515,8 +516,8 @@ ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes)
|
||||
return bytes->encodeLatin1(cx, str);
|
||||
}
|
||||
|
||||
if (obj->isRegExp()) {
|
||||
JSString *source = obj->asRegExp().toString(cx);
|
||||
if (obj->is<RegExpObject>()) {
|
||||
JSString *source = obj->as<RegExpObject>().toString(cx);
|
||||
if (!source)
|
||||
return false;
|
||||
JS::Anchor<JSString *> anchor(source);
|
||||
@ -1089,7 +1090,8 @@ GetBlockChainAtPC(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
case JSOP_ENTERLET0:
|
||||
case JSOP_ENTERLET1: {
|
||||
JSObject *child = script->getObject(p);
|
||||
JS_ASSERT_IF(blockChain, child->asBlock().stackDepth() >= blockChain->asBlock().stackDepth());
|
||||
JS_ASSERT_IF(blockChain, child->as<BlockObject>().stackDepth() >=
|
||||
blockChain->as<BlockObject>().stackDepth());
|
||||
blockChain = child;
|
||||
break;
|
||||
}
|
||||
@ -1104,7 +1106,7 @@ GetBlockChainAtPC(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
if (!(sn && SN_TYPE(sn) == SRC_HIDDEN)) {
|
||||
JS_ASSERT(blockChain);
|
||||
blockChain = blockChain->asStaticBlock().enclosingBlock();
|
||||
JS_ASSERT_IF(blockChain, blockChain->isBlock());
|
||||
JS_ASSERT_IF(blockChain, blockChain->is<BlockObject>());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1404,9 +1406,9 @@ ExpressionDecompiler::findLetVar(jsbytecode *pc, unsigned depth)
|
||||
JSObject *chain = GetBlockChainAtPC(cx, script, pc);
|
||||
if (!chain)
|
||||
return NULL;
|
||||
JS_ASSERT(chain->isBlock());
|
||||
JS_ASSERT(chain->is<BlockObject>());
|
||||
do {
|
||||
BlockObject &block = chain->asBlock();
|
||||
BlockObject &block = chain->as<BlockObject>();
|
||||
uint32_t blockDepth = block.stackDepth();
|
||||
uint32_t blockCount = block.slotCount();
|
||||
if (uint32_t(depth - blockDepth) < uint32_t(blockCount)) {
|
||||
@ -1417,7 +1419,7 @@ ExpressionDecompiler::findLetVar(jsbytecode *pc, unsigned depth)
|
||||
}
|
||||
}
|
||||
chain = chain->getParent();
|
||||
} while (chain && chain->isBlock());
|
||||
} while (chain && chain->is<BlockObject>());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2649,7 +2649,7 @@ ASTSerializer::literal(ParseNode *pn, MutableHandleValue dst)
|
||||
case PNK_REGEXP:
|
||||
{
|
||||
RootedObject re1(cx, pn->pn_objbox ? pn->pn_objbox->object : NULL);
|
||||
LOCAL_ASSERT(re1 && re1->isRegExp());
|
||||
LOCAL_ASSERT(re1 && re1->is<RegExpObject>());
|
||||
|
||||
RootedObject proto(cx);
|
||||
if (!js_GetClassPrototype(cx, JSProto_RegExp, &proto))
|
||||
|
@ -92,7 +92,7 @@ Bindings::initWithTemporaryStorage(JSContext *cx, InternalBindingsHandle self,
|
||||
gc::AllocKind allocKind = gc::FINALIZE_OBJECT2_BACKGROUND;
|
||||
JS_ASSERT(gc::GetGCKindSlots(allocKind) == CallObject::RESERVED_SLOTS);
|
||||
RootedShape initial(cx,
|
||||
EmptyShape::getInitialShape(cx, &CallClass, NULL, cx->global(), NULL,
|
||||
EmptyShape::getInitialShape(cx, &CallObject::class_, NULL, cx->global(), NULL,
|
||||
allocKind, BaseShape::VAROBJ | BaseShape::DELEGATE));
|
||||
if (!initial)
|
||||
return false;
|
||||
@ -117,7 +117,7 @@ Bindings::initWithTemporaryStorage(JSContext *cx, InternalBindingsHandle self,
|
||||
return false;
|
||||
#endif
|
||||
|
||||
StackBaseShape base(cx->compartment(), &CallClass, cx->global(), NULL,
|
||||
StackBaseShape base(cx->compartment(), &CallObject::class_, cx->global(), NULL,
|
||||
BaseShape::VAROBJ | BaseShape::DELEGATE);
|
||||
|
||||
UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
|
||||
@ -657,7 +657,7 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
|
||||
if (mode == XDR_ENCODE) {
|
||||
JSObject *obj = *objp;
|
||||
JS_ASSERT(obj->isFunction() || obj->isStaticBlock());
|
||||
isBlock = obj->isBlock() ? 1 : 0;
|
||||
isBlock = obj->is<BlockObject>() ? 1 : 0;
|
||||
}
|
||||
if (!xdr->codeUint32(&isBlock))
|
||||
return false;
|
||||
@ -786,7 +786,7 @@ js::XDRScript(XDRState<XDR_DECODE> *, HandleObject, HandleScript, HandleFunction
|
||||
js::ScriptSourceObject *
|
||||
JSScript::sourceObject() const
|
||||
{
|
||||
return &sourceObject_->asScriptSource();
|
||||
return &sourceObject_->as<ScriptSourceObject>();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -917,10 +917,10 @@ void
|
||||
ScriptSourceObject::finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
// ScriptSource::setSource automatically takes care of the refcount
|
||||
obj->asScriptSource().setSource(NULL);
|
||||
obj->as<ScriptSourceObject>().setSource(NULL);
|
||||
}
|
||||
|
||||
Class js::ScriptSourceClass = {
|
||||
Class ScriptSourceObject::class_ = {
|
||||
"ScriptSource",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS,
|
||||
JS_PropertyStub, /* addProperty */
|
||||
@ -936,10 +936,10 @@ Class js::ScriptSourceClass = {
|
||||
ScriptSourceObject *
|
||||
ScriptSourceObject::create(JSContext *cx, ScriptSource *source)
|
||||
{
|
||||
RootedObject object(cx, NewObjectWithGivenProto(cx, &ScriptSourceClass, NULL, cx->global()));
|
||||
RootedObject object(cx, NewObjectWithGivenProto(cx, &class_, NULL, cx->global()));
|
||||
if (!object)
|
||||
return NULL;
|
||||
JS::RootedScriptSource sourceObject(cx, &object->asScriptSource());
|
||||
JS::RootedScriptSource sourceObject(cx, &object->as<ScriptSourceObject>());
|
||||
sourceObject->setSlot(SOURCE_SLOT, PrivateValue(source));
|
||||
source->incref();
|
||||
return sourceObject;
|
||||
@ -2356,7 +2356,7 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
|
||||
for (unsigned i = 0; i < nregexps; i++) {
|
||||
HeapPtrObject *vector = src->regexps()->vector;
|
||||
for (unsigned i = 0; i < nregexps; i++) {
|
||||
JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->asRegExp());
|
||||
JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>());
|
||||
if (!clone || !regexps.append(clone))
|
||||
return NULL;
|
||||
}
|
||||
@ -2992,7 +2992,7 @@ LazyScript::setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject
|
||||
ScriptSourceObject *
|
||||
LazyScript::sourceObject() const
|
||||
{
|
||||
return sourceObject_ ? &sourceObject_->asScriptSource() : NULL;
|
||||
return sourceObject_ ? &sourceObject_->as<ScriptSourceObject>() : NULL;
|
||||
}
|
||||
|
||||
/* static */ LazyScript *
|
||||
|
@ -386,8 +386,11 @@ class ScriptSourceHolder
|
||||
}
|
||||
};
|
||||
|
||||
class ScriptSourceObject : public JSObject {
|
||||
class ScriptSourceObject : public JSObject
|
||||
{
|
||||
public:
|
||||
static Class class_;
|
||||
|
||||
static void finalize(FreeOp *fop, JSObject *obj);
|
||||
static ScriptSourceObject *create(JSContext *cx, ScriptSource *source);
|
||||
|
||||
|
@ -127,7 +127,7 @@ JSScript::getRegExp(size_t index)
|
||||
js::ObjectArray *arr = regexps();
|
||||
JS_ASSERT(uint32_t(index) < arr->length);
|
||||
JSObject *obj = arr->vector[index];
|
||||
JS_ASSERT(obj->isRegExp());
|
||||
JS_ASSERT(obj->is<js::RegExpObject>());
|
||||
return (js::RegExpObject *) obj;
|
||||
}
|
||||
|
||||
|
@ -2686,17 +2686,20 @@ static const uint32_t ReplaceOptArg = 2;
|
||||
* Dean Edwards packer) to efficiently encode large scripts. We only handle the
|
||||
* code patterns generated by such packers here.
|
||||
*/
|
||||
static JSObject *
|
||||
LambdaIsGetElem(JSObject &lambda)
|
||||
static bool
|
||||
LambdaIsGetElem(JSContext *cx, JSObject &lambda, MutableHandleObject pobj)
|
||||
{
|
||||
if (!lambda.isFunction())
|
||||
return NULL;
|
||||
return true;
|
||||
|
||||
JSFunction *fun = lambda.toFunction();
|
||||
if (!fun->hasScript())
|
||||
return NULL;
|
||||
if (!fun->isInterpreted())
|
||||
return true;
|
||||
|
||||
JSScript *script = fun->getOrCreateScript(cx);
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
JSScript *script = fun->nonLazyScript();
|
||||
jsbytecode *pc = script->code;
|
||||
|
||||
/*
|
||||
@ -2705,7 +2708,7 @@ LambdaIsGetElem(JSObject &lambda)
|
||||
* would make our scope walk off by 1.
|
||||
*/
|
||||
if (JSOp(*pc) != JSOP_GETALIASEDVAR || fun->isHeavyweight())
|
||||
return NULL;
|
||||
return true;
|
||||
ScopeCoordinate sc(pc);
|
||||
ScopeObject *scope = &fun->environment()->asScope();
|
||||
for (unsigned i = 0; i < sc.hops; ++i)
|
||||
@ -2715,28 +2718,29 @@ LambdaIsGetElem(JSObject &lambda)
|
||||
|
||||
/* Look for 'a' to be the lambda's first argument. */
|
||||
if (JSOp(*pc) != JSOP_GETARG || GET_SLOTNO(pc) != 0)
|
||||
return NULL;
|
||||
return true;
|
||||
pc += JSOP_GETARG_LENGTH;
|
||||
|
||||
/* 'b[a]' */
|
||||
if (JSOp(*pc) != JSOP_GETELEM)
|
||||
return NULL;
|
||||
return true;
|
||||
pc += JSOP_GETELEM_LENGTH;
|
||||
|
||||
/* 'return b[a]' */
|
||||
if (JSOp(*pc) != JSOP_RETURN)
|
||||
return NULL;
|
||||
return true;
|
||||
|
||||
/* 'b' must behave like a normal object. */
|
||||
if (!b.isObject())
|
||||
return NULL;
|
||||
return true;
|
||||
|
||||
JSObject &bobj = b.toObject();
|
||||
Class *clasp = bobj.getClass();
|
||||
if (!clasp->isNative() || clasp->ops.lookupProperty || clasp->ops.getProperty)
|
||||
return NULL;
|
||||
return true;
|
||||
|
||||
return &bobj;
|
||||
pobj.set(&bobj);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
@ -2759,8 +2763,8 @@ js::str_replace(JSContext *cx, unsigned argc, Value *vp)
|
||||
rdata.repstr = NULL;
|
||||
rdata.dollar = rdata.dollarEnd = NULL;
|
||||
|
||||
if (JSObject *base = LambdaIsGetElem(*rdata.lambda))
|
||||
rdata.elembase = base;
|
||||
if (!LambdaIsGetElem(cx, *rdata.lambda, &rdata.elembase))
|
||||
return false;
|
||||
} else {
|
||||
rdata.lambda = NULL;
|
||||
rdata.elembase = NULL;
|
||||
|
@ -114,14 +114,14 @@ ToClampedIndex(JSContext *cx, const Value &v, uint32_t length, uint32_t *out)
|
||||
JS_ALWAYS_INLINE bool
|
||||
IsArrayBuffer(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().hasClass(&ArrayBufferClass);
|
||||
return v.isObject() && v.toObject().hasClass(&ArrayBufferObject::class_);
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE bool
|
||||
ArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsArrayBuffer(args.thisv()));
|
||||
args.rval().setInt32(args.thisv().toObject().asArrayBuffer().byteLength());
|
||||
args.rval().setInt32(args.thisv().toObject().as<ArrayBufferObject>().byteLength());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ ArrayBufferObject::fun_slice_impl(JSContext *cx, CallArgs args)
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
|
||||
// these are the default values
|
||||
uint32_t length = thisObj->asArrayBuffer().byteLength();
|
||||
uint32_t length = thisObj->as<ArrayBufferObject>().byteLength();
|
||||
uint32_t begin = 0, end = length;
|
||||
|
||||
if (args.length() > 0) {
|
||||
@ -156,7 +156,7 @@ ArrayBufferObject::fun_slice_impl(JSContext *cx, CallArgs args)
|
||||
if (begin > end)
|
||||
begin = end;
|
||||
|
||||
JSObject *nobj = createSlice(cx, thisObj->asArrayBuffer(), begin, end);
|
||||
JSObject *nobj = createSlice(cx, thisObj->as<ArrayBufferObject>(), begin, end);
|
||||
if (!nobj)
|
||||
return false;
|
||||
args.rval().setObject(*nobj);
|
||||
@ -244,7 +244,7 @@ ArrayBufferObject::allocateSlots(JSContext *maybecx, uint32_t bytes, uint8_t *co
|
||||
* their internal layout can use the object's fixed slots for storage.
|
||||
* Set up the object to look like an array with an elements header.
|
||||
*/
|
||||
JS_ASSERT(isArrayBuffer() && !hasDynamicSlots() && !hasDynamicElements());
|
||||
JS_ASSERT(is<ArrayBufferObject>() && !hasDynamicSlots() && !hasDynamicElements());
|
||||
|
||||
size_t usableSlots = ARRAYBUFFER_RESERVED_SLOTS - ObjectElements::VALUES_PER_HEADER;
|
||||
|
||||
@ -412,7 +412,7 @@ ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buf
|
||||
void
|
||||
ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
ArrayBufferObject &buffer = obj->asArrayBuffer();
|
||||
ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
|
||||
JS_ASSERT(buffer.isAsmJSArrayBuffer());
|
||||
|
||||
uint8_t *p = buffer.dataPointer() - PageSize ;
|
||||
@ -453,7 +453,7 @@ ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buf
|
||||
void
|
||||
ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
fop->free_(obj->asArrayBuffer().getElementsHeader());
|
||||
fop->free_(obj->as<ArrayBufferObject>().getElementsHeader());
|
||||
}
|
||||
|
||||
void
|
||||
@ -551,13 +551,13 @@ ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, uint8_t *contents)
|
||||
{
|
||||
SkipRoot skip(cx, &contents);
|
||||
|
||||
RootedObject obj(cx, NewBuiltinClassInstance(cx, &ArrayBufferClass));
|
||||
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT_IF(obj->isTenured(), obj->tenuredGetAllocKind() == gc::FINALIZE_OBJECT16_BACKGROUND);
|
||||
JS_ASSERT(obj->getClass() == &ArrayBufferClass);
|
||||
JS_ASSERT(obj->getClass() == &class_);
|
||||
|
||||
js::Shape *empty = EmptyShape::getInitialShape(cx, &ArrayBufferClass,
|
||||
js::Shape *empty = EmptyShape::getInitialShape(cx, &class_,
|
||||
obj->getProto(), obj->getParent(), obj->getMetadata(),
|
||||
gc::FINALIZE_OBJECT16_BACKGROUND);
|
||||
if (!empty)
|
||||
@ -568,7 +568,7 @@ ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, uint8_t *contents)
|
||||
* The beginning stores an ObjectElements header structure holding the
|
||||
* length. The rest of it is a flat data store for the array buffer.
|
||||
*/
|
||||
if (!obj->asArrayBuffer().allocateSlots(cx, nbytes, contents))
|
||||
if (!obj->as<ArrayBufferObject>().allocateSlots(cx, nbytes, contents))
|
||||
return NULL;
|
||||
|
||||
return obj;
|
||||
@ -624,7 +624,7 @@ bool
|
||||
ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents,
|
||||
uint8_t **data)
|
||||
{
|
||||
ArrayBufferObject &buffer = obj->asArrayBuffer();
|
||||
ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
|
||||
JSObject *views = *GetViewList(&buffer);
|
||||
js::ObjectElements *header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
|
||||
if (buffer.hasDynamicElements() && !buffer.isAsmJSArrayBuffer()) {
|
||||
@ -686,7 +686,7 @@ ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
|
||||
// linked list during collection, and then swept to prune out their dead
|
||||
// views.
|
||||
|
||||
HeapPtrObject *views = GetViewList(&obj->asArrayBuffer());
|
||||
HeapPtrObject *views = GetViewList(&obj->as<ArrayBufferObject>());
|
||||
if (!*views)
|
||||
return;
|
||||
|
||||
@ -742,7 +742,7 @@ ArrayBufferObject::sweep(JSCompartment *compartment)
|
||||
compartment->gcLiveArrayBuffers = NULL;
|
||||
|
||||
while (buffer) {
|
||||
HeapPtrObject *views = GetViewList(&buffer->asArrayBuffer());
|
||||
HeapPtrObject *views = GetViewList(&buffer->as<ArrayBufferObject>());
|
||||
JS_ASSERT(*views);
|
||||
|
||||
JSObject *nextBuffer = BufferLink(*views);
|
||||
@ -776,7 +776,7 @@ ArrayBufferObject::resetArrayBufferList(JSCompartment *comp)
|
||||
comp->gcLiveArrayBuffers = NULL;
|
||||
|
||||
while (buffer) {
|
||||
JSObject *view = *GetViewList(&buffer->asArrayBuffer());
|
||||
JSObject *view = *GetViewList(&buffer->as<ArrayBufferObject>());
|
||||
JS_ASSERT(view);
|
||||
|
||||
JSObject *nextBuffer = BufferLink(view);
|
||||
@ -793,7 +793,7 @@ ArrayBufferObject::saveArrayBufferList(JSCompartment *comp, ArrayBufferVector &v
|
||||
JSObject *obj = comp->gcLiveArrayBuffers;
|
||||
while (obj) {
|
||||
JS_ASSERT(obj != UNSET_BUFFER_LINK);
|
||||
ArrayBufferObject *buffer = &obj->asArrayBuffer();
|
||||
ArrayBufferObject *buffer = &obj->as<ArrayBufferObject>();
|
||||
if (!vector.append(buffer))
|
||||
return false;
|
||||
|
||||
@ -810,7 +810,7 @@ ArrayBufferObject::restoreArrayBufferLists(ArrayBufferVector &vector)
|
||||
for (ArrayBufferObject **p = vector.begin(); p != vector.end(); p++) {
|
||||
ArrayBufferObject *buffer = *p;
|
||||
JSCompartment *comp = buffer->compartment();
|
||||
JSObject *firstView = *GetViewList(&buffer->asArrayBuffer());
|
||||
JSObject *firstView = *GetViewList(&buffer->as<ArrayBufferObject>());
|
||||
JS_ASSERT(firstView);
|
||||
JS_ASSERT(firstView->compartment() == comp);
|
||||
JS_ASSERT(BufferLink(firstView) == UNSET_BUFFER_LINK);
|
||||
@ -946,7 +946,7 @@ JSBool
|
||||
ArrayBufferObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp)
|
||||
{
|
||||
JS_ASSERT(obj->isArrayBuffer());
|
||||
JS_ASSERT(obj->is<ArrayBufferObject>());
|
||||
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
|
||||
if (!delegate)
|
||||
return false;
|
||||
@ -957,7 +957,7 @@ JSBool
|
||||
ArrayBufferObject::obj_getProperty(JSContext *cx, HandleObject obj,
|
||||
HandleObject receiver, HandlePropertyName name, MutableHandleValue vp)
|
||||
{
|
||||
JS_ASSERT(obj->isArrayBuffer());
|
||||
JS_ASSERT(obj->is<ArrayBufferObject>());
|
||||
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
|
||||
if (!delegate)
|
||||
return false;
|
||||
@ -969,7 +969,7 @@ JSBool
|
||||
ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj,
|
||||
HandleObject receiver, uint32_t index, MutableHandleValue vp)
|
||||
{
|
||||
JS_ASSERT(obj->isArrayBuffer());
|
||||
JS_ASSERT(obj->is<ArrayBufferObject>());
|
||||
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
|
||||
if (!delegate)
|
||||
return false;
|
||||
@ -980,7 +980,7 @@ JSBool
|
||||
ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
|
||||
uint32_t index, MutableHandleValue vp, bool *present)
|
||||
{
|
||||
JS_ASSERT(obj->isArrayBuffer());
|
||||
JS_ASSERT(obj->is<ArrayBufferObject>());
|
||||
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
|
||||
if (!delegate)
|
||||
return false;
|
||||
@ -1169,7 +1169,7 @@ bool
|
||||
js::IsDataView(JSObject* obj)
|
||||
{
|
||||
JS_ASSERT(obj);
|
||||
return obj->isDataView();
|
||||
return obj->is<DataViewObject>();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1767,8 +1767,8 @@ class TypedArrayTemplate
|
||||
obj->setSlot(TYPE_SLOT, Int32Value(ArrayTypeID()));
|
||||
obj->setSlot(BUFFER_SLOT, ObjectValue(*bufobj));
|
||||
|
||||
JS_ASSERT(bufobj->isArrayBuffer());
|
||||
Rooted<ArrayBufferObject *> buffer(cx, &bufobj->asArrayBuffer());
|
||||
JS_ASSERT(bufobj->is<ArrayBufferObject>());
|
||||
Rooted<ArrayBufferObject *> buffer(cx, &bufobj->as<ArrayBufferObject>());
|
||||
|
||||
InitArrayBufferViewDataPointer(obj, buffer, byteOffset);
|
||||
obj->setSlot(LENGTH_SLOT, Int32Value(len));
|
||||
@ -1858,7 +1858,7 @@ class TypedArrayTemplate
|
||||
* properties from the object, treating it as some sort of array.
|
||||
* Note that offset and length will be ignored
|
||||
*/
|
||||
if (!UncheckedUnwrap(dataObj)->isArrayBuffer())
|
||||
if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObject>())
|
||||
return fromArray(cx, dataObj);
|
||||
|
||||
/* (ArrayBuffer, [byteOffset, [length]]) */
|
||||
@ -2128,7 +2128,7 @@ class TypedArrayTemplate
|
||||
return NULL; // must be arrayBuffer
|
||||
}
|
||||
|
||||
JS_ASSERT(bufobj->isArrayBuffer() || bufobj->isProxy());
|
||||
JS_ASSERT(bufobj->is<ArrayBufferObject>() || bufobj->isProxy());
|
||||
if (bufobj->isProxy()) {
|
||||
/*
|
||||
* Normally, NonGenericMethodGuard handles the case of transparent
|
||||
@ -2146,7 +2146,7 @@ class TypedArrayTemplate
|
||||
JS_ReportError(cx, "Permission denied to access object");
|
||||
return NULL;
|
||||
}
|
||||
if (wrapped->isArrayBuffer()) {
|
||||
if (wrapped->is<ArrayBufferObject>()) {
|
||||
/*
|
||||
* And for even more fun, the new view's prototype should be
|
||||
* set to the origin compartment's prototype object, not the
|
||||
@ -2181,12 +2181,12 @@ class TypedArrayTemplate
|
||||
}
|
||||
}
|
||||
|
||||
if (!bufobj->isArrayBuffer()) {
|
||||
if (!bufobj->is<ArrayBufferObject>()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
return NULL; // must be arrayBuffer
|
||||
}
|
||||
|
||||
ArrayBufferObject &buffer = bufobj->asArrayBuffer();
|
||||
ArrayBufferObject &buffer = bufobj->as<ArrayBufferObject>();
|
||||
|
||||
if (byteOffset > buffer.byteLength() || byteOffset % sizeof(NativeType) != 0) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
@ -2703,13 +2703,13 @@ TypedArrayTemplate<double>::copyIndexToValue(JSObject *tarray, uint32_t index,
|
||||
JSBool
|
||||
DataViewObject::construct(JSContext *cx, JSObject *bufobj, const CallArgs &args, HandleObject proto)
|
||||
{
|
||||
if (!bufobj->isArrayBuffer()) {
|
||||
if (!bufobj->is<ArrayBufferObject>()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_EXPECTED_TYPE,
|
||||
"DataView", "ArrayBuffer", bufobj->getClass()->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &bufobj->asArrayBuffer());
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &bufobj->as<ArrayBufferObject>());
|
||||
uint32_t bufferLength = buffer->byteLength();
|
||||
uint32_t byteOffset = 0;
|
||||
uint32_t byteLength = bufferLength;
|
||||
@ -2766,7 +2766,7 @@ DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
|
||||
if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj))
|
||||
return false;
|
||||
|
||||
if (bufobj->isWrapper() && UncheckedUnwrap(bufobj)->isArrayBuffer()) {
|
||||
if (bufobj->isWrapper() && UncheckedUnwrap(bufobj)->is<ArrayBufferObject>()) {
|
||||
Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
|
||||
Rooted<JSObject*> proto(cx, global->getOrCreateDataViewPrototype(cx));
|
||||
if (!proto)
|
||||
@ -2961,7 +2961,7 @@ DataViewObject::getInt8Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
int8_t val;
|
||||
if (!read(cx, thisView, args, &val, "getInt8"))
|
||||
@ -2982,7 +2982,7 @@ DataViewObject::getUint8Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
uint8_t val;
|
||||
if (!read(cx, thisView, args, &val, "getUint8"))
|
||||
@ -3003,7 +3003,7 @@ DataViewObject::getInt16Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
int16_t val;
|
||||
if (!read(cx, thisView, args, &val, "getInt16"))
|
||||
@ -3024,7 +3024,7 @@ DataViewObject::getUint16Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
uint16_t val;
|
||||
if (!read(cx, thisView, args, &val, "getUint16"))
|
||||
@ -3045,7 +3045,7 @@ DataViewObject::getInt32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
int32_t val;
|
||||
if (!read(cx, thisView, args, &val, "getInt32"))
|
||||
@ -3066,7 +3066,7 @@ DataViewObject::getUint32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
uint32_t val;
|
||||
if (!read(cx, thisView, args, &val, "getUint32"))
|
||||
@ -3087,7 +3087,7 @@ DataViewObject::getFloat32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
float val;
|
||||
if (!read(cx, thisView, args, &val, "getFloat32"))
|
||||
@ -3109,7 +3109,7 @@ DataViewObject::getFloat64Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
double val;
|
||||
if (!read(cx, thisView, args, &val, "getFloat64"))
|
||||
@ -3131,7 +3131,7 @@ DataViewObject::setInt8Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
if (!write<int8_t>(cx, thisView, args, "setInt8"))
|
||||
return false;
|
||||
@ -3151,7 +3151,7 @@ DataViewObject::setUint8Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
if (!write<uint8_t>(cx, thisView, args, "setUint8"))
|
||||
return false;
|
||||
@ -3171,7 +3171,7 @@ DataViewObject::setInt16Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
if (!write<int16_t>(cx, thisView, args, "setInt16"))
|
||||
return false;
|
||||
@ -3191,7 +3191,7 @@ DataViewObject::setUint16Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
if (!write<uint16_t>(cx, thisView, args, "setUint16"))
|
||||
return false;
|
||||
@ -3211,7 +3211,7 @@ DataViewObject::setInt32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
if (!write<int32_t>(cx, thisView, args, "setInt32"))
|
||||
return false;
|
||||
@ -3231,7 +3231,7 @@ DataViewObject::setUint32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
if (!write<uint32_t>(cx, thisView, args, "setUint32"))
|
||||
return false;
|
||||
@ -3251,7 +3251,7 @@ DataViewObject::setFloat32Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
if (!write<float>(cx, thisView, args, "setFloat32"))
|
||||
return false;
|
||||
@ -3271,7 +3271,7 @@ DataViewObject::setFloat64Impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().asDataView());
|
||||
Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
|
||||
|
||||
if (!write<double>(cx, thisView, args, "setFloat64"))
|
||||
return false;
|
||||
@ -3308,7 +3308,7 @@ Class ArrayBufferObject::protoClass = {
|
||||
JS_ConvertStub
|
||||
};
|
||||
|
||||
Class js::ArrayBufferClass = {
|
||||
Class ArrayBufferObject::class_ = {
|
||||
"ArrayBuffer",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
@ -3672,7 +3672,7 @@ InitArrayBufferClass(JSContext *cx)
|
||||
return arrayBufferProto;
|
||||
}
|
||||
|
||||
Class js::DataViewObject::protoClass = {
|
||||
Class DataViewObject::protoClass = {
|
||||
"DataViewPrototype",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) |
|
||||
@ -3686,7 +3686,7 @@ Class js::DataViewObject::protoClass = {
|
||||
JS_ConvertStub
|
||||
};
|
||||
|
||||
Class js::DataViewClass = {
|
||||
Class DataViewObject::class_ = {
|
||||
"DataView",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
@ -3735,7 +3735,7 @@ DataViewObject::getterImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(is(args.thisv()));
|
||||
|
||||
args.rval().set(ValueGetter(args.thisv().toObject().asDataView()));
|
||||
args.rval().set(ValueGetter(args.thisv().toObject().as<DataViewObject>()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3872,7 +3872,7 @@ js::IsTypedArrayConstructor(const Value &v, uint32_t type)
|
||||
bool
|
||||
js::IsTypedArrayBuffer(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().isArrayBuffer();
|
||||
return v.isObject() && v.toObject().is<ArrayBufferObject>();
|
||||
}
|
||||
|
||||
/* JS Friend API */
|
||||
@ -3881,7 +3881,7 @@ JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferObject(JSObject *obj)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
return obj ? obj->isArrayBuffer() : false;
|
||||
return obj ? obj->is<ArrayBufferObject>() : false;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
@ -3895,14 +3895,14 @@ JS_FRIEND_API(JSBool)
|
||||
JS_IsArrayBufferViewObject(JSObject *obj)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
return obj ? (obj->isTypedArray() || obj->isDataView()) : false;
|
||||
return obj ? (obj->isTypedArray() || obj->is<DataViewObject>()) : false;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
JS_GetArrayBufferByteLength(JSObject *obj)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
return obj ? obj->asArrayBuffer().byteLength() : 0;
|
||||
return obj ? obj->as<ArrayBufferObject>().byteLength() : 0;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint8_t *)
|
||||
@ -3911,7 +3911,7 @@ JS_GetArrayBufferData(JSObject *obj)
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
ArrayBufferObject &buffer = obj->asArrayBuffer();
|
||||
ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
|
||||
if (!buffer.uninlineData(NULL))
|
||||
return NULL;
|
||||
return buffer.dataPointer();
|
||||
@ -3932,7 +3932,7 @@ JS_NewArrayBufferWithContents(JSContext *cx, void *contents)
|
||||
if (!obj)
|
||||
return NULL;
|
||||
obj->setDynamicElements(reinterpret_cast<js::ObjectElements *>(contents));
|
||||
JS_ASSERT(*GetViewList(&obj->asArrayBuffer()) == NULL);
|
||||
JS_ASSERT(*GetViewList(&obj->as<ArrayBufferObject>()) == NULL);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -3971,7 +3971,7 @@ JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents,
|
||||
if (!(obj = CheckedUnwrap(obj)))
|
||||
return false;
|
||||
|
||||
if (!obj->isArrayBuffer()) {
|
||||
if (!obj->is<ArrayBufferObject>()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
return false;
|
||||
}
|
||||
@ -4021,7 +4021,7 @@ JS_GetArrayBufferViewType(JSObject *obj)
|
||||
|
||||
if (obj->isTypedArray())
|
||||
return static_cast<JSArrayBufferViewType>(TypedArray::type(obj));
|
||||
else if (obj->isDataView())
|
||||
else if (obj->is<DataViewObject>())
|
||||
return ArrayBufferView::TYPE_DATAVIEW;
|
||||
JS_NOT_REACHED("invalid ArrayBufferView type");
|
||||
return ArrayBufferView::TYPE_MAX;
|
||||
@ -4130,7 +4130,7 @@ JS_FRIEND_API(JSBool)
|
||||
JS_IsDataViewObject(JSObject *obj)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
return obj ? obj->isDataView() : false;
|
||||
return obj ? obj->is<DataViewObject>() : false;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
@ -4139,7 +4139,7 @@ JS_GetDataViewByteOffset(JSObject *obj)
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
return obj->asDataView().byteOffset();
|
||||
return obj->as<DataViewObject>().byteOffset();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
@ -4148,8 +4148,8 @@ JS_GetDataViewData(JSObject *obj)
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isDataView());
|
||||
return obj->asDataView().dataPointer();
|
||||
JS_ASSERT(obj->is<DataViewObject>());
|
||||
return obj->as<DataViewObject>().dataPointer();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint32_t)
|
||||
@ -4158,8 +4158,8 @@ JS_GetDataViewByteLength(JSObject *obj)
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isDataView());
|
||||
return obj->asDataView().byteLength();
|
||||
JS_ASSERT(obj->is<DataViewObject>());
|
||||
return obj->as<DataViewObject>().byteLength();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
@ -4168,8 +4168,9 @@ JS_GetArrayBufferViewData(JSObject *obj)
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
|
||||
return obj->isDataView() ? obj->asDataView().dataPointer() : TypedArray::viewData(obj);
|
||||
JS_ASSERT(obj->isTypedArray() || obj->is<DataViewObject>());
|
||||
return obj->is<DataViewObject>() ? obj->as<DataViewObject>().dataPointer()
|
||||
: TypedArray::viewData(obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
@ -4178,7 +4179,7 @@ JS_GetArrayBufferViewBuffer(JSObject *obj)
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
|
||||
JS_ASSERT(obj->isTypedArray() || obj->is<DataViewObject>());
|
||||
return &obj->getFixedSlot(BufferView::BUFFER_SLOT).toObject();
|
||||
}
|
||||
|
||||
@ -4188,9 +4189,9 @@ JS_GetArrayBufferViewByteLength(JSObject *obj)
|
||||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
return 0;
|
||||
JS_ASSERT(obj->isTypedArray() || obj->isDataView());
|
||||
return obj->isDataView()
|
||||
? obj->asDataView().byteLength()
|
||||
JS_ASSERT(obj->isTypedArray() || obj->is<DataViewObject>());
|
||||
return obj->is<DataViewObject>()
|
||||
? obj->as<DataViewObject>().byteLength()
|
||||
: TypedArray::byteLengthValue(obj).toInt32();
|
||||
}
|
||||
|
||||
@ -4199,14 +4200,15 @@ JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data)
|
||||
{
|
||||
if (!(obj = CheckedUnwrap(obj)))
|
||||
return NULL;
|
||||
if (!(obj->isTypedArray() || obj->isDataView()))
|
||||
if (!(obj->isTypedArray() || obj->is<DataViewObject>()))
|
||||
return NULL;
|
||||
|
||||
*length = obj->isDataView() ? obj->asDataView().byteLength()
|
||||
: TypedArray::byteLengthValue(obj).toInt32();
|
||||
*length = obj->is<DataViewObject>() ? obj->as<DataViewObject>().byteLength()
|
||||
: TypedArray::byteLengthValue(obj).toInt32();
|
||||
|
||||
*data = static_cast<uint8_t *>(obj->isDataView() ? obj->asDataView().dataPointer()
|
||||
: TypedArray::viewData(obj));
|
||||
*data = static_cast<uint8_t *>(obj->is<DataViewObject>()
|
||||
? obj->as<DataViewObject>().dataPointer()
|
||||
: TypedArray::viewData(obj));
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -4215,11 +4217,11 @@ JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
|
||||
{
|
||||
if (!(obj = CheckedUnwrap(obj)))
|
||||
return NULL;
|
||||
if (!obj->isArrayBuffer())
|
||||
if (!obj->is<ArrayBufferObject>())
|
||||
return NULL;
|
||||
|
||||
*length = obj->asArrayBuffer().byteLength();
|
||||
*data = obj->asArrayBuffer().dataPointer();
|
||||
*length = obj->as<ArrayBufferObject>().byteLength();
|
||||
*data = obj->as<ArrayBufferObject>().dataPointer();
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ class ArrayBufferObject : public JSObject
|
||||
static bool fun_slice_impl(JSContext *cx, CallArgs args);
|
||||
|
||||
public:
|
||||
static Class class_;
|
||||
|
||||
static Class protoClass;
|
||||
static const JSFunctionSpec jsfuncs[];
|
||||
|
||||
@ -342,6 +344,7 @@ TypedArrayShift(ArrayBufferView::ViewType viewType)
|
||||
class DataViewObject : public JSObject, public BufferView
|
||||
{
|
||||
public:
|
||||
static Class class_;
|
||||
|
||||
private:
|
||||
static Class protoClass;
|
||||
|
@ -38,7 +38,7 @@ js::ArrayBufferObject::getElementsHeaderInitializedLength(const js::ObjectElemen
|
||||
inline uint32_t
|
||||
js::ArrayBufferObject::byteLength() const
|
||||
{
|
||||
JS_ASSERT(isArrayBuffer());
|
||||
JS_ASSERT(is<ArrayBufferObject>());
|
||||
return getElementsHeader()->initializedLength;
|
||||
}
|
||||
|
||||
@ -48,26 +48,12 @@ js::ArrayBufferObject::dataPointer() const
|
||||
return (uint8_t *) elements;
|
||||
}
|
||||
|
||||
inline js::ArrayBufferObject &
|
||||
JSObject::asArrayBuffer()
|
||||
{
|
||||
JS_ASSERT(isArrayBuffer());
|
||||
return *static_cast<js::ArrayBufferObject *>(this);
|
||||
}
|
||||
|
||||
inline js::DataViewObject &
|
||||
JSObject::asDataView()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
return *static_cast<js::DataViewObject *>(this);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
inline bool
|
||||
ArrayBufferObject::hasData() const
|
||||
{
|
||||
return getClass() == &ArrayBufferClass;
|
||||
return getClass() == &class_;
|
||||
}
|
||||
|
||||
inline bool
|
||||
@ -142,7 +128,7 @@ TypedArray::bufferValue(JSObject *obj)
|
||||
inline ArrayBufferObject *
|
||||
TypedArray::buffer(JSObject *obj)
|
||||
{
|
||||
return &bufferValue(obj).toObject().asArrayBuffer();
|
||||
return &bufferValue(obj).toObject().as<ArrayBufferObject>();
|
||||
}
|
||||
|
||||
inline void *
|
||||
@ -182,7 +168,7 @@ TypedArray::slotWidth(JSObject *obj) {
|
||||
bool
|
||||
DataViewObject::is(const Value &v)
|
||||
{
|
||||
return v.isObject() && v.toObject().hasClass(&DataViewClass);
|
||||
return v.isObject() && v.toObject().hasClass(&class_);
|
||||
}
|
||||
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
@ -203,7 +189,7 @@ class ArrayBufferViewByteOffsetRef : public gc::BufferableRef
|
||||
MarkObjectUnbarriered(trc, &obj, "TypedArray");
|
||||
HeapSlot &bufSlot = obj->getReservedSlotRef(BufferView::BUFFER_SLOT);
|
||||
gc::MarkSlot(trc, &bufSlot, "TypedArray::BUFFER_SLOT");
|
||||
ArrayBufferObject &buf = bufSlot.toObject().asArrayBuffer();
|
||||
ArrayBufferObject &buf = bufSlot.toObject().as<ArrayBufferObject>();
|
||||
int32_t offset = obj->getReservedSlot(BufferView::BYTEOFFSET_SLOT).toInt32();
|
||||
obj->initPrivate(buf.dataPointer() + offset);
|
||||
}
|
||||
@ -234,7 +220,7 @@ DataViewNewObjectKind(JSContext *cx, uint32_t byteLength, JSObject *proto)
|
||||
JSScript *script = cx->stack.currentScript(&pc);
|
||||
if (!script)
|
||||
return GenericObject;
|
||||
return types::UseNewTypeForInitializer(cx, script, pc, &DataViewClass);
|
||||
return types::UseNewTypeForInitializer(cx, script, pc, &DataViewObject::class_);
|
||||
}
|
||||
|
||||
inline DataViewObject *
|
||||
@ -248,12 +234,12 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
RootedObject obj(cx);
|
||||
|
||||
NewObjectKind newKind = DataViewNewObjectKind(cx, byteLength, proto);
|
||||
obj = NewBuiltinClassInstance(cx, &DataViewClass, newKind);
|
||||
obj = NewBuiltinClassInstance(cx, &class_, newKind);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
if (proto) {
|
||||
types::TypeObject *type = proto->getNewType(cx, &DataViewClass);
|
||||
types::TypeObject *type = proto->getNewType(cx, &class_);
|
||||
if (!type)
|
||||
return NULL;
|
||||
obj->setType(type);
|
||||
@ -270,9 +256,9 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
}
|
||||
}
|
||||
|
||||
JS_ASSERT(arrayBuffer->isArrayBuffer());
|
||||
JS_ASSERT(arrayBuffer->is<ArrayBufferObject>());
|
||||
|
||||
DataViewObject &dvobj = obj->asDataView();
|
||||
DataViewObject &dvobj = obj->as<DataViewObject>();
|
||||
dvobj.setFixedSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
|
||||
dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(byteLength));
|
||||
dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer));
|
||||
@ -284,7 +270,7 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
// Verify that the private slot is at the expected place
|
||||
JS_ASSERT(dvobj.numFixedSlots() == DATA_SLOT);
|
||||
|
||||
arrayBuffer->asArrayBuffer().addView(&dvobj);
|
||||
arrayBuffer->as<ArrayBufferObject>().addView(&dvobj);
|
||||
|
||||
return &dvobj;
|
||||
}
|
||||
@ -292,7 +278,7 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
inline uint32_t
|
||||
DataViewObject::byteLength()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
JS_ASSERT(JSObject::is<DataViewObject>());
|
||||
int32_t length = getReservedSlot(BYTELENGTH_SLOT).toInt32();
|
||||
JS_ASSERT(length >= 0);
|
||||
return static_cast<uint32_t>(length);
|
||||
@ -301,7 +287,7 @@ DataViewObject::byteLength()
|
||||
inline uint32_t
|
||||
DataViewObject::byteOffset()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
JS_ASSERT(JSObject::is<DataViewObject>());
|
||||
int32_t offset = getReservedSlot(BYTEOFFSET_SLOT).toInt32();
|
||||
JS_ASSERT(offset >= 0);
|
||||
return static_cast<uint32_t>(offset);
|
||||
@ -310,21 +296,21 @@ DataViewObject::byteOffset()
|
||||
inline void *
|
||||
DataViewObject::dataPointer()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
JS_ASSERT(JSObject::is<DataViewObject>());
|
||||
return getPrivate();
|
||||
}
|
||||
|
||||
inline ArrayBufferObject &
|
||||
DataViewObject::arrayBuffer()
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
return getReservedSlot(BUFFER_SLOT).toObject().asArrayBuffer();
|
||||
JS_ASSERT(JSObject::is<DataViewObject>());
|
||||
return getReservedSlot(BUFFER_SLOT).toObject().as<ArrayBufferObject>();
|
||||
}
|
||||
|
||||
inline bool
|
||||
DataViewObject::hasBuffer() const
|
||||
{
|
||||
JS_ASSERT(isDataView());
|
||||
JS_ASSERT(JSObject::is<DataViewObject>());
|
||||
return getReservedSlot(BUFFER_SLOT).isObject();
|
||||
}
|
||||
|
||||
|
@ -346,8 +346,8 @@ CanReify(HandleValue vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
return vp.isObject() &&
|
||||
(obj = &vp.toObject())->isPropertyIterator() &&
|
||||
(obj->asPropertyIterator().getNativeIterator()->flags & JSITER_ENUMERATE);
|
||||
(obj = &vp.toObject())->is<PropertyIteratorObject>() &&
|
||||
(obj->as<PropertyIteratorObject>().getNativeIterator()->flags & JSITER_ENUMERATE);
|
||||
}
|
||||
|
||||
struct AutoCloseIterator
|
||||
@ -366,7 +366,7 @@ struct AutoCloseIterator
|
||||
static bool
|
||||
Reify(JSContext *cx, JSCompartment *origin, MutableHandleValue vp)
|
||||
{
|
||||
Rooted<PropertyIteratorObject*> iterObj(cx, &vp.toObject().asPropertyIterator());
|
||||
Rooted<PropertyIteratorObject*> iterObj(cx, &vp.toObject().as<PropertyIteratorObject>());
|
||||
NativeIterator *ni = iterObj->getNativeIterator();
|
||||
|
||||
AutoCloseIterator close(cx, iterObj);
|
||||
|
@ -383,10 +383,10 @@ class ReferenceFinder {
|
||||
JSObject *object = static_cast<JSObject *>(cell);
|
||||
|
||||
/* Certain classes of object are for internal use only. */
|
||||
if (object->isBlock() ||
|
||||
object->isCall() ||
|
||||
if (object->is<BlockObject>() ||
|
||||
object->is<CallObject>() ||
|
||||
object->isWith() ||
|
||||
object->isDeclEnv()) {
|
||||
object->is<DeclEnvObject>()) {
|
||||
return JSVAL_VOID;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ ArgumentsObject::element(uint32_t i) const
|
||||
JS_ASSERT(!isElementDeleted(i));
|
||||
const Value &v = data()->args[i];
|
||||
if (v.isMagic(JS_FORWARD_TO_CALL_OBJECT)) {
|
||||
CallObject &callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall();
|
||||
CallObject &callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().as<CallObject>();
|
||||
for (AliasedFormalIter fi(callobj.callee().nonLazyScript()); ; fi++) {
|
||||
if (fi.frameIndex() == i)
|
||||
return callobj.aliasedVar(fi);
|
||||
@ -86,7 +86,7 @@ ArgumentsObject::setElement(JSContext *cx, uint32_t i, const Value &v)
|
||||
JS_ASSERT(!isElementDeleted(i));
|
||||
HeapValue &lhs = data()->args[i];
|
||||
if (lhs.isMagic(JS_FORWARD_TO_CALL_OBJECT)) {
|
||||
CallObject &callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().asCall();
|
||||
CallObject &callobj = getFixedSlot(MAYBE_CALL_SLOT).toObject().as<CallObject>();
|
||||
for (AliasedFormalIter fi(callobj.callee().nonLazyScript()); ; fi++) {
|
||||
if (fi.frameIndex() == i) {
|
||||
callobj.setAliasedVar(cx, fi, fi->name(), v);
|
||||
|
@ -59,7 +59,7 @@ ArgumentsObject::MaybeForwardToCallObject(ion::IonJSFrameLayout *frame, HandleOb
|
||||
JSFunction *callee = ion::CalleeTokenToFunction(frame->calleeToken());
|
||||
JSScript *script = callee->nonLazyScript();
|
||||
if (callee->isHeavyweight() && script->argsObjAliasesFormals()) {
|
||||
JS_ASSERT(callObj && callObj->isCall());
|
||||
JS_ASSERT(callObj && callObj->is<CallObject>());
|
||||
obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
|
||||
for (AliasedFormalIter fi(script); fi; fi++)
|
||||
data->args[fi.frameIndex()] = MagicValue(JS_FORWARD_TO_CALL_OBJECT);
|
||||
@ -180,7 +180,7 @@ ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction calle
|
||||
return NULL;
|
||||
|
||||
bool strict = callee->strict();
|
||||
Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
|
||||
Class *clasp = strict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_;
|
||||
|
||||
RootedTypeObject type(cx, proto->getNewType(cx, clasp));
|
||||
if (!type)
|
||||
@ -226,7 +226,7 @@ ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction calle
|
||||
|
||||
copy.maybeForwardToCallObject(obj, data);
|
||||
|
||||
ArgumentsObject &argsobj = obj->asArguments();
|
||||
ArgumentsObject &argsobj = obj->as<ArgumentsObject>();
|
||||
JS_ASSERT(argsobj.initialLength() == numActuals);
|
||||
JS_ASSERT(!argsobj.hasOverriddenLength());
|
||||
return &argsobj;
|
||||
@ -273,7 +273,7 @@ ArgumentsObject::createForIon(JSContext *cx, ion::IonJSFrameLayout *frame, Handl
|
||||
JS_ASSERT(ion::CalleeTokenIsFunction(token));
|
||||
RootedScript script(cx, ion::ScriptFromCalleeToken(token));
|
||||
RootedFunction callee(cx, ion::CalleeTokenToFunction(token));
|
||||
RootedObject callObj(cx, scopeChain->isCall() ? scopeChain.get() : NULL);
|
||||
RootedObject callObj(cx, scopeChain->is<CallObject>() ? scopeChain.get() : NULL);
|
||||
CopyIonJSFrameArgs copy(frame, callObj);
|
||||
return create(cx, script, callee, frame->numActualArgs(), copy);
|
||||
}
|
||||
@ -282,7 +282,7 @@ ArgumentsObject::createForIon(JSContext *cx, ion::IonJSFrameLayout *frame, Handl
|
||||
static JSBool
|
||||
args_delProperty(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded)
|
||||
{
|
||||
ArgumentsObject &argsobj = obj->asArguments();
|
||||
ArgumentsObject &argsobj = obj->as<ArgumentsObject>();
|
||||
if (JSID_IS_INT(id)) {
|
||||
unsigned arg = unsigned(JSID_TO_INT(id));
|
||||
if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg))
|
||||
@ -290,7 +290,7 @@ args_delProperty(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded
|
||||
} else if (JSID_IS_ATOM(id, cx->names().length)) {
|
||||
argsobj.markLengthOverridden();
|
||||
} else if (JSID_IS_ATOM(id, cx->names().callee)) {
|
||||
argsobj.asNormalArguments().clearCallee();
|
||||
argsobj.as<NormalArgumentsObject>().clearCallee();
|
||||
}
|
||||
*succeeded = true;
|
||||
return true;
|
||||
@ -299,10 +299,10 @@ args_delProperty(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded
|
||||
static JSBool
|
||||
ArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
|
||||
{
|
||||
if (!obj->isNormalArguments())
|
||||
if (!obj->is<NormalArgumentsObject>())
|
||||
return true;
|
||||
|
||||
NormalArgumentsObject &argsobj = obj->asNormalArguments();
|
||||
NormalArgumentsObject &argsobj = obj->as<NormalArgumentsObject>();
|
||||
if (JSID_IS_INT(id)) {
|
||||
/*
|
||||
* arg can exceed the number of arguments if a script changed the
|
||||
@ -325,7 +325,7 @@ ArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
|
||||
static JSBool
|
||||
ArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHandleValue vp)
|
||||
{
|
||||
if (!obj->isNormalArguments())
|
||||
if (!obj->is<NormalArgumentsObject>())
|
||||
return true;
|
||||
|
||||
unsigned attrs;
|
||||
@ -334,7 +334,7 @@ ArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHa
|
||||
JS_ASSERT(!(attrs & JSPROP_READONLY));
|
||||
attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */
|
||||
|
||||
NormalArgumentsObject &argsobj = obj->asNormalArguments();
|
||||
NormalArgumentsObject &argsobj = obj->as<NormalArgumentsObject>();
|
||||
RootedScript script(cx, argsobj.containingScript());
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
@ -368,7 +368,7 @@ args_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
|
||||
{
|
||||
objp.set(NULL);
|
||||
|
||||
Rooted<NormalArgumentsObject*> argsobj(cx, &obj->asNormalArguments());
|
||||
Rooted<NormalArgumentsObject*> argsobj(cx, &obj->as<NormalArgumentsObject>());
|
||||
|
||||
unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
|
||||
if (JSID_IS_INT(id)) {
|
||||
@ -399,7 +399,7 @@ args_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
|
||||
static JSBool
|
||||
args_enumerate(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
Rooted<NormalArgumentsObject*> argsobj(cx, &obj->asNormalArguments());
|
||||
Rooted<NormalArgumentsObject*> argsobj(cx, &obj->as<NormalArgumentsObject>());
|
||||
RootedId id(cx);
|
||||
|
||||
/*
|
||||
@ -425,10 +425,10 @@ args_enumerate(JSContext *cx, HandleObject obj)
|
||||
static JSBool
|
||||
StrictArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
|
||||
{
|
||||
if (!obj->isStrictArguments())
|
||||
if (!obj->is<StrictArgumentsObject>())
|
||||
return true;
|
||||
|
||||
StrictArgumentsObject &argsobj = obj->asStrictArguments();
|
||||
StrictArgumentsObject &argsobj = obj->as<StrictArgumentsObject>();
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
/*
|
||||
@ -449,7 +449,7 @@ StrictArgGetter(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue
|
||||
static JSBool
|
||||
StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, MutableHandleValue vp)
|
||||
{
|
||||
if (!obj->isStrictArguments())
|
||||
if (!obj->is<StrictArgumentsObject>())
|
||||
return true;
|
||||
|
||||
unsigned attrs;
|
||||
@ -458,7 +458,7 @@ StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Mut
|
||||
JS_ASSERT(!(attrs & JSPROP_READONLY));
|
||||
attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */
|
||||
|
||||
Rooted<StrictArgumentsObject*> argsobj(cx, &obj->asStrictArguments());
|
||||
Rooted<StrictArgumentsObject*> argsobj(cx, &obj->as<StrictArgumentsObject>());
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
unsigned arg = unsigned(JSID_TO_INT(id));
|
||||
@ -487,7 +487,7 @@ strictargs_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
|
||||
{
|
||||
objp.set(NULL);
|
||||
|
||||
Rooted<StrictArgumentsObject*> argsobj(cx, &obj->asStrictArguments());
|
||||
Rooted<StrictArgumentsObject*> argsobj(cx, &obj->as<StrictArgumentsObject>());
|
||||
|
||||
unsigned attrs = JSPROP_SHARED | JSPROP_SHADOWABLE;
|
||||
PropertyOp getter = StrictArgGetter;
|
||||
@ -522,7 +522,7 @@ strictargs_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
|
||||
static JSBool
|
||||
strictargs_enumerate(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
Rooted<StrictArgumentsObject*> argsobj(cx, &obj->asStrictArguments());
|
||||
Rooted<StrictArgumentsObject*> argsobj(cx, &obj->as<StrictArgumentsObject>());
|
||||
|
||||
/*
|
||||
* Trigger reflection in strictargs_resolve using a series of
|
||||
@ -559,13 +559,13 @@ strictargs_enumerate(JSContext *cx, HandleObject obj)
|
||||
void
|
||||
ArgumentsObject::finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
fop->free_(reinterpret_cast<void *>(obj->asArguments().data()));
|
||||
fop->free_(reinterpret_cast<void *>(obj->as<ArgumentsObject>().data()));
|
||||
}
|
||||
|
||||
void
|
||||
ArgumentsObject::trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
ArgumentsObject &argsobj = obj->asArguments();
|
||||
ArgumentsObject &argsobj = obj->as<ArgumentsObject>();
|
||||
ArgumentsData *data = argsobj.data();
|
||||
MarkValue(trc, &data->callee, js_callee_str);
|
||||
MarkValueRange(trc, data->numArgs, data->args, js_arguments_str);
|
||||
@ -578,7 +578,7 @@ ArgumentsObject::trace(JSTracer *trc, JSObject *obj)
|
||||
* StackFrame with their corresponding property values in the frame's
|
||||
* arguments object.
|
||||
*/
|
||||
Class js::NormalArgumentsObjectClass = {
|
||||
Class NormalArgumentsObject::class_ = {
|
||||
"Arguments",
|
||||
JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(NormalArgumentsObject::RESERVED_SLOTS) |
|
||||
@ -609,7 +609,7 @@ Class js::NormalArgumentsObjectClass = {
|
||||
* arguments, so it is represented by a different class while sharing some
|
||||
* functionality.
|
||||
*/
|
||||
Class js::StrictArgumentsObjectClass = {
|
||||
Class StrictArgumentsObject::class_ = {
|
||||
"Arguments",
|
||||
JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(StrictArgumentsObject::RESERVED_SLOTS) |
|
||||
|
@ -220,6 +220,8 @@ class ArgumentsObject : public JSObject
|
||||
class NormalArgumentsObject : public ArgumentsObject
|
||||
{
|
||||
public:
|
||||
static Class class_;
|
||||
|
||||
/*
|
||||
* Stores arguments.callee, or MagicValue(JS_ARGS_HOLE) if the callee has
|
||||
* been cleared.
|
||||
@ -231,36 +233,18 @@ class NormalArgumentsObject : public ArgumentsObject
|
||||
};
|
||||
|
||||
class StrictArgumentsObject : public ArgumentsObject
|
||||
{};
|
||||
{
|
||||
public:
|
||||
static Class class_;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
js::NormalArgumentsObject &
|
||||
JSObject::asNormalArguments()
|
||||
template<>
|
||||
inline bool
|
||||
JSObject::is<js::ArgumentsObject>() const
|
||||
{
|
||||
JS_ASSERT(isNormalArguments());
|
||||
return *static_cast<js::NormalArgumentsObject *>(this);
|
||||
}
|
||||
|
||||
js::StrictArgumentsObject &
|
||||
JSObject::asStrictArguments()
|
||||
{
|
||||
JS_ASSERT(isStrictArguments());
|
||||
return *static_cast<js::StrictArgumentsObject *>(this);
|
||||
}
|
||||
|
||||
js::ArgumentsObject &
|
||||
JSObject::asArguments()
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
return *static_cast<js::ArgumentsObject *>(this);
|
||||
}
|
||||
|
||||
const js::ArgumentsObject &
|
||||
JSObject::asArguments() const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
return *static_cast<const js::ArgumentsObject *>(this);
|
||||
return is<js::NormalArgumentsObject>() || is<js::StrictArgumentsObject>();
|
||||
}
|
||||
|
||||
#endif /* ArgumentsObject_h___ */
|
||||
|
@ -5234,10 +5234,10 @@ DebuggerEnv_getCallee(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
|
||||
JSObject &scope = env->asDebugScope().scope();
|
||||
if (!scope.isCall())
|
||||
if (!scope.is<CallObject>())
|
||||
return true;
|
||||
|
||||
CallObject &callobj = scope.asCall();
|
||||
CallObject &callobj = scope.as<CallObject>();
|
||||
if (callobj.isForEval())
|
||||
return true;
|
||||
|
||||
|
@ -135,7 +135,7 @@ ProtoSetterImpl(JSContext *cx, CallArgs args)
|
||||
* which due to their complicated delegate-object shenanigans can't easily
|
||||
* have a mutable [[Prototype]].
|
||||
*/
|
||||
if (obj->isProxy() || obj->isArrayBuffer()) {
|
||||
if (obj->isProxy() || obj->is<ArrayBufferObject>()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
|
||||
"Object", "__proto__ setter",
|
||||
obj->isProxy() ? "Proxy" : "ArrayBuffer");
|
||||
|
@ -227,8 +227,8 @@ GetLengthProperty(const Value &lval, MutableHandleValue vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj->isArguments()) {
|
||||
ArgumentsObject *argsobj = &obj->asArguments();
|
||||
if (obj->is<ArgumentsObject>()) {
|
||||
ArgumentsObject *argsobj = &obj->as<ArgumentsObject>();
|
||||
if (!argsobj->hasOverriddenLength()) {
|
||||
uint32_t length = argsobj->initialLength();
|
||||
JS_ASSERT(length < INT32_MAX);
|
||||
@ -1130,10 +1130,8 @@ class FastInvokeGuard
|
||||
void initFunction(const Value &fval) {
|
||||
if (fval.isObject() && fval.toObject().isFunction()) {
|
||||
JSFunction *fun = fval.toObject().toFunction();
|
||||
if (fun->hasScript()) {
|
||||
if (fun->isInterpreted())
|
||||
fun_ = fun;
|
||||
script_ = fun->nonLazyScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1144,6 +1142,11 @@ class FastInvokeGuard
|
||||
bool invoke(JSContext *cx) {
|
||||
#ifdef JS_ION
|
||||
if (useIon_ && fun_) {
|
||||
if (!script_) {
|
||||
script_ = fun_->getOrCreateScript(cx);
|
||||
if (!script_)
|
||||
return false;
|
||||
}
|
||||
if (ictx_.empty())
|
||||
ictx_.construct(cx, (js::ion::TempAllocator *)NULL);
|
||||
JS_ASSERT(fun_->nonLazyScript() == script_);
|
||||
|
@ -959,8 +959,8 @@ JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1);
|
||||
bool
|
||||
js::IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, MutableHandleValue rval)
|
||||
{
|
||||
if (iterobj->isPropertyIterator()) {
|
||||
NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
|
||||
if (iterobj->is<PropertyIteratorObject>()) {
|
||||
NativeIterator *ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
if (ni->isKeyIter()) {
|
||||
*cond = (ni->props_cursor < ni->props_end);
|
||||
return true;
|
||||
@ -976,8 +976,8 @@ js::IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, MutableHandleValu
|
||||
bool
|
||||
js::IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval)
|
||||
{
|
||||
if (iterobj->isPropertyIterator()) {
|
||||
NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
|
||||
if (iterobj->is<PropertyIteratorObject>()) {
|
||||
NativeIterator *ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
|
||||
if (ni->isKeyIter()) {
|
||||
JS_ASSERT(ni->props_cursor < ni->props_end);
|
||||
rval.setString(*ni->current());
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user