Merge mozilla-central and inbound

This commit is contained in:
Ed Morley 2013-05-22 11:28:59 +01:00
Родитель 9d91c011b4 ac855585e9
Коммит 6a91572c71
192 изменённых файлов: 4452 добавлений и 2099 удалений

Просмотреть файл

@ -112,10 +112,12 @@ this.AccessFu = {
TouchAdapter.start();
Services.obs.addObserver(this, 'remote-browser-frame-shown', false);
Services.obs.addObserver(this, 'in-process-browser-or-app-frame-shown', false);
Services.obs.addObserver(this, 'Accessibility:NextObject', false);
Services.obs.addObserver(this, 'Accessibility:PreviousObject', false);
Services.obs.addObserver(this, 'Accessibility:Focus', false);
Utils.win.addEventListener('TabOpen', this);
Utils.win.addEventListener('TabClose', this);
Utils.win.addEventListener('TabSelect', this);
if (this.readyCallback) {
@ -147,9 +149,11 @@ this.AccessFu = {
TouchAdapter.stop();
Utils.win.removeEventListener('TabOpen', this);
Utils.win.removeEventListener('TabClose', this);
Utils.win.removeEventListener('TabSelect', this);
Services.obs.removeObserver(this, 'remote-browser-frame-shown');
Services.obs.removeObserver(this, 'in-process-browser-or-app-frame-shown');
Services.obs.removeObserver(this, 'Accessibility:NextObject');
Services.obs.removeObserver(this, 'Accessibility:PreviousObject');
Services.obs.removeObserver(this, 'Accessibility:Focus');
@ -280,6 +284,7 @@ this.AccessFu = {
}
break;
case 'remote-browser-frame-shown':
case 'in-process-browser-or-app-frame-shown':
{
let mm = aSubject.QueryInterface(Ci.nsIFrameLoader).messageManager;
this._handleMessageManager(mm);
@ -310,6 +315,16 @@ this.AccessFu = {
this._handleMessageManager(mm);
break;
}
case 'TabClose':
{
let mm = Utils.getMessageManager(aEvent.target);
let mmIndex = this._processedMessageManagers.indexOf(mm);
if (mmIndex > -1) {
this._removeMessageListeners(mm);
this._processedMessageManagers.splice(mmIndex, 1);
}
break;
}
case 'TabSelect':
{
if (this._focused) {
@ -464,9 +479,20 @@ var Output = {
aJsonBounds.right - aJsonBounds.left,
aJsonBounds.bottom - aJsonBounds.top);
let vp = Utils.getViewport(Utils.win) || { zoom: 1.0, offsetY: 0 };
let browserOffset = aBrowser.getBoundingClientRect();
let root = Utils.win;
let offset = { left: -root.mozInnerScreenX, top: -root.mozInnerScreenY };
let scale = 1 / Utils.getPixelsPerCSSPixel(Utils.win);
return bounds.translate(browserOffset.left, browserOffset.top).
if (!aBrowser.contentWindow) {
// OOP browser, add offset of browser.
// The offset of the browser element in relation to its parent window.
let clientRect = aBrowser.getBoundingClientRect();
let win = aBrowser.ownerDocument.defaultView;
offset.left += clientRect.left + win.mozInnerScreenX;
offset.top += clientRect.top + win.mozInnerScreenY;
}
return bounds.scale(scale, scale).translate(offset.left, offset.top).
scale(vp.zoom, vp.zoom).expandToIntegers();
}
};

Просмотреть файл

@ -2,33 +2,58 @@
* 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/. */
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
'use strict';
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
Cu.import('resource://gre/modules/accessibility/Presentation.jsm');
Cu.import('resource://gre/modules/accessibility/TraversalRules.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Services',
'resource://gre/modules/Services.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
'resource://gre/modules/accessibility/Utils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
'resource://gre/modules/accessibility/Utils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Presentation',
'resource://gre/modules/accessibility/Presentation.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'TraversalRules',
'resource://gre/modules/accessibility/TraversalRules.jsm');
this.EXPORTED_SYMBOLS = ['EventManager'];
this.EventManager = {
this.EventManager = function EventManager(aContentScope) {
this.contentScope = aContentScope;
this.addEventListener = this.contentScope.addEventListener.bind(
this.contentScope);
this.removeEventListener = this.contentScope.removeEventListener.bind(
this.contentScope);
this.sendMsgFunc = this.contentScope.sendAsyncMessage.bind(
this.contentScope);
this.webProgress = this.contentScope.docShell.
QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebProgress);
};
this.EventManager.prototype = {
editState: {},
start: function start(aSendMsgFunc) {
start: function start() {
try {
if (!this._started) {
this.sendMsgFunc = aSendMsgFunc || function() {};
Logger.info('EventManager.start', Utils.MozBuildApp);
this._started = true;
Services.obs.addObserver(this, 'accessible-event', false);
}
AccessibilityEventObserver.addListener(this);
this.webProgress.addProgressListener(this,
(Ci.nsIWebProgress.NOTIFY_STATE_ALL |
Ci.nsIWebProgress.NOTIFY_LOCATION));
this.addEventListener('scroll', this, true);
this.addEventListener('resize', this, true);
// XXX: Ideally this would be an a11y event. Bug #742280.
this.addEventListener('DOMActivate', this, true);
}
this.present(Presentation.tabStateChanged(null, 'newtab'));
} catch (x) {
@ -37,13 +62,25 @@ this.EventManager = {
}
},
// XXX: Stop is not called when the tab is closed (|TabClose| event is too
// late). It is only called when the AccessFu is disabled explicitly.
stop: function stop() {
if (!this._started) {
return;
}
Logger.info('EventManager.stop', Utils.MozBuildApp);
Services.obs.removeObserver(this, 'accessible-event');
this._started = false;
AccessibilityEventObserver.removeListener(this);
try {
this.webProgress.removeProgressListener(this);
this.removeEventListener('scroll', this, true);
this.removeEventListener('resize', this, true);
// XXX: Ideally this would be an a11y event. Bug #742280.
this.removeEventListener('DOMActivate', this, true);
} catch (x) {
// contentScope is dead.
} finally {
this._started = false;
}
},
handleEvent: function handleEvent(aEvent) {
@ -85,21 +122,6 @@ this.EventManager = {
}
},
observe: function observe(aSubject, aTopic, aData) {
switch (aTopic) {
case 'accessible-event':
var event;
try {
event = aSubject.QueryInterface(Ci.nsIAccessibleEvent);
this.handleAccEvent(event);
} catch (x) {
Logger.error('Error handing accessible event');
Logger.logException(x);
return;
}
}
},
handleAccEvent: function handleAccEvent(aEvent) {
if (Logger.logLevel >= Logger.DEBUG)
Logger.debug('A11yEvent', Logger.eventToString(aEvent),
@ -116,7 +138,7 @@ this.EventManager = {
case Ci.nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED:
{
let pivot = aEvent.accessible.
QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor;
QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
let position = pivot.position;
if (position.role == Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME)
break;
@ -227,11 +249,6 @@ this.EventManager = {
this.sendMsgFunc("AccessFu:Present", aPresentationData);
},
presentVirtualCursorPosition: function presentVirtualCursorPosition(aVirtualCursor) {
this.present(Presentation.pivotChanged(aVirtualCursor.position, null,
Ci.nsIAccessiblePivot.REASON_NONE));
},
onStateChange: function onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
let tabstate = '';
@ -269,3 +286,145 @@ this.EventManager = {
Ci.nsISupports,
Ci.nsIObserver])
};
const AccessibilityEventObserver = {
/**
* A WeakMap containing [content, EventManager] pairs.
*/
eventManagers: new WeakMap(),
/**
* A total number of registered eventManagers.
*/
listenerCount: 0,
/**
* An indicator of an active 'accessible-event' observer.
*/
started: false,
/**
* Start an AccessibilityEventObserver.
*/
start: function start() {
if (this.started || this.listenerCount === 0) {
return;
}
Services.obs.addObserver(this, 'accessible-event', false);
this.started = true;
},
/**
* Stop an AccessibilityEventObserver.
*/
stop: function stop() {
if (!this.started) {
return;
}
Services.obs.removeObserver(this, 'accessible-event');
// Clean up all registered event managers.
this.eventManagers.clear();
this.listenerCount = 0;
this.started = false;
},
/**
* Register an EventManager and start listening to the
* 'accessible-event' messages.
*
* @param aEventManager EventManager
* An EventManager object that was loaded into the specific content.
*/
addListener: function addListener(aEventManager) {
let content = aEventManager.contentScope.content;
if (!this.eventManagers.has(content)) {
this.listenerCount++;
}
this.eventManagers.set(content, aEventManager);
// Since at least one EventManager was registered, start listening.
Logger.debug('AccessibilityEventObserver.addListener. Total:',
this.listenerCount);
this.start();
},
/**
* Unregister an EventManager and, optionally, stop listening to the
* 'accessible-event' messages.
*
* @param aEventManager EventManager
* An EventManager object that was stopped in the specific content.
*/
removeListener: function removeListener(aEventManager) {
let content = aEventManager.contentScope.content;
if (!this.eventManagers.delete(content)) {
return;
}
this.listenerCount--;
Logger.debug('AccessibilityEventObserver.removeListener. Total:',
this.listenerCount);
if (this.listenerCount === 0) {
// If there are no EventManagers registered at the moment, stop listening
// to the 'accessible-event' messages.
this.stop();
}
},
/**
* Lookup an EventManager for a specific content. If the EventManager is not
* found, walk up the hierarchy of parent windows.
* @param content Window
* A content Window used to lookup the corresponding EventManager.
*/
getListener: function getListener(content) {
let eventManager = this.eventManagers.get(content);
if (eventManager) {
return eventManager;
}
let parent = content.parent;
if (parent === content) {
// There is no parent or the parent is of a different type.
return null;
}
return this.getListener(parent);
},
/**
* Handle the 'accessible-event' message.
*/
observe: function observe(aSubject, aTopic, aData) {
if (aTopic !== 'accessible-event') {
return;
}
let event = aSubject.QueryInterface(Ci.nsIAccessibleEvent);
if (!event.accessibleDocument) {
Logger.warning(
'AccessibilityEventObserver.observe: no accessible document:',
Logger.eventToString(event), "accessible:",
Logger.accessibleToString(event.accessible));
return;
}
let content = event.accessibleDocument.window;
// Match the content window to its EventManager.
let eventManager = this.getListener(content);
if (!eventManager || !eventManager._started) {
if (Utils.MozBuildApp === 'browser' &&
!(content instanceof Ci.nsIDOMChromeWindow)) {
Logger.warning(
'AccessibilityEventObserver.observe: ignored event:',
Logger.eventToString(event), "accessible:",
Logger.accessibleToString(event.accessible), "document:",
Logger.accessibleToString(event.accessibleDocument));
}
return;
}
try {
eventManager.handleAccEvent(event);
} catch (x) {
Logger.error('Error handing accessible event');
Logger.logException(x);
} finally {
return;
}
}
};

Просмотреть файл

@ -31,9 +31,9 @@ BaseTraversalRule.prototype = {
match: function BaseTraversalRule_match(aAccessible)
{
if (aAccessible.role == Ci.nsIAccessibleRole.ROLE_INTERNAL_FRAME) {
return (aAccessible.childCount) ?
Ci.nsIAccessibleTraversalRule.FILTER_IGNORE :
Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
return (Utils.getMessageManager(aAccessible.DOMNode)) ?
Ci.nsIAccessibleTraversalRule.FILTER_MATCH :
Ci.nsIAccessibleTraversalRule.FILTER_IGNORE;
}
if (this._matchFunc)

Просмотреть файл

@ -37,6 +37,9 @@ this.Utils = {
},
get win() {
if (!this._win) {
return null;
}
return this._win.get();
},
@ -90,6 +93,9 @@ this.Utils = {
},
get BrowserApp() {
if (!this.win) {
return null;
}
switch (this.MozBuildApp) {
case 'mobile/android':
return this.win.BrowserApp;
@ -103,6 +109,9 @@ this.Utils = {
},
get CurrentBrowser() {
if (!this.BrowserApp) {
return null;
}
if (this.MozBuildApp == 'b2g')
return this.BrowserApp.contentBrowser;
return this.BrowserApp.selectedBrowser;
@ -122,15 +131,27 @@ this.Utils = {
let document = this.CurrentContentDoc;
if (document) {
let remoteframes = document.querySelectorAll('iframe[remote=true]');
let remoteframes = document.querySelectorAll('iframe');
for (let i = 0; i < remoteframes.length; ++i) {
let mm = this.getMessageManager(remoteframes[i]);
if (mm) {
messageManagers.push(mm);
}
}
for (let i = 0; i < remoteframes.length; ++i)
messageManagers.push(this.getMessageManager(remoteframes[i]));
}
return messageManagers;
},
get isContentProcess() {
delete this.isContentProcess;
this.isContentProcess =
Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
return this.isContentProcess;
},
getMessageManager: function getMessageManager(aBrowser) {
try {
return aBrowser.QueryInterface(Ci.nsIFrameLoaderOwner).
@ -164,15 +185,12 @@ this.Utils = {
let doc = (aDocument instanceof Ci.nsIAccessible) ? aDocument :
this.AccRetrieval.getAccessibleFor(aDocument);
while (doc) {
try {
return doc.QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor;
} catch (x) {
doc = doc.parentDocument;
}
}
return doc.QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
},
return null;
getPixelsPerCSSPixel: function getPixelsPerCSSPixel(aWindow) {
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils).screenPixelsPerCSSPixel;
}
};
@ -228,9 +246,10 @@ this.Logger = {
logException: function logException(aException) {
try {
this.error(
aException.message,
'(' + aException.fileName + ':' + aException.lineNumber + ')');
let args = [aException.message];
args.push.apply(args, aException.stack ? ['\n', aException.stack] :
['(' + aException.fileName + ':' + aException.lineNumber + ')']);
this.error.apply(this, args);
} catch (x) {
this.error(x);
}
@ -392,15 +411,7 @@ PivotContext.prototype = {
this._accessible.getBounds(objX, objY, objW, objH);
// XXX: OOP content provides a screen offset of 0, while in-process provides a real
// offset. Removing the offset and using content-relative coords normalizes this.
let docX = {}, docY = {};
let docRoot = this._accessible.rootDocument.
QueryInterface(Ci.nsIAccessible);
docRoot.getBounds(docX, docY, {}, {});
this._bounds = new Rect(objX.value, objY.value, objW.value, objH.value).
translate(-docX.value, -docY.value);
this._bounds = new Rect(objX.value, objY.value, objW.value, objH.value);
}
return this._bounds.clone();

Просмотреть файл

@ -2,18 +2,25 @@
* 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/. */
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
var Cr = Components.results;
let Ci = Components.interfaces;
let Cu = Components.utils;
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
Cu.import('resource://gre/modules/accessibility/EventManager.jsm');
Cu.import('resource://gre/modules/accessibility/TraversalRules.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Logger',
'resource://gre/modules/accessibility/Utils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Presentation',
'resource://gre/modules/accessibility/Presentation.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'TraversalRules',
'resource://gre/modules/accessibility/TraversalRules.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'Utils',
'resource://gre/modules/accessibility/Utils.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'EventManager',
'resource://gre/modules/accessibility/EventManager.jsm');
Logger.debug('content-script.js');
let eventManager = null;
function virtualCursorControl(aMessage) {
if (Logger.logLevel >= Logger.DEBUG)
Logger.debug(aMessage.name, JSON.stringify(aMessage.json));
@ -52,14 +59,21 @@ function virtualCursorControl(aMessage) {
}
break;
case 'moveToPoint':
moved = vc.moveToPoint(rule, details.x, details.y, true);
if (!this._ppcp) {
this._ppcp = Utils.getPixelsPerCSSPixel(content);
}
moved = vc.moveToPoint(rule,
details.x * this._ppcp, details.y * this._ppcp,
true);
break;
case 'whereIsIt':
if (!forwardMessage(vc, aMessage)) {
if (!vc.position && aMessage.json.move)
vc.moveFirst(TraversalRules.Simple);
else
EventManager.presentVirtualCursorPosition(vc);
else {
sendAsyncMessage('AccessFu:Present', Presentation.pivotChanged(
vc.position, null, Ci.nsIAccessiblePivot.REASON_NONE));
}
}
break;
@ -88,10 +102,12 @@ function forwardMessage(aVirtualCursor, aMessage) {
let mm = Utils.getMessageManager(acc.DOMNode);
mm.addMessageListener(aMessage.name, virtualCursorControl);
aMessage.json.origin = 'parent';
// XXX: OOP content's screen offset is 0,
// so we remove the real screen offset here.
aMessage.json.x -= content.mozInnerScreenX;
aMessage.json.y -= content.mozInnerScreenY;
if (Utils.isContentProcess) {
// XXX: OOP content's screen offset is 0,
// so we remove the real screen offset here.
aMessage.json.x -= content.mozInnerScreenX;
aMessage.json.y -= content.mozInnerScreenY;
}
mm.sendAsyncMessage(aMessage.name, aMessage.json);
return true;
}
@ -124,14 +140,14 @@ function activateCurrent(aMessage) {
let node = aAccessible.DOMNode || aAccessible.parent.DOMNode;
function dispatchMouseEvent(aEventType) {
let evt = content.document.createEvent("MouseEvents");
let evt = content.document.createEvent('MouseEvents');
evt.initMouseEvent(aEventType, true, true, content,
x, y, 0, 0, 0, false, false, false, false, 0, null);
node.dispatchEvent(evt);
}
dispatchMouseEvent("mousedown");
dispatchMouseEvent("mouseup");
dispatchMouseEvent('mousedown');
dispatchMouseEvent('mouseup');
}
}
@ -234,20 +250,10 @@ addMessageListener(
addMessageListener('AccessFu:Activate', activateCurrent);
addMessageListener('AccessFu:Scroll', scroll);
EventManager.start(
function sendMessage(aName, aDetails) {
sendAsyncMessage(aName, aDetails);
});
docShell.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebProgress).
addProgressListener(EventManager,
(Ci.nsIWebProgress.NOTIFY_STATE_ALL |
Ci.nsIWebProgress.NOTIFY_LOCATION));
addEventListener('scroll', EventManager, true);
addEventListener('resize', EventManager, true);
// XXX: Ideally this would be an a11y event. Bug #742280.
addEventListener('DOMActivate', EventManager, true);
if (!eventManager) {
eventManager = new EventManager(this);
}
eventManager.start();
});
addMessageListener(
@ -259,15 +265,7 @@ addMessageListener(
removeMessageListener('AccessFu:Activate', activateCurrent);
removeMessageListener('AccessFu:Scroll', scroll);
EventManager.stop();
docShell.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIWebProgress).
removeProgressListener(EventManager);
removeEventListener('scroll', EventManager, true);
removeEventListener('resize', EventManager, true);
// XXX: Ideally this would be an a11y event. Bug #742280.
removeEventListener('DOMActivate', EventManager, true);
eventManager.stop();
});
sendAsyncMessage('AccessFu:Ready');

Просмотреть файл

@ -38,21 +38,23 @@
// Firs listen for initial 'EventManager.start' and disable AccessFu.
var initialStartListener = makeEventManagerListener("EventManager.start",
function () {
ok(EventManager._started, "EventManager was started.");
ok(true, "EventManager was started.");
Services.console.registerListener(stopListener);
AccessFu._disable();
});
// Listen for 'EventManager.stop' and enable AccessFu again.
var stopListener = makeEventManagerListener("EventManager.stop",
function () {
isnot(EventManager._started, true, "EventManager was stopped.");
ok(true, "EventManager was stopped.");
isnot(AccessFu._enabled, true, "AccessFu was disabled.");
Services.console.registerListener(finalStartListener);
AccessFu._enable();
});
// Make sure EventManager is started again.
var finalStartListener = makeEventManagerListener("EventManager.start",
function () {
ok(EventManager._started, "EventManager was started again.");
ok(true, "EventManager was started again.");
ok(AccessFu._enabled, "AccessFu was enabled again.");
AccessFuTest.finish();
});

Просмотреть файл

@ -3507,9 +3507,11 @@ let SessionStoreInternal = {
var _this = this;
aWindow.setTimeout(function() {
_this.restoreDimensions.apply(_this, [aWindow, aWinData.width || 0,
aWinData.height || 0, "screenX" in aWinData ? aWinData.screenX : NaN,
"screenY" in aWinData ? aWinData.screenY : NaN,
_this.restoreDimensions.apply(_this, [aWindow,
+aWinData.width || 0,
+aWinData.height || 0,
"screenX" in aWinData ? +aWinData.screenX : NaN,
"screenY" in aWinData ? +aWinData.screenY : NaN,
aWinData.sizemode || "", aWinData.sidebar || ""]);
}, 0);
},

Просмотреть файл

@ -148,6 +148,7 @@ _BROWSER_FILES = \
browser_tabview_snapping.js \
browser_tabview_startup_transitions.js \
browser_tabview_undo_group.js \
browser_tabview_bug610242.js \
dummy_page.html \
head.js \
search1.html \

Просмотреть файл

@ -3700,7 +3700,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
}
#social-provider-button {
-moz-image-region: rect(0, 16px, 16px, 0);
list-style-image: url(chrome://browser/skin/social/services-16.png);
}
@ -3708,6 +3707,9 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
#social-provider-button {
list-style-image: url(chrome://browser/skin/social/services-16@2x.png);
}
#social-provider-button > .toolbarbutton-icon {
width: 16px;
}
}
#social-provider-button > .toolbarbutton-menu-dropmarker {

Просмотреть файл

@ -11,7 +11,6 @@ class TestBuildDict(unittest.TestCase):
"""
Test that missing required values raises.
"""
self.assertRaises(Exception, build_dict, {})
self.assertRaises(Exception, build_dict, {'OS_TARGET':'foo'})
self.assertRaises(Exception, build_dict, {'TARGET_CPU':'foo'})
self.assertRaises(Exception, build_dict, {'MOZ_WIDGET_TOOLKIT':'foo'})

Просмотреть файл

@ -15,35 +15,38 @@ import re
import sys
import json
import buildconfig
def build_dict(env=os.environ):
def build_dict(env=None):
"""
Build a dict containing data about the build configuration from
the environment.
"""
d = {}
substs = env or buildconfig.substs
env = env or os.environ
# Check that all required variables are present first.
required = ["TARGET_CPU", "OS_TARGET", "MOZ_WIDGET_TOOLKIT"]
missing = [r for r in required if r not in env]
missing = [r for r in required if r not in substs]
if missing:
raise Exception("Missing required environment variables: %s" %
', '.join(missing))
d = {}
d['topsrcdir'] = substs.get('TOPSRCDIR', buildconfig.topsrcdir)
if 'MOZCONFIG' in env:
mozconfig = env["MOZCONFIG"]
if 'TOPSRCDIR' in env:
mozconfig = os.path.join(env["TOPSRCDIR"], mozconfig)
d['mozconfig'] = os.path.normpath(mozconfig)
if 'TOPSRCDIR' in env:
d["topsrcdir"] = env["TOPSRCDIR"]
# os
o = env["OS_TARGET"]
o = substs["OS_TARGET"]
known_os = {"Linux": "linux",
"WINNT": "win",
"Darwin": "mac",
"Android": "b2g" if env["MOZ_WIDGET_TOOLKIT"] == "gonk" else "android"}
"Android": "b2g" if substs["MOZ_WIDGET_TOOLKIT"] == "gonk" else "android"}
if o in known_os:
d["os"] = known_os[o]
else:
@ -51,16 +54,16 @@ def build_dict(env=os.environ):
d["os"] = o.lower()
# Widget toolkit, just pass the value directly through.
d["toolkit"] = env["MOZ_WIDGET_TOOLKIT"]
d["toolkit"] = substs["MOZ_WIDGET_TOOLKIT"]
# Application name
if 'MOZ_APP_NAME' in env:
d["appname"] = env["MOZ_APP_NAME"]
if 'MOZ_APP_NAME' in substs:
d["appname"] = substs["MOZ_APP_NAME"]
# processor
p = env["TARGET_CPU"]
p = substs["TARGET_CPU"]
# for universal mac builds, put in a special value
if d["os"] == "mac" and "UNIVERSAL_BINARY" in env and env["UNIVERSAL_BINARY"] == "1":
if d["os"] == "mac" and "UNIVERSAL_BINARY" in substs and substs["UNIVERSAL_BINARY"] == "1":
p = "universal-x86-x86_64"
else:
# do some slight massaging for some values
@ -78,24 +81,22 @@ def build_dict(env=os.environ):
d["bits"] = 32
# other CPUs will wind up with unknown bits
# debug
d["debug"] = 'MOZ_DEBUG' in env and env['MOZ_DEBUG'] == '1'
d['debug'] = substs.get('MOZ_DEBUG') == '1'
d['crashreporter'] = substs.get('MOZ_CRASHREPORTER') == '1'
d['asan'] = substs.get('MOZ_ASAN') == '1'
d['tests_enabled'] = substs.get('ENABLE_TESTS') == "1"
d['bin_suffix'] = substs.get('BIN_SUFFIX', '')
# crashreporter
d["crashreporter"] = 'MOZ_CRASHREPORTER' in env and env['MOZ_CRASHREPORTER'] == '1'
# asan
d["asan"] = 'MOZ_ASAN' in env and env['MOZ_ASAN'] == '1'
return d
def write_json(file, env=os.environ):
def write_json(file, env=None):
"""
Write JSON data about the configuration specified in |env|
to |file|, which may be a filename or file-like object.
See build_dict for information about what environment variables are used,
and what keys are produced.
"""
build_conf = build_dict(env)
build_conf = build_dict(env=env)
if isinstance(file, basestring):
with open(file, "w") as f:
json.dump(build_conf, f)

Просмотреть файл

@ -4183,7 +4183,6 @@ ENABLE_SYSTEM_EXTENSION_DIRS=1
MOZ_BRANDING_DIRECTORY=
MOZ_OFFICIAL_BRANDING=
MOZ_FEEDS=1
MOZ_FLEXBOX=1
MOZ_WEBAPP_RUNTIME=
MOZ_JSDEBUGGER=1
MOZ_AUTH_EXTENSION=1
@ -6204,13 +6203,6 @@ if test -n "$MOZ_USE_NATIVE_POPUP_WINDOWS"; then
AC_DEFINE(MOZ_USE_NATIVE_POPUP_WINDOWS)
fi
dnl ========================================================
dnl CSS3 Flexbox Support
dnl ========================================================
if test -n "$MOZ_FLEXBOX"; then
AC_DEFINE(MOZ_FLEXBOX)
fi
dnl ========================================================
dnl Build Freetype in the tree
dnl ========================================================
@ -8812,7 +8804,6 @@ AC_SUBST(MOZ_NATIVE_JPEG)
AC_SUBST(MOZ_NATIVE_PNG)
AC_SUBST(MOZ_NATIVE_BZ2)
AC_SUBST(MOZ_FLEXBOX)
AC_SUBST(MOZ_JPEG_CFLAGS)
AC_SUBST(MOZ_JPEG_LIBS)
AC_SUBST(MOZ_BZ2_CFLAGS)

Просмотреть файл

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/Text.h"
#include "nsTextNode.h"
namespace mozilla {
namespace dom {
@ -19,5 +20,18 @@ Text::SplitText(uint32_t aOffset, ErrorResult& rv)
return newChild.forget().downcast<Text>();
}
/* static */ already_AddRefed<Text>
Text::Constructor(const GlobalObject& aGlobal, const nsAString& aData,
ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
if (!window || !window->GetDoc()) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
return window->GetDoc()->CreateTextNode(aData);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -27,6 +27,10 @@ public:
{
rv = GetWholeText(aWholeText);
}
static already_AddRefed<Text>
Constructor(const GlobalObject& aGlobal, const nsAString& aData,
ErrorResult& aRv);
};
} // namespace dom

Просмотреть файл

@ -2346,6 +2346,16 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
}
#endif
#ifdef DEBUG
{
uint32_t appId;
nsresult rv = NodePrincipal()->GetAppId(&appId);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Document should never have UNKNOWN_APP_ID");
}
#endif
MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED,
"Bad readyState");
SetReadyStateInternal(READYSTATE_LOADING);

Просмотреть файл

@ -3077,3 +3077,15 @@ nsRange::AutoInvalidateSelection::~AutoInvalidateSelection()
::InvalidateAllFrames(commonAncestor);
}
}
/* static */ already_AddRefed<nsRange>
nsRange::Constructor(const dom::GlobalObject& aGlobal, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
if (!window || !window->GetDoc()) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
return window->GetDoc()->CreateRange(aRv);
}

Просмотреть файл

@ -164,6 +164,10 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
// WebIDL
static already_AddRefed<nsRange>
Constructor(const mozilla::dom::GlobalObject& global,
mozilla::ErrorResult& aRv);
bool Collapsed() const
{
return mIsPositioned && mStartParent == mEndParent &&

Просмотреть файл

@ -626,6 +626,8 @@ MOCHITEST_FILES_C= \
badMessageEvent2.eventsource^headers^ \
test_object.html \
test_bug869006.html \
test_bug868999.html \
test_bug869000.html \
$(NULL)
# OOP tests don't work on Windows (bug 763081) or native-fennec

Просмотреть файл

@ -0,0 +1,39 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=868999
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 868999</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=868999">Mozilla Bug 869006</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 868999 **/
var r = new Range();
ok(r, "Range has been created");
var doc = document.implementation.createDocument("", "", null);
var h1 = doc.createElement('h1');
doc.appendChild(h1);
var t = doc.createTextNode('Hello world');
h1.appendChild(t);
r.selectNodeContents(doc);
is(r.toString(), "Hello world", "new Range() works!");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -0,0 +1,37 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=869000
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 869000</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=869000">Mozilla Bug 869006</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 869000 **/
var c = new Text();
ok(c, "Text has been created without content");
is(c.data, "", "Text.data is ok");
c = new Text('foo');
ok(c, "Text has been created");
is(c.data, "foo", "Text.data is ok");
document.getElementById('display').appendChild(c);
ok(true, "Text has been added to the document");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -158,7 +158,7 @@ WebGLContext::WebGLContext()
mScissorTestEnabled = 0;
mDitherEnabled = 1;
// initialize some GL values: we're going to get them from the GL and use them as the sizes of arrays,
// so in case glGetIntegerv leaves them uninitialized because of a GL bug, we would have very weird crashes.
mGLMaxVertexAttribs = 0;
@ -198,6 +198,8 @@ WebGLContext::WebGLContext()
mIsScreenCleared = false;
mDisableFragHighP = false;
mDrawCallsSinceLastFlush = 0;
}
WebGLContext::~WebGLContext()
@ -520,12 +522,12 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// try the default provider, whatever that is
if (!gl && useOpenGL) {
GLContext::ContextFlags flag = useMesaLlvmPipe
GLContext::ContextFlags flag = useMesaLlvmPipe
? GLContext::ContextFlagsMesaLLVMPipe
: GLContext::ContextFlagsNone;
gl = gl::GLContextProvider::CreateOffscreen(size, caps, flag);
if (gl && !InitAndValidateGL()) {
GenerateWarning("Error during %s initialization",
GenerateWarning("Error during %s initialization",
useMesaLlvmPipe ? "Mesa LLVMpipe" : "OpenGL");
return NS_ERROR_FAILURE;
}
@ -806,6 +808,7 @@ public:
// Present our screenbuffer, if needed.
context->PresentScreenBuffer();
context->mDrawCallsSinceLastFlush = 0;
}
/** DidTransactionCallback gets called by the Layers code everytime the WebGL canvas gets composite,
@ -975,9 +978,9 @@ bool WebGLContext::IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) con
case WEBGL_compressed_texture_pvrtc:
return gl->IsExtensionSupported(GLContext::IMG_texture_compression_pvrtc);
case WEBGL_depth_texture:
if (gl->IsGLES2() &&
if (gl->IsGLES2() &&
gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil) &&
gl->IsExtensionSupported(GLContext::OES_depth_texture))
gl->IsExtensionSupported(GLContext::OES_depth_texture))
{
return true;
}
@ -1389,7 +1392,7 @@ WebGLContext::MaybeRestoreContext()
resetStatus = GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB;
}
}
if (resetStatus != GLContext::CONTEXT_NO_ERROR) {
// It's already lost, but clean up after it and signal to JS that it is
// lost.

Просмотреть файл

@ -1128,6 +1128,10 @@ protected:
ContextStatus mContextStatus;
bool mContextLostErrorSet;
// Used for some hardware (particularly Tegra 2 and 4) that likes to
// be Flushed while doing hundreds of draw calls.
int mDrawCallsSinceLastFlush;
int mAlreadyGeneratedWarnings;
bool mAlreadyWarnedAboutFakeVertexAttrib0;

Просмотреть файл

@ -38,6 +38,9 @@ using namespace mozilla::dom;
static bool BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize);
static WebGLenum InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2);
// For a Tegra workaround.
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
//
// WebGL API
//
@ -1477,6 +1480,17 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
mShouldPresent = true;
mIsScreenCleared = false;
}
if (gl->WorkAroundDriverBugs()) {
if (gl->Renderer() == gl::GLContext::RendererTegra) {
mDrawCallsSinceLastFlush++;
if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
gl->fFlush();
mDrawCallsSinceLastFlush = 0;
}
}
}
}
void
@ -1576,6 +1590,17 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
mShouldPresent = true;
mIsScreenCleared = false;
}
if (gl->WorkAroundDriverBugs()) {
if (gl->Renderer() == gl::GLContext::RendererTegra) {
mDrawCallsSinceLastFlush++;
if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
gl->fFlush();
mDrawCallsSinceLastFlush = 0;
}
}
}
}
void

Просмотреть файл

@ -448,7 +448,7 @@ public:
bool Muted() const
{
return mMuted;
return mMuted & MUTED_BY_CONTENT;
}
// XPCOM SetMuted() is OK
@ -786,9 +786,9 @@ protected:
void ProcessMediaFragmentURI();
/**
* Mute or unmute the audio, without changing the value that |muted| reports.
* Mute or unmute the audio and change the value that the |muted| map.
*/
void SetMutedInternal(bool aMuted);
void SetMutedInternal(uint32_t aMuted);
/**
* Suspend (if aPauseForInactiveDocument) or resume element playback and
@ -1009,8 +1009,13 @@ protected:
// 'Pause' method, or playback not yet having started.
WakeLockBoolWrapper mPaused;
// True if the sound is muted.
bool mMuted;
enum MutedReasons {
MUTED_BY_CONTENT = 0x01,
MUTED_BY_INVALID_PLAYBACK_RATE = 0x02,
MUTED_BY_AUDIO_CHANNEL = 0x04
};
uint32_t mMuted;
// True if the sound is being captured.
bool mAudioCaptured;
@ -1093,9 +1098,6 @@ protected:
// Audio Channel Type.
AudioChannelType mAudioChannelType;
// The audiochannel has been suspended.
bool mChannelSuspended;
// Is this media element playing?
bool mPlayingThroughTheAudioChannel;

Просмотреть файл

@ -129,7 +129,7 @@ HTMLAudioElement::MozSetup(uint32_t aChannels, uint32_t aRate, ErrorResult& aRv)
}
MetadataLoaded(aChannels, aRate, true, false, nullptr);
mAudioStream->SetVolume(mVolume);
mAudioStream->SetVolume(mMuted ? 0.0 : mVolume);
}
uint32_t
@ -248,11 +248,12 @@ HTMLAudioElement::CanPlayChanged(bool canPlay)
return HTMLMediaElement::CanPlayChanged(canPlay);
}
#ifdef MOZ_B2G
if (mChannelSuspended == !canPlay) {
return NS_OK;
if (canPlay) {
SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_CHANNEL);
} else {
SetMutedInternal(mMuted | MUTED_BY_AUDIO_CHANNEL);
}
mChannelSuspended = !canPlay;
SetMutedInternal(mChannelSuspended);
#endif
return NS_OK;
}
@ -299,6 +300,7 @@ HTMLAudioElement::UpdateAudioChannelPlayingState()
if (mPlayingThroughTheAudioChannel) {
bool canPlay;
mAudioChannelAgent->StartPlaying(&canPlay);
CanPlayChanged(canPlay);
} else {
mAudioChannelAgent->StopPlaying();
mAudioChannelAgent = nullptr;

Просмотреть файл

@ -1506,15 +1506,8 @@ HTMLMediaElement::SetVolume(double aVolume, ErrorResult& aRv)
mVolume = aVolume;
if (!mMuted) {
if (mDecoder) {
mDecoder->SetVolume(mVolume);
} else if (mAudioStream) {
mAudioStream->SetVolume(mVolume);
} else if (mSrcStream) {
GetSrcMediaStream()->SetAudioOutputVolume(this, float(mVolume));
}
}
// Here we want just to update the volume.
SetMutedInternal(mMuted);
DispatchAsyncEvent(NS_LITERAL_STRING("volumechange"));
}
@ -1683,9 +1676,16 @@ NS_IMETHODIMP HTMLMediaElement::GetMuted(bool* aMuted)
return NS_OK;
}
void HTMLMediaElement::SetMutedInternal(bool aMuted)
void HTMLMediaElement::SetMutedInternal(uint32_t aMuted)
{
float effectiveVolume = aMuted ? 0.0f : float(mVolume);
uint32_t oldMuted = mMuted;
mMuted = aMuted;
if (!!aMuted == !!oldMuted) {
return;
}
float effectiveVolume = mMuted ? 0.0f : float(mVolume);
if (mDecoder) {
mDecoder->SetVolume(effectiveVolume);
@ -1698,11 +1698,11 @@ void HTMLMediaElement::SetMutedInternal(bool aMuted)
NS_IMETHODIMP HTMLMediaElement::SetMuted(bool aMuted)
{
if (aMuted == mMuted)
return NS_OK;
mMuted = aMuted;
SetMutedInternal(aMuted);
if (aMuted) {
SetMutedInternal(mMuted | MUTED_BY_CONTENT);
} else {
SetMutedInternal(mMuted & ~MUTED_BY_CONTENT);
}
DispatchAsyncEvent(NS_LITERAL_STRING("volumechange"));
return NS_OK;
@ -1910,7 +1910,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo)
mAutoplaying(true),
mAutoplayEnabled(true),
mPaused(true),
mMuted(false),
mMuted(0),
mAudioCaptured(false),
mPlayingBeforeSeek(false),
mPausedForInactiveDocumentOrChannel(false),
@ -1932,7 +1932,6 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo)
mHasAudio(false),
mDownloadSuspendedByCache(false),
mAudioChannelType(AUDIO_CHANNEL_NORMAL),
mChannelSuspended(false),
mPlayingThroughTheAudioChannel(false)
{
#ifdef PR_LOGGING
@ -2238,8 +2237,9 @@ bool HTMLMediaElement::CheckAudioChannelPermissions(const nsAString& aString)
void HTMLMediaElement::DoneCreatingElement()
{
if (HasAttr(kNameSpaceID_None, nsGkAtoms::muted))
mMuted = true;
if (HasAttr(kNameSpaceID_None, nsGkAtoms::muted)) {
mMuted |= MUTED_BY_CONTENT;
}
}
bool HTMLMediaElement::IsHTMLFocusable(bool aWithMouse,
@ -3067,7 +3067,8 @@ bool HTMLMediaElement::CanActivateAutoplay()
// For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
// this element itself might be blocking the stream from making progress by
// being paused.
return mAutoplaying &&
return !mPausedForInactiveDocumentOrChannel &&
mAutoplaying &&
mPaused &&
(mDownloadSuspendedByCache ||
(mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
@ -3278,13 +3279,14 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
{
nsIDocument* ownerDoc = OwnerDoc();
// SetVisibilityState will update mChannelSuspended via the CanPlayChanged callback.
// SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the
// CanPlayChanged callback.
if (UseAudioChannelService() && mPlayingThroughTheAudioChannel &&
mAudioChannelAgent) {
mAudioChannelAgent->SetVisibilityState(!ownerDoc->Hidden());
}
bool suspendEvents = !ownerDoc->IsActive() || !ownerDoc->IsVisible();
bool pauseElement = suspendEvents || mChannelSuspended;
bool pauseElement = suspendEvents || (mMuted & MUTED_BY_AUDIO_CHANNEL);
SuspendOrResumeElement(pauseElement, suspendEvents);
@ -3661,14 +3663,12 @@ HTMLMediaElement::SetPlaybackRate(double aPlaybackRate, ErrorResult& aRv)
mPlaybackRate = ClampPlaybackRate(aPlaybackRate);
if (!mMuted) {
if (mPlaybackRate < 0 ||
mPlaybackRate > THRESHOLD_HIGH_PLAYBACKRATE_AUDIO ||
mPlaybackRate < THRESHOLD_LOW_PLAYBACKRATE_AUDIO) {
SetMutedInternal(true);
} else {
SetMutedInternal(false);
}
if (mPlaybackRate < 0 ||
mPlaybackRate > THRESHOLD_HIGH_PLAYBACKRATE_AUDIO ||
mPlaybackRate < THRESHOLD_LOW_PLAYBACKRATE_AUDIO) {
SetMutedInternal(mMuted | MUTED_BY_INVALID_PLAYBACK_RATE);
} else {
SetMutedInternal(mMuted & ~MUTED_BY_INVALID_PLAYBACK_RATE);
}
if (mDecoder) {
@ -3712,16 +3712,16 @@ nsresult HTMLMediaElement::UpdateChannelMuteState(bool aCanPlay)
return NS_OK;
}
// We have to mute this channel:
if (!aCanPlay && !mChannelSuspended) {
mChannelSuspended = true;
// We have to mute this channel.
if (!aCanPlay && !(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
SetMutedInternal(mMuted | MUTED_BY_AUDIO_CHANNEL);
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin"));
} else if (aCanPlay && mChannelSuspended) {
mChannelSuspended = false;
} else if (aCanPlay && (mMuted & MUTED_BY_AUDIO_CHANNEL)) {
SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_CHANNEL);
DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend"));
}
SuspendOrResumeElement(mChannelSuspended, false);
SuspendOrResumeElement(mMuted & MUTED_BY_AUDIO_CHANNEL, false);
return NS_OK;
}
@ -3753,7 +3753,7 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
if (mPlayingThroughTheAudioChannel) {
bool canPlay;
mAudioChannelAgent->StartPlaying(&canPlay);
mPaused.SetCanPlay(canPlay);
CanPlayChanged(canPlay);
} else {
mAudioChannelAgent->StopPlaying();
mAudioChannelAgent = nullptr;

Просмотреть файл

@ -19,11 +19,11 @@
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ScriptProcessorNode, AudioNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptProcessorNode)
if (tmp->Context()) {
tmp->Context()->UnregisterScriptProcessorNode(tmp);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(AudioNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ScriptProcessorNode, AudioNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

Просмотреть файл

@ -48,6 +48,8 @@ WMFReader::WMFReader(AbstractMediaDecoder* aDecoder)
mVideoWidth(0),
mVideoHeight(0),
mVideoStride(0),
mAudioFrameSum(0),
mAudioFrameOffset(0),
mHasAudio(false),
mHasVideo(false),
mCanSeek(false),
@ -605,6 +607,31 @@ GetSampleDuration(IMFSample* aSample)
return HNsToUsecs(duration);
}
HRESULT
HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames)
{
MOZ_ASSERT(aOutFrames);
const int64_t HNS_PER_S = USECS_PER_S * 10;
CheckedInt<int64_t> i = aHNs;
i *= aRate;
i /= HNS_PER_S;
NS_ENSURE_TRUE(i.isValid(), E_FAIL);
*aOutFrames = i.value();
return S_OK;
}
HRESULT
FramesToUsecs(int64_t aSamples, uint32_t aRate, int64_t* aOutUsecs)
{
MOZ_ASSERT(aOutUsecs);
CheckedInt<int64_t> i = aSamples;
i *= USECS_PER_S;
i /= aRate;
NS_ENSURE_TRUE(i.isValid(), E_FAIL);
*aOutUsecs = i.value();
return S_OK;
}
bool
WMFReader::DecodeAudioData()
{
@ -660,11 +687,32 @@ WMFReader::DecodeAudioData()
memcpy(pcmSamples.get(), data, currentLength);
buffer->Unlock();
int64_t offset = mDecoder->GetResource()->Tell();
int64_t timestamp = HNsToUsecs(timestampHns);
int64_t duration = GetSampleDuration(sample);
// We calculate the timestamp and the duration based on the number of audio
// frames we've already played. We don't trust the timestamp stored on the
// IMFSample, as sometimes it's wrong, possibly due to buggy encoders?
mAudioQueue.Push(new AudioData(offset,
// If this sample block comes after a discontinuity (i.e. a gap or seek)
// reset the frame counters, and capture the timestamp. Future timestamps
// will be offset from this block's timestamp.
UINT32 discontinuity = false;
sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity);
if (discontinuity) {
mAudioFrameSum = 0;
hr = HNsToFrames(timestampHns, mAudioRate, &mAudioFrameOffset);
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
}
int64_t timestamp;
hr = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate, &timestamp);
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
mAudioFrameSum += numFrames;
int64_t duration;
hr = FramesToUsecs(numFrames, mAudioRate, &duration);
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(),
timestamp,
duration,
numFrames,

Просмотреть файл

@ -91,6 +91,13 @@ private:
uint32_t mVideoHeight;
uint32_t mVideoStride;
// The offset, in audio frames, at which playback started since the
// last discontinuity.
int64_t mAudioFrameOffset;
// The number of audio frames that we've played since the last
// discontinuity.
int64_t mAudioFrameSum;
bool mHasAudio;
bool mHasVideo;
bool mCanSeek;

Просмотреть файл

@ -13,8 +13,8 @@ namespace mozilla {
namespace dom {
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGAnimatedRect)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedRect, mSVGElement)

Просмотреть файл

@ -92,6 +92,7 @@ MOCHITEST_FILES = \
test_viewport.html \
zoom-helper.svg \
test_zoom.xhtml \
test_bug872812.html \
$(NULL)
ifneq (android,$(MOZ_WIDGET_TOOLKIT))

Просмотреть файл

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=872812
-->
<head>
<title>Test for Bug 872812</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=872812">Mozilla Bug 872812</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<iframe id="svg" src="viewport-helper.svg"></iframe>
<pre id="test">
<script class="testbody" type="application/javascript">
var svg = document.createElementNS("http://www.w3.org/2000/svg", 'svg');
ok(svg, "SVG exists");
var a = document.createEvent('CustomEvent').initCustomEvent('', '', '', svg.viewBox);
ok(true, "CustomEvent exists and we are not crashed!");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -4983,10 +4983,11 @@ nsLocationSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
NS_IMETHODIMP
nsLocationSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, bool *_retval)
JSObject *obj, jsid aId, jsval *vp, bool *_retval)
{
// Shadowing protection. This will go away when nsLocation moves to the new
// bindings.
JS::Rooted<jsid> id(cx, aId);
if (wrapper->HasNativeMember(id)) {
JS_ReportError(cx, "Permission denied to shadow native property");
return NS_ERROR_FAILURE;

Просмотреть файл

@ -213,7 +213,7 @@ nsFocusManager::Observe(nsISupports *aSubject,
if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
nsDependentString data(aData);
if (data.EqualsLiteral("accessibility.browsewithcaret")) {
UpdateCaret(false, true, mFocusedContent);
UpdateCaretForCaretBrowsingMode();
}
else if (data.EqualsLiteral("accessibility.tabfocus_applies_to_xul")) {
nsIContent::sTabFocusModelAppliesToXUL =
@ -1994,6 +1994,12 @@ nsFocusManager::RaiseWindow(nsPIDOMWindow* aWindow)
#endif
}
void
nsFocusManager::UpdateCaretForCaretBrowsingMode()
{
UpdateCaret(false, true, mFocusedContent);
}
void
nsFocusManager::UpdateCaret(bool aMoveCaretToFocus,
bool aUpdateVisibility,
@ -2139,6 +2145,8 @@ nsFocusManager::SetCaretVisible(nsIPresShell* aPresShell,
// First, hide the caret to prevent attempting to show it in SetCaretDOMSelection
caret->SetCaretVisible(false);
// Caret must blink on non-editable elements
caret->SetIgnoreUserModify(true);
// Tell the caret which selection to use
caret->SetCaretDOMSelection(domSelection);
@ -2150,6 +2158,7 @@ nsFocusManager::SetCaretVisible(nsIPresShell* aPresShell,
if (!selCon)
return NS_ERROR_FAILURE;
selCon->SetCaretReadOnly(false);
selCon->SetCaretEnabled(aVisible);
caret->SetCaretVisible(aVisible);
}

Просмотреть файл

@ -84,6 +84,11 @@ public:
mMouseDownEventHandlingDocument = aDocument;
}
/**
* Update the caret with current mode (whether in caret browsing mode or not).
*/
void UpdateCaretForCaretBrowsingMode();
/**
* Returns the content node that would be focused if aWindow was in an
* active window. This will traverse down the frame hierarchy, starting at

Просмотреть файл

@ -6896,16 +6896,18 @@ nsGlobalWindow::PostMessageMoz(const JS::Value& aMessage,
class nsCloseEvent : public nsRunnable {
nsRefPtr<nsGlobalWindow> mWindow;
bool mIndirect;
nsCloseEvent(nsGlobalWindow *aWindow)
nsCloseEvent(nsGlobalWindow *aWindow, bool aIndirect)
: mWindow(aWindow)
, mIndirect(aIndirect)
{}
public:
static nsresult
PostCloseEvent(nsGlobalWindow* aWindow) {
nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow);
PostCloseEvent(nsGlobalWindow* aWindow, bool aIndirect) {
nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
nsresult rv = NS_DispatchToCurrentThread(ev);
if (NS_SUCCEEDED(rv))
aWindow->MaybeForgiveSpamCount();
@ -6913,8 +6915,12 @@ public:
}
NS_IMETHOD Run() {
if (mWindow)
if (mWindow) {
if (mIndirect) {
return PostCloseEvent(mWindow, false);
}
mWindow->ReallyCloseWindow();
}
return NS_OK;
}
@ -7047,23 +7053,29 @@ nsGlobalWindow::FinalClose()
// Flag that we were closed.
mIsClosed = true;
JSContext *cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
if (currentCX && currentCX == GetContextInternal()) {
currentCX->SetTerminationFunction(CloseWindow, this);
mHavePendingClose = true;
return NS_OK;
}
}
// We may have plugins on the page that have issued this close from their
// event loop and because we currently destroy the plugin window with
// frames, we crash. So, if we are called from Javascript, post an event
// to really close the window.
if (nsContentUtils::IsCallerChrome() ||
NS_FAILED(nsCloseEvent::PostCloseEvent(this))) {
// This stuff is non-sensical but incredibly fragile. The reasons for the
// behavior here don't make sense today and may not have ever made sense,
// but various bits of frontend code break when you change them. If you need
// to fix up this behavior, feel free to. It's a righteous task, but involves
// wrestling with various download manager tests, frontend code, and possible
// broken addons. The chrome tests in toolkit/mozapps/downloads are a good
// testing ground.
//
// Here are some quirks that the test suite depends on:
//
// * When chrome code executes |win|.close(), that close happens immediately,
// along with the accompanying "domwindowclosed" notification. But _only_ if
// |win|'s JSContext is not at the top of the stack. If it is, the close
// _must not_ happen immediately.
//
// * If |win|'s JSContext is at the top of the stack, we must complete _two_
// round-trips to the event loop before the call to ReallyCloseWindow. This
// allows setTimeout handlers that are set after FinalClose() is called to
// run before the window is torn down.
bool indirect = nsContentUtils::GetCurrentJSContext() ==
GetContextInternal()->GetNativeContext();
if ((!indirect && nsContentUtils::IsCallerChrome()) ||
NS_FAILED(nsCloseEvent::PostCloseEvent(this, indirect))) {
ReallyCloseWindow();
} else {
mHavePendingClose = true;
@ -9714,15 +9726,25 @@ nsGlobalWindow::GetParentInternal()
return NULL;
}
// static
void
nsGlobalWindow::CloseBlockScriptTerminationFunc(nsISupports *aRef)
nsGlobalWindow::UnblockScriptedClosing()
{
nsGlobalWindow* pwin = static_cast<nsGlobalWindow*>
(static_cast<nsPIDOMWindow*>(aRef));
pwin->mBlockScriptedClosingFlag = false;
mBlockScriptedClosingFlag = false;
}
class AutoUnblockScriptClosing
{
private:
nsRefPtr<nsGlobalWindow> mWin;
public:
AutoUnblockScriptClosing(nsGlobalWindow *aWin) : mWin(aWin) {};
~AutoUnblockScriptClosing()
{
void (nsGlobalWindow::*run)() = &nsGlobalWindow::UnblockScriptedClosing;
NS_DispatchToCurrentThread(NS_NewRunnableMethod(mWin, run));
};
};
nsresult
nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
const nsAString& aOptions, bool aDialog,
@ -9752,6 +9774,8 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
"Shouldn't have caller context when called noscript");
mozilla::Maybe<AutoUnblockScriptClosing> closeUnblocker;
// Calls to window.open from script should navigate.
MOZ_ASSERT(aCalledNoScript || aNavigate);
@ -9813,8 +9837,7 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
// so that whatever popup blocker UI the app has will be visible.
if (mContext == GetScriptContextFromJSContext(aJSCallerContext)) {
mBlockScriptedClosingFlag = true;
mContext->SetTerminationFunction(CloseBlockScriptTerminationFunc,
this);
closeUnblocker.construct(this);
}
}
@ -9918,22 +9941,6 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
return rv;
}
// static
void
nsGlobalWindow::CloseWindow(nsISupports *aWindow)
{
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aWindow));
nsGlobalWindow* globalWin =
static_cast<nsGlobalWindow *>
(static_cast<nsPIDOMWindow*>(win));
// Need to post an event for closing, otherwise window and
// presshell etc. may get destroyed while creating frames, bug 338897.
nsCloseEvent::PostCloseEvent(globalWin);
// else if OOM, better not to close. That might cause a crash.
}
//*****************************************************************************
// nsGlobalWindow: Timeout Functions
//*****************************************************************************

Просмотреть файл

@ -580,11 +580,12 @@ public:
nsresult Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData);
void UnblockScriptedClosing();
static void Init();
static void ShutDown();
static void CleanupCachedXBLHandlers(nsGlobalWindow* aWindow);
static bool IsCallerChrome();
static void CloseBlockScriptTerminationFunc(nsISupports *aRef);
static void RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
nsGlobalWindow *aWindow);
@ -903,8 +904,6 @@ protected:
JSContext *aJSCallerContext,
nsIDOMWindow **aReturn);
static void CloseWindow(nsISupports* aWindow);
// Timeout Functions
// Language agnostic timeout function (all args passed).
// |interval| is in milliseconds.

Просмотреть файл

@ -27,11 +27,9 @@ class nsIScriptObjectPrincipal;
class nsIDOMWindow;
class nsIURI;
typedef void (*nsScriptTerminationFunc)(nsISupports* aRef);
#define NS_ISCRIPTCONTEXT_IID \
{ 0x821c5be9, 0xbf9e, 0x4041, \
{ 0x9f, 0xf2, 0x1f, 0xca, 0x39, 0xf7, 0x89, 0xf3 } }
{ 0xef0c91ce, 0x14f6, 0x41c9, \
{ 0xa5, 0x77, 0xa6, 0xeb, 0xdc, 0x6d, 0x44, 0x7b } }
/* This MUST match JSVERSION_DEFAULT. This version stuff if we don't
know what language we have is a little silly... */
@ -179,11 +177,10 @@ public:
* A GC may be done if "necessary."
* This call is necessary if script evaluation is done
* without using the EvaluateScript method.
* @param aTerminated If true then call termination function if it was
* previously set. Within DOM this will always be true, but outside
* callers (such as xpconnect) who may do script evaluations nested
* inside DOM script evaluations can pass false to avoid premature
* calls to the termination function.
* @param aTerminated If true then do script termination handling. Within DOM
* this will always be true, but outside callers (such as xpconnect) who
* may do script evaluations nested inside inside DOM script evaluations
* can pass false to avoid premature termination handling.
* @return NS_OK if the method is successful
*/
virtual void ScriptEvaluated(bool aTerminated) = 0;
@ -196,19 +193,6 @@ public:
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
JS::MutableHandle<JSScript*> aResult) = 0;
/**
* JS only - this function need not be implemented by languages other
* than JS (ie, this should be moved to a private interface!)
* Called to specify a function that should be called when the current
* script (if there is one) terminates. Generally used if breakdown
* of script state needs to happen, but should be deferred till
* the end of script evaluation.
*
* @throws NS_ERROR_OUT_OF_MEMORY if that happens
*/
virtual void SetTerminationFunction(nsScriptTerminationFunc aFunc,
nsIDOMWindow* aRef) = 0;
/**
* Called to disable/enable script execution in this context.
*/

Просмотреть файл

@ -1141,7 +1141,6 @@ nsJSContext::nsJSContext(JSRuntime *aRuntime, bool aGCOnDestruction,
::JS_SetOperationCallback(mContext, DOMOperationCallback);
}
mIsInitialized = false;
mTerminations = nullptr;
mScriptsEnabled = true;
mOperationCallbackTime = 0;
mModalStateTime = 0;
@ -1156,11 +1155,6 @@ nsJSContext::~nsJSContext()
mNext->mPrev = mPrev;
}
// We may still have pending termination functions if the context is destroyed
// before they could be executed. In this case, free the references to their
// parameters, but don't execute the functions (see bug 622326).
delete mTerminations;
mGlobalObjectRef = nullptr;
DestroyJSContext();
@ -1289,8 +1283,6 @@ nsJSContext::EvaluateString(const nsAString& aScript,
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(ok, NS_OK);
nsJSContext::TerminationFuncHolder holder(this);
// Scope the JSAutoCompartment so that it gets destroyed before we pop the
// cx and potentially call JS_RestoreFrameChain.
XPCAutoRequest ar(mContext);
@ -1414,7 +1406,6 @@ nsJSContext::ExecuteScript(JSScript* aScriptObject_,
nsCxPusher pusher;
pusher.Push(mContext);
nsJSContext::TerminationFuncHolder holder(this);
XPCAutoRequest ar(mContext);
// Scope the JSAutoCompartment so that it gets destroyed before we pop the
@ -2361,20 +2352,6 @@ nsJSContext::IsContextInitialized()
void
nsJSContext::ScriptEvaluated(bool aTerminated)
{
if (aTerminated && mTerminations) {
// Make sure to null out mTerminations before doing anything that
// might cause new termination funcs to be added!
nsJSContext::TerminationFuncClosure* start = mTerminations;
mTerminations = nullptr;
for (nsJSContext::TerminationFuncClosure* cur = start;
cur;
cur = cur->mNext) {
(*(cur->mTerminationFunc))(cur->mTerminationFuncArg);
}
delete start;
}
JS_MaybeGC(mContext);
if (aTerminated) {
@ -2384,17 +2361,6 @@ nsJSContext::ScriptEvaluated(bool aTerminated)
}
}
void
nsJSContext::SetTerminationFunction(nsScriptTerminationFunc aFunc,
nsIDOMWindow* aRef)
{
NS_PRECONDITION(GetExecutingScript(), "should be executing script");
nsJSContext::TerminationFuncClosure* newClosure =
new nsJSContext::TerminationFuncClosure(aFunc, aRef, mTerminations);
mTerminations = newClosure;
}
bool
nsJSContext::GetScriptsEnabled()
{

Просмотреть файл

@ -75,8 +75,6 @@ public:
virtual bool IsContextInitialized();
virtual void ScriptEvaluated(bool aTerminated);
virtual void SetTerminationFunction(nsScriptTerminationFunc aFunc,
nsIDOMWindow* aRef);
virtual bool GetScriptsEnabled();
virtual void SetScriptsEnabled(bool aEnabled, bool aFireTimeouts);
@ -186,66 +184,6 @@ private:
JSContext *mContext;
bool mActive;
// Public so we can use it from CallbackFunction
public:
struct TerminationFuncHolder;
protected:
friend struct TerminationFuncHolder;
struct TerminationFuncClosure
{
TerminationFuncClosure(nsScriptTerminationFunc aFunc,
nsISupports* aArg,
TerminationFuncClosure* aNext) :
mTerminationFunc(aFunc),
mTerminationFuncArg(aArg),
mNext(aNext)
{
}
~TerminationFuncClosure()
{
delete mNext;
}
nsScriptTerminationFunc mTerminationFunc;
nsCOMPtr<nsISupports> mTerminationFuncArg;
TerminationFuncClosure* mNext;
};
// Public so we can use it from CallbackFunction
public:
struct TerminationFuncHolder
{
TerminationFuncHolder(nsJSContext* aContext)
: mContext(aContext),
mTerminations(aContext->mTerminations)
{
aContext->mTerminations = nullptr;
}
~TerminationFuncHolder()
{
// Have to be careful here. mContext might have picked up new
// termination funcs while the script was evaluating. Prepend whatever
// we have to the current termination funcs on the context (since our
// termination funcs were posted first).
if (mTerminations) {
TerminationFuncClosure* cur = mTerminations;
while (cur->mNext) {
cur = cur->mNext;
}
cur->mNext = mContext->mTerminations;
mContext->mTerminations = mTerminations;
}
}
nsJSContext* mContext;
TerminationFuncClosure* mTerminations;
};
protected:
TerminationFuncClosure* mTerminations;
private:
bool mIsInitialized;
bool mScriptsEnabled;
bool mGCOnDestruction;

Просмотреть файл

@ -314,6 +314,65 @@ public:
{}
};
// A specialization of Optional for JSObject* to make sure that when someone
// calls Construct() on it we will pre-initialized the JSObject* to nullptr so
// it can be traced safely.
template<>
class Optional<JSObject*> : public Optional_base<JSObject*, JSObject*>
{
public:
Optional() :
Optional_base<JSObject*, JSObject*>()
{}
explicit Optional(JSObject* aValue) :
Optional_base<JSObject*, JSObject*>(aValue)
{}
// Don't allow us to have an uninitialized JSObject*
void Construct()
{
// The Android compiler sucks and thinks we're trying to construct
// a JSObject* from an int if we don't cast here. :(
Optional_base<JSObject*, JSObject*>::Construct(
static_cast<JSObject*>(nullptr));
}
template <class T1>
void Construct(const T1& t1)
{
Optional_base<JSObject*, JSObject*>::Construct(t1);
}
};
// A specialization of Optional for JS::Value to make sure that when someone
// calls Construct() on it we will pre-initialized the JS::Value to
// JS::UndefinedValue() so it can be traced safely.
template<>
class Optional<JS::Value> : public Optional_base<JS::Value, JS::Value>
{
public:
Optional() :
Optional_base<JS::Value, JS::Value>()
{}
explicit Optional(JS::Value aValue) :
Optional_base<JS::Value, JS::Value>(aValue)
{}
// Don't allow us to have an uninitialized JS::Value
void Construct()
{
Optional_base<JS::Value, JS::Value>::Construct(JS::UndefinedValue());
}
template <class T1>
void Construct(const T1& t1)
{
Optional_base<JS::Value, JS::Value>::Construct(t1);
}
};
// Specialization for strings.
// XXXbz we can't pull in FakeDependentString here, because it depends on
// internal strings. So we just have to forward-declare it and reimplement its

Просмотреть файл

@ -92,6 +92,11 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
// Victory! We have a JSContext. Now do the things we need a JSContext for.
mAr.construct(cx);
// And go ahead and stick our callable in a Rooted, to make sure it can't go
// gray again. We can do this even though we're not in the right compartment
// yet, because Rooted<> does not care about compartments.
mRootedCallable.construct(cx, aCallback);
// Make sure our JSContext is pushed on the stack.
mCxPusher.Push(cx);
@ -109,14 +114,6 @@ CallbackObject::CallSetup::CallSetup(JS::Handle<JSObject*> aCallback,
nsresult rv = nsContentUtils::GetSecurityManager()->
CheckFunctionAccess(cx, js::UncheckedUnwrap(aCallback), nullptr);
// Construct a termination func holder even if we're not planning to
// run any script. We need this because we're going to call
// ScriptEvaluated even if we don't run the script... See XXX
// comment above.
if (ctx) {
mTerminationFuncHolder.construct(static_cast<nsJSContext*>(ctx));
}
if (NS_FAILED(rv)) {
// Security check failed. We're done here.
return;

Просмотреть файл

@ -148,9 +148,10 @@ protected:
// this needs to be a Maybe.
Maybe<XPCAutoRequest> mAr;
// Can't construct a TerminationFuncHolder without an nsJSContext. But we
// generally want its destructor to come after the destructor of mCxPusher.
Maybe<nsJSContext::TerminationFuncHolder> mTerminationFuncHolder;
// We construct our JS::Rooted right after our JSAutoRequest; let's just
// hope that the change in ordering wrt the mCxPusher constructor here is
// ok.
Maybe<JS::Rooted<JSObject*> > mRootedCallable;
nsCxPusher mCxPusher;

Просмотреть файл

@ -7710,7 +7710,9 @@ class CGDictionary(CGThing):
selfName = self.makeClassName(d)
members = [ClassMember(self.makeMemberName(m[0].identifier.name),
self.getMemberType(m),
visibility="public") for m in self.memberInfo]
visibility="public",
body=self.getMemberInitializer(m))
for m in self.memberInfo]
ctor = ClassConstructor([], bodyInHeader=True, visibility="public")
methods = []
@ -7931,6 +7933,25 @@ class CGDictionary(CGThing):
return trace.define()
def getMemberInitializer(self, memberInfo):
"""
Get the right initializer for the member. Most members don't need one,
but we need to pre-initialize 'any' and 'object' that have a default
value, so they're safe to trace at all times.
"""
(member, _) = memberInfo
if not member.defaultValue:
# No default value means no need to set it up front, since it's
# inside an Optional and won't get traced until it's actually set
# up.
return None
type = member.type
if type.isAny():
return "JS::UndefinedValue()"
if type.isObject():
return "nullptr"
return None
@staticmethod
def makeIdName(name):
return name + "_id"

Просмотреть файл

@ -647,6 +647,7 @@ dictionary Dict : ParentDict {
object? anotherObj = null;
TestCallback? someCallback = null;
any someAny;
any anotherAny = null;
unrestricted float urFloat = 0;
unrestricted float urFloat2 = 1.1;

Просмотреть файл

@ -7,6 +7,7 @@ tail =
[test_add_put.js]
[test_add_twice_failure.js]
[test_advance.js]
[test_autoIncrement.js]
[test_autoIncrement_indexes.js]
[test_clear.js]
[test_complex_keyPaths.js]
@ -18,6 +19,7 @@ tail =
[test_cursor_update_updates_indexes.js]
[test_cursors.js]
[test_deleteDatabase.js]
[test_deleteDatabase_interactions.js]
[test_event_source.js]
[test_getAll.js]
[test_global_data.js]
@ -43,6 +45,7 @@ tail =
[test_overlapping_transactions.js]
[test_put_get_values.js]
[test_put_get_values_autoIncrement.js]
[test_readonly_transactions.js]
[test_remove_index.js]
[test_remove_objectStore.js]
[test_request_readyState.js]
@ -56,5 +59,7 @@ tail =
[test_transaction_lifetimes.js]
[test_transaction_lifetimes_nested.js]
[test_transaction_ordering.js]
[test_unique_index_update.js]
[test_writer_starvation.js]
# When adding files here please also update test/unit/xpcshell.ini!

Просмотреть файл

@ -9,392 +9,9 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function genCheck(key, value, test, options) {
return function(event) {
is(JSON.stringify(event.target.result), JSON.stringify(key),
"correct returned key in " + test);
if (options && options.store) {
is(event.target.source, options.store, "correct store in " + test);
}
if (options && options.trans) {
is(event.target.transaction, options.trans, "correct transaction in " + test);
}
event.target.source.get(key).onsuccess = function(event) {
is(JSON.stringify(event.target.result), JSON.stringify(value),
"correct stored value in " + test);
continueToNextStepSync();
}
}
}
function testSteps()
{
const dbname = window.location.pathname;
const RW = IDBTransaction.READ_WRITE
let c1 = 1;
let c2 = 1;
let openRequest = indexedDB.open(dbname, 1);
openRequest.onerror = errorHandler;
openRequest.onupgradeneeded = grabEventAndContinueHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
let trans = event.target.transaction;
// Create test stores
let store1 = db.createObjectStore("store1", { autoIncrement: true });
let store2 = db.createObjectStore("store2", { autoIncrement: true, keyPath: "id" });
let store3 = db.createObjectStore("store3", { autoIncrement: false });
is(store1.autoIncrement, true, "store1 .autoIncrement");
is(store2.autoIncrement, true, "store2 .autoIncrement");
is(store3.autoIncrement, false, "store3 .autoIncrement");
store1.createIndex("unique1", "unique", { unique: true });
store2.createIndex("unique1", "unique", { unique: true });
// Test simple inserts
let test = " for test simple insert"
store1.add({ foo: "value1" }).onsuccess =
genCheck(c1++, { foo: "value1" }, "first" + test);
store1.add({ foo: "value2" }).onsuccess =
genCheck(c1++, { foo: "value2" }, "second" + test);
yield;
yield;
store2.put({ bar: "value1" }).onsuccess =
genCheck(c2, { bar: "value1", id: c2 }, "first in store2" + test,
{ store: store2 });
c2++;
store1.put({ foo: "value3" }).onsuccess =
genCheck(c1++, { foo: "value3" }, "third" + test,
{ store: store1 });
yield;
yield;
store2.get(IDBKeyRange.lowerBound(c2)).onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result, undefined, "no such value" + test);
// Close version_change transaction
openRequest.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target, openRequest, "succeeded to open" + test);
is(event.type, "success", "succeeded to open" + test);
// Test inserting explicit keys
test = " for test explicit keys";
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 1 }, 100).onsuccess =
genCheck(100, { explicit: 1 }, "first" + test);
c1 = 101;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 2 }).onsuccess =
genCheck(c1++, { explicit: 2 }, "second" + test);
yield; yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 3 }, 200).onsuccess =
genCheck(200, { explicit: 3 }, "third" + test);
c1 = 201;
trans.objectStore("store1").add({ explicit: 4 }).onsuccess =
genCheck(c1++, { explicit: 4 }, "fourth" + test);
yield; yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 5 }, 150).onsuccess =
genCheck(150, { explicit: 5 }, "fifth" + test);
yield;
trans.objectStore("store1").add({ explicit: 6 }).onsuccess =
genCheck(c1++, { explicit: 6 }, "sixth" + test);
yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 7 }, "key").onsuccess =
genCheck("key", { explicit: 7 }, "seventh" + test);
yield;
trans.objectStore("store1").add({ explicit: 8 }).onsuccess =
genCheck(c1++, { explicit: 8 }, "eighth" + test);
yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 7 }, [100000]).onsuccess =
genCheck([100000], { explicit: 7 }, "seventh" + test);
yield;
trans.objectStore("store1").add({ explicit: 8 }).onsuccess =
genCheck(c1++, { explicit: 8 }, "eighth" + test);
yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 9 }, -100000).onsuccess =
genCheck(-100000, { explicit: 9 }, "ninth" + test);
yield;
trans.objectStore("store1").add({ explicit: 10 }).onsuccess =
genCheck(c1++, { explicit: 10 }, "tenth" + test);
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit2: 1, id: 300 }).onsuccess =
genCheck(300, { explicit2: 1, id: 300 }, "first store2" + test);
c2 = 301;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit2: 2 }).onsuccess =
genCheck(c2, { explicit2: 2, id: c2 }, "second store2" + test);
c2++;
yield; yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit2: 3, id: 400 }).onsuccess =
genCheck(400, { explicit2: 3, id: 400 }, "third store2" + test);
c2 = 401;
trans.objectStore("store2").add({ explicit2: 4 }).onsuccess =
genCheck(c2, { explicit2: 4, id: c2 }, "fourth store2" + test);
c2++;
yield; yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 5, id: 150 }).onsuccess =
genCheck(150, { explicit: 5, id: 150 }, "fifth store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 6 }).onsuccess =
genCheck(c2, { explicit: 6, id: c2 }, "sixth store2" + test);
c2++;
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 7, id: "key" }).onsuccess =
genCheck("key", { explicit: 7, id: "key" }, "seventh store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 8 }).onsuccess =
genCheck(c2, { explicit: 8, id: c2 }, "eighth store2" + test);
c2++;
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 7, id: [100000] }).onsuccess =
genCheck([100000], { explicit: 7, id: [100000] }, "seventh store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 8 }).onsuccess =
genCheck(c2, { explicit: 8, id: c2 }, "eighth store2" + test);
c2++;
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 9, id: -100000 }).onsuccess =
genCheck(-100000, { explicit: 9, id: -100000 }, "ninth store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 10 }).onsuccess =
genCheck(c2, { explicit: 10, id: c2 }, "tenth store2" + test);
c2++;
yield;
// Test separate transactions doesn't generate overlapping numbers
test = " for test non-overlapping counts";
trans = db.transaction("store1", RW);
trans2 = db.transaction("store1", RW);
trans2.objectStore("store1").put({ over: 2 }).onsuccess =
genCheck(c1 + 1, { over: 2 }, "first" + test,
{ trans: trans2 });
trans.objectStore("store1").put({ over: 1 }).onsuccess =
genCheck(c1, { over: 1 }, "second" + test,
{ trans: trans });
c1 += 2;
yield; yield;
trans = db.transaction("store2", RW);
trans2 = db.transaction("store2", RW);
trans2.objectStore("store2").put({ over: 2 }).onsuccess =
genCheck(c2 + 1, { over: 2, id: c2 + 1 }, "third" + test,
{ trans: trans2 });
trans.objectStore("store2").put({ over: 1 }).onsuccess =
genCheck(c2, { over: 1, id: c2 }, "fourth" + test,
{ trans: trans });
c2 += 2;
yield; yield;
// Test that error inserts doesn't increase generator
test = " for test error inserts";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ unique: 1 }, -1);
trans.objectStore("store2").add({ unique: 1, id: "unique" });
trans.objectStore("store1").add({ error: 1, unique: 1 }).
addEventListener("error", new ExpectError("ConstraintError", true));
trans.objectStore("store1").add({ error: 2 }).onsuccess =
genCheck(c1++, { error: 2 }, "first" + test);
yield; yield;
trans.objectStore("store2").add({ error: 3, unique: 1 }).
addEventListener("error", new ExpectError("ConstraintError", true));
trans.objectStore("store2").add({ error: 4 }).onsuccess =
genCheck(c2, { error: 4, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").add({ error: 5, unique: 1 }, 100000).
addEventListener("error", new ExpectError("ConstraintError", true));
trans.objectStore("store1").add({ error: 6 }).onsuccess =
genCheck(c1++, { error: 6 }, "third" + test);
yield; yield;
trans.objectStore("store2").add({ error: 7, unique: 1, id: 100000 }).
addEventListener("error", new ExpectError("ConstraintError", true));
trans.objectStore("store2").add({ error: 8 }).onsuccess =
genCheck(c2, { error: 8, id: c2 }, "fourth" + test);
c2++;
yield; yield;
// Test that aborts doesn't increase generator
test = " for test aborted transaction";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ abort: 1 }).onsuccess =
genCheck(c1, { abort: 1 }, "first" + test);
trans.objectStore("store2").put({ abort: 2 }).onsuccess =
genCheck(c2, { abort: 2, id: c2 }, "second" + test);
yield; yield;
trans.objectStore("store1").add({ abort: 3 }, 500).onsuccess =
genCheck(500, { abort: 3 }, "third" + test);
trans.objectStore("store2").put({ abort: 4, id: 600 }).onsuccess =
genCheck(600, { abort: 4, id: 600 }, "fourth" + test);
yield; yield;
trans.objectStore("store1").add({ abort: 5 }).onsuccess =
genCheck(501, { abort: 5 }, "fifth" + test);
trans.objectStore("store2").put({ abort: 6 }).onsuccess =
genCheck(601, { abort: 6, id: 601 }, "sixth" + test);
yield; yield;
trans.abort();
trans.onabort = grabEventAndContinueHandler;
event = yield
is(event.type, "abort", "transaction aborted");
is(event.target, trans, "correct transaction aborted");
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ abort: 1 }).onsuccess =
genCheck(c1++, { abort: 1 }, "re-first" + test);
trans.objectStore("store2").put({ abort: 2 }).onsuccess =
genCheck(c2, { abort: 2, id: c2 }, "re-second" + test);
c2++;
yield; yield;
// Test that delete doesn't decrease generator
test = " for test delete items"
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ delete: 1 }).onsuccess =
genCheck(c1++, { delete: 1 }, "first" + test);
trans.objectStore("store2").put({ delete: 2 }).onsuccess =
genCheck(c2, { delete: 2, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").delete(c1 - 1).onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").delete(c2 - 1).onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans.objectStore("store1").add({ delete: 3 }).onsuccess =
genCheck(c1++, { delete: 3 }, "first" + test);
trans.objectStore("store2").put({ delete: 4 }).onsuccess =
genCheck(c2, { delete: 4, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").delete(c1 - 1).onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").delete(c2 - 1).onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ delete: 5 }).onsuccess =
genCheck(c1++, { delete: 5 }, "first" + test);
trans.objectStore("store2").put({ delete: 6 }).onsuccess =
genCheck(c2, { delete: 6, id: c2 }, "second" + test);
c2++;
yield; yield;
// Test that clears doesn't decrease generator
test = " for test clear stores";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ clear: 1 }).onsuccess =
genCheck(c1++, { clear: 1 }, "first" + test);
trans.objectStore("store2").put({ clear: 2 }).onsuccess =
genCheck(c2, { clear: 2, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").clear().onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").clear().onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans.objectStore("store1").add({ clear: 3 }).onsuccess =
genCheck(c1++, { clear: 3 }, "third" + test);
trans.objectStore("store2").put({ clear: 4 }).onsuccess =
genCheck(c2, { clear: 4, id: c2 }, "forth" + test);
c2++;
yield; yield;
trans.objectStore("store1").clear().onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").clear().onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ clear: 5 }).onsuccess =
genCheck(c1++, { clear: 5 }, "fifth" + test);
trans.objectStore("store2").put({ clear: 6 }).onsuccess =
genCheck(c2, { clear: 6, id: c2 }, "sixth" + test);
c2++;
yield; yield;
// Test that close/reopen doesn't decrease generator
test = " for test clear stores";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").clear().onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").clear().onsuccess =
grabEventAndContinueHandler;
yield; yield;
db.close();
SpecialPowers.gc();
openRequest = indexedDB.open(dbname, 2);
openRequest.onerror = errorHandler;
openRequest.onupgradeneeded = grabEventAndContinueHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
event = yield;
db = event.target.result;
trans = event.target.transaction;
trans.objectStore("store1").add({ reopen: 1 }).onsuccess =
genCheck(c1++, { reopen: 1 }, "first" + test);
trans.objectStore("store2").put({ reopen: 2 }).onsuccess =
genCheck(c2, { reopen: 2, id: c2 }, "second" + test);
c2++;
yield; yield;
openRequest.onsuccess = grabEventAndContinueHandler;
yield;
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="unit/test_autoIncrement.js"></script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>

