Merge m-c and birch.

This commit is contained in:
Ryan VanderMeulen 2013-06-17 20:05:54 -04:00
commit b6a943bbd8
159 changed files with 4323 additions and 3007 deletions

View File

@ -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,

View File

@ -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

View File

@ -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;
}
};

View File

@ -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;

View File

@ -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

View 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);
}

View 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>

View File

@ -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();
}
@ -163,4 +166,4 @@
</ul>
</div>
</body>
</html>
</html>

View File

@ -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);
}
);
});

View File

@ -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);
}

View File

@ -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.

View File

@ -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

View File

@ -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: }

View File

@ -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>

View File

@ -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"],

View File

@ -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() {

View File

@ -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");
}

View File

@ -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);

View File

@ -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"/>

View 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

View File

@ -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;
},

View 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);
},
};

View File

@ -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)

View File

@ -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

View File

@ -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",

View File

@ -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();
}

View File

@ -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.

View File

@ -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 {

View File

@ -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)

View File

@ -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([]);

View File

@ -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));

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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.")

View File

@ -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,

View File

@ -132,4 +132,12 @@ quicknav_PageTab = Page tabs
quicknav_RadioButton = Radio buttons
quicknav_Separator = Separators
quicknav_Table = Tables
quicknav_Checkbox = Check boxes
quicknav_Checkbox = Check boxes
# Shortened role names for braille
linkAbbr = lnk
pushbuttonAbbr = btn
passwordtextAbbr = passwdtxt
imagemapAbbr = imgmap
figureAbbr = fig
textareaAbbr = txtarea

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -555,7 +555,7 @@ private:
gfx::IntSize mSize;
GLuint mTextureHandle;
GLenum mGLFormat;
gl::GLContext* mGL;
nsRefPtr<gl::GLContext> mGL;
};
#ifdef MOZ_WIDGET_GONK

View File

@ -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());
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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, &regexp->asRegExp());
Rooted<RegExpObject*> reobj(cx, &regexp->as<RegExpObject>());
RegExpGuard re(cx);
if (!reobj->getShared(cx, &re))

View File

@ -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;

View File

@ -811,7 +811,7 @@ ObjectBox::ObjectBox(Module *module, ObjectBox* traceLink)
traceLink(traceLink),
emitLink(NULL)
{
JS_ASSERT(object->isModule());
JS_ASSERT(object->is<Module>());
}
void

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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));

View File

@ -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");

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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 {

View File

@ -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++) {

View File

@ -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;

View File

@ -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);
}

View File

@ -11,6 +11,7 @@
namespace js {
class DeclEnvObject;
class ForkJoinSlice;
namespace ion {

View File

@ -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();

View File

@ -0,0 +1 @@
if(1) /a/.test("a"); // should not be a SyntaxError.

View File

@ -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];

View File

@ -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();
}
/************************************************************************/

View File

@ -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) {

View File

@ -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) {

View File

@ -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;

View File

@ -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();
}

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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());

View File

@ -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_;

View File

@ -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;

View File

@ -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[];

View File

@ -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.

View File

@ -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();

View File

@ -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");

View File

@ -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;
}

View File

@ -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))

View File

@ -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 *

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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) |

View File

@ -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___ */

View File

@ -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;

View File

@ -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");

View File

@ -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_);

View File

@ -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