Просмотреть файл

@ -9,64 +9,7 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function testSteps()
{
const name = window.location.pathname;
let request = indexedDB.open(name, 10);
request.onerror = errorHandler;
request.onsuccess = unexpectedSuccessHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
let event = yield;
is(event.type, "upgradeneeded", "Expect an upgradeneeded event");
ok(event instanceof IDBVersionChangeEvent, "Expect a versionchange event");
let db = event.target.result;
db.createObjectStore("stuff");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.type, "success", "Expect a success event");
is(event.target, request, "Event has right target");
ok(event.target.result instanceof IDBDatabase, "Result should be a database");
is(db.objectStoreNames.length, 1, "Expect an objectStore here");
db.close();
let request = indexedDB.deleteDatabase(name);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
let openRequest = indexedDB.open(name, 1);
openRequest.onerror = errorHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
event = yield;
is(event.type, "success", "expect a success event");
is(event.target, request, "event has right target");
is(event.target.result, null, "event should have no result");
openRequest.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result.version, 1, "DB has proper version");
is(event.target.result.objectStoreNames.length, 0, "DB should have no object stores");
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="unit/test_deleteDatabase_interactions.js"></script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>

Просмотреть файл

@ -9,175 +9,7 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function testSteps()
{
const name = window.location.pathname;
const osName = "foo";
let request = indexedDB.open(name, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
db.createObjectStore(osName, { autoIncrement: "true" });
yield;
let key1, key2;
request = db.transaction([osName], "readwrite")
.objectStore(osName)
.add({});
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
key1 = event.target.result;
testGenerator.next();
}
yield;
request = db.transaction(osName, "readwrite").objectStore(osName).add({});
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
key2 = event.target.result;
testGenerator.next();
}
yield;
request = db.transaction([osName], "readwrite")
.objectStore(osName)
.put({}, key1);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction(osName, "readwrite")
.objectStore(osName)
.put({}, key2);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction([osName], "readwrite")
.objectStore(osName)
.put({}, key1);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction(osName, "readwrite")
.objectStore(osName)
.put({}, key1);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction([osName], "readwrite")
.objectStore(osName)
.delete(key1);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction(osName, "readwrite")
.objectStore(osName)
.delete(key2);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
try {
request = db.transaction([osName]).objectStore(osName).add({});
ok(false, "Adding to a readonly transaction should fail!");
}
catch (e) {
ok(true, "Adding to a readonly transaction failed");
}
try {
request = db.transaction(osName).objectStore(osName).add({});
ok(false, "Adding to a readonly transaction should fail!");
}
catch (e) {
ok(true, "Adding to a readonly transaction failed");
}
try {
request = db.transaction([osName]).objectStore(osName).put({});
ok(false, "Adding or modifying a readonly transaction should fail!");
}
catch (e) {
ok(true, "Adding or modifying a readonly transaction failed");
}
try {
request = db.transaction(osName).objectStore(osName).put({});
ok(false, "Adding or modifying a readonly transaction should fail!");
}
catch (e) {
ok(true, "Adding or modifying a readonly transaction failed");
}
try {
request = db.transaction([osName]).objectStore(osName).put({}, key1);
ok(false, "Modifying a readonly transaction should fail!");
}
catch (e) {
ok(true, "Modifying a readonly transaction failed");
}
try {
request = db.transaction(osName).objectStore(osName).put({}, key1);
ok(false, "Modifying a readonly transaction should fail!");
}
catch (e) {
ok(true, "Modifying a readonly transaction failed");
}
try {
request = db.transaction([osName]).objectStore(osName).delete(key1);
ok(false, "Removing from a readonly transaction should fail!");
}
catch (e) {
ok(true, "Removing from a readonly transaction failed");
}
try {
request = db.transaction(osName).objectStore(osName).delete(key2);
ok(false, "Removing from a readonly transaction should fail!");
}
catch (e) {
ok(true, "Removing from a readonly transaction failed");
}
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="unit/test_readonly_transactions.js"></script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>

Просмотреть файл

@ -9,66 +9,7 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function testSteps()
{
let request = indexedDB.open(window.location.pathname, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
for each (let autoIncrement in [false, true]) {
let objectStore =
db.createObjectStore(autoIncrement, { keyPath: "id",
autoIncrement: autoIncrement });
objectStore.createIndex("", "index", { unique: true });
for (let i = 0; i < 10; i++) {
objectStore.add({ id: i, index: i });
}
}
event = yield;
is(event.type, "success", "expect a success event");
for each (let autoIncrement in [false, true]) {
objectStore = db.transaction(autoIncrement, IDBTransaction.READ_WRITE)
.objectStore(autoIncrement);
request = objectStore.put({ id: 5, index: 6 });
request.onsuccess = unexpectedSuccessHandler;
request.addEventListener("error", new ExpectError("ConstraintError", true));
event = yield;
event.preventDefault();
let keyRange = IDBKeyRange.only(5);
objectStore.index("").openCursor(keyRange).onsuccess = function(event) {
let cursor = event.target.result;
ok(cursor, "Must have a cursor here");
is(cursor.value.index, 5, "Still have the right index value");
cursor.value.index = 6;
request = cursor.update(cursor.value);
request.onsuccess = unexpectedSuccessHandler;
request.addEventListener("error", new ExpectError("ConstraintError", true));
};
yield;
}
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="unit/test_unique_index_update.js"></script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>

Просмотреть файл

@ -9,98 +9,7 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript;version=1.7">
function testSteps()
{
const name = window.location.pathname;
// Needs to be enough to saturate the thread pool.
const SYNC_REQUEST_COUNT = 25;
let request = indexedDB.open(name, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
is(event.target.transaction.mode, "versionchange", "Correct mode");
let objectStore = db.createObjectStore("foo", { autoIncrement: true });
request = objectStore.add({});
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let key = event.target.result;
ok(key, "Got a key");
yield;
let continueReading = true;
let readerCount = 0;
let writerCount = 0;
let callbackCount = 0;
// Generate a bunch of reads right away without returning to the event
// loop.
info("Generating " + SYNC_REQUEST_COUNT + " readonly requests");
for (let i = 0; i < SYNC_REQUEST_COUNT; i++) {
readerCount++;
let request = db.transaction("foo").objectStore("foo").get(key);
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readonly", "Correct mode");
callbackCount++;
};
}
while (continueReading) {
readerCount++;
info("Generating additional readonly request (" + readerCount + ")");
let request = db.transaction("foo").objectStore("foo").get(key);
request.onsuccess = function(event) {
callbackCount++;
info("Received readonly request callback (" + callbackCount + ")");
is(event.target.transaction.mode, "readonly", "Correct mode");
if (callbackCount == SYNC_REQUEST_COUNT) {
writerCount++;
info("Generating 1 readwrite request with " + readerCount +
" previous readonly requests");
let request = db.transaction("foo", "readwrite")
.objectStore("foo")
.add({}, readerCount);
request.onsuccess = function(event) {
callbackCount++;
info("Received readwrite request callback (" + callbackCount + ")");
is(event.target.transaction.mode, "readwrite", "Correct mode");
is(event.target.result, callbackCount,
"write callback came before later reads");
}
}
else if (callbackCount == SYNC_REQUEST_COUNT + 5) {
continueReading = false;
}
};
setTimeout(function() { testGenerator.next(); }, writerCount ? 1000 : 100);
yield;
}
while (callbackCount < (readerCount + writerCount)) {
executeSoon(function() { testGenerator.next(); });
yield;
}
is(callbackCount, readerCount + writerCount, "All requests accounted for");
finishTest();
yield;
}
</script>
<script type="text/javascript;version=1.7" src="unit/test_writer_starvation.js"></script>
<script type="text/javascript;version=1.7" src="helpers.js"></script>
</head>

Просмотреть файл

@ -14,6 +14,7 @@ MOCHITEST_FILES = \
test_add_put.js \
test_add_twice_failure.js \
test_advance.js \
test_autoIncrement.js \
test_autoIncrement_indexes.js \
test_clear.js \
test_complex_keyPaths.js \
@ -25,6 +26,7 @@ MOCHITEST_FILES = \
test_cursor_update_updates_indexes.js \
test_cursors.js \
test_deleteDatabase.js \
test_deleteDatabase_interactions.js \
test_event_source.js \
test_getAll.js \
test_global_data.js \
@ -54,6 +56,7 @@ MOCHITEST_FILES = \
test_overlapping_transactions.js \
test_put_get_values.js \
test_put_get_values_autoIncrement.js \
test_readonly_transactions.js \
test_remove_index.js \
test_remove_objectStore.js \
test_request_readyState.js \
@ -68,6 +71,8 @@ MOCHITEST_FILES = \
test_transaction_lifetimes.js \
test_transaction_lifetimes_nested.js \
test_transaction_ordering.js \
test_unique_index_update.js \
test_writer_starvation.js \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -38,8 +38,8 @@ function todo(condition, name, diag) {
dump("TODO: ", diag);
}
function info(msg) {
do_print(msg);
function info(name, message) {
do_print(name);
}
function run_test() {
@ -193,6 +193,19 @@ function gc()
Components.utils.forceCC();
}
function setTimeout(fun, timeout) {
let timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
var event = {
notify: function (timer) {
fun();
}
};
timer.initWithCallback(event, timeout,
Components.interfaces.nsITimer.TYPE_ONE_SHOT);
return timer;
}
var SpecialPowers = {
isMainProcess: function() {
return Components.classes["@mozilla.org/xre/app-info;1"]

Просмотреть файл

@ -0,0 +1,398 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
if (!this.window) {
this.runTest = function() {
todo(false, "Test disabled in xpcshell test suite for now");
finishTest();
}
}
var testGenerator = testSteps();
function genCheck(key, value, test, options) {
return function(event) {
is(JSON.stringify(event.target.result), JSON.stringify(key),
"correct returned key in " + test);
if (options && options.store) {
is(event.target.source, options.store, "correct store in " + test);
}
if (options && options.trans) {
is(event.target.transaction, options.trans, "correct transaction in " + test);
}
event.target.source.get(key).onsuccess = function(event) {
is(JSON.stringify(event.target.result), JSON.stringify(value),
"correct stored value in " + test);
continueToNextStepSync();
}
}
}
function testSteps()
{
const dbname = this.window ? window.location.pathname : "Splendid Test";
const RW = "readwrite";
let c1 = 1;
let c2 = 1;
let openRequest = indexedDB.open(dbname, 1);
openRequest.onerror = errorHandler;
openRequest.onupgradeneeded = grabEventAndContinueHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
let event = yield;
let db = event.target.result;
let trans = event.target.transaction;
// Create test stores
let store1 = db.createObjectStore("store1", { autoIncrement: true });
let store2 = db.createObjectStore("store2", { autoIncrement: true, keyPath: "id" });
let store3 = db.createObjectStore("store3", { autoIncrement: false });
is(store1.autoIncrement, true, "store1 .autoIncrement");
is(store2.autoIncrement, true, "store2 .autoIncrement");
is(store3.autoIncrement, false, "store3 .autoIncrement");
store1.createIndex("unique1", "unique", { unique: true });
store2.createIndex("unique1", "unique", { unique: true });
// Test simple inserts
let test = " for test simple insert"
store1.add({ foo: "value1" }).onsuccess =
genCheck(c1++, { foo: "value1" }, "first" + test);
store1.add({ foo: "value2" }).onsuccess =
genCheck(c1++, { foo: "value2" }, "second" + test);
yield;
yield;
store2.put({ bar: "value1" }).onsuccess =
genCheck(c2, { bar: "value1", id: c2 }, "first in store2" + test,
{ store: store2 });
c2++;
store1.put({ foo: "value3" }).onsuccess =
genCheck(c1++, { foo: "value3" }, "third" + test,
{ store: store1 });
yield;
yield;
store2.get(IDBKeyRange.lowerBound(c2)).onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result, undefined, "no such value" + test);
// Close version_change transaction
openRequest.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target, openRequest, "succeeded to open" + test);
is(event.type, "success", "succeeded to open" + test);
// Test inserting explicit keys
test = " for test explicit keys";
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 1 }, 100).onsuccess =
genCheck(100, { explicit: 1 }, "first" + test);
c1 = 101;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 2 }).onsuccess =
genCheck(c1++, { explicit: 2 }, "second" + test);
yield; yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 3 }, 200).onsuccess =
genCheck(200, { explicit: 3 }, "third" + test);
c1 = 201;
trans.objectStore("store1").add({ explicit: 4 }).onsuccess =
genCheck(c1++, { explicit: 4 }, "fourth" + test);
yield; yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 5 }, 150).onsuccess =
genCheck(150, { explicit: 5 }, "fifth" + test);
yield;
trans.objectStore("store1").add({ explicit: 6 }).onsuccess =
genCheck(c1++, { explicit: 6 }, "sixth" + test);
yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 7 }, "key").onsuccess =
genCheck("key", { explicit: 7 }, "seventh" + test);
yield;
trans.objectStore("store1").add({ explicit: 8 }).onsuccess =
genCheck(c1++, { explicit: 8 }, "eighth" + test);
yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 7 }, [100000]).onsuccess =
genCheck([100000], { explicit: 7 }, "seventh" + test);
yield;
trans.objectStore("store1").add({ explicit: 8 }).onsuccess =
genCheck(c1++, { explicit: 8 }, "eighth" + test);
yield;
trans = db.transaction("store1", RW);
trans.objectStore("store1").add({ explicit: 9 }, -100000).onsuccess =
genCheck(-100000, { explicit: 9 }, "ninth" + test);
yield;
trans.objectStore("store1").add({ explicit: 10 }).onsuccess =
genCheck(c1++, { explicit: 10 }, "tenth" + test);
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit2: 1, id: 300 }).onsuccess =
genCheck(300, { explicit2: 1, id: 300 }, "first store2" + test);
c2 = 301;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit2: 2 }).onsuccess =
genCheck(c2, { explicit2: 2, id: c2 }, "second store2" + test);
c2++;
yield; yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit2: 3, id: 400 }).onsuccess =
genCheck(400, { explicit2: 3, id: 400 }, "third store2" + test);
c2 = 401;
trans.objectStore("store2").add({ explicit2: 4 }).onsuccess =
genCheck(c2, { explicit2: 4, id: c2 }, "fourth store2" + test);
c2++;
yield; yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 5, id: 150 }).onsuccess =
genCheck(150, { explicit: 5, id: 150 }, "fifth store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 6 }).onsuccess =
genCheck(c2, { explicit: 6, id: c2 }, "sixth store2" + test);
c2++;
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 7, id: "key" }).onsuccess =
genCheck("key", { explicit: 7, id: "key" }, "seventh store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 8 }).onsuccess =
genCheck(c2, { explicit: 8, id: c2 }, "eighth store2" + test);
c2++;
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 7, id: [100000] }).onsuccess =
genCheck([100000], { explicit: 7, id: [100000] }, "seventh store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 8 }).onsuccess =
genCheck(c2, { explicit: 8, id: c2 }, "eighth store2" + test);
c2++;
yield;
trans = db.transaction("store2", RW);
trans.objectStore("store2").add({ explicit: 9, id: -100000 }).onsuccess =
genCheck(-100000, { explicit: 9, id: -100000 }, "ninth store2" + test);
yield;
trans.objectStore("store2").add({ explicit: 10 }).onsuccess =
genCheck(c2, { explicit: 10, id: c2 }, "tenth store2" + test);
c2++;
yield;
// Test separate transactions doesn't generate overlapping numbers
test = " for test non-overlapping counts";
trans = db.transaction("store1", RW);
trans2 = db.transaction("store1", RW);
trans2.objectStore("store1").put({ over: 2 }).onsuccess =
genCheck(c1 + 1, { over: 2 }, "first" + test,
{ trans: trans2 });
trans.objectStore("store1").put({ over: 1 }).onsuccess =
genCheck(c1, { over: 1 }, "second" + test,
{ trans: trans });
c1 += 2;
yield; yield;
trans = db.transaction("store2", RW);
trans2 = db.transaction("store2", RW);
trans2.objectStore("store2").put({ over: 2 }).onsuccess =
genCheck(c2 + 1, { over: 2, id: c2 + 1 }, "third" + test,
{ trans: trans2 });
trans.objectStore("store2").put({ over: 1 }).onsuccess =
genCheck(c2, { over: 1, id: c2 }, "fourth" + test,
{ trans: trans });
c2 += 2;
yield; yield;
// Test that error inserts doesn't increase generator
test = " for test error inserts";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ unique: 1 }, -1);
trans.objectStore("store2").add({ unique: 1, id: "unique" });
trans.objectStore("store1").add({ error: 1, unique: 1 }).
addEventListener("error", new ExpectError("ConstraintError", true));
trans.objectStore("store1").add({ error: 2 }).onsuccess =
genCheck(c1++, { error: 2 }, "first" + test);
yield; yield;
trans.objectStore("store2").add({ error: 3, unique: 1 }).
addEventListener("error", new ExpectError("ConstraintError", true));
trans.objectStore("store2").add({ error: 4 }).onsuccess =
genCheck(c2, { error: 4, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").add({ error: 5, unique: 1 }, 100000).
addEventListener("error", new ExpectError("ConstraintError", true));
trans.objectStore("store1").add({ error: 6 }).onsuccess =
genCheck(c1++, { error: 6 }, "third" + test);
yield; yield;
trans.objectStore("store2").add({ error: 7, unique: 1, id: 100000 }).
addEventListener("error", new ExpectError("ConstraintError", true));
trans.objectStore("store2").add({ error: 8 }).onsuccess =
genCheck(c2, { error: 8, id: c2 }, "fourth" + test);
c2++;
yield; yield;
// Test that aborts doesn't increase generator
test = " for test aborted transaction";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ abort: 1 }).onsuccess =
genCheck(c1, { abort: 1 }, "first" + test);
trans.objectStore("store2").put({ abort: 2 }).onsuccess =
genCheck(c2, { abort: 2, id: c2 }, "second" + test);
yield; yield;
trans.objectStore("store1").add({ abort: 3 }, 500).onsuccess =
genCheck(500, { abort: 3 }, "third" + test);
trans.objectStore("store2").put({ abort: 4, id: 600 }).onsuccess =
genCheck(600, { abort: 4, id: 600 }, "fourth" + test);
yield; yield;
trans.objectStore("store1").add({ abort: 5 }).onsuccess =
genCheck(501, { abort: 5 }, "fifth" + test);
trans.objectStore("store2").put({ abort: 6 }).onsuccess =
genCheck(601, { abort: 6, id: 601 }, "sixth" + test);
yield; yield;
trans.abort();
trans.onabort = grabEventAndContinueHandler;
event = yield
is(event.type, "abort", "transaction aborted");
is(event.target, trans, "correct transaction aborted");
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ abort: 1 }).onsuccess =
genCheck(c1++, { abort: 1 }, "re-first" + test);
trans.objectStore("store2").put({ abort: 2 }).onsuccess =
genCheck(c2, { abort: 2, id: c2 }, "re-second" + test);
c2++;
yield; yield;
// Test that delete doesn't decrease generator
test = " for test delete items"
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ delete: 1 }).onsuccess =
genCheck(c1++, { delete: 1 }, "first" + test);
trans.objectStore("store2").put({ delete: 2 }).onsuccess =
genCheck(c2, { delete: 2, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").delete(c1 - 1).onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").delete(c2 - 1).onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans.objectStore("store1").add({ delete: 3 }).onsuccess =
genCheck(c1++, { delete: 3 }, "first" + test);
trans.objectStore("store2").put({ delete: 4 }).onsuccess =
genCheck(c2, { delete: 4, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").delete(c1 - 1).onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").delete(c2 - 1).onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ delete: 5 }).onsuccess =
genCheck(c1++, { delete: 5 }, "first" + test);
trans.objectStore("store2").put({ delete: 6 }).onsuccess =
genCheck(c2, { delete: 6, id: c2 }, "second" + test);
c2++;
yield; yield;
// Test that clears doesn't decrease generator
test = " for test clear stores";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ clear: 1 }).onsuccess =
genCheck(c1++, { clear: 1 }, "first" + test);
trans.objectStore("store2").put({ clear: 2 }).onsuccess =
genCheck(c2, { clear: 2, id: c2 }, "second" + test);
c2++;
yield; yield;
trans.objectStore("store1").clear().onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").clear().onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans.objectStore("store1").add({ clear: 3 }).onsuccess =
genCheck(c1++, { clear: 3 }, "third" + test);
trans.objectStore("store2").put({ clear: 4 }).onsuccess =
genCheck(c2, { clear: 4, id: c2 }, "forth" + test);
c2++;
yield; yield;
trans.objectStore("store1").clear().onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").clear().onsuccess =
grabEventAndContinueHandler;
yield; yield;
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").add({ clear: 5 }).onsuccess =
genCheck(c1++, { clear: 5 }, "fifth" + test);
trans.objectStore("store2").put({ clear: 6 }).onsuccess =
genCheck(c2, { clear: 6, id: c2 }, "sixth" + test);
c2++;
yield; yield;
// Test that close/reopen doesn't decrease generator
test = " for test clear stores";
trans = db.transaction(["store1", "store2"], RW);
trans.objectStore("store1").clear().onsuccess =
grabEventAndContinueHandler;
trans.objectStore("store2").clear().onsuccess =
grabEventAndContinueHandler;
yield; yield;
db.close();
SpecialPowers.gc();
openRequest = indexedDB.open(dbname, 2);
openRequest.onerror = errorHandler;
openRequest.onupgradeneeded = grabEventAndContinueHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
event = yield;
db = event.target.result;
trans = event.target.transaction;
trans.objectStore("store1").add({ reopen: 1 }).onsuccess =
genCheck(c1++, { reopen: 1 }, "first" + test);
trans.objectStore("store2").put({ reopen: 2 }).onsuccess =
genCheck(c2, { reopen: 2, id: c2 }, "second" + test);
c2++;
yield; yield;
openRequest.onsuccess = grabEventAndContinueHandler;
yield;
finishTest();
yield;
}

Просмотреть файл

@ -0,0 +1,62 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function testSteps()
{
const name = this.window ? window.location.pathname : "Splendid Test";
let request = indexedDB.open(name, 10);
request.onerror = errorHandler;
request.onsuccess = unexpectedSuccessHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
let event = yield;
is(event.type, "upgradeneeded", "Expect an upgradeneeded event");
ok(event instanceof IDBVersionChangeEvent, "Expect a versionchange event");
let db = event.target.result;
db.createObjectStore("stuff");
request.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.type, "success", "Expect a success event");
is(event.target, request, "Event has right target");
ok(event.target.result instanceof IDBDatabase, "Result should be a database");
is(db.objectStoreNames.length, 1, "Expect an objectStore here");
db.close();
let request = indexedDB.deleteDatabase(name);
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
ok(request instanceof IDBOpenDBRequest, "Expect an IDBOpenDBRequest");
let openRequest = indexedDB.open(name, 1);
openRequest.onerror = errorHandler;
openRequest.onsuccess = unexpectedSuccessHandler;
event = yield;
is(event.type, "success", "expect a success event");
is(event.target, request, "event has right target");
is(event.target.result, null, "event should have no result");
openRequest.onsuccess = grabEventAndContinueHandler;
event = yield;
is(event.target.result.version, 1, "DB has proper version");
is(event.target.result.objectStoreNames.length, 0, "DB should have no object stores");
finishTest();
yield;
}

Просмотреть файл

@ -0,0 +1,181 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
if (!this.window) {
this.runTest = function() {
todo(false, "Test disabled in xpcshell test suite for now");
finishTest();
}
}
var testGenerator = testSteps();
function testSteps()
{
const name = this.window ? window.location.pathname : "Splendid Test";
const osName = "foo";
let request = indexedDB.open(name, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
db.createObjectStore(osName, { autoIncrement: "true" });
yield;
let key1, key2;
request = db.transaction([osName], "readwrite")
.objectStore(osName)
.add({});
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
key1 = event.target.result;
testGenerator.next();
}
yield;
request = db.transaction(osName, "readwrite").objectStore(osName).add({});
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
key2 = event.target.result;
testGenerator.next();
}
yield;
request = db.transaction([osName], "readwrite")
.objectStore(osName)
.put({}, key1);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction(osName, "readwrite")
.objectStore(osName)
.put({}, key2);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction([osName], "readwrite")
.objectStore(osName)
.put({}, key1);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction(osName, "readwrite")
.objectStore(osName)
.put({}, key1);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction([osName], "readwrite")
.objectStore(osName)
.delete(key1);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
request = db.transaction(osName, "readwrite")
.objectStore(osName)
.delete(key2);
request.onerror = errorHandler;
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readwrite", "Correct mode");
testGenerator.next();
}
yield;
try {
request = db.transaction([osName]).objectStore(osName).add({});
ok(false, "Adding to a readonly transaction should fail!");
}
catch (e) {
ok(true, "Adding to a readonly transaction failed");
}
try {
request = db.transaction(osName).objectStore(osName).add({});
ok(false, "Adding to a readonly transaction should fail!");
}
catch (e) {
ok(true, "Adding to a readonly transaction failed");
}
try {
request = db.transaction([osName]).objectStore(osName).put({});
ok(false, "Adding or modifying a readonly transaction should fail!");
}
catch (e) {
ok(true, "Adding or modifying a readonly transaction failed");
}
try {
request = db.transaction(osName).objectStore(osName).put({});
ok(false, "Adding or modifying a readonly transaction should fail!");
}
catch (e) {
ok(true, "Adding or modifying a readonly transaction failed");
}
try {
request = db.transaction([osName]).objectStore(osName).put({}, key1);
ok(false, "Modifying a readonly transaction should fail!");
}
catch (e) {
ok(true, "Modifying a readonly transaction failed");
}
try {
request = db.transaction(osName).objectStore(osName).put({}, key1);
ok(false, "Modifying a readonly transaction should fail!");
}
catch (e) {
ok(true, "Modifying a readonly transaction failed");
}
try {
request = db.transaction([osName]).objectStore(osName).delete(key1);
ok(false, "Removing from a readonly transaction should fail!");
}
catch (e) {
ok(true, "Removing from a readonly transaction failed");
}
try {
request = db.transaction(osName).objectStore(osName).delete(key2);
ok(false, "Removing from a readonly transaction should fail!");
}
catch (e) {
ok(true, "Removing from a readonly transaction failed");
}
finishTest();
yield;
}

Просмотреть файл

@ -0,0 +1,64 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function testSteps()
{
let request = indexedDB.open(this.window ? window.location.pathname : "Splendid Test", 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
for each (let autoIncrement in [false, true]) {
let objectStore =
db.createObjectStore(autoIncrement, { keyPath: "id",
autoIncrement: autoIncrement });
objectStore.createIndex("", "index", { unique: true });
for (let i = 0; i < 10; i++) {
objectStore.add({ id: i, index: i });
}
}
event = yield;
is(event.type, "success", "expect a success event");
for each (let autoIncrement in [false, true]) {
objectStore = db.transaction(autoIncrement, "readwrite")
.objectStore(autoIncrement);
request = objectStore.put({ id: 5, index: 6 });
request.onsuccess = unexpectedSuccessHandler;
request.addEventListener("error", new ExpectError("ConstraintError", true));
event = yield;
event.preventDefault();
let keyRange = IDBKeyRange.only(5);
objectStore.index("").openCursor(keyRange).onsuccess = function(event) {
let cursor = event.target.result;
ok(cursor, "Must have a cursor here");
is(cursor.value.index, 5, "Still have the right index value");
cursor.value.index = 6;
request = cursor.update(cursor.value);
request.onsuccess = unexpectedSuccessHandler;
request.addEventListener("error", new ExpectError("ConstraintError", true));
};
yield;
}
finishTest();
yield;
}

Просмотреть файл

@ -0,0 +1,104 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
if (!this.window) {
this.runTest = function() {
todo(false, "Test disabled in xpcshell test suite for now");
finishTest();
}
}
var testGenerator = testSteps();
function testSteps()
{
const name = this.window ? window.location.pathname : "Splendid Test";
// Needs to be enough to saturate the thread pool.
const SYNC_REQUEST_COUNT = 25;
let request = indexedDB.open(name, 1);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = grabEventAndContinueHandler;
let event = yield;
let db = event.target.result;
db.onerror = errorHandler;
is(event.target.transaction.mode, "versionchange", "Correct mode");
let objectStore = db.createObjectStore("foo", { autoIncrement: true });
request = objectStore.add({});
request.onerror = errorHandler;
request.onsuccess = grabEventAndContinueHandler;
event = yield;
let key = event.target.result;
ok(key, "Got a key");
yield;
let continueReading = true;
let readerCount = 0;
let writerCount = 0;
let callbackCount = 0;
// Generate a bunch of reads right away without returning to the event
// loop.
info("Generating " + SYNC_REQUEST_COUNT + " readonly requests");
for (let i = 0; i < SYNC_REQUEST_COUNT; i++) {
readerCount++;
let request = db.transaction("foo").objectStore("foo").get(key);
request.onsuccess = function(event) {
is(event.target.transaction.mode, "readonly", "Correct mode");
callbackCount++;
};
}
while (continueReading) {
readerCount++;
info("Generating additional readonly request (" + readerCount + ")");
let request = db.transaction("foo").objectStore("foo").get(key);
request.onsuccess = function(event) {
callbackCount++;
info("Received readonly request callback (" + callbackCount + ")");
is(event.target.transaction.mode, "readonly", "Correct mode");
if (callbackCount == SYNC_REQUEST_COUNT) {
writerCount++;
info("Generating 1 readwrite request with " + readerCount +
" previous readonly requests");
let request = db.transaction("foo", "readwrite")
.objectStore("foo")
.add({}, readerCount);
request.onsuccess = function(event) {
callbackCount++;
info("Received readwrite request callback (" + callbackCount + ")");
is(event.target.transaction.mode, "readwrite", "Correct mode");
is(event.target.result, callbackCount,
"write callback came before later reads");
}
}
else if (callbackCount == SYNC_REQUEST_COUNT + 5) {
continueReading = false;
}
};
setTimeout(function() { testGenerator.next(); }, writerCount ? 1000 : 100);
yield;
}
while (callbackCount < (readerCount + writerCount)) {
executeSoon(function() { testGenerator.next(); });
yield;
}
is(callbackCount, readerCount + writerCount, "All requests accounted for");
finishTest();
yield;
}

Просмотреть файл

@ -7,6 +7,7 @@ tail =
[test_add_put.js]
[test_add_twice_failure.js]
[test_advance.js]
[test_autoIncrement.js]
[test_autoIncrement_indexes.js]
[test_clear.js]
[test_complex_keyPaths.js]
@ -18,6 +19,7 @@ tail =
[test_cursor_update_updates_indexes.js]
[test_cursors.js]
[test_deleteDatabase.js]
[test_deleteDatabase_interactions.js]
[test_event_source.js]
[test_getAll.js]
[test_global_data.js]
@ -47,6 +49,7 @@ tail =
[test_overlapping_transactions.js]
[test_put_get_values.js]
[test_put_get_values_autoIncrement.js]
[test_readonly_transactions.js]
[test_remove_index.js]
[test_remove_objectStore.js]
[test_request_readyState.js]
@ -61,5 +64,7 @@ tail =
[test_transaction_lifetimes.js]
[test_transaction_lifetimes_nested.js]
[test_transaction_ordering.js]
[test_unique_index_update.js]
[test_writer_starvation.js]
# When adding files here please also update ipc/unit/xpcshell.ini!

Просмотреть файл

@ -40,7 +40,6 @@ MOCHITEST_FILES = \
test_peerConnection_bug827843.html \
test_peerConnection_bug834153.html \
test_peerConnection_bug835370.html \
test_peerConnection_bug840344.html \
head.js \
mediaStreamPlayback.js \
pc.js \

Просмотреть файл

@ -1,119 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="head.js"></script>
<script type="application/javascript" src="pc.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript">
createHTML({
bug: "840344",
title: "Prevent multiple creations of local SDP"
});
// SDP to stand in for an offer coming from a (theoretical) remote endpoint
var offer = {
sdp: "v=0\r\n"+
"o=Mozilla-SIPUA 23597 0 IN IP4 0.0.0.0\r\n"+
"s=SIP Call\r\n"+
"t=0 0\r\n"+
"a=ice-ufrag:f5fda439\r\n"+
"a=ice-pwd:d0df8e2904bdbd29587966e797655970\r\n"+
"a=fingerprint:sha-256 DF:69:78:20:8D:2E:08:CE:49:82:A3:11:79:1D:BF:"+
"B5:49:49:2D:32:82:2F:0D:88:84:A7:C6:63:23:63:A9:0F\r\n"+
"m=audio 52757 RTP/SAVPF 109 0 8 101\r\n"+
"c=IN IP4 192.168.129.33\r\n"+
"a=rtpmap:109 opus/48000/2\r\n"+
"a=ptime:20\r\n"+
"a=rtpmap:0 PCMU/8000\r\n"+
"a=rtpmap:8 PCMA/8000\r\n"+
"a=rtpmap:101 telephone-event/8000\r\n"+
"a=fmtp:101 0-15\r\n"+
"a=sendrecv\r\n"+
"a=candidate:0 1 UDP 2113601791 192.168.129.33 52757 typ host\r\n"+
"a=candidate:0 2 UDP 2113601790 192.168.129.33 59738 typ host\r\n"+
"m=video 63901 RTP/SAVPF 120\r\n"+
"c=IN IP4 192.168.129.33\r\n"+
"a=rtpmap:120 VP8/90000\r\n"+
"a=sendrecv\r\n"+
"a=candidate:0 1 UDP 2113601791 192.168.129.33 63901 typ host\r\n"+
"a=candidate:0 2 UDP 2113601790 192.168.129.33 54165 typ host\r\n"+
"m=application 65080 SCTP/DTLS 5000 \r\n"+
"c=IN IP4 192.168.129.33\r\n"+
"a=fmtp:5000 protocol=webrtc-datachannel;streams=16\r\n"+
"a=sendrecv\r\n"+
"a=candidate:0 1 UDP 2113601791 192.168.129.33 65080 typ host\r\n"+
"a=candidate:0 2 UDP 2113601790 192.168.129.33 62658 typ host\r\n",
type: "offer"
};
var steps = [
[
"SET_REMOTE_DESCRIPTION",
function (test) {
test.pcLocal.setRemoteDescription(new mozRTCSessionDescription(offer),
function () {
test.next();
});
}
],
[
"CHECK_MULTIPLE_ANSWERS",
function (test) {
var answerCount = 0;
var setLocalCount = 0;
info("Create answer #1");
test.pcLocal.createAnswer(answerSuccess);
info("Create answer #2");
test.pcLocal.createAnswer(answerSuccess);
// Fourth: Count the answers and push them into the local description
function answerSuccess(answer) {
answerCount++;
ok (answerCount < 3, "Answer count is less than three.")
info("Got answer #" + answerCount);
is(answer.type, 'answer', "Answer is of type 'answer'");
ok(answer.sdp.length > 10, "Answer has length " + answer.sdp.length);
info("Set local description for answer #" + answerCount);
test.pcLocal.setLocalDescription(answer, setLocalSuccess);
}
// Fifth: Once we have two successful rounds through here, we're done.
function setLocalSuccess() {
setLocalCount++;
info("Set local description #" + setLocalCount);
// Then shalt thou count to two, no more, no less. Two shall be the
// number thou shalt count, and the number of the counting shall be
// two. Three shalt thou not count, neither count thou one, excepting
// that thou then proceed to two. Four is right out. Once the number two,
// being the second number, be reached, then thou shalt declare success.
ok (setLocalCount < 3, "Set local count is less than three.")
if (setLocalCount === 2) {
is (answerCount, 2, "Answer count is 2.")
test.next();
}
}
}
]
];
var test;
runTest(function () {
test = new PeerConnectionTest();
test.setMediaConstraints([{audio: true, video: true}], [ ]);
test.chain.replaceAfter("PC_LOCAL_GUM", steps);
test.run();
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -12,6 +12,7 @@
* liability, trademark and document use rules apply.
*/
[Constructor]
interface Range {
[Throws]
readonly attribute Node startContainer;

Просмотреть файл

@ -10,6 +10,7 @@
* liability, trademark and document use rules apply.
*/
[Constructor(optional DOMString data = "")]
interface Text : CharacterData {
[Throws]
Text splitText(unsigned long offset);

Просмотреть файл

@ -4977,13 +4977,12 @@ nsEditor::FinalizeSelection()
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
NS_ENSURE_TRUE_VOID(presShell);
nsRefPtr<nsCaret> caret = presShell->GetCaret();
if (caret) {
caret->SetIgnoreUserModify(true);
}
selCon->SetCaretEnabled(false);
nsFocusManager* fm = nsFocusManager::GetFocusManager();
NS_ENSURE_TRUE_VOID(fm);
fm->UpdateCaretForCaretBrowsingMode();
if (!HasIndependentSelection()) {
// If this editor doesn't have an independent selection, i.e., it must
// mean that it is an HTML editor, the selection controller is shared with

Просмотреть файл

@ -355,7 +355,8 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
"Adreno (TM) 205",
"Adreno (TM) 320",
"PowerVR SGX 530",
"PowerVR SGX 540"
"PowerVR SGX 540",
"NVIDIA Tegra"
};
mRenderer = RendererOther;
@ -534,7 +535,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
mSymbols.fEGLImageTargetRenderbufferStorage = nullptr;
}
}
// Load developer symbols, don't fail if we can't find them.
SymLoadStruct auxSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
@ -779,10 +780,10 @@ GLContext::ListHasExtension(const GLubyte *extensions, const char *extension)
if (where || *extension == '\0')
return false;
/*
/*
* It takes a bit of care to be fool-proof about parsing the
* OpenGL extensions string. Don't be fooled by sub-strings,
* etc.
* etc.
*/
start = extensions;
for (;;) {
@ -1385,7 +1386,7 @@ GLContext::GetTexImage(GLuint aTexture, bool aYInvert, ShaderProgramType aShader
gfxIntSize size;
fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, &size.width);
fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, &size.height);
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(size, gfxASurface::ImageFormatARGB32);
if (!surf || surf->CairoStatus()) {
return NULL;
@ -1400,7 +1401,7 @@ GLContext::GetTexImage(GLuint aTexture, bool aYInvert, ShaderProgramType aShader
if (currentPackAlignment != 4) {
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
}
if (aShader == RGBALayerProgramType || aShader == RGBXLayerProgramType) {
SwapRAndBComponents(surf);
}
@ -1838,8 +1839,8 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
if (srcSubRect.IsEmpty()) {
continue;
}
// We now have the intersection of
// the current source tile
// We now have the intersection of
// the current source tile
// and the desired source rectangle
// and the destination tile
// and the desired destination rectange
@ -1922,7 +1923,7 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
fEnable(LOCAL_GL_BLEND);
}
static unsigned int
static unsigned int
DataOffset(gfxImageSurface *aSurf, const nsIntPoint &aPoint)
{
unsigned int data = aPoint.y * aSurf->Stride();
@ -1930,8 +1931,8 @@ DataOffset(gfxImageSurface *aSurf, const nsIntPoint &aPoint)
return data;
}
ShaderProgramType
GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
ShaderProgramType
GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
bool aOverwrite,
@ -1942,21 +1943,21 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
bool textureInited = aOverwrite ? false : true;
MakeCurrent();
fActiveTexture(aTextureUnit);
if (!aTexture) {
fGenTextures(1, &aTexture);
fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MIN_FILTER,
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MIN_FILTER,
LOCAL_GL_LINEAR);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MAG_FILTER,
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MAG_FILTER,
LOCAL_GL_LINEAR);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_S,
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_T,
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
textureInited = false;
} else {
@ -1973,17 +1974,17 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
unsigned char* data = NULL;
if (!imageSurface ||
if (!imageSurface ||
(imageSurface->Format() != gfxASurface::ImageFormatARGB32 &&
imageSurface->Format() != gfxASurface::ImageFormatRGB24 &&
imageSurface->Format() != gfxASurface::ImageFormatRGB16_565 &&
imageSurface->Format() != gfxASurface::ImageFormatA8)) {
// We can't get suitable pixel data for the surface, make a copy
nsIntRect bounds = aDstRegion.GetBounds();
imageSurface =
new gfxImageSurface(gfxIntSize(bounds.width, bounds.height),
imageSurface =
new gfxImageSurface(gfxIntSize(bounds.width, bounds.height),
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y));
@ -2052,10 +2053,10 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
// The inital data pointer is at the top left point of the region's
// bounding rectangle. We need to find the offset of this rect
// within the region and adjust the data pointer accordingly.
unsigned char *rectData =
unsigned char *rectData =
data + DataOffset(imageSurface, iterRect->TopLeft() - topLeft);
NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
"Must be uploading to the origin when we don't have an existing texture");
if (textureInited && CanUploadSubTextures()) {
@ -2545,7 +2546,7 @@ GLContext::UseBlitProgram()
shaders[0] = fCreateShader(LOCAL_GL_VERTEX_SHADER);
shaders[1] = fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
const char *blitVSSrc =
const char *blitVSSrc =
"attribute vec2 aVertex;"
"attribute vec2 aTexCoord;"
"varying vec2 vTexCoord;"

Просмотреть файл

@ -262,7 +262,7 @@ public:
bool IsGLES2() const {
return mIsGLES2;
}
/**
* Returns true if either this is the GLES2 API, or had the GL_ARB_ES2_compatibility extension
*/
@ -301,6 +301,7 @@ public:
RendererAdrenoTM320,
RendererSGX530,
RendererSGX540,
RendererTegra,
RendererOther
};
@ -859,14 +860,14 @@ public:
* The aDstPoint parameter is ignored if no texture was provided
* or aOverwrite is true.
*
* \param aSurface Surface to upload.
* \param aSurface Surface to upload.
* \param aDstRegion Region of texture to upload to.
* \param aTexture Texture to use, or 0 to have one created for you.
* \param aOverwrite Over an existing texture with a new one.
* \param aSrcPoint Offset into aSrc where the region's bound's
* \param aSrcPoint Offset into aSrc where the region's bound's
* TopLeft() sits.
* \param aPixelBuffer Pass true to upload texture data with an
* offset from the base data (generally for pixel buffer objects),
* offset from the base data (generally for pixel buffer objects),
* otherwise textures are upload with an absolute pointer to the data.
* \param aTextureUnit, the texture unit used temporarily to upload the
* surface. This testure may be overridden, clients should not rely on
@ -874,7 +875,7 @@ public:
* texture unit being active.
* \return Shader program needed to render this texture.
*/
ShaderProgramType UploadSurfaceToTexture(gfxASurface *aSurface,
ShaderProgramType UploadSurfaceToTexture(gfxASurface *aSurface,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
bool aOverwrite = false,
@ -882,16 +883,16 @@ public:
bool aPixelBuffer = false,
GLenum aTextureUnit = LOCAL_GL_TEXTURE0);
void TexImage2D(GLenum target, GLint level, GLint internalformat,
void TexImage2D(GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLsizei stride,
GLint pixelsize, GLint border, GLenum format,
GLint pixelsize, GLint border, GLenum format,
GLenum type, const GLvoid *pixels);
void TexSubImage2D(GLenum target, GLint level,
GLint xoffset, GLint yoffset,
void TexSubImage2D(GLenum target, GLint level,
GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height, GLsizei stride,
GLint pixelsize, GLenum format,
GLint pixelsize, GLenum format,
GLenum type, const GLvoid* pixels);
/**
@ -1399,19 +1400,19 @@ protected:
}
public:
/** \returns the first GL error, and guarantees that all GL error flags are cleared,
* i.e. that a subsequent GetError call will return NO_ERROR
*/
GLenum GetAndClearError() {
// the first error is what we want to return
GLenum error = fGetError();
if (error) {
// clear all pending errors
while(fGetError()) {}
}
return error;
}
@ -1460,7 +1461,7 @@ public:
if (DebugMode() & DebugTrace)
printf_stderr("[gl:%p] < %s [0x%04x]\n", this, glFunction, mGLError);
if (mGLError != LOCAL_GL_NO_ERROR) {
printf_stderr("GL ERROR: %s generated GL error %s(0x%04x)\n",
printf_stderr("GL ERROR: %s generated GL error %s(0x%04x)\n",
glFunction,
GLErrorToString(mGLError),
mGLError);
@ -1497,7 +1498,7 @@ public:
#define BEFORE_GL_CALL do { \
BeforeGLCall(MOZ_FUNCTION_NAME); \
} while (0)
#define AFTER_GL_CALL do { \
AfterGLCall(MOZ_FUNCTION_NAME); \
} while (0)
@ -1591,7 +1592,7 @@ private:
// we use viewport instead and assume viewport size matches the
// destination. If we ever try use partial viewports for layers we need
// to fix this, and remove the assertion.
NS_ASSERTION(!mFlipped || (x == 0 && y == 0), "TODO: Need to flip the viewport rect");
NS_ASSERTION(!mFlipped || (x == 0 && y == 0), "TODO: Need to flip the viewport rect");
mSymbols.fViewport(x, y, width, height);
AFTER_GL_CALL;
}
@ -1985,7 +1986,7 @@ public:
}
void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
{
{
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fGetTexLevelParameteriv);
mSymbols.fGetTexLevelParameteriv(target, level, pname, params);

Просмотреть файл

@ -109,7 +109,6 @@ ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
// don't signal a new transaction to ShadowLayerForwarder. Carry on adding
// to the previous transaction.
ScreenOrientation orientation;
nsIntRect clientBounds;
if (TabChild* window = mWidget->GetOwningTabChild()) {
orientation = window->GetOrientation();
} else {
@ -117,7 +116,9 @@ ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
hal::GetCurrentScreenConfiguration(&currentConfig);
orientation = currentConfig.orientation();
}
nsIntRect clientBounds;
mWidget->GetClientBounds(clientBounds);
clientBounds.x = clientBounds.y = 0;
ShadowLayerForwarder::BeginTransaction(mTargetBounds, mTargetRotation, clientBounds, orientation);
// If we're drawing on behalf of a context with async pan/zoom

Просмотреть файл

@ -97,6 +97,7 @@ TextureClientShmem::SetDescriptor(const SurfaceDescriptor& aDescriptor)
NS_ASSERTION(mDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorGralloc ||
mDescriptor.type() == SurfaceDescriptor::TShmem ||
mDescriptor.type() == SurfaceDescriptor::TMemoryImage ||
mDescriptor.type() == SurfaceDescriptor::TRGBImage,
"Invalid surface descriptor");
}

Просмотреть файл

@ -450,7 +450,8 @@ ContentHostIncremental::UpdateIncremental(TextureIdentifier aTextureId,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
{
mUpdateList.AppendElement(new TextureUpdateRequest(aTextureId,
mUpdateList.AppendElement(new TextureUpdateRequest(mDeAllocator,
aTextureId,
aSurface,
aUpdated,
aBufferRect,
@ -642,9 +643,6 @@ ContentHostIncremental::TextureUpdateRequest::Execute(ContentHostIncremental* aH
} else {
aHost->mTextureHostOnWhite->Update(mDescriptor, &mUpdated, &offset);
}
//TODO: Recycle these?
aHost->mDeAllocator->DestroySharedSurface(&mDescriptor);
}
#ifdef MOZ_LAYERS_HAVE_LOG

Просмотреть файл

@ -308,18 +308,26 @@ private:
class TextureUpdateRequest : public Request
{
public:
TextureUpdateRequest(TextureIdentifier aTextureId,
TextureUpdateRequest(ISurfaceAllocator* aDeAllocator,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdated,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
: mTextureId(aTextureId)
: mDeAllocator(aDeAllocator)
, mTextureId(aTextureId)
, mDescriptor(aDescriptor)
, mUpdated(aUpdated)
, mBufferRect(aBufferRect)
, mBufferRotation(aBufferRotation)
{}
~TextureUpdateRequest()
{
//TODO: Recycle these?
mDeAllocator->DestroySharedSurface(&mDescriptor);
}
virtual void Execute(ContentHostIncremental *aHost);
private:
@ -332,6 +340,7 @@ private:
nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
ISurfaceAllocator* mDeAllocator;
TextureIdentifier mTextureId;
SurfaceDescriptor mDescriptor;
nsIntRegion mUpdated;

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/layers/SharedPlanarYCbCrImage.h"
#include "mozilla/layers/SharedRGBImage.h"
#include "nsXULAppAPI.h"
#ifdef DEBUG
#include "prenv.h"
@ -85,6 +86,16 @@ ISurfaceAllocator::AllocSurfaceDescriptorWithCaps(const gfxIntSize& aSize,
return true;
}
if (XRE_GetProcessType() == GeckoProcessType_Default) {
gfxImageFormat format =
gfxPlatform::GetPlatform()->OptimalFormatForContent(aContent);
int32_t stride = gfxASurface::FormatStrideForWidth(format, aSize.width);
uint8_t *data = new uint8_t[stride * aSize.height];
*aBuffer = MemoryImage((uintptr_t)data, aSize, stride, format);
return true;
}
nsRefPtr<gfxSharedImageSurface> buffer;
if (!AllocSharedImageSurface(aSize, aContent,
getter_AddRefs(buffer))) {
@ -122,6 +133,9 @@ ISurfaceAllocator::DestroySharedSurface(SurfaceDescriptor* aSurface)
break;
case SurfaceDescriptor::TSurfaceDescriptorD3D10:
break;
case SurfaceDescriptor::TMemoryImage:
delete [] (unsigned char *)aSurface->get_MemoryImage().data();
break;
case SurfaceDescriptor::Tnull_t:
case SurfaceDescriptor::T__None:
break;

Просмотреть файл

@ -83,6 +83,13 @@ struct RGBImage {
uint64_t owner;
};
struct MemoryImage {
uintptr_t data;
gfxIntSize size;
uint32_t stride;
uint32_t format;
};
union SurfaceDescriptor {
Shmem;
SurfaceDescriptorD3D10;
@ -92,6 +99,7 @@ union SurfaceDescriptor {
RGBImage;
SharedTextureDescriptor;
SurfaceStreamDescriptor;
MemoryImage;
null_t;
};

Просмотреть файл

@ -32,10 +32,22 @@ ISurfaceAllocator::PlatformAllocSurfaceDescriptor(const gfxIntSize& aSize,
ShadowLayerForwarder::PlatformOpenDescriptor(OpenMode aMode,
const SurfaceDescriptor& aSurface)
{
if (SurfaceDescriptor::TShmem != aSurface.type()) {
return nullptr;
if (aSurface.type() == SurfaceDescriptor::TShmem) {
return gfxSharedQuartzSurface::Open(aSurface.get_Shmem());
} else if (aSurface.type() == SurfaceDescriptor::TMemoryImage) {
const MemoryImage& image = aSurface.get_MemoryImage();
gfxASurface::gfxImageFormat format
= static_cast<gfxASurface::gfxImageFormat>(image.format());
nsRefPtr<gfxASurface> surf =
new gfxQuartzSurface((unsigned char*)image.data(),
image.size(),
image.stride(),
format);
return surf.forget();
}
return gfxSharedQuartzSurface::Open(aSurface.get_Shmem());
return nullptr;
}
/*static*/ bool

Просмотреть файл

@ -358,12 +358,12 @@ ShadowLayerForwarder::UpdateTextureIncremental(CompositableClient* aCompositable
{
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(aCompositable->GetIPDLActor());
mTxn->AddPaint(OpPaintTextureIncremental(nullptr, aCompositable->GetIPDLActor(),
aTextureId,
aDescriptor,
aUpdatedRegion,
aBufferRect,
aBufferRotation));
mTxn->AddNoSwapPaint(OpPaintTextureIncremental(nullptr, aCompositable->GetIPDLActor(),
aTextureId,
aDescriptor,
aUpdatedRegion,
aBufferRect,
aBufferRotation));
}
@ -530,6 +530,16 @@ ShadowLayerForwarder::OpenDescriptor(OpenMode aMode,
rgbFormat);
return surf.forget();
}
case SurfaceDescriptor::TMemoryImage: {
const MemoryImage& image = aSurface.get_MemoryImage();
gfxASurface::gfxImageFormat format
= static_cast<gfxASurface::gfxImageFormat>(image.format());
surf = new gfxImageSurface((unsigned char *)image.data(),
image.size(),
image.stride(),
format);
return surf.forget();
}
default:
NS_ERROR("unexpected SurfaceDescriptor type!");
return nullptr;
@ -730,8 +740,8 @@ ShadowLayerForwarder::CreatedIncrementalBuffer(CompositableClient* aCompositable
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect)
{
mTxn->AddPaint(OpCreatedIncrementalTexture(nullptr, aCompositable->GetIPDLActor(),
aTextureInfo, aBufferRect));
mTxn->AddNoSwapPaint(OpCreatedIncrementalTexture(nullptr, aCompositable->GetIPDLActor(),
aTextureInfo, aBufferRect));
}
void

Просмотреть файл

@ -777,7 +777,7 @@ CompositorOGL::BeginFrame(const Rect *aClipRectIn, const gfxMatrix& aTransform,
// sent atomically with rotation changes
nsIntRect intRect;
mWidget->GetClientBounds(intRect);
rect = gfxRect(intRect.x, intRect.y, intRect.width, intRect.height);
rect = gfxRect(0, 0, intRect.width, intRect.height);
}
}

Просмотреть файл

@ -786,6 +786,7 @@ LayerManagerOGL::Render()
// thread, and undoes all the care we take with layers txns being
// sent atomically with rotation changes
mWidget->GetClientBounds(rect);
rect.x = rect.y = 0;
}
}
WorldTransformRect(rect);

Просмотреть файл

@ -125,6 +125,29 @@ gfxQuartzSurface::gfxQuartzSurface(unsigned char *data,
}
}
gfxQuartzSurface::gfxQuartzSurface(unsigned char *data,
const gfxIntSize& aSize,
long stride,
gfxImageFormat format,
bool aForPrinting)
: mCGContext(nullptr), mSize(aSize.width, aSize.height), mForPrinting(aForPrinting)
{
if (!CheckSurfaceSize(aSize))
MakeInvalid();
cairo_surface_t *surf = cairo_quartz_surface_create_for_data
(data, (cairo_format_t) format, aSize.width, aSize.height, stride);
mCGContext = cairo_quartz_surface_get_cg_context (surf);
CGContextRetain(mCGContext);
Init(surf);
if (mSurfaceValid) {
RecordMemoryUsed(mSize.height * stride + sizeof(gfxQuartzSurface));
}
}
already_AddRefed<gfxASurface>
gfxQuartzSurface::CreateSimilarSurface(gfxContentType aType,
const gfxIntSize& aSize)

Просмотреть файл

@ -20,6 +20,7 @@ public:
gfxQuartzSurface(CGContextRef context, const gfxIntSize& size, bool aForPrinting = false);
gfxQuartzSurface(cairo_surface_t *csurf, bool aForPrinting = false);
gfxQuartzSurface(unsigned char *data, const gfxSize& size, long stride, gfxImageFormat format, bool aForPrinting = false);
gfxQuartzSurface(unsigned char *data, const gfxIntSize& size, long stride, gfxImageFormat format, bool aForPrinting = false);
virtual ~gfxQuartzSurface();

Просмотреть файл

@ -14,8 +14,10 @@
#include "nsUnicharUtils.h"
#include "prlong.h"
#include "nsNetUtil.h"
#include "nsICacheService.h"
#include "nsIProtocolHandler.h"
#include "nsIPrincipal.h"
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
#include "opentype-sanitiser.h"
@ -330,7 +332,7 @@ gfxUserFontSet::SanitizeOpenTypeData(gfxMixedFontFamily *aFamily,
static void
StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
const nsAString& aOriginalName,
bool aPrivate, const nsAString& aOriginalName,
nsTArray<uint8_t>* aMetadata, uint32_t aMetaOrigLen)
{
if (!aFontEntry->mUserFontData) {
@ -345,6 +347,7 @@ StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
userFontData->mURI = src.mURI;
userFontData->mPrincipal = aProxy->mPrincipal;
}
userFontData->mPrivate = aPrivate;
userFontData->mFormat = src.mFormatFlags;
userFontData->mRealName = aOriginalName;
if (aMetadata) {
@ -484,7 +487,10 @@ gfxUserFontSet::LoadNext(gfxMixedFontFamily *aFamily,
uint32_t(mGeneration)));
fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
StoreUserFontData(fe, aProxyEntry, nsString(), nullptr, 0);
// For src:local(), we don't care whether the request is from
// a private window as there's no issue of caching resources;
// local fonts are just available all the time.
StoreUserFontData(fe, aProxyEntry, false, nsString(), nullptr, 0);
ReplaceFontEntry(aFamily, aProxyEntry, fe);
return STATUS_LOADED;
} else {
@ -501,16 +507,20 @@ gfxUserFontSet::LoadNext(gfxMixedFontFamily *aFamily,
currSrc.mFormatFlags)) {
nsIPrincipal *principal = nullptr;
nsresult rv = CheckFontLoad(&currSrc, &principal);
bool bypassCache;
nsresult rv = CheckFontLoad(&currSrc, &principal, &bypassCache);
if (NS_SUCCEEDED(rv) && principal != nullptr) {
// see if we have an existing entry for this source
gfxFontEntry *fe =
UserFontCache::GetFont(currSrc.mURI, principal,
aProxyEntry);
if (fe) {
ReplaceFontEntry(aFamily, aProxyEntry, fe);
return STATUS_LOADED;
if (!bypassCache) {
// see if we have an existing entry for this source
gfxFontEntry *fe =
UserFontCache::GetFont(currSrc.mURI, principal,
aProxyEntry,
GetPrivateBrowsing());
if (fe) {
ReplaceFontEntry(aFamily, aProxyEntry, fe);
return STATUS_LOADED;
}
}
// record the principal returned by CheckFontLoad,
@ -529,9 +539,8 @@ gfxUserFontSet::LoadNext(gfxMixedFontFamily *aFamily,
// sync load font immediately
rv = SyncLoadFontData(aProxyEntry, &currSrc,
buffer, bufferLength);
if (NS_SUCCEEDED(rv) &&
(fe = LoadFont(aFamily, aProxyEntry,
buffer, bufferLength))) {
if (NS_SUCCEEDED(rv) && LoadFont(aFamily, aProxyEntry,
buffer, bufferLength)) {
return STATUS_LOADED;
} else {
LogMessage(aFamily, aProxyEntry,
@ -654,8 +663,8 @@ gfxUserFontSet::LoadFont(gfxMixedFontFamily *aFamily,
// newly-created font entry
fe->mFeatureSettings.AppendElements(aProxy->mFeatureSettings);
fe->mLanguageOverride = aProxy->mLanguageOverride;
StoreUserFontData(fe, aProxy, originalFullName,
&metadata, metaOrigLen);
StoreUserFontData(fe, aProxy, GetPrivateBrowsing(),
originalFullName, &metadata, metaOrigLen);
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
nsAutoCString fontURI;
@ -741,6 +750,35 @@ gfxUserFontSet::FindFamilyFor(gfxFontEntry* aFontEntry) const
nsTHashtable<gfxUserFontSet::UserFontCache::Entry>*
gfxUserFontSet::UserFontCache::sUserFonts = nullptr;
NS_IMPL_ISUPPORTS1(gfxUserFontSet::UserFontCache::Flusher, nsIObserver)
PLDHashOperator
gfxUserFontSet::UserFontCache::Entry::RemoveIfPrivate(Entry* aEntry,
void* aUserData)
{
return aEntry->mPrivate ? PL_DHASH_REMOVE : PL_DHASH_NEXT;
}
NS_IMETHODIMP
gfxUserFontSet::UserFontCache::Flusher::Observe(nsISupports* aSubject,
const char* aTopic,
const PRUnichar* aData)
{
if (!sUserFonts) {
return NS_OK;
}
if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID)) {
sUserFonts->Clear();
} else if (!strcmp(aTopic, "last-pb-context-exited")) {
sUserFonts->EnumerateEntries(Entry::RemoveIfPrivate, nullptr);
} else {
NS_NOTREACHED("unexpected topic");
}
return NS_OK;
}
bool
gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const
{
@ -753,6 +791,10 @@ gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const
return false;
}
if (mPrivate != aKey->mPrivate) {
return false;
}
const gfxFontEntry *fe = aKey->mFontEntry;
if (mFontEntry->mItalic != fe->mItalic ||
mFontEntry->mWeight != fe->mWeight ||
@ -774,10 +816,20 @@ gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry *aFontEntry)
if (!sUserFonts) {
sUserFonts = new nsTHashtable<Entry>;
sUserFonts->Init();
nsCOMPtr<nsIObserverService> obs =
mozilla::services::GetObserverService();
if (obs) {
Flusher *flusher = new Flusher;
obs->AddObserver(flusher, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID,
false);
obs->AddObserver(flusher, "last-pb-context-exited", false);
}
}
gfxUserFontData *data = aFontEntry->mUserFontData;
sUserFonts->PutEntry(Key(data->mURI, data->mPrincipal, aFontEntry));
sUserFonts->PutEntry(Key(data->mURI, data->mPrincipal, aFontEntry,
data->mPrivate));
}
void
@ -791,20 +843,23 @@ gfxUserFontSet::UserFontCache::ForgetFont(gfxFontEntry *aFontEntry)
gfxUserFontData *data = aFontEntry->mUserFontData;
if (data) {
sUserFonts->RemoveEntry(Key(data->mURI, data->mPrincipal, aFontEntry));
sUserFonts->RemoveEntry(Key(data->mURI, data->mPrincipal, aFontEntry,
data->mPrivate));
}
}
gfxFontEntry*
gfxUserFontSet::UserFontCache::GetFont(nsIURI *aSrcURI,
nsIPrincipal *aPrincipal,
gfxProxyFontEntry *aProxy)
gfxProxyFontEntry *aProxy,
bool aPrivate)
{
if (!sUserFonts) {
return nullptr;
}
Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, aPrincipal, aProxy));
Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, aPrincipal, aProxy,
aPrivate));
if (entry) {
return entry->GetFontEntry();
}

Просмотреть файл

@ -62,6 +62,7 @@ public:
uint32_t mSrcIndex; // index in the rule's source list
uint32_t mFormat; // format hint for the source used, if any
uint32_t mMetaOrigLen; // length needed to decompress metadata
bool mPrivate; // whether font belongs to a private window
};
// initially contains a set of proxy font entry objects, replaced with
@ -203,9 +204,12 @@ public:
// which does not directly track families in the font group's list.
gfxFontFamily *FindFamilyFor(gfxFontEntry *aFontEntry) const;
// check whether the given source is allowed to be loaded
// check whether the given source is allowed to be loaded;
// returns the Principal (for use in the key when caching the loaded font),
// and whether the load should bypass the cache (force-reload).
virtual nsresult CheckFontLoad(const gfxFontFaceSrc *aFontFaceSrc,
nsIPrincipal **aPrincipal) = 0;
nsIPrincipal **aPrincipal,
bool *aBypassCache) = 0;
// initialize the process that loads external font data, which upon
// completion will call OnLoadComplete method
@ -250,15 +254,30 @@ public:
static void ForgetFont(gfxFontEntry *aFontEntry);
// Return the gfxFontEntry corresponding to a given URI and principal,
// and the features of the given proxy, or nullptr if none is available
// and the features of the given proxy, or nullptr if none is available.
// The aPrivate flag is set for requests coming from private windows,
// so we can avoid leaking fonts cached in private windows mode out to
// normal windows.
static gfxFontEntry* GetFont(nsIURI *aSrcURI,
nsIPrincipal *aPrincipal,
gfxProxyFontEntry *aProxy);
gfxProxyFontEntry *aProxy,
bool aPrivate);
// Clear everything so that we don't leak URIs and Principals.
static void Shutdown();
private:
// Helper that we use to observe the empty-cache notification
// from nsICacheService.
class Flusher : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
Flusher() {}
virtual ~Flusher() {}
};
// Key used to look up entries in the user-font cache.
// Note that key comparison does *not* use the mFontEntry field
// as a whole; it only compares specific fields within the entry
@ -269,12 +288,14 @@ public:
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mPrincipal;
gfxFontEntry *mFontEntry;
bool mPrivate;
Key(nsIURI* aURI, nsIPrincipal* aPrincipal,
gfxFontEntry* aFontEntry)
gfxFontEntry* aFontEntry, bool aPrivate)
: mURI(aURI),
mPrincipal(aPrincipal),
mFontEntry(aFontEntry)
mFontEntry(aFontEntry),
mPrivate(aPrivate)
{ }
};
@ -286,13 +307,15 @@ public:
Entry(KeyTypePointer aKey)
: mURI(aKey->mURI),
mPrincipal(aKey->mPrincipal),
mFontEntry(aKey->mFontEntry)
mFontEntry(aKey->mFontEntry),
mPrivate(aKey->mPrivate)
{ }
Entry(const Entry& aOther)
: mURI(aOther.mURI),
mPrincipal(aOther.mPrincipal),
mFontEntry(aOther.mFontEntry)
mFontEntry(aOther.mFontEntry),
mPrivate(aOther.mPrivate)
{ }
~Entry() { }
@ -304,7 +327,7 @@ public:
static PLDHashNumber HashKey(const KeyTypePointer aKey) {
uint32_t principalHash;
aKey->mPrincipal->GetHashValue(&principalHash);
return mozilla::HashGeneric(principalHash,
return mozilla::HashGeneric(principalHash + int(aKey->mPrivate),
nsURIHashKey::HashKey(aKey->mURI),
HashFeatures(aKey->mFontEntry->mFeatureSettings),
mozilla::HashString(aKey->mFontEntry->mFamilyName),
@ -318,6 +341,8 @@ public:
gfxFontEntry* GetFontEntry() const { return mFontEntry; }
static PLDHashOperator RemoveIfPrivate(Entry* aEntry, void* aUserData);
private:
static uint32_t
HashFeatures(const nsTArray<gfxFontFeature>& aFeatures) {
@ -332,12 +357,18 @@ public:
// The font entry MUST notify the cache when it is destroyed
// (by calling Forget()).
gfxFontEntry *mFontEntry;
// Whether this font was loaded from a private window.
bool mPrivate;
};
static nsTHashtable<Entry> *sUserFonts;
};
protected:
// Return whether the font set is associated with a private-browsing tab.
virtual bool GetPrivateBrowsing() = 0;
// for a given proxy font entry, attempt to load the next resource
// in the src list
LoadStatus LoadNext(gfxMixedFontFamily *aFamily,

Просмотреть файл

@ -663,7 +663,7 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
}
}
if (!decoder->mFrameIsHidden && decoder->NeedsNewFrame()) {
if (decoder->NeedsNewFrame()) {
/* We know that we need a new frame, so pause input so the decoder
* infrastructure can give it to us.
*/
@ -829,10 +829,12 @@ nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
/* We know that we need a new frame, so pause input so the decoder
* infrastructure can give it to us.
*/
png_process_data_pause(png_ptr, /* save = */ 1);
if (decoder->NeedsNewFrame()) {
/* We know that we need a new frame, so pause input so the decoder
* infrastructure can give it to us.
*/
png_process_data_pause(png_ptr, /* save = */ 1);
}
#endif
}

Просмотреть файл

@ -1257,6 +1257,10 @@ RasterImage::InternalAddFrame(uint32_t framenum,
nsAutoPtr<imgFrame> frame(new imgFrame());
nsresult rv = frame->Init(aX, aY, aWidth, aHeight, aFormat, aPaletteDepth);
if (!(mSize.width > 0 && mSize.height > 0))
NS_WARNING("Shouldn't call InternalAddFrame with zero size");
if (!NS_SUCCEEDED(rv))
NS_WARNING("imgFrame::Init should succeed");
NS_ENSURE_SUCCESS(rv, rv);
// We know we are in a decoder. Therefore, we must unlock the previous frame
@ -2752,6 +2756,12 @@ RasterImage::RequestDecodeCore(RequestDecodeType aDecodeType)
if (mDecoded)
return NS_OK;
// If we don't have any bytes to flush to the decoder, we can't do anything.
// mBytesDecoded can be bigger than mSourceData.Length() if we're not storing
// the source data.
if (mBytesDecoded > mSourceData.Length())
return NS_OK;
// mFinishing protects against the case when we enter RequestDecode from
// ShutdownDecoder -- in that case, we're done with the decode, we're just
// not quite ready to admit it. See bug 744309.
@ -2901,6 +2911,12 @@ RasterImage::SyncDecode()
if (mDecoded)
return NS_OK;
// If we don't have any bytes to flush to the decoder, we can't do anything.
// mBytesDecoded can be bigger than mSourceData.Length() if we're not storing
// the source data.
if (mBytesDecoded > mSourceData.Length())
return NS_OK;
// If we have a decoder open with different flags than what we need, shut it
// down
if (mDecoder && mDecoder->GetDecodeFlags() != mFrameDecodeFlags) {
@ -3286,6 +3302,8 @@ RasterImage::DecodeSomeData(uint32_t aMaxBytes)
if (mBytesDecoded == mSourceData.Length())
return NS_OK;
MOZ_ASSERT(mBytesDecoded < mSourceData.Length());
// write the proper amount of data
uint32_t bytesToDecode = std::min(aMaxBytes,
mSourceData.Length() - mBytesDecoded);

Просмотреть файл

@ -150,8 +150,10 @@ nsresult imgFrame::Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
gfxASurface::gfxImageFormat aFormat, uint8_t aPaletteDepth /* = 0 */)
{
// assert for properties that should be verified by decoders, warn for properties related to bad content
if (!AllowedImageSize(aWidth, aHeight))
if (!AllowedImageSize(aWidth, aHeight)) {
NS_WARNING("Should have legal image size");
return NS_ERROR_FAILURE;
}
mOffset.MoveTo(aX, aY);
mSize.SizeTo(aWidth, aHeight);
@ -162,12 +164,15 @@ nsresult imgFrame::Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
if (aPaletteDepth != 0) {
// We're creating for a paletted image.
if (aPaletteDepth > 8) {
NS_WARNING("Should have legal palette depth");
NS_ERROR("This Depth is not supported");
return NS_ERROR_FAILURE;
}
// Use the fallible allocator here
mPalettedImageData = (uint8_t*)moz_malloc(PaletteDataLength() + GetImageDataLength());
if (!mPalettedImageData)
NS_WARNING("moz_malloc for paletted image data should succeed");
NS_ENSURE_TRUE(mPalettedImageData, NS_ERROR_OUT_OF_MEMORY);
} else {
// For Windows, we must create the device surface first (if we're
@ -195,6 +200,11 @@ nsresult imgFrame::Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight,
if (!mImageSurface || mImageSurface->CairoStatus()) {
mImageSurface = nullptr;
// guess
if (!mImageSurface) {
NS_WARNING("Allocation of gfxImageSurface should succeed");
} else if (!mImageSurface->CairoStatus()) {
NS_WARNING("gfxImageSurface should have good CairoStatus");
}
return NS_ERROR_OUT_OF_MEMORY;
}

Просмотреть файл

@ -39,6 +39,7 @@ class ProxyBehaviour
virtual imgStatusTracker& GetStatusTracker() const = 0;
virtual imgRequest* GetOwner() const = 0;
virtual void SetOwner(imgRequest* aOwner) = 0;
virtual bool IsStatic() = 0;
};
class RequestBehaviour : public ProxyBehaviour
@ -63,6 +64,8 @@ class RequestBehaviour : public ProxyBehaviour
}
}
virtual bool IsStatic() { return false; }
private:
// We maintain the following invariant:
// The proxy is registered at most with a single imgRequest as an observer,
@ -78,6 +81,11 @@ class RequestBehaviour : public ProxyBehaviour
mozilla::image::Image*
RequestBehaviour::GetImage() const
{
if (mOwnerHasImage && !mOwner) {
NS_WARNING("If mOwnerHasImage is true mOwner must be true");
MOZ_CRASH();
}
if (!mOwnerHasImage)
return nullptr;
return GetStatusTracker().GetImage();
@ -92,6 +100,11 @@ RequestBehaviour::GetStatusTracker() const
// That's why this method uses mOwner->GetStatusTracker() instead of just
// mOwner->mStatusTracker -- we might have a null mImage and yet have an
// mOwner with a non-null mImage (and a null mStatusTracker pointer).
if (mOwnerHasImage && !mOwner) {
NS_WARNING("If mOwnerHasImage is true mOwner must be true");
MOZ_CRASH();
}
return mOwner->GetStatusTracker();
}
@ -165,6 +178,11 @@ nsresult imgRequestProxy::Init(imgRequest* aOwner,
NS_ABORT_IF_FALSE(mAnimationConsumers == 0, "Cannot have animation before Init");
if (!mBehaviour->IsStatic() && !aOwner) {
NS_WARNING("Non-static imgRequestProxies should be initialized with an owner");
MOZ_CRASH();
}
mBehaviour->SetOwner(aOwner);
mListener = aObserver;
// Make sure to addref mListener before the AddProxy call below, since
@ -213,6 +231,11 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
GetOwner()->RemoveProxy(this, NS_IMAGELIB_CHANGING_OWNER);
if (!mBehaviour->IsStatic() && !aNewOwner) {
NS_WARNING("Non-static imgRequestProxies should be only changed to a non-null owner");
MOZ_CRASH();
}
mBehaviour->SetOwner(aNewOwner);
// If we were locked, apply the locks here
@ -562,6 +585,10 @@ NS_IMETHODIMP imgRequestProxy::Clone(imgINotificationObserver* aObserver,
{
nsresult result;
imgRequestProxy* proxy;
if (mBehaviour->IsStatic()) {
NS_WARNING("Calling non-static imgRequestProxy::Clone with static mBehaviour");
MOZ_CRASH();
}
result = Clone(aObserver, &proxy);
*aClone = proxy;
return result;
@ -1022,6 +1049,8 @@ public:
MOZ_ASSERT(!aOwner, "We shouldn't be giving static requests a non-null owner.");
}
virtual bool IsStatic() { return true; }
private:
// Our image. We have to hold a strong reference here, because that's normally
// the job of the underlying request.
@ -1051,6 +1080,10 @@ imgRequestProxyStatic::Clone(imgINotificationObserver* aObserver,
{
nsresult result;
imgRequestProxy* proxy;
if (!mBehaviour->IsStatic()) {
NS_WARNING("Calling static imgRequestProxy::Clone with non-static mBehaviour");
MOZ_CRASH();
}
result = PerformClone(aObserver, NewStaticProxy, &proxy);
*aClone = proxy;
return result;

Просмотреть файл

@ -925,8 +925,15 @@ selfhosted_out_h_deps := \
$(srcdir)/builtin/embedjs.py \
$(NULL)
SELFHOSTED_DEFINES += $(DEFINES) $(ACDEFINES)
ifdef MOZ_DEBUG
SELFHOSTED_DEFINES += $(MOZ_DEBUG_ENABLE_DEFS)
else
SELFHOSTED_DEFINES += $(MOZ_DEBUG_DISABLE_DEFS)
endif
selfhosted.out.h: $(selfhosted_out_h_deps)
$(PYTHON) $(srcdir)/builtin/embedjs.py $(DEFINES) $(ACDEFINES) \
$(PYTHON) $(srcdir)/builtin/embedjs.py $(SELFHOSTED_DEFINES) \
-p '$(CPP)' -m $(srcdir)/js.msg -o $@ $(selfhosting_srcs)
###############################################

Просмотреть файл

@ -1000,6 +1000,7 @@ BytecodeEmitter::isAliasedName(ParseNode *pn)
return script->varIsAliased(pn->pn_cookie.slot());
case Definition::PLACEHOLDER:
case Definition::NAMED_LAMBDA:
case Definition::MISSING:
JS_NOT_REACHED("unexpected dn->kind");
}
return false;
@ -1343,6 +1344,9 @@ BindNameToSlotHelper(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
case Definition::PLACEHOLDER:
return true;
case Definition::MISSING:
JS_NOT_REACHED("missing");
}
/*

Просмотреть файл

@ -6220,7 +6220,7 @@ Parser<ParseHandler>::primaryExpr(TokenKind tt)
bool spread = false, missingTrailingComma = false;
unsigned index = 0;
for (; ; index++) {
if (index == StackSpace::ARGS_LENGTH_MAX) {
if (index == JSObject::NELEMENTS_LIMIT) {
report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG);
return null();
}

Просмотреть файл

@ -170,7 +170,6 @@ class MinorCollectionTracer : public JSTracer
{
public:
Nursery *nursery;
JSRuntime *runtime;
AutoTraceSession session;
/*
@ -195,18 +194,17 @@ class MinorCollectionTracer : public JSTracer
MinorCollectionTracer(JSRuntime *rt, Nursery *nursery)
: JSTracer(),
nursery(nursery),
runtime(rt),
session(runtime, MinorCollecting),
session(rt, MinorCollecting),
head(NULL),
tail(&head),
savedNeedsBarrier(runtime->needsBarrier()),
disableStrictProxyChecking(runtime)
savedNeedsBarrier(rt->needsBarrier()),
disableStrictProxyChecking(rt)
{
JS_TracerInit(this, runtime, Nursery::MinorGCCallback);
JS_TracerInit(this, rt, Nursery::MinorGCCallback);
eagerlyTraceWeakMaps = TraceWeakMapKeysValues;
runtime->gcNumber++;
runtime->setNeedsBarrier(false);
rt->gcNumber++;
rt->setNeedsBarrier(false);
for (ZonesIter zone(rt); !zone.done(); zone.next())
zone->saveNeedsBarrier(false);
}
@ -222,11 +220,16 @@ class MinorCollectionTracer : public JSTracer
} /* namespace js */
static AllocKind
GetObjectAllocKindForCopy(JSObject *obj)
GetObjectAllocKindForCopy(JSRuntime *rt, JSObject *obj)
{
if (obj->isArray()) {
JS_ASSERT(obj->numFixedSlots() == 0);
size_t nelements = obj->getDenseInitializedLength();
/* Use minimal size object if we are just going to copy the pointer. */
if (!IsInsideNursery(rt, (void *)obj->getElementsHeader()))
return FINALIZE_OBJECT0_BACKGROUND;
size_t nelements = obj->getDenseCapacity();
return GetBackgroundAllocKind(GetGCArrayKind(nelements));
}
@ -262,7 +265,7 @@ void *
js::Nursery::moveToTenured(MinorCollectionTracer *trc, JSObject *src)
{
Zone *zone = src->zone();
AllocKind dstKind = GetObjectAllocKindForCopy(src);
AllocKind dstKind = GetObjectAllocKindForCopy(trc->runtime, src);
JSObject *dst = static_cast<JSObject *>(allocateFromTenured(zone, dstKind));
if (!dst)
MOZ_CRASH();
@ -326,6 +329,7 @@ js::Nursery::moveElementsToTenured(JSObject *dst, JSObject *src, AllocKind dstKi
ObjectElements *srcHeader = src->getElementsHeader();
ObjectElements *dstHeader;
/* TODO Bug 874151: Prefer to put element data inline if we have space. */
if (!isInside(srcHeader)) {
JS_ASSERT(src->elements == dst->elements);
hugeSlots.remove(reinterpret_cast<HeapSlot*>(srcHeader));
@ -348,14 +352,13 @@ js::Nursery::moveElementsToTenured(JSObject *dst, JSObject *src, AllocKind dstKi
return;
}
size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->initializedLength;
size_t nslots = ObjectElements::VALUES_PER_HEADER + srcHeader->capacity;
/* Unlike other objects, Arrays can have fixed elements. */
if (src->isArray() && nslots <= GetGCKindSlots(dstKind)) {
dst->setFixedElements();
dstHeader = dst->getElementsHeader();
js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
dstHeader->capacity = GetGCKindSlots(dstKind) - ObjectElements::VALUES_PER_HEADER;
return;
}
@ -364,7 +367,6 @@ js::Nursery::moveElementsToTenured(JSObject *dst, JSObject *src, AllocKind dstKi
if (!dstHeader)
MOZ_CRASH();
js_memcpy(dstHeader, srcHeader, nslots * sizeof(HeapSlot));
dstHeader->capacity = srcHeader->initializedLength;
dst->elements = dstHeader->elements();
}
@ -488,6 +490,7 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason)
comp->markAllInitialShapeTableEntries(&trc);
}
markStoreBuffer(&trc);
rt->newObjectCache.clearNurseryObjects(rt);
/*
* Most of the work is done here. This loop iterates over objects that have

Просмотреть файл

@ -843,7 +843,7 @@ TypedArrayStoreType(ArrayBufferView::ViewType viewType)
/*****************************************************************************/
typedef Vector<PropertyName*,1> LabelVector;
typedef Vector<MBasicBlock*,16> CaseVector;
typedef Vector<MBasicBlock*,8> BlockVector;
// ModuleCompiler encapsulates the compilation of an entire asm.js module. Over
// the course of an ModuleCompiler object's lifetime, many FunctionCompiler
@ -1546,7 +1546,6 @@ class FunctionCompiler
typedef HashMap<PropertyName*, Local> LocalMap;
private:
typedef Vector<MBasicBlock*, 2> BlockVector;
typedef HashMap<PropertyName*, BlockVector> LabeledBlockMap;
typedef HashMap<ParseNode*, BlockVector> UnlabeledBlockMap;
typedef Vector<ParseNode*, 4> NodeStack;
@ -2019,42 +2018,48 @@ class FunctionCompiler
return true;
}
void joinIf(MBasicBlock *joinBlock)
bool appendThenBlock(BlockVector *thenBlocks) {
if (!curBlock_)
return true;
return thenBlocks->append(curBlock_);
}
void joinIf(const BlockVector &thenBlocks, MBasicBlock *joinBlock)
{
if (!joinBlock)
return;
if (curBlock_) {
curBlock_->end(MGoto::New(joinBlock));
joinBlock->addPredecessor(curBlock_);
JS_ASSERT_IF(curBlock_, thenBlocks.back() == curBlock_);
for (size_t i = 0; i < thenBlocks.length(); i++) {
thenBlocks[i]->end(MGoto::New(joinBlock));
joinBlock->addPredecessor(thenBlocks[i]);
}
curBlock_ = joinBlock;
mirGraph().moveBlockToEnd(curBlock_);
}
MBasicBlock *switchToElse(MBasicBlock *elseBlock)
void switchToElse(MBasicBlock *elseBlock)
{
if (!elseBlock)
return NULL;
MBasicBlock *thenEnd = curBlock_;
return;
curBlock_ = elseBlock;
mirGraph().moveBlockToEnd(curBlock_);
return thenEnd;
}
bool joinIfElse(MBasicBlock *thenEnd)
bool joinIfElse(const BlockVector &thenBlocks)
{
if (!curBlock_ && !thenEnd)
if (!curBlock_ && thenBlocks.empty())
return true;
MBasicBlock *pred = curBlock_ ? curBlock_ : thenEnd;
MBasicBlock *pred = curBlock_ ? curBlock_ : thenBlocks[0];
MBasicBlock *join;
if (!newBlock(pred, &join))
return false;
if (curBlock_)
curBlock_->end(MGoto::New(join));
if (thenEnd)
thenEnd->end(MGoto::New(join));
if (curBlock_ && thenEnd)
join->addPredecessor(thenEnd);
for (size_t i = 0; i < thenBlocks.length(); i++) {
thenBlocks[i]->end(MGoto::New(join));
if (pred == curBlock_ || i > 0)
join->addPredecessor(thenBlocks[i]);
}
curBlock_ = join;
return true;
}
@ -2244,7 +2249,7 @@ class FunctionCompiler
return true;
}
bool startSwitchDefault(MBasicBlock *switchBlock, CaseVector *cases, MBasicBlock **defaultBlock)
bool startSwitchDefault(MBasicBlock *switchBlock, BlockVector *cases, MBasicBlock **defaultBlock)
{
if (!startSwitchCase(switchBlock, defaultBlock))
return false;
@ -2264,7 +2269,7 @@ class FunctionCompiler
return true;
}
bool joinSwitch(MBasicBlock *switchBlock, const CaseVector &cases, MBasicBlock *defaultBlock)
bool joinSwitch(MBasicBlock *switchBlock, const BlockVector &cases, MBasicBlock *defaultBlock)
{
ParseNode *pn = breakableStack_.popCopy();
if (!switchBlock)
@ -3751,8 +3756,12 @@ CheckConditional(FunctionCompiler &f, ParseNode *ternary, MDefinition **def, Typ
if (!CheckExpr(f, thenExpr, Use::NoCoercion, &thenDef, &thenType))
return false;
BlockVector thenBlocks(f.cx());
if (!f.appendThenBlock(&thenBlocks))
return false;
f.pushPhiInput(thenDef);
MBasicBlock *thenEnd = f.switchToElse(elseBlock);
f.switchToElse(elseBlock);
MDefinition *elseDef;
Type elseType;
@ -3760,7 +3769,7 @@ CheckConditional(FunctionCompiler &f, ParseNode *ternary, MDefinition **def, Typ
return false;
f.pushPhiInput(elseDef);
if (!f.joinIfElse(thenEnd))
if (!f.joinIfElse(thenBlocks))
return false;
*def = f.popPhiOutput();
@ -4243,6 +4252,13 @@ CheckLabel(FunctionCompiler &f, ParseNode *labeledStmt, LabelVector *maybeLabels
static bool
CheckIf(FunctionCompiler &f, ParseNode *ifStmt)
{
// Handle if/else-if chains using iteration instead of recursion. This
// avoids blowing the C stack quota for long if/else-if chains and also
// creates fewer MBasicBlocks at join points (by creating one join block
// for the entire if/else-if chain).
BlockVector thenBlocks(f.cx());
recurse:
JS_ASSERT(ifStmt->isKind(PNK_IF));
ParseNode *cond = TernaryKid1(ifStmt);
ParseNode *thenStmt = TernaryKid2(ifStmt);
@ -4263,13 +4279,23 @@ CheckIf(FunctionCompiler &f, ParseNode *ifStmt)
if (!CheckStatement(f, thenStmt))
return false;
if (!f.appendThenBlock(&thenBlocks))
return false;
if (!elseStmt) {
f.joinIf(elseBlock);
f.joinIf(thenBlocks, elseBlock);
} else {
MBasicBlock *thenEnd = f.switchToElse(elseBlock);
f.switchToElse(elseBlock);
if (elseStmt->isKind(PNK_IF)) {
ifStmt = elseStmt;
goto recurse;
}
if (!CheckStatement(f, elseStmt))
return false;
if (!f.joinIfElse(thenEnd))
if (!f.joinIfElse(thenBlocks))
return false;
}
@ -4374,7 +4400,7 @@ CheckSwitch(FunctionCompiler &f, ParseNode *switchStmt)
if (!CheckSwitchRange(f, stmt, &low, &high, &tableLength))
return false;
CaseVector cases(f.cx());
BlockVector cases(f.cx());
if (!cases.resize(tableLength))
return false;

Просмотреть файл

@ -1373,26 +1373,33 @@ BacktrackingAllocator::minimalInterval(const LiveInterval *interval, bool *pfixe
return minimalDef(interval, reg.ins());
}
bool fixed = false, minimal = false;
for (UsePositionIterator iter = interval->usesBegin(); iter != interval->usesEnd(); iter++) {
LUse *use = iter->use;
switch (use->policy()) {
case LUse::FIXED:
if (pfixed)
*pfixed = true;
return minimalUse(interval, insData[iter->pos].ins());
if (fixed)
return false;
fixed = true;
if (minimalUse(interval, insData[iter->pos].ins()))
minimal = true;
break;
case LUse::REGISTER:
if (pfixed)
*pfixed = false;
return minimalUse(interval, insData[iter->pos].ins());
if (minimalUse(interval, insData[iter->pos].ins()))
minimal = true;
break;
default:
break;
}
}
return false;
if (pfixed)
*pfixed = fixed;
return minimal;
}
size_t
@ -1648,8 +1655,9 @@ BacktrackingAllocator::splitAtAllRegisterUses(LiveInterval *interval)
CodePosition from = inputOf(ins);
CodePosition to = iter->pos.next();
// Watch for duplicate register use positions.
if (newIntervals.empty() || newIntervals.back()->end() != to) {
// Use the same interval for duplicate use positions, except when
// the uses are fixed (they may require incompatible registers).
if (newIntervals.empty() || newIntervals.back()->end() != to || iter->use->policy() == LUse::FIXED) {
if (!addLiveInterval(newIntervals, vreg, from, to))
return false;
}

Просмотреть файл

@ -2434,3 +2434,21 @@ BaselineCompiler::emit_JSOP_ARGUMENTS()
frame.push(R0);
return true;
}
bool
BaselineCompiler::emit_JSOP_REST()
{
frame.syncStack(0);
RootedTypeObject type(cx, types::TypeScript::InitObject(cx, script, pc, JSProto_Array));
if (!type)
return false;
masm.movePtr(ImmGCPtr(type), R0.scratchReg());
ICRest_Fallback::Compiler stubCompiler(cx);
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
return false;
frame.push(R0);
return true;
}

Просмотреть файл

@ -152,6 +152,7 @@ namespace ion {
_(JSOP_EXCEPTION) \
_(JSOP_DEBUGGER) \
_(JSOP_ARGUMENTS) \
_(JSOP_REST) \
_(JSOP_TOID) \
_(JSOP_TABLESWITCH) \
_(JSOP_ITER) \

Просмотреть файл

@ -318,6 +318,12 @@ ICStub::trace(JSTracer *trc)
MarkObject(trc, &propStub->getter(), "baseline-getproplistbasenative-stub-getter");
break;
}
case ICStub::GetProp_ListBaseShadowed: {
ICGetProp_ListBaseShadowed *propStub = toGetProp_ListBaseShadowed();
MarkShape(trc, &propStub->shape(), "baseline-getproplistbaseshadowed-stub-shape");
MarkString(trc, &propStub->name(), "baseline-getproplistbaseshadowed-stub-name");
break;
}
case ICStub::GetProp_CallScripted: {
ICGetProp_CallScripted *callStub = toGetProp_CallScripted();
MarkShape(trc, &callStub->shape(), "baseline-getpropcallscripted-stub-shape");
@ -614,6 +620,7 @@ ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, La
kind == ICStub::GetProp_CallNative || kind == ICStub::GetProp_CallListBaseNative ||
kind == ICStub::Call_ScriptedApplyArguments ||
kind == ICStub::GetProp_CallListBaseWithGenerationNative ||
kind == ICStub::GetProp_ListBaseShadowed ||
kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
// Guard on bit in frame that indicates if the SPS frame was pushed in the first
@ -3042,7 +3049,7 @@ GetListBaseProto(JSObject *obj)
static void
GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, Register object,
Address checkProxyHandlerAddr,
Address checkExpandoShapeAddr,
Address *checkExpandoShapeAddr,
Address *expandoAndGenerationAddr,
Address *generationAddr,
Register scratch,
@ -3060,8 +3067,12 @@ GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, Register object,
masm.loadPtr(checkProxyHandlerAddr, scratch);
masm.branchPrivatePtr(Assembler::NotEqual, handlerAddr, scratch, checkFailed);
// At this point, if not checking for an expando object, just return.
if (!checkExpandoShapeAddr)
return;
// For the remaining code, we need to reserve some registers to load a value.
// This is ugly, but unvaoidable.
// This is ugly, but unavoidable.
ValueOperand tempVal = listBaseRegSet.takeAnyValue();
masm.pushValue(tempVal);
@ -3092,7 +3103,7 @@ GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, Register object,
// The reference object used to generate this check may not have had an
// expando object at all, in which case the presence of a non-undefined
// expando value in the incoming object is automatically a failure.
masm.loadPtr(checkExpandoShapeAddr, scratch);
masm.loadPtr(*checkExpandoShapeAddr, scratch);
masm.branchPtr(Assembler::Equal, scratch, ImmWord((void*)NULL), &failListBaseCheck);
// Otherwise, ensure that the incoming object has an object for its expando value and that
@ -3117,7 +3128,9 @@ GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, Register object,
static bool
EffectlesslyLookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
MutableHandleObject holder, MutableHandleShape shape,
bool *checkListBase=NULL, bool *listBaseHasGeneration=NULL)
bool *checkListBase=NULL,
ListBaseShadowsResult *shadowsResult=NULL,
bool *listBaseHasGeneration=NULL)
{
shape.set(NULL);
holder.set(NULL);
@ -3130,20 +3143,23 @@ EffectlesslyLookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName n
RootedObject checkObj(cx, obj);
if (checkListBase && IsCacheableListBase(obj)) {
JS_ASSERT(listBaseHasGeneration);
JS_ASSERT(shadowsResult);
*checkListBase = isListBase = true;
if (obj->hasUncacheableProto())
return true;
RootedId id(cx, NameToId(name));
ListBaseShadowsResult shadows =
GetListBaseShadowsCheck()(cx, obj, id);
if (shadows == ShadowCheckFailed)
*shadowsResult = GetListBaseShadowsCheck()(cx, obj, id);
if (*shadowsResult == ShadowCheckFailed)
return false;
if (shadows == Shadows)
return true;
*listBaseHasGeneration = (shadows == DoesntShadowUnique);
if (*shadowsResult == Shadows) {
holder.set(obj);
return true;
}
*listBaseHasGeneration = (*shadowsResult == DoesntShadowUnique);
checkObj = GetListBaseProto(obj);
}
@ -5158,11 +5174,14 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
bool isListBase;
bool listBaseHasGeneration;
ListBaseShadowsResult listBaseShadowsResult;
RootedShape shape(cx);
RootedObject holder(cx);
if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape, &isListBase,
&listBaseHasGeneration))
&listBaseShadowsResult, &listBaseHasGeneration))
{
return false;
}
if (!isListBase && !obj->isNative())
return true;
@ -5250,6 +5269,21 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
return true;
}
// If it's a shadowed listbase proxy property, attach stub to call Proxy::get instead.
if (isListBase && listBaseShadowsResult == Shadows) {
JS_ASSERT(obj == holder);
IonSpew(IonSpew_BaselineIC, " Generating GetProp(ListBaseProxy) stub");
ICGetProp_ListBaseShadowed::Compiler compiler(cx, monitorStub, obj, name,
pc - script->code);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
*attached = true;
return true;
}
return true;
}
@ -5558,14 +5592,7 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
Label failure;
Label failureLeaveStubFrame;
GeneralRegisterSet regs(availableGeneralRegs(1));
Register scratch;
if (regs.has(BaselineTailCallReg)) {
regs.take(BaselineTailCallReg);
scratch = regs.takeAny();
regs.add(BaselineTailCallReg);
} else {
scratch = regs.takeAny();
}
Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
// Guard input is an object.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
@ -5689,14 +5716,7 @@ ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
{
Label failure;
GeneralRegisterSet regs(availableGeneralRegs(1));
Register scratch;
if (regs.has(BaselineTailCallReg)) {
regs.take(BaselineTailCallReg);
scratch = regs.takeAny();
regs.add(BaselineTailCallReg);
} else {
scratch = regs.takeAny();
}
Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
// Guard input is an object.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
@ -5763,14 +5783,7 @@ ICGetPropCallListBaseNativeCompiler::generateStubCode(MacroAssembler &masm,
{
Label failure;
GeneralRegisterSet regs(availableGeneralRegs(1));
Register scratch;
if (regs.has(BaselineTailCallReg)) {
regs.take(BaselineTailCallReg);
scratch = regs.takeAny();
regs.add(BaselineTailCallReg);
} else {
scratch = regs.takeAny();
}
Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
// Guard input is an object.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
@ -5788,11 +5801,11 @@ ICGetPropCallListBaseNativeCompiler::generateStubCode(MacroAssembler &masm,
listBaseRegSet.take(BaselineStubReg);
listBaseRegSet.take(objReg);
listBaseRegSet.take(scratch);
Address expandoShapeAddr(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfExpandoShape());
GenerateListBaseChecks(
cx, masm, objReg,
Address(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfProxyHandler()),
Address(BaselineStubReg, ICGetProp_CallListBaseNative::offsetOfExpandoShape()),
expandoAndGenerationAddr, generationAddr,
&expandoShapeAddr, expandoAndGenerationAddr, generationAddr,
scratch,
listBaseRegSet,
&failure);
@ -5864,7 +5877,7 @@ ICGetPropCallListBaseNativeCompiler::generateStubCode(MacroAssembler &masm)
return generateStubCode(masm, &internalStructAddress, &generationAddress);
}
ICStub*
ICStub *
ICGetPropCallListBaseNativeCompiler::getStub(ICStubSpace *space)
{
RootedShape shape(cx, obj_->lastProperty());
@ -5899,6 +5912,105 @@ ICGetPropCallListBaseNativeCompiler::getStub(ICStubSpace *space)
expandoAndGeneration, generation, expandoShape, holder_, holderShape, getter_,
pcOffset_);
}
ICStub *
ICGetProp_ListBaseShadowed::Compiler::getStub(ICStubSpace *space)
{
RootedShape shape(cx, obj_->lastProperty());
return ICGetProp_ListBaseShadowed::New(space, getStubCode(), firstMonitorStub_,
shape, GetProxyHandler(obj_), name_, pcOffset_);
}
static bool
ProxyGet(JSContext *cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp)
{
RootedId id(cx, NameToId(name));
return Proxy::get(cx, proxy, proxy, id, vp);
}
typedef bool (*ProxyGetFn)(JSContext *cx, HandleObject proxy, HandlePropertyName name,
MutableHandleValue vp);
static const VMFunction ProxyGetInfo = FunctionInfo<ProxyGetFn>(ProxyGet);
bool
ICGetProp_ListBaseShadowed::Compiler::generateStubCode(MacroAssembler &masm)
{
Label failure;
GeneralRegisterSet regs(availableGeneralRegs(1));
// Need to reserve a scratch register, but the scratch register should not be
// BaselineTailCallReg, because it's used for |enterStubFrame| which needs a
// non-BaselineTailCallReg scratch reg.
Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
// Guard input is an object.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
// Unbox.
Register objReg = masm.extractObject(R0, ExtractTemp0);
// Shape guard.
masm.loadPtr(Address(BaselineStubReg, ICGetProp_ListBaseShadowed::offsetOfShape()), scratch);
masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
// Guard for ListObject.
{
GeneralRegisterSet listBaseRegSet(GeneralRegisterSet::All());
listBaseRegSet.take(BaselineStubReg);
listBaseRegSet.take(objReg);
listBaseRegSet.take(scratch);
GenerateListBaseChecks(
cx, masm, objReg,
Address(BaselineStubReg, ICGetProp_ListBaseShadowed::offsetOfProxyHandler()),
/*expandoShapeAddr=*/NULL, /*expandoAndGenerationAddr=*/NULL, /*generationAddr=*/NULL,
scratch,
listBaseRegSet,
&failure);
}
// Call ProxyGet(JSContext *cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp);
// Push a stub frame so that we can perform a non-tail call.
enterStubFrame(masm, scratch);
// Push property name and proxy object.
masm.loadPtr(Address(BaselineStubReg, ICGetProp_ListBaseShadowed::offsetOfName()), scratch);
masm.push(scratch);
masm.push(objReg);
// Don't have to preserve R0 anymore.
regs.add(R0);
// If needed, update SPS Profiler frame entry.
{
Label skipProfilerUpdate;
Register scratch = regs.takeAny();
Register pcIdx = regs.takeAny();
// Check if profiling is enabled.
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
// Update profiling entry before leaving function.
masm.load32(Address(BaselineStubReg, ICGetProp_ListBaseShadowed::offsetOfPCOffset()), pcIdx);
masm.spsUpdatePCIdx(&cx->runtime->spsProfiler, pcIdx, scratch);
masm.bind(&skipProfilerUpdate);
regs.add(scratch);
regs.add(pcIdx);
}
if (!callVM(ProxyGetInfo, masm))
return false;
leaveStubFrame(masm);
// Enter type monitor IC to type-check result.
EmitEnterTypeMonitorIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
bool
ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler &masm)
{
@ -6323,14 +6435,7 @@ ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
EmitStowICValues(masm, 2);
GeneralRegisterSet regs(availableGeneralRegs(1));
Register scratch;
if (regs.has(BaselineTailCallReg)) {
regs.take(BaselineTailCallReg);
scratch = regs.takeAny();
regs.add(BaselineTailCallReg);
} else {
scratch = regs.takeAny();
}
Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
// Unbox and shape guard.
Register objReg = masm.extractObject(R0, ExtractTemp0);
@ -6465,14 +6570,7 @@ ICSetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
EmitStowICValues(masm, 2);
GeneralRegisterSet regs(availableGeneralRegs(1));
Register scratch;
if (regs.has(BaselineTailCallReg)) {
regs.take(BaselineTailCallReg);
scratch = regs.takeAny();
regs.add(BaselineTailCallReg);
} else {
scratch = regs.takeAny();
}
Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
// Unbox and shape guard.
Register objReg = masm.extractObject(R0, ExtractTemp0);
@ -7897,6 +7995,46 @@ ICTypeOf_Typed::Compiler::generateStubCode(MacroAssembler &masm)
return true;
}
//
// Rest_Fallback
//
static bool
DoCreateRestParameter(JSContext *cx, BaselineFrame *frame, ICRest_Fallback *stub,
HandleTypeObject type, MutableHandleValue res)
{
FallbackICSpew(cx, stub, "Rest");
unsigned numFormals = frame->numFormalArgs() - 1;
unsigned numActuals = frame->numActualArgs();
unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
JSObject *obj = NewDenseCopiedArray(cx, numRest, frame->actuals() + numFormals, NULL);
if (!obj)
return false;
obj->setType(type);
res.setObject(*obj);
return true;
}
typedef bool(*DoCreateRestParameterFn)(JSContext *cx, BaselineFrame *, ICRest_Fallback *,
HandleTypeObject, MutableHandleValue);
static const VMFunction DoCreateRestParameterInfo =
FunctionInfo<DoCreateRestParameterFn>(DoCreateRestParameter);
bool
ICRest_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
{
EmitRestoreTailCallReg(masm);
masm.push(R0.scratchReg()); // type
masm.push(BaselineStubReg); // stub
masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg()); // frame pointer
return tailCallVM(DoCreateRestParameterInfo, masm);
}
ICProfiler_PushFunction::ICProfiler_PushFunction(IonCode *stubCode, const char *str,
HandleScript script)
: ICStub(ICStub::Profiler_PushFunction, stubCode),
@ -8184,5 +8322,18 @@ ICGetPropCallListBaseNativeCompiler::ICGetPropCallListBaseNativeCompiler(JSConte
JS_ASSERT(GetProxyHandler(obj_)->family() == GetListBaseHandlerFamily());
}
ICGetProp_ListBaseShadowed::ICGetProp_ListBaseShadowed(IonCode *stubCode,
ICStub *firstMonitorStub,
HandleShape shape,
BaseProxyHandler *proxyHandler,
HandlePropertyName name,
uint32_t pcOffset)
: ICMonitoredStub(ICStub::GetProp_ListBaseShadowed, stubCode, firstMonitorStub),
shape_(shape),
proxyHandler_(proxyHandler),
name_(name),
pcOffset_(pcOffset)
{ }
} // namespace ion
} // namespace js

Просмотреть файл

@ -367,6 +367,7 @@ class ICEntry
_(GetProp_CallNative) \
_(GetProp_CallListBaseNative)\
_(GetProp_CallListBaseWithGenerationNative)\
_(GetProp_ListBaseShadowed) \
_(GetProp_ArgumentsLength) \
\
_(SetProp_Fallback) \
@ -387,7 +388,9 @@ class ICEntry
_(InstanceOf_Fallback) \
\
_(TypeOf_Fallback) \
_(TypeOf_Typed)
_(TypeOf_Typed) \
\
_(Rest_Fallback)
#define FORWARD_DECLARE_STUBS(kindName) class IC##kindName;
IC_STUB_KIND_LIST(FORWARD_DECLARE_STUBS)
@ -732,6 +735,7 @@ class ICStub
case GetProp_CallNative:
case GetProp_CallListBaseNative:
case GetProp_CallListBaseWithGenerationNative:
case GetProp_ListBaseShadowed:
case SetProp_CallScripted:
case SetProp_CallNative:
return true;
@ -4357,6 +4361,73 @@ class ICGetPropCallListBaseNativeCompiler : public ICStubCompiler {
ICStub *getStub(ICStubSpace *space);
};
class ICGetProp_ListBaseShadowed : public ICMonitoredStub
{
friend class ICStubSpace;
protected:
HeapPtrShape shape_;
BaseProxyHandler *proxyHandler_;
HeapPtrPropertyName name_;
uint32_t pcOffset_;
ICGetProp_ListBaseShadowed(IonCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
BaseProxyHandler *proxyHandler, HandlePropertyName name,
uint32_t pcOffset);
public:
static inline ICGetProp_ListBaseShadowed *New(ICStubSpace *space, IonCode *code,
ICStub *firstMonitorStub, HandleShape shape,
BaseProxyHandler *proxyHandler,
HandlePropertyName name, uint32_t pcOffset)
{
if (!code)
return NULL;
return space->allocate<ICGetProp_ListBaseShadowed>(code, firstMonitorStub, shape,
proxyHandler, name, pcOffset);
}
HeapPtrShape &shape() {
return shape_;
}
HeapPtrPropertyName &name() {
return name_;
}
static size_t offsetOfShape() {
return offsetof(ICGetProp_ListBaseShadowed, shape_);
}
static size_t offsetOfProxyHandler() {
return offsetof(ICGetProp_ListBaseShadowed, proxyHandler_);
}
static size_t offsetOfName() {
return offsetof(ICGetProp_ListBaseShadowed, name_);
}
static size_t offsetOfPCOffset() {
return offsetof(ICGetProp_ListBaseShadowed, pcOffset_);
}
class Compiler : public ICStubCompiler {
ICStub *firstMonitorStub_;
RootedObject obj_;
RootedPropertyName name_;
uint32_t pcOffset_;
bool generateStubCode(MacroAssembler &masm);
public:
Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj, HandlePropertyName name,
uint32_t pcOffset)
: ICStubCompiler(cx, ICStub::GetProp_CallNative),
firstMonitorStub_(firstMonitorStub),
obj_(cx, obj),
name_(cx, name),
pcOffset_(pcOffset)
{}
ICStub *getStub(ICStubSpace *space);
};
};
class ICGetProp_ArgumentsLength : public ICStub
{
friend class ICStubSpace;
@ -5411,6 +5482,38 @@ class ICTypeOf_Typed : public ICFallbackStub
};
};
// Rest
// JSOP_REST
class ICRest_Fallback : public ICFallbackStub
{
friend class ICStubSpace;
ICRest_Fallback(IonCode *stubCode)
: ICFallbackStub(ICStub::Rest_Fallback, stubCode)
{ }
public:
static inline ICRest_Fallback *New(ICStubSpace *space, IonCode *code) {
if (!code)
return NULL;
return space->allocate<ICRest_Fallback>(code);
}
class Compiler : public ICStubCompiler {
protected:
bool generateStubCode(MacroAssembler &masm);
public:
Compiler(JSContext *cx)
: ICStubCompiler(cx, ICStub::Rest_Fallback)
{ }
ICStub *getStub(ICStubSpace *space) {
return ICRest_Fallback::New(space, getStubCode());
}
};
};
} // namespace ion
} // namespace js

Просмотреть файл

@ -4859,6 +4859,89 @@ CodeGenerator::visitGetArgument(LGetArgument *lir)
return true;
}
bool
CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
Register temp0, Register temp1, unsigned numFormals,
JSObject *templateObject, const VMFunction &f)
{
// Compute actuals() + numFormals.
size_t actualsOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs();
masm.movePtr(StackPointer, temp1);
masm.addPtr(Imm32(sizeof(Value) * numFormals + actualsOffset), temp1);
// Compute numActuals - numFormals.
Label emptyLength, joinLength;
masm.movePtr(numActuals, temp0);
masm.branch32(Assembler::LessThanOrEqual, temp0, Imm32(numFormals), &emptyLength);
masm.sub32(Imm32(numFormals), temp0);
masm.jump(&joinLength);
{
masm.bind(&emptyLength);
masm.move32(Imm32(0), temp0);
}
masm.bind(&joinLength);
pushArg(array);
pushArg(ImmGCPtr(templateObject));
pushArg(temp1);
pushArg(temp0);
return callVM(f, lir);
}
typedef JSObject *(*InitRestParameterFn)(JSContext *, uint32_t, Value *, HandleObject,
HandleObject);
static const VMFunction InitRestParameterInfo =
FunctionInfo<InitRestParameterFn>(InitRestParameter);
bool
CodeGenerator::visitRest(LRest *lir)
{
Register numActuals = ToRegister(lir->numActuals());
Register temp0 = ToRegister(lir->getTemp(0));
Register temp1 = ToRegister(lir->getTemp(1));
Register temp2 = ToRegister(lir->getTemp(2));
unsigned numFormals = lir->mir()->numFormals();
JSObject *templateObject = lir->mir()->templateObject();
Label joinAlloc, failAlloc;
masm.newGCThing(temp2, templateObject, &failAlloc);
masm.initGCThing(temp2, templateObject);
masm.jump(&joinAlloc);
{
masm.bind(&failAlloc);
masm.movePtr(ImmWord((void *)NULL), temp2);
}
masm.bind(&joinAlloc);
return emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject,
InitRestParameterInfo);
}
typedef ParallelResult (*ParallelInitRestParameterFn)(ForkJoinSlice *, uint32_t, Value *,
HandleObject, HandleObject,
MutableHandleObject);
static const VMFunction ParallelInitRestParameterInfo =
FunctionInfo<ParallelInitRestParameterFn>(InitRestParameter);
bool
CodeGenerator::visitParRest(LParRest *lir)
{
Register numActuals = ToRegister(lir->numActuals());
Register slice = ToRegister(lir->parSlice());
Register temp0 = ToRegister(lir->getTemp(0));
Register temp1 = ToRegister(lir->getTemp(1));
Register temp2 = ToRegister(lir->getTemp(2));
unsigned numFormals = lir->mir()->numFormals();
JSObject *templateObject = lir->mir()->templateObject();
if (!emitParAllocateGCThing(lir, temp2, slice, temp0, temp1, templateObject))
return false;
return emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject,
ParallelInitRestParameterInfo);
}
bool
CodeGenerator::generateAsmJS()
{

Просмотреть файл

@ -211,6 +211,11 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitIteratorEnd(LIteratorEnd *lir);
bool visitArgumentsLength(LArgumentsLength *lir);
bool visitGetArgument(LGetArgument *lir);
bool emitRest(LInstruction *lir, Register array, Register numActuals,
Register temp0, Register temp1, unsigned numFormals,
JSObject *templateObject, const VMFunction &f);
bool visitRest(LRest *lir);
bool visitParRest(LParRest *lir);
bool visitCallSetProperty(LCallSetProperty *ins);
bool visitCallDeleteProperty(LCallDeleteProperty *lir);
bool visitBitNotV(LBitNotV *lir);

Просмотреть файл

@ -1184,6 +1184,9 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_ARGUMENTS:
return jsop_arguments();
case JSOP_REST:
return jsop_rest();
case JSOP_NOTEARG:
return jsop_notearg();
@ -6864,6 +6867,62 @@ IonBuilder::jsop_arguments_setelem(MDefinition *object, MDefinition *index, MDef
return abort("NYI arguments[]=");
}
bool
IonBuilder::jsop_rest()
{
// We don't know anything about the callee.
if (inliningDepth_ == 0) {
// Get an empty template array.
JSObject *templateObject = getNewArrayTemplateObject(0);
if (!templateObject)
return false;
MArgumentsLength *numActuals = MArgumentsLength::New();
current->add(numActuals);
// Pass in the number of actual arguments, the number of formals (not
// including the rest parameter slot itself), and the template object.
MRest *rest = MRest::New(numActuals, info().nargs() - 1, templateObject);
current->add(rest);
current->push(rest);
return true;
}
// We know the exact number of arguments the callee pushed.
unsigned numActuals = inlinedArguments_.length();
unsigned numFormals = info().nargs() - 1;
unsigned numRest = numActuals - numFormals;
JSObject *templateObject = getNewArrayTemplateObject(numRest);
MNewArray *array = new MNewArray(numRest, templateObject, MNewArray::NewArray_Allocating);
current->add(array);
if (numFormals >= numActuals) {
current->push(array);
return true;
}
MElements *elements = MElements::New(array);
current->add(elements);
// Unroll the argument copy loop. We don't need to do any bounds or hole
// checking here.
MConstant *index;
for (unsigned i = numFormals; i < numActuals; i++) {
index = MConstant::New(Int32Value(i));
current->add(index);
MStoreElement *store = MStoreElement::New(elements, index, inlinedArguments_[i],
/* needsHoleCheck = */ false);
current->add(store);
}
MSetInitializedLength *initLength = MSetInitializedLength::New(elements, index);
current->add(initLength);
current->push(array);
return true;
}
inline types::HeapTypeSet *
GetDefiniteSlot(JSContext *cx, types::StackTypeSet *types, JSAtom *atom)
{

Просмотреть файл

@ -406,6 +406,7 @@ class IonBuilder : public MIRGenerator
bool jsop_arguments_length();
bool jsop_arguments_getelem();
bool jsop_arguments_setelem(MDefinition *object, MDefinition *index, MDefinition *value);
bool jsop_rest();
bool jsop_not();
bool jsop_getprop(HandlePropertyName name);
bool jsop_setprop(HandlePropertyName name);

Просмотреть файл

@ -625,7 +625,8 @@ EmitLoadSlot(MacroAssembler &masm, JSObject *holder, Shape *shape, Register hold
static void
GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, JSObject *obj,
PropertyName *name, Register object, Label *stubFailure)
PropertyName *name, Register object, Label *stubFailure,
bool skipExpandoCheck = false)
{
MOZ_ASSERT(IsCacheableListBase(obj));
@ -639,6 +640,9 @@ GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, JSObject *obj,
// Check that object is a ListBase.
masm.branchPrivatePtr(Assembler::NotEqual, handlerAddr, ImmWord(GetProxyHandler(obj)), stubFailure);
if (skipExpandoCheck)
return;
// For the remaining code, we need to reserve some registers to load a value.
// This is ugly, but unvaoidable.
RegisterSet listBaseRegSet(RegisterSet::All());
@ -1015,6 +1019,118 @@ GetPropertyIC::attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSOb
return linkAndAttachStub(cx, masm, attacher, ion, attachKind);
}
bool
GetPropertyIC::attachListBaseShadowed(JSContext *cx, IonScript *ion, JSObject *obj,
void *returnAddr)
{
JS_ASSERT(!idempotent());
JS_ASSERT(IsCacheableListBase(obj));
JS_ASSERT(output().hasValue());
Label failures;
MacroAssembler masm(cx);
RepatchStubAppender attacher(*this);
masm.setFramePushed(ion->frameSize());
// Guard on the shape of the object.
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object(), JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()),
&failures);
// Make sure object is a ListBase proxy
GenerateListBaseChecks(cx, masm, obj, name(), object(), &failures,
/*skipExpandoCheck=*/true);
// saveLive()
masm.PushRegsInMask(liveRegs_);
DebugOnly<uint32_t> initialStack = masm.framePushed();
// Remaining registers should be free, but we need to use |object| still
// so leave it alone.
RegisterSet regSet(RegisterSet::All());
regSet.take(AnyRegister(object()));
// Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
// MutableHandleValue vp)
Register argJSContextReg = regSet.takeGeneral();
Register argProxyReg = regSet.takeGeneral();
Register argIdReg = regSet.takeGeneral();
Register argVpReg = regSet.takeGeneral();
Register scratch = regSet.takeGeneral();
// Push args on stack first so we can take pointers to make handles.
masm.Push(UndefinedValue());
masm.movePtr(StackPointer, argVpReg);
RootedId propId(cx, AtomToId(name()));
masm.Push(propId, scratch);
masm.movePtr(StackPointer, argIdReg);
// Pushing object and receiver. Both are same, so Handle to one is equivalent to
// handle to other.
masm.Push(object());
masm.Push(object());
masm.movePtr(StackPointer, argProxyReg);
masm.loadJSContext(argJSContextReg);
if (!masm.buildOOLFakeExitFrame(returnAddr))
return false;
masm.enterFakeExitFrame(ION_FRAME_OOL_PROXY_GET);
// Make the call.
masm.setupUnalignedABICall(5, scratch);
masm.passABIArg(argJSContextReg);
masm.passABIArg(argProxyReg);
masm.passABIArg(argProxyReg);
masm.passABIArg(argIdReg);
masm.passABIArg(argVpReg);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, Proxy::get));
// Test for failure.
Label exception;
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &exception);
// Load the outparam vp[0] into output register(s).
masm.loadValue(
Address(StackPointer, IonOOLProxyGetExitFrameLayout::offsetOfResult()),
JSReturnOperand);
Label success;
masm.jump(&success);
// Handle exception case.
masm.bind(&exception);
masm.handleException();
// Handle success case.
masm.bind(&success);
masm.storeCallResultValue(output());
// The next instruction is removing the footer of the exit frame, so there
// is no need for leaveFakeExitFrame.
// Move the StackPointer back to its original location, unwinding the exit frame.
masm.adjustStack(IonOOLPropertyOpExitFrameLayout::Size());
JS_ASSERT(masm.framePushed() == initialStack);
// restoreLive()
masm.PopRegsInMask(liveRegs_);
// Success.
attacher.jumpRejoin(masm);
// Failure.
masm.bind(&failures);
attacher.jumpNextStub(masm);
return linkAndAttachStub(cx, masm, attacher, ion, "list base shadowed get");
}
bool
GetPropertyIC::attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj,
JSObject *holder, HandleShape shape,
@ -1264,12 +1380,15 @@ TryAttachNativeGetPropStub(JSContext *cx, IonScript *ion,
RootedObject checkObj(cx, obj);
if (IsCacheableListBase(obj)) {
RootedId id(cx, NameToId(name));
ListBaseShadowsResult shadows =
GetListBaseShadowsCheck()(cx, obj, id);
ListBaseShadowsResult shadows = GetListBaseShadowsCheck()(cx, obj, id);
if (shadows == ShadowCheckFailed)
return false;
if (shadows == Shadows)
return true;
if (shadows == Shadows) {
if (cache.idempotent() || !cache.output().hasValue())
return true;
*isCacheable = true;
return cache.attachListBaseShadowed(cx, ion, obj, returnAddr);
}
if (shadows == DoesntShadowUnique)
// We reset the cache to clear out an existing IC for this object
// (if there is one). The generation is a constant in the generated

Просмотреть файл

@ -542,6 +542,7 @@ class GetPropertyIC : public RepatchIonCache
bool attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
HandleShape shape);
bool attachListBaseShadowed(JSContext *cx, IonScript *ion, JSObject *obj, void *returnAddr);
bool attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
HandleShape shape,
const SafepointIndex *safepointIndex, void *returnAddr);

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше