Merge latest green b2g-inbound changeset and mozilla-central; a=merge

This commit is contained in:
Ed Morley 2014-08-20 14:46:55 +01:00
commit acd103862f
395 changed files with 7569 additions and 2798 deletions

View File

@ -9,9 +9,14 @@
display: none;
border-radius: 2px;
box-shadow: 1px 1px 1px #444;
display: none;
}
#virtual-cursor-inset {
#virtual-cursor-box.show {
display: block;
}
#virtual-cursor-box > div {
border-radius: 1px;
box-shadow: inset 1px 1px 1px #444;
display: block;

View File

@ -394,23 +394,19 @@ this.AccessFu = { // jshint ignore:line
_processedMessageManagers: [],
/**
* Adjusts the given bounds relative to the given browser. Converts from
* screen or device pixels to either device or CSS pixels.
* Adjusts the given bounds relative to the given browser.
* @param {Rect} aJsonBounds the bounds to adjust
* @param {browser} aBrowser the browser we want the bounds relative to
* @param {bool} aToCSSPixels whether to convert to CSS pixels (as opposed to
* device pixels)
* @param {bool} aFromDevicePixels whether to convert from device pixels (as
* opposed to screen pixels)
*/
adjustContentBounds:
function(aJsonBounds, aBrowser, aToCSSPixels, aFromDevicePixels) {
function(aJsonBounds, aBrowser, aToCSSPixels) {
let bounds = new Rect(aJsonBounds.left, aJsonBounds.top,
aJsonBounds.right - aJsonBounds.left,
aJsonBounds.bottom - aJsonBounds.top);
let win = Utils.win;
let dpr = win.devicePixelRatio;
let vp = Utils.getViewport(win);
let offset = { left: -win.mozInnerScreenX, top: -win.mozInnerScreenY };
if (!aBrowser.contentWindow) {
@ -421,16 +417,6 @@ this.AccessFu = { // jshint ignore:line
offset.left += clientRect.left + win.mozInnerScreenX;
offset.top += clientRect.top + win.mozInnerScreenY;
}
// Here we scale from screen pixels to layout device pixels by dividing by
// the resolution (caused by pinch-zooming). The resolution is the
// viewport zoom divided by the devicePixelRatio. If there's no viewport,
// then we're on a platform without pinch-zooming and we can just ignore
// this.
if (!aFromDevicePixels && vp) {
bounds = bounds.scale(vp.zoom / dpr, vp.zoom / dpr);
}
// Add the offset; the offset is in CSS pixels, so multiply the
// devicePixelRatio back in before adding to preserve unit consistency.
bounds = bounds.translate(offset.left * dpr, offset.top * dpr);
@ -545,11 +531,10 @@ var Output = {
highlightBox.id = 'virtual-cursor-box';
// Add highlight inset for inner shadow
let inset = Utils.win.document.
createElementNS('http://www.w3.org/1999/xhtml', 'div');
inset.id = 'virtual-cursor-inset';
highlightBox.appendChild(
Utils.win.document.createElementNS(
'http://www.w3.org/1999/xhtml', 'div'));
highlightBox.appendChild(inset);
this.highlightBox = Cu.getWeakReference(highlightBox);
} else {
highlightBox = this.highlightBox.get();
@ -559,12 +544,12 @@ var Output = {
let r = AccessFu.adjustContentBounds(aDetail.bounds, aBrowser, true);
// First hide it to avoid flickering when changing the style.
highlightBox.style.display = 'none';
highlightBox.classList.remove('show');
highlightBox.style.top = (r.top - padding) + 'px';
highlightBox.style.left = (r.left - padding) + 'px';
highlightBox.style.width = (r.width + padding*2) + 'px';
highlightBox.style.height = (r.height + padding*2) + 'px';
highlightBox.style.display = 'block';
highlightBox.classList.add('show');
break;
}
@ -572,7 +557,7 @@ var Output = {
{
let highlightBox = this.highlightBox ? this.highlightBox.get() : null;
if (highlightBox) {
highlightBox.style.display = 'none';
highlightBox.classList.remove('show');
}
break;
}
@ -889,8 +874,7 @@ var Input = {
activateContextMenu: function activateContextMenu(aDetails) {
if (Utils.MozBuildApp === 'mobile/android') {
let p = AccessFu.adjustContentBounds(aDetails.bounds,
Utils.CurrentBrowser,
true, true).center();
Utils.CurrentBrowser, true).center();
Services.obs.notifyObservers(null, 'Gesture:LongPress',
JSON.stringify({x: p.x, y: p.y}));
}
@ -915,8 +899,8 @@ var Input = {
doScroll: function doScroll(aDetails) {
let horizontal = aDetails.horizontal;
let page = aDetails.page;
let p = AccessFu.adjustContentBounds(aDetails.bounds, Utils.CurrentBrowser,
true, true).center();
let p = AccessFu.adjustContentBounds(
aDetails.bounds, Utils.CurrentBrowser, true).center();
Utils.winUtils.sendWheelEvent(p.x, p.y,
horizontal ? page : 0, horizontal ? 0 : page, 0,
Utils.win.WheelEvent.DOM_DELTA_PAGE, 0, 0, 0, 0);

View File

@ -255,15 +255,6 @@ this.Utils = { // jshint ignore:line
}
},
getViewport: function getViewport(aWindow) {
switch (this.MozBuildApp) {
case 'mobile/android':
return aWindow.BrowserApp.selectedTab.getViewport();
default:
return null;
}
},
getState: function getState(aAccessibleOrEvent) {
if (aAccessibleOrEvent instanceof Ci.nsIAccessibleStateChangeEvent) {
return new State(
@ -302,18 +293,37 @@ this.Utils = { // jshint ignore:line
return doc.QueryInterface(Ci.nsIAccessibleDocument).virtualCursor;
},
getBounds: function getBounds(aAccessible) {
let objX = {}, objY = {}, objW = {}, objH = {};
aAccessible.getBounds(objX, objY, objW, objH);
return new Rect(objX.value, objY.value, objW.value, objH.value);
getContentResolution: function _getContentResolution(aAccessible) {
let resX = { value: 1 }, resY = { value: 1 };
aAccessible.document.window.QueryInterface(
Ci.nsIInterfaceRequestor).getInterface(
Ci.nsIDOMWindowUtils).getResolution(resX, resY);
return [resX.value, resY.value];
},
getTextBounds: function getTextBounds(aAccessible, aStart, aEnd) {
let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
let objX = {}, objY = {}, objW = {}, objH = {};
accText.getRangeExtents(aStart, aEnd, objX, objY, objW, objH,
Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE);
return new Rect(objX.value, objY.value, objW.value, objH.value);
getBounds: function getBounds(aAccessible, aPreserveContentScale) {
let objX = {}, objY = {}, objW = {}, objH = {};
aAccessible.getBounds(objX, objY, objW, objH);
let [scaleX, scaleY] = aPreserveContentScale ? [1, 1] :
this.getContentResolution(aAccessible);
return new Rect(objX.value, objY.value, objW.value, objH.value).scale(
scaleX, scaleY);
},
getTextBounds: function getTextBounds(aAccessible, aStart, aEnd,
aPreserveContentScale) {
let accText = aAccessible.QueryInterface(Ci.nsIAccessibleText);
let objX = {}, objY = {}, objW = {}, objH = {};
accText.getRangeExtents(aStart, aEnd, objX, objY, objW, objH,
Ci.nsIAccessibleCoordinateType.COORDTYPE_SCREEN_RELATIVE);
let [scaleX, scaleY] = aPreserveContentScale ? [1, 1] :
this.getContentResolution(aAccessible);
return new Rect(objX.value, objY.value, objW.value, objH.value).scale(
scaleX, scaleY);
},
/**

View File

@ -65,14 +65,10 @@ function forwardToChild(aMessage, aListener, aVCPosition) {
}
function activateContextMenu(aMessage) {
function sendContextMenuCoordinates(aAccessible) {
let bounds = Utils.getBounds(aAccessible);
sendAsyncMessage('AccessFu:ActivateContextMenu', {bounds: bounds});
}
let position = Utils.getVirtualCursor(content.document).position;
if (!forwardToChild(aMessage, activateContextMenu, position)) {
sendContextMenuCoordinates(position);
sendAsyncMessage('AccessFu:ActivateContextMenu',
{ bounds: Utils.getBounds(position, true) });
}
}
@ -85,16 +81,12 @@ function presentCaretChange(aText, aOldOffset, aNewOffset) {
}
function scroll(aMessage) {
function sendScrollCoordinates(aAccessible) {
let bounds = Utils.getBounds(aAccessible);
sendAsyncMessage('AccessFu:DoScroll',
{ bounds: bounds,
page: aMessage.json.page,
horizontal: aMessage.json.horizontal });
}
let position = Utils.getVirtualCursor(content.document).position;
if (!forwardToChild(aMessage, scroll, position)) {
sendAsyncMessage('AccessFu:DoScroll',
{ bounds: Utils.getBounds(position, true),
page: aMessage.json.page,
horizontal: aMessage.json.horizontal });
sendScrollCoordinates(position);
}
}

View File

@ -407,18 +407,18 @@ const nodeResolve = iced(function nodeResolve(id, requirer, { rootURI }) {
let fullId = join(rootURI, id);
let resolvedPath;
if (resolvedPath = loadAsFile(fullId))
if ((resolvedPath = loadAsFile(fullId)))
return stripBase(rootURI, resolvedPath);
else if (resolvedPath = loadAsDirectory(fullId))
else if ((resolvedPath = loadAsDirectory(fullId)))
return stripBase(rootURI, resolvedPath);
// If manifest has dependencies, attempt to look up node modules
// in the `dependencies` list
else {
let dirs = getNodeModulePaths(dirname(join(rootURI, requirer))).map(dir => join(dir, id));
for (let i = 0; i < dirs.length; i++) {
if (resolvedPath = loadAsFile(dirs[i]))
if ((resolvedPath = loadAsFile(dirs[i])))
return stripBase(rootURI, resolvedPath);
if (resolvedPath = loadAsDirectory(dirs[i]))
if ((resolvedPath = loadAsDirectory(dirs[i])))
return stripBase(rootURI, resolvedPath);
}
}
@ -459,7 +459,7 @@ function loadAsDirectory (path) {
let main = getManifestMain(JSON.parse(readURI(path + '/package.json')));
if (main != null) {
let tmpPath = join(path, main);
if (found = loadAsFile(tmpPath))
if ((found = loadAsFile(tmpPath)))
return found
}
try {

View File

@ -1201,8 +1201,7 @@ const kTransferContractId = "@mozilla.org/transfer;1";
// Override Toolkit's nsITransfer implementation with the one from the
// JavaScript API for downloads. This will eventually be removed when
// nsIDownloadManager will not be available anymore (bug 851471). The
// old code in this module will be removed in bug 899110.
// nsIDownloadManager will not be available anymore (bug 851471).
Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
.registerFactory(kTransferCid, "",
kTransferContractId, null);

View File

@ -980,7 +980,11 @@ pref("browser.safebrowsing.reportMalwareURL", "http://%LOCALE%.malware-report.mo
pref("browser.safebrowsing.reportMalwareErrorURL", "http://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%");
pref("browser.safebrowsing.malware.reportURL", "https://safebrowsing.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
// Turn off remote lookups in beta and stable channel.
#ifndef RELEASE_BUILD
pref("browser.safebrowsing.appRepURL", "https://sb-ssl.google.com/safebrowsing/clientreport/download?key=%GOOGLE_API_KEY%");
#endif
#ifdef MOZILLA_OFFICIAL
// Normally the "client ID" sent in updates is appinfo.name, but for

View File

@ -438,6 +438,13 @@ var gPopupBlockerObserver = {
// Hide the icon in the location bar (if the location bar exists)
if (gURLBar)
this._reportButton.hidden = true;
// Hide the notification box (if it's visible).
var notificationBox = gBrowser.getNotificationBox();
var notification = notificationBox.getNotificationWithValue("popup-blocked");
if (notification) {
notificationBox.removeNotification(notification, false);
}
return;
}

View File

@ -293,7 +293,14 @@ AppCacheUtils.prototype = {
},
clearAll: function ACU_clearAll() {
Services.cache.evictEntries(Ci.nsICache.STORE_OFFLINE);
if (!Services.prefs.getBoolPref("browser.cache.disk.enable")) {
throw new Error(l10n.GetStringFromName("cacheDisabled"));
}
let appCacheStorage = Services.cache2.appCacheStorage(LoadContextInfo.default, null);
appCacheStorage.asyncEvictStorage({
onCacheEntryDoomed: function(result) {}
});
},
_getManifestURI: function ACU__getManifestURI() {

View File

@ -15,7 +15,7 @@ let test = asyncTest(function*() {
info("Creating the test document");
content.document.body.innerHTML = '<style type="text/css"> ' +
'span { font-variant: small-caps; color: #000000; } ' +
'span { font-variant-caps: small-caps; color: #000000; } ' +
'.nomatches {color: #ff0000;}</style> <div id="first" style="margin: 10em; ' +
'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">\n' +
'<h1>Some header text</h1>\n' +
@ -58,7 +58,7 @@ function checkCopySelection(view) {
let expectedPattern = "font-family: helvetica,sans-serif;[\\r\\n]+" +
"font-size: 16px;[\\r\\n]+" +
"font-variant: small-caps;[\\r\\n]*";
"font-variant-caps: small-caps;[\\r\\n]*";
return waitForClipboard(() => {
fireCopyEvent(props[0]);
@ -80,7 +80,7 @@ function checkSelectAll(view) {
let expectedPattern = "color: #FF0;[\\r\\n]+" +
"font-family: helvetica,sans-serif;[\\r\\n]+" +
"font-size: 16px;[\\r\\n]+" +
"font-variant: small-caps;[\\r\\n]*";
"font-variant-caps: small-caps;[\\r\\n]*";
return waitForClipboard(() => {
fireCopyEvent(prop);

View File

@ -816,6 +816,7 @@ bin/libfreebl_32int64_3.so
@BINPATH@/webapprt/components/PaymentUIGlue.js
@BINPATH@/webapprt/components/components.manifest
@BINPATH@/webapprt/defaults/preferences/prefs.js
@BINPATH@/webapprt/modules/DownloadView.jsm
@BINPATH@/webapprt/modules/Startup.jsm
@BINPATH@/webapprt/modules/WebappRT.jsm
@BINPATH@/webapprt/modules/WebappManager.jsm

View File

@ -28,12 +28,43 @@ leak:GI___strdup
###
### Many leaks only affect some test suites. The suite annotations are not checked.
### Bug 979928 - WebRTC leaks. m2, m3.
###
# Bug 979928 - WebRTC is leaky. m2, m3
leak:/media/mtransport/
leak:/media/webrtc/signaling/
# WebRTC leaks added for Mochitest 2.
leak:NR_reg_init
leak:fsmdef_init
leak:r_log_register
leak:nr_reg_set
leak:ccsnap_device_init
leak:ccsnap_line_init
leak:media/webrtc/signaling/src/sipcc/core/common/init.c
leak:cprPostMessage
leak:mozilla::NrIceStunServer::Create
# Additional WebRTC leak suppressions added for Mochitest 3.
leak:mozilla::TransportLayerDtls::Setup
leak:mozilla::NrIceTurnServer::Create
# There are about 228KB of leaks from the call to |pmsg->sdp = cpr_malloc(sdp_size);|
# in send_message_helper.
leak:send_message_helper
leak:fsmdef_ev_createoffer
leak:fsmdef_ev_setremotedesc
leak:fsmdef_ev_setlocaldesc
leak:fsmdef_ev_createanswer
# About 70KB of leaks under this stack.
leak:vcmRxAllocICE_s
leak:vcmRxStartICE_m
# About 50KB of leaks under this stack.
leak:ccsnap_EscapeStrToLocaleStr
leak:gsmsdp_add_default_audio_formats_to_local_sdp
leak:gsmsdp_add_default_video_formats_to_local_sdp
leak:CCAPI_CallInfo_getMediaStreams
###
### Many leaks only affect some test suites. The suite annotations are not checked.
###
# Bug 981195 - Small leak in the parser. m4
leak:TypeCompartment::fixObjectType

View File

@ -728,7 +728,7 @@ public:
int32_t ScrollTop()
{
nsIScrollableFrame* sf = GetScrollFrame();
return sf ? sf->GetScrollPositionCSSPixels().y : 0;
return sf ? sf->GetScrollPositionCSSPixels().y.value : 0;
}
void SetScrollTop(int32_t aScrollTop)
{
@ -741,7 +741,7 @@ public:
int32_t ScrollLeft()
{
nsIScrollableFrame* sf = GetScrollFrame();
return sf ? sf->GetScrollPositionCSSPixels().x : 0;
return sf ? sf->GetScrollPositionCSSPixels().x.value : 0;
}
void SetScrollLeft(int32_t aScrollLeft)
{

View File

@ -405,15 +405,6 @@ public:
static bool CanCallerAccess(nsPIDOMWindow* aWindow);
/**
* Get the window through the JS context that's currently on the stack.
* If there's no JS context currently on the stack, returns null.
*/
static nsPIDOMWindow *GetWindowFromCaller();
/**
* The two GetDocumentFrom* functions below allow a caller to get at a
* document that is relevant to the currently executing script.
*
* GetDocumentFromCaller gets its document by looking at the last called
* function and finding the document that the function itself relates to.
* For example, consider two windows A and B in the same origin. B has a
@ -421,28 +412,10 @@ public:
* If a script in window A were to call B's function, GetDocumentFromCaller
* would find that function (in B) and return B's document.
*
* GetDocumentFromContext gets its document by looking at the currently
* executing context's global object and returning its document. Thus,
* given the example above, GetDocumentFromCaller would see that the
* currently executing script was in window A, and return A's document.
*/
/**
* Get the document from the currently executing function. This will return
* the document that the currently executing function is in/from.
*
* @return The document or null if no JS Context.
*/
static nsIDocument* GetDocumentFromCaller();
/**
* Get the document through the JS context that's currently on the stack.
* If there's no JS context currently on the stack it will return null.
* This will return the document of the calling script.
*
* @return The document or null if no JS context
*/
static nsIDocument* GetDocumentFromContext();
// Check if a node is in the document prolog, i.e. before the document
// element.
static bool InProlog(nsINode *aNode);
@ -2279,9 +2252,7 @@ private:
static bool sInitialized;
static uint32_t sScriptBlockerCount;
#ifdef DEBUG
static uint32_t sDOMNodeRemovedSuppressCount;
#endif
static uint32_t sMicroTaskLevel;
// Not an nsCOMArray because removing elements from those is slower
static nsTArray< nsCOMPtr<nsIRunnable> >* sBlockedScriptRunners;
@ -2338,14 +2309,10 @@ class MOZ_STACK_CLASS nsAutoScriptBlockerSuppressNodeRemoved :
public nsAutoScriptBlocker {
public:
nsAutoScriptBlockerSuppressNodeRemoved() {
#ifdef DEBUG
++nsContentUtils::sDOMNodeRemovedSuppressCount;
#endif
}
~nsAutoScriptBlockerSuppressNodeRemoved() {
#ifdef DEBUG
--nsContentUtils::sDOMNodeRemovedSuppressCount;
#endif
}
};

View File

@ -686,7 +686,7 @@ WebSocket::Init(JSContext* aCx,
// Confirmed we are opening plain ws:// and want to prevent this from a
// secure context (e.g. https). Check the principal's uri to determine if
// we were loaded from https.
nsCOMPtr<nsIGlobalObject> globalObject(BrokenGetEntryGlobal());
nsCOMPtr<nsIGlobalObject> globalObject(GetEntryGlobal());
if (globalObject) {
nsCOMPtr<nsIPrincipal> principal(globalObject->PrincipalOrNull());
if (principal) {

View File

@ -214,9 +214,7 @@ nsILineBreaker *nsContentUtils::sLineBreaker;
nsIWordBreaker *nsContentUtils::sWordBreaker;
nsIBidiKeyboard *nsContentUtils::sBidiKeyboard = nullptr;
uint32_t nsContentUtils::sScriptBlockerCount = 0;
#ifdef DEBUG
uint32_t nsContentUtils::sDOMNodeRemovedSuppressCount = 0;
#endif
uint32_t nsContentUtils::sMicroTaskLevel = 0;
nsTArray< nsCOMPtr<nsIRunnable> >* nsContentUtils::sBlockedScriptRunners = nullptr;
uint32_t nsContentUtils::sRunnersCountAtFirstBlocker = 0;
@ -1953,19 +1951,6 @@ nsContentUtils::TraceSafeJSContext(JSTracer* aTrc)
}
}
nsPIDOMWindow *
nsContentUtils::GetWindowFromCaller()
{
JSContext *cx = GetCurrentJSContext();
if (cx) {
nsCOMPtr<nsPIDOMWindow> win =
do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
return win;
}
return nullptr;
}
nsIDocument*
nsContentUtils::GetDocumentFromCaller()
{
@ -1980,24 +1965,6 @@ nsContentUtils::GetDocumentFromCaller()
return win->GetExtantDoc();
}
nsIDocument*
nsContentUtils::GetDocumentFromContext()
{
JSContext *cx = GetCurrentJSContext();
if (cx) {
nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
if (sgo) {
nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(sgo);
if (pwin) {
return pwin->GetExtantDoc();
}
}
}
return nullptr;
}
bool
nsContentUtils::IsCallerChrome()
{
@ -3920,30 +3887,27 @@ nsContentUtils::MaybeFireNodeRemoved(nsINode* aChild, nsINode* aParent,
NS_PRECONDITION(aChild->GetParentNode() == aParent, "Wrong parent");
NS_PRECONDITION(aChild->OwnerDoc() == aOwnerDoc, "Wrong owner-doc");
// This checks that IsSafeToRunScript is true since we don't want to fire
// events when that is false. We can't rely on EventDispatcher to assert
// this in this situation since most of the time there are no mutation
// event listeners, in which case we won't even attempt to dispatch events.
// However this also allows for two exceptions. First off, we don't assert
// if the mutation happens to native anonymous content since we never fire
// mutation events on such content anyway.
// Second, we don't assert if sDOMNodeRemovedSuppressCount is true since
// that is a know case when we'd normally fire a mutation event, but can't
// make that safe and so we suppress it at this time. Ideally this should
// go away eventually.
NS_ASSERTION((aChild->IsNodeOfType(nsINode::eCONTENT) &&
static_cast<nsIContent*>(aChild)->
IsInNativeAnonymousSubtree()) ||
IsSafeToRunScript() ||
sDOMNodeRemovedSuppressCount,
"Want to fire DOMNodeRemoved event, but it's not safe");
// Having an explicit check here since it's an easy mistake to fall into,
// and there might be existing code with problems. We'd rather be safe
// than fire DOMNodeRemoved in all corner cases. We also rely on it for
// nsAutoScriptBlockerSuppressNodeRemoved.
if (!IsSafeToRunScript()) {
WarnScriptWasIgnored(aOwnerDoc);
// This checks that IsSafeToRunScript is true since we don't want to fire
// events when that is false. We can't rely on EventDispatcher to assert
// this in this situation since most of the time there are no mutation
// event listeners, in which case we won't even attempt to dispatch events.
// However this also allows for two exceptions. First off, we don't assert
// if the mutation happens to native anonymous content since we never fire
// mutation events on such content anyway.
// Second, we don't assert if sDOMNodeRemovedSuppressCount is true since
// that is a know case when we'd normally fire a mutation event, but can't
// make that safe and so we suppress it at this time. Ideally this should
// go away eventually.
if (!(aChild->IsContent() && aChild->AsContent()->IsInNativeAnonymousSubtree()) &&
!sDOMNodeRemovedSuppressCount) {
NS_ERROR("Want to fire DOMNodeRemoved event, but it's not safe");
WarnScriptWasIgnored(aOwnerDoc);
}
return;
}

View File

@ -1429,10 +1429,10 @@ nsHTMLDocument::Open(JSContext* cx,
return ret.forget();
}
// Note: We want to use GetDocumentFromContext here because this document
// Note: We want to use GetEntryDocument here because this document
// should inherit the security information of the document that's opening us,
// (since if it's secure, then it's presumably trusted).
nsCOMPtr<nsIDocument> callerDoc = nsContentUtils::GetDocumentFromContext();
nsCOMPtr<nsIDocument> callerDoc = GetEntryDocument();
if (!callerDoc) {
// If we're called from C++ or in some other way without an originating
// document we can't do a document.open w/o changing the principal of the

View File

@ -128,14 +128,15 @@ GMPChild::Init(const std::string& aPluginPath,
return false;
}
#ifdef MOZ_CRASHREPORTER
SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
#endif
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
mPluginPath = aPluginPath;
return true;
#endif
#ifdef MOZ_CRASHREPORTER
SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
#endif
#if defined(XP_WIN)
mozilla::SandboxTarget::Instance()->StartSandbox();
#endif

View File

@ -75,6 +75,7 @@ private:
public:
ResourceQueue() :
nsDeque(new ResourceQueueDeallocator()),
mLogicalLength(0),
mOffset(0)
{
}
@ -87,12 +88,7 @@ private:
// Returns the length of all items in the queue plus the offset.
// This is the logical length of the resource.
inline uint64_t GetLength() {
uint64_t s = mOffset;
for (uint32_t i = 0; i < GetSize(); ++i) {
ResourceItem* item = ResourceAt(i);
s += item->mData.Length();
}
return s;
return mLogicalLength;
}
// Copies aCount bytes from aOffset in the queue into aDest.
@ -113,6 +109,7 @@ private:
}
inline void PushBack(ResourceItem* aItem) {
mLogicalLength += aItem->mData.Length();
nsDeque::Push(aItem);
}
@ -184,8 +181,10 @@ private:
return static_cast<ResourceItem*>(nsDeque::PopFront());
}
// Logical offset into the resource of the first element
// in the queue.
// Logical length of the resource.
uint64_t mLogicalLength;
// Logical offset into the resource of the first element in the queue.
uint64_t mOffset;
};

View File

@ -67,9 +67,6 @@ EXPORTS += [
'AudioCompactor.h',
'AudioEventTimeline.h',
'AudioMixer.h',
'AudioNodeEngine.h',
'AudioNodeExternalInputStream.h',
'AudioNodeStream.h',
'AudioSampleFormat.h',
'AudioSegment.h',
'AudioStream.h',
@ -130,9 +127,6 @@ EXPORTS.mozilla.dom += [
UNIFIED_SOURCES += [
'AudioChannelFormat.cpp',
'AudioCompactor.cpp',
'AudioNodeEngine.cpp',
'AudioNodeExternalInputStream.cpp',
'AudioNodeStream.cpp',
'AudioSegment.cpp',
'AudioSink.cpp',
'AudioStream.cpp',
@ -185,10 +179,6 @@ SOURCES += [
FAIL_ON_WARNINGS = True
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
SOURCES += ['AudioNodeEngineNEON.cpp']
SOURCES['AudioNodeEngineNEON.cpp'].flags += ['-mfpu=neon']
MSVC_ENABLE_PGO = True
include('/ipc/chromium/chromium-config.mozbuild')

View File

@ -19,6 +19,9 @@ BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
EXPORTS += [
'AudioContext.h',
'AudioNodeEngine.h',
'AudioNodeExternalInputStream.h',
'AudioNodeStream.h',
'AudioParamTimeline.h',
'MediaBufferDecoder.h',
'ThreeDPoint.h',
@ -65,6 +68,9 @@ UNIFIED_SOURCES += [
'AudioDestinationNode.cpp',
'AudioListener.cpp',
'AudioNode.cpp',
'AudioNodeEngine.cpp',
'AudioNodeExternalInputStream.cpp',
'AudioNodeStream.cpp',
'AudioParam.cpp',
'AudioProcessingEvent.cpp',
'BiquadFilterNode.cpp',
@ -90,8 +96,15 @@ UNIFIED_SOURCES += [
'WebAudioUtils.cpp',
]
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
SOURCES += ['AudioNodeEngineNEON.cpp']
SOURCES['AudioNodeEngineNEON.cpp'].flags += ['-mfpu=neon']
FAIL_ON_WARNINGS = True
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'..'
]

View File

@ -128,6 +128,7 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_periodicWave.html]
[test_scriptProcessorNode.html]
[test_scriptProcessorNodeChannelCount.html]
[test_scriptProcessorNodePassThrough.html]
[test_scriptProcessorNode_playbackTime1.html]
[test_scriptProcessorNodeZeroInputOutput.html]
[test_scriptProcessorNodeNotConnected.html]

View File

@ -26,7 +26,7 @@ addLoadEvent(function() {
for (var i = 0; i < 2048; ++i) {
// Make sure our first sample won't be zero
e.outputBuffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * (i + 1) / context.sampleRate);
e.outputBuffer.getChannelData(0)[i] = Math.sin(880 * 2 * Math.PI * (i + 1) / context.sampleRate);
e.outputBuffer.getChannelData(1)[i] = Math.sin(880 * 2 * Math.PI * (i + 1) / context.sampleRate);
}
// Remember our generated audio
buffer = e.outputBuffer;

View File

@ -0,0 +1,103 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test ScriptProcessorNode with passthrough</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
// We do not use our generic graph test framework here because
// the testing logic here is sort of complicated, and would
// not be easy to map to OfflineAudioContext, as ScriptProcessorNodes
// can experience delays.
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var context = new AudioContext();
var buffer = null;
var sourceSP = context.createScriptProcessor(2048);
sourceSP.addEventListener("audioprocess", function(e) {
// generate the audio
for (var i = 0; i < 2048; ++i) {
// Make sure our first sample won't be zero
e.outputBuffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * (i + 1) / context.sampleRate);
e.outputBuffer.getChannelData(1)[i] = Math.sin(880 * 2 * Math.PI * (i + 1) / context.sampleRate);
}
// Remember our generated audio
buffer = e.outputBuffer;
sourceSP.removeEventListener("audioprocess", arguments.callee);
}, false);
function findFirstNonZeroSample(buffer) {
for (var i = 0; i < buffer.length; ++i) {
if (buffer.getChannelData(0)[i] != 0) {
return i;
}
}
return buffer.length;
}
var sp = context.createScriptProcessor(2048);
sourceSP.connect(sp);
var spWrapped = SpecialPowers.wrap(sp);
ok("passThrough" in spWrapped, "ScriptProcessorNode should support the passThrough API");
spWrapped.passThrough = true;
sp.onaudioprocess = function() {
ok(false, "The audioprocess event must never be dispatched on the passthrough ScriptProcessorNode");
};
var sp2 = context.createScriptProcessor(2048);
sp.connect(sp2);
sp2.connect(context.destination);
var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
sp2.onaudioprocess = function(e) {
// Because of the initial latency added by the second script processor node,
// we will never see any generated audio frames in the first callback.
compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
sp2.onaudioprocess = function(e) {
var firstNonZero = findFirstNonZeroSample(e.inputBuffer);
ok(firstNonZero <= 2048, "First non-zero sample within range");
compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), firstNonZero);
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), firstNonZero);
compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), 2048 - firstNonZero, firstNonZero, 0);
compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), 2048 - firstNonZero, firstNonZero, 0);
if (firstNonZero == 0) {
// If we did not experience any delays, the test is done!
sp2.onaudioprocess = null;
SimpleTest.finish();
} else if (firstNonZero != 2048) {
// In case we just saw a zero buffer this time, wait one more round
sp2.onaudioprocess = function(e) {
compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), firstNonZero, 0, 2048 - firstNonZero);
compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), firstNonZero, 0, 2048 - firstNonZero);
compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), undefined, firstNonZero);
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), undefined, firstNonZero);
sp2.onaudioprocess = null;
SimpleTest.finish();
};
}
};
};
});
</script>
</pre>
</body>
</html>

View File

@ -60,7 +60,7 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
// and return to CLUSTER_SYNC.
if (mClusterIDPos == sizeof(CLUSTER_ID)) {
mClusterIDPos = 0;
mClusterOffset = mCurrentOffset + (p - aBuffer) - 1;
mClusterOffset = mCurrentOffset + (p - aBuffer) - sizeof(CLUSTER_ID);
mState = READ_VINT;
mNextState = TIMECODE_SYNC;
}

View File

@ -1965,16 +1965,16 @@ Navigator::GetMozCameras(ErrorResult& aRv)
return mCameraManager;
}
already_AddRefed<workers::ServiceWorkerContainer>
already_AddRefed<ServiceWorkerContainer>
Navigator::ServiceWorker()
{
MOZ_ASSERT(mWindow);
if (!mServiceWorkerContainer) {
mServiceWorkerContainer = new workers::ServiceWorkerContainer(mWindow);
mServiceWorkerContainer = new ServiceWorkerContainer(mWindow);
}
nsRefPtr<workers::ServiceWorkerContainer> ref = mServiceWorkerContainer;
nsRefPtr<ServiceWorkerContainer> ref = mServiceWorkerContainer;
return ref.forget();
}

View File

@ -36,6 +36,7 @@ struct MediaStreamConstraints;
class WakeLock;
class ArrayBufferViewOrBlobOrStringOrFormData;
struct MobileIdOptions;
class ServiceWorkerContainer;
}
}
@ -104,10 +105,6 @@ class AudioChannelManager;
#endif
} // namespace system
namespace workers {
class ServiceWorkerContainer;
} // namespace workers
class Navigator : public nsIDOMNavigator
, public nsIMozNavigatorNetwork
, public nsWrapperCache
@ -262,7 +259,7 @@ public:
ErrorResult& aRv);
#endif // MOZ_MEDIA_NAVIGATOR
already_AddRefed<workers::ServiceWorkerContainer> ServiceWorker();
already_AddRefed<ServiceWorkerContainer> ServiceWorker();
bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
JS::Handle<jsid> aId,
@ -340,7 +337,7 @@ private:
nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
nsTArray<nsRefPtr<nsDOMDeviceStorage> > mDeviceStorageStores;
nsRefPtr<time::TimeManager> mTimeManager;
nsRefPtr<workers::ServiceWorkerContainer> mServiceWorkerContainer;
nsRefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
nsCOMPtr<nsPIDOMWindow> mWindow;
// Hashtable for saving cached objects newresolve created, so we don't create

View File

@ -122,27 +122,18 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry()
ScriptSettingsStack::Pop(this);
}
// This mostly gets the entry global, but doesn't entirely match the spec in
// certain edge cases. It's good enough for some purposes, but not others. If
// you want to call this function, ping bholley and describe your use-case.
nsIGlobalObject*
BrokenGetEntryGlobal()
GetEntryGlobal()
{
// We need the current JSContext in order to check the JS for
// scripted frames that may have appeared since anyone last
// manipulated the stack. If it's null, that means that there
// must be no entry global on the stack.
JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
if (!cx) {
MOZ_ASSERT(ScriptSettingsStack::EntryGlobal() == nullptr);
return nullptr;
}
return nsJSUtils::GetDynamicScriptGlobal(cx);
return ScriptSettingsStack::EntryGlobal();
}
// Note: When we're ready to expose it, GetEntryGlobal will look similar to
// GetIncumbentGlobal below.
nsIDocument*
GetEntryDocument()
{
nsCOMPtr<nsPIDOMWindow> entryWin = do_QueryInterface(GetEntryGlobal());
return entryWin ? entryWin->GetExtantDoc() : nullptr;
}
nsIGlobalObject*
GetIncumbentGlobal()
@ -171,6 +162,22 @@ GetIncumbentGlobal()
return ScriptSettingsStack::IncumbentGlobal();
}
nsIGlobalObject*
GetCurrentGlobal()
{
JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
if (!cx) {
return nullptr;
}
JSObject *global = JS::CurrentGlobalOrNull(cx);
if (!global) {
return nullptr;
}
return xpc::GetNativeForGlobal(global);
}
nsIPrincipal*
GetWebIDLCallerPrincipal()
{

View File

@ -20,6 +20,7 @@
class nsPIDOMWindow;
class nsGlobalWindow;
class nsIScriptContext;
class nsIDocument;
namespace mozilla {
namespace dom {
@ -63,17 +64,57 @@ private:
void InitScriptSettings();
void DestroyScriptSettings();
// This mostly gets the entry global, but doesn't entirely match the spec in
// certain edge cases. It's good enough for some purposes, but not others. If
// you want to call this function, ping bholley and describe your use-case.
nsIGlobalObject* BrokenGetEntryGlobal();
// To implement a web-compatible browser, it is often necessary to obtain the
// global object that is "associated" with the currently-running code. This
// process is made more complicated by the fact that, historically, different
// algorithms have operated with different definitions of the "associated"
// global.
//
// HTML5 formalizes this into two concepts: the "incumbent global" and the
// "entry global". The incumbent global corresponds to the global of the
// current script being executed, whereas the entry global corresponds to the
// global of the script where the current JS execution began.
//
// There is also a potentially-distinct third global that is determined by the
// current compartment. This roughly corresponds with the notion of Realms in
// ECMAScript.
//
// Suppose some event triggers an event listener in window |A|, which invokes a
// scripted function in window |B|, which invokes the |window.location.href|
// setter in window |C|. The entry global would be |A|, the incumbent global
// would be |B|, and the current compartment would be that of |C|.
//
// In general, it's best to use to use the most-closely-associated global
// unless the spec says to do otherwise. In 95% of the cases, the global of
// the current compartment (GetCurrentGlobal()) is the right thing. For
// example, WebIDL constructors (new C.XMLHttpRequest()) are initialized with
// the global of the current compartment (i.e. |C|).
//
// The incumbent global is very similar, but differs in a few edge cases. For
// example, if window |B| does |C.location.href = "..."|, the incumbent global
// used for the navigation algorithm is B, because no script from |C| was ever run.
//
// The entry global is used for various things like computing base URIs, mostly
// for historical reasons.
//
// Note that all of these functions return bonafide global objects. This means
// that, for Windows, they always return the inner.
// Note: We don't yet expose GetEntryGlobal, because in order for it to be
// correct, we first need to replace a bunch of explicit cx pushing in the
// browser with AutoEntryScript. But GetIncumbentGlobal is simpler, because it
// can mostly be inferred from the JS stack.
// Returns the global associated with the top-most Candidate Entry Point on
// the Script Settings Stack. See the HTML spec. This may be null.
nsIGlobalObject* GetEntryGlobal();
// If the entry global is a window, returns its extant document. Otherwise,
// returns null.
nsIDocument* GetEntryDocument();
// Returns the global associated with the top-most entry of the the Script
// Settings Stack. See the HTML spec. This may be null.
nsIGlobalObject* GetIncumbentGlobal();
// Returns the global associated with the current compartment. This may be null.
nsIGlobalObject* GetCurrentGlobal();
// JS-implemented WebIDL presents an interesting situation with respect to the
// subject principal. A regular C++-implemented API can simply examine the
// compartment of the most-recently-executed script, and use that to infer the

View File

@ -2501,11 +2501,6 @@ OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct,
}
}
// Don't expose CSSFontFeatureValuesRule unless the pref is enabled
if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSFontFeatureValuesRule_id) {
return nsCSSFontFeatureValuesRule::PrefEnabled();
}
return true;
}

View File

@ -420,7 +420,7 @@ nsFocusManager::GetLastFocusMethod(nsIDOMWindow* aWindow, uint32_t* aLastFocusMe
{
// the focus method is stored on the inner window
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
if (window)
if (window && window->IsOuterWindow())
window = window->GetCurrentInnerWindow();
if (!window)
window = mFocusedWindow;

View File

@ -1482,10 +1482,11 @@ nsGlobalWindow::CleanUp()
mChromeEventHandler = nullptr; // Forces Release
mParentTarget = nullptr;
nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
if (inner) {
inner->CleanUp();
if (IsOuterWindow()) {
nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
if (inner) {
inner->CleanUp();
}
}
if (IsInnerWindow()) {
@ -5915,15 +5916,8 @@ nsGlobalWindow::RefreshCompartmentPrincipal()
static already_AddRefed<nsIDocShellTreeItem>
GetCallerDocShellTreeItem()
{
JSContext *cx = nsContentUtils::GetCurrentJSContext();
nsCOMPtr<nsIDocShellTreeItem> callerItem;
if (cx) {
nsCOMPtr<nsIWebNavigation> callerWebNav =
do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
callerItem = do_QueryInterface(callerWebNav);
}
nsCOMPtr<nsIWebNavigation> callerWebNav = do_GetInterface(GetEntryGlobal());
nsCOMPtr<nsIDocShellTreeItem> callerItem = do_QueryInterface(callerWebNav);
return callerItem.forget();
}
@ -6557,7 +6551,7 @@ nsGlobalWindow::Focus(ErrorResult& aError)
return;
}
nsIDOMWindow *caller = nsContentUtils::GetWindowFromCaller();
nsCOMPtr<nsIDOMWindow> caller = do_QueryInterface(GetEntryGlobal());
nsCOMPtr<nsIDOMWindow> opener;
GetOpener(getter_AddRefs(opener));
@ -7535,20 +7529,7 @@ nsGlobalWindow::FireAbuseEvents(bool aBlocked, bool aWindow,
nsIURI *baseURL = nullptr;
JSContext *cx = nsContentUtils::GetCurrentJSContext();
nsCOMPtr<nsPIDOMWindow> contextWindow;
if (cx) {
nsIScriptContext *currentCX = nsJSUtils::GetDynamicScriptContext(cx);
if (currentCX) {
contextWindow = do_QueryInterface(currentCX->GetGlobalObject());
}
}
if (!contextWindow) {
contextWindow = this;
}
nsCOMPtr<nsIDocument> doc = contextWindow->GetDoc();
nsCOMPtr<nsIDocument> doc = GetEntryDocument();
if (doc)
baseURL = doc->GetDocBaseURI();
@ -8253,7 +8234,7 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
nsCOMPtr<nsIPrincipal> providedPrincipal;
if (aTargetOrigin.EqualsASCII("/")) {
providedPrincipal = BrokenGetEntryGlobal()->PrincipalOrNull();
providedPrincipal = GetEntryGlobal()->PrincipalOrNull();
if (NS_WARN_IF(!providedPrincipal))
return;
}
@ -12803,11 +12784,7 @@ nsGlobalWindow::GetScrollFrame()
nsresult
nsGlobalWindow::SecurityCheckURL(const char *aURL)
{
nsCOMPtr<nsPIDOMWindow> sourceWindow;
JSContext* topCx = nsContentUtils::GetCurrentJSContext();
if (topCx) {
sourceWindow = do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(topCx));
}
nsCOMPtr<nsPIDOMWindow> sourceWindow = do_QueryInterface(GetEntryGlobal());
if (!sourceWindow) {
sourceWindow = this;
}

View File

@ -599,6 +599,7 @@ public:
nsGlobalWindow *GetCurrentInnerWindowInternal() const
{
MOZ_ASSERT(IsOuterWindow());
return static_cast<nsGlobalWindow *>(mInnerWindow);
}

View File

@ -557,46 +557,38 @@ NS_ScriptErrorReporter(JSContext *cx,
}
}
// XXX this means we are not going to get error reports on non DOM contexts
nsIScriptContext *context = nsJSUtils::GetDynamicScriptContext(cx);
JS::Rooted<JS::Value> exception(cx);
::JS_GetPendingException(cx, &exception);
// Note: we must do this before running any more code on cx (if cx is the
// dynamic script context).
// Note: we must do this before running any more code on cx.
::JS_ClearPendingException(cx);
if (context) {
nsIScriptGlobalObject *globalObject = context->GetGlobalObject();
MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
nsCOMPtr<nsIGlobalObject> globalObject = GetEntryGlobal();
if (globalObject) {
if (globalObject) {
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
if (win) {
win = win->GetCurrentInnerWindow();
}
nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
do_QueryInterface(globalObject);
NS_ASSERTION(scriptPrincipal, "Global objects must implement "
"nsIScriptObjectPrincipal");
nsContentUtils::AddScriptRunner(
new ScriptErrorEvent(JS_GetRuntime(cx),
report,
message,
nsJSPrincipals::get(report->originPrincipals),
scriptPrincipal->GetPrincipal(),
win,
exception,
/* We do not try to report Out Of Memory via a dom
* event because the dom event handler would
* encounter an OOM exception trying to process the
* event, and then we'd need to generate a new OOM
* event for that new OOM instance -- this isn't
* pretty.
*/
report->errorNumber != JSMSG_OUT_OF_MEMORY));
}
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
MOZ_ASSERT_IF(win, win->IsInnerWindow());
nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
do_QueryInterface(globalObject);
NS_ASSERTION(scriptPrincipal, "Global objects must implement "
"nsIScriptObjectPrincipal");
nsContentUtils::AddScriptRunner(
new ScriptErrorEvent(JS_GetRuntime(cx),
report,
message,
nsJSPrincipals::get(report->originPrincipals),
scriptPrincipal->GetPrincipal(),
win,
exception,
/* We do not try to report Out Of Memory via a dom
* event because the dom event handler would
* encounter an OOM exception trying to process the
* event, and then we'd need to generate a new OOM
* event for that new OOM instance -- this isn't
* pretty.
*/
report->errorNumber != JSMSG_OUT_OF_MEMORY));
}
if (nsContentUtils::DOMWindowDumpEnabled()) {

View File

@ -63,21 +63,6 @@ nsJSUtils::GetStaticScriptContext(JSObject* aObj)
return nativeGlobal->GetScriptContext();
}
nsIScriptGlobalObject *
nsJSUtils::GetDynamicScriptGlobal(JSContext* aContext)
{
nsIScriptContext *scriptCX = GetDynamicScriptContext(aContext);
if (!scriptCX)
return nullptr;
return scriptCX->GetGlobalObject();
}
nsIScriptContext *
nsJSUtils::GetDynamicScriptContext(JSContext *aContext)
{
return GetScriptContextFromJSContext(aContext);
}
uint64_t
nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
{

View File

@ -32,10 +32,6 @@ public:
static nsIScriptContext *GetStaticScriptContext(JSObject* aObj);
static nsIScriptGlobalObject *GetDynamicScriptGlobal(JSContext *aContext);
static nsIScriptContext *GetDynamicScriptContext(JSContext *aContext);
/**
* Retrieve the inner window ID based on the given JSContext.
*

View File

@ -28,6 +28,7 @@
#include "nsITextToSubURI.h"
#include "nsJSUtils.h"
#include "nsContentUtils.h"
#include "nsGlobalWindow.h"
#include "mozilla/Likely.h"
#include "nsCycleCollectionParticipant.h"
#include "nsNullPrincipal.h"
@ -42,15 +43,8 @@ GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset)
{
aCharset.Truncate();
JSContext *cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
nsCOMPtr<nsPIDOMWindow> window =
do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
if (nsIDocument* doc = window->GetDoc()) {
aCharset = doc->GetDocumentCharacterSet();
}
if (nsIDocument* doc = GetEntryDocument()) {
aCharset = doc->GetDocumentCharacterSet();
}
return NS_OK;
@ -545,23 +539,23 @@ nsLocation::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
* anywhere else. This is part of solution for bug # 39938, 72197
*
*/
bool inScriptTag=false;
JSContext *cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
nsIScriptContext *scriptContext =
nsJSUtils::GetDynamicScriptContext(cx);
bool inScriptTag = false;
nsIScriptContext* scriptContext = nullptr;
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(GetEntryGlobal());
if (win) {
scriptContext = static_cast<nsGlobalWindow*>(win.get())->GetContextInternal();
}
if (scriptContext) {
if (scriptContext->GetProcessingScriptTag()) {
// Now check to make sure that the script is running in our window,
// since we only want to replace if the location is set by a
// <script> tag in the same window. See bug 178729.
nsCOMPtr<nsIScriptGlobalObject> ourGlobal =
docShell ? docShell->GetScriptGlobalObject() : nullptr;
inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
}
if (scriptContext) {
if (scriptContext->GetProcessingScriptTag()) {
// Now check to make sure that the script is running in our window,
// since we only want to replace if the location is set by a
// <script> tag in the same window. See bug 178729.
nsCOMPtr<nsIScriptGlobalObject> ourGlobal =
docShell ? docShell->GetScriptGlobalObject() : nullptr;
inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
}
} //cx
}
return SetURI(newUri, aReplace || inScriptTag);
}
@ -1020,22 +1014,20 @@ nsLocation::ValueOf(nsIDOMLocation** aReturn)
nsresult
nsLocation::GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL)
{
*sourceURL = nullptr;
nsCOMPtr<nsIScriptGlobalObject> sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
// If this JS context doesn't have an associated DOM window, we effectively
// have no script entry point stack. This doesn't generally happen with the DOM,
nsIDocument* doc = GetEntryDocument();
// If there's no entry document, we either have no Script Entry Point or one
// that isn't a DOM Window. This doesn't generally happen with the DOM,
// but can sometimes happen with extension code in certain IPC configurations.
// If this happens, try falling back on the current document associated with
// the docshell. If that fails, just return null and hope that the caller passed
// an absolute URI.
if (!sgo && GetDocShell()) {
sgo = GetDocShell()->GetScriptGlobalObject();
if (!doc && GetDocShell()) {
nsCOMPtr<nsPIDOMWindow> docShellWin = do_QueryInterface(GetDocShell()->GetScriptGlobalObject());
if (docShellWin) {
doc = docShellWin->GetDoc();
}
}
NS_ENSURE_TRUE(sgo, NS_OK);
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(sgo);
NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
nsIDocument* doc = window->GetDoc();
NS_ENSURE_TRUE(doc, NS_OK);
*sourceURL = doc->GetBaseURI().take();
return NS_OK;

View File

@ -192,12 +192,7 @@ public:
bool IsLoadingOrRunningTimeout() const
{
const nsPIDOMWindow *win = GetCurrentInnerWindow();
if (!win) {
win = this;
}
const nsPIDOMWindow* win = IsInnerWindow() ? this : GetCurrentInnerWindow();
return !win->mIsDocumentLoaded || win->mRunningTimeout;
}
@ -299,6 +294,7 @@ public:
nsPIDOMWindow *GetCurrentInnerWindow() const
{
MOZ_ASSERT(IsOuterWindow());
return mInnerWindow;
}

View File

@ -56,7 +56,8 @@ AddNonJSSizeOfWindowAndItsDescendents(nsGlobalWindow* aWindow,
// Measure the inner window, if there is one.
nsWindowSizes innerWindowSizes(moz_malloc_size_of);
nsGlobalWindow* inner = aWindow->GetCurrentInnerWindowInternal();
nsGlobalWindow* inner = aWindow->IsOuterWindow() ? aWindow->GetCurrentInnerWindowInternal()
: nullptr;
if (inner) {
inner->AddSizeOfIncludingThis(&innerWindowSizes);
innerWindowSizes.addToTabSizes(aSizes);

View File

@ -2645,5 +2645,12 @@ AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitInfo,
}
#endif
bool
CallerSubsumes(JSObject *aObject)
{
nsIPrincipal* objPrin = nsContentUtils::ObjectPrincipal(js::UncheckedUnwrap(aObject));
return nsContentUtils::SubjectPrincipal()->Subsumes(objPrin);
}
} // namespace dom
} // namespace mozilla

View File

@ -2937,6 +2937,18 @@ AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
bool
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
bool
CallerSubsumes(JSObject* aObject);
MOZ_ALWAYS_INLINE bool
CallerSubsumes(JS::Handle<JS::Value> aValue)
{
if (!aValue.isObject()) {
return true;
}
return CallerSubsumes(&aValue.toObject());
}
} // namespace dom
} // namespace mozilla

View File

@ -1053,11 +1053,6 @@ DOMInterfaces = {
'headerFile': 'mozilla/dom/workers/bindings/ServiceWorker.h',
},
'ServiceWorkerContainer': {
'nativeType': 'mozilla::dom::workers::ServiceWorkerContainer',
'headerFile': 'mozilla/dom/ServiceWorkerContainer.h',
},
'ServiceWorkerGlobalScope': {
'headerFile': 'mozilla/dom/WorkerScope.h',
'workers': True,

View File

@ -3572,6 +3572,9 @@ class JSToNativeConversionInfo():
for whether we have a JS::Value. Only used when
defaultValue is not None or when True is passed for
checkForValue to instantiateJSToNativeConversion.
${passedToJSImpl} replaced by an expression that evaluates to a boolean
for whether this value is being passed to a JS-
implemented interface.
declType: A CGThing representing the native C++ type we're converting
to. This is allowed to be None if the conversion code is
@ -3827,7 +3830,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
return templateBody
# A helper function for converting things that look like a JSObject*.
def handleJSObjectType(type, isMember, failureCode):
def handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription):
if not isMember:
if isOptional:
# We have a specialization of Optional that will use a
@ -3843,6 +3846,19 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
declType = CGGeneric("JSObject*")
declArgs = None
templateBody = "${declName} = &${val}.toObject();\n"
# For JS-implemented APIs, we refuse to allow passing objects that the
# API consumer does not subsume.
if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
templateBody = fill("""
if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
$*{exceptionCode}
}
""",
sourceDescription=sourceDescription,
exceptionCode=exceptionCode) + templateBody
setToNullCode = "${declName} = nullptr;\n"
template = wrapObjectTemplate(templateBody, type, setToNullCode,
failureCode)
@ -3917,7 +3933,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# We only need holderName here to handle isExternal()
# interfaces, which use an internal holder for the
# conversion even when forceOwningType ends up true.
"holderName": "tempHolder"
"holderName": "tempHolder",
"passedToJSImpl": "${passedToJSImpl}"
})
# NOTE: Keep this in sync with variadic conversions as needed
@ -4021,7 +4038,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# We only need holderName here to handle isExternal()
# interfaces, which use an internal holder for the
# conversion even when forceOwningType ends up true.
"holderName": "tempHolder"
"holderName": "tempHolder",
"passedToJSImpl": "${passedToJSImpl}"
})
templateBody = fill(
@ -4114,7 +4132,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
for memberType in interfaceMemberTypes:
name = getUnionMemberName(memberType)
interfaceObject.append(
CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext" %
CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext" %
(unionArgumentObj, name)))
names.append(name)
interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"),
@ -4127,7 +4145,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert len(arrayObjectMemberTypes) == 1
name = getUnionMemberName(arrayObjectMemberTypes[0])
arrayObject = CGGeneric(
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
(unionArgumentObj, name))
names.append(name)
else:
@ -4151,7 +4169,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
memberType = callbackMemberTypes[0]
name = getUnionMemberName(memberType)
callbackObject = CGGeneric(
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
(unionArgumentObj, name))
names.append(name)
else:
@ -4162,7 +4180,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert len(dictionaryMemberTypes) == 1
name = getUnionMemberName(dictionaryMemberTypes[0])
setDictionary = CGGeneric(
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
(unionArgumentObj, name))
names.append(name)
else:
@ -4173,7 +4191,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert len(mozMapMemberTypes) == 1
name = getUnionMemberName(mozMapMemberTypes[0])
mozMapObject = CGGeneric(
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n" %
"done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext, ${passedToJSImpl})) || !tryNext;\n" %
(unionArgumentObj, name))
names.append(name)
else:
@ -4185,8 +4203,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# Very important to NOT construct a temporary Rooted here, since the
# SetToObject call can call a Rooted constructor and we need to keep
# stack discipline for Rooted.
object = CGGeneric("%s.SetToObject(cx, &${val}.toObject());\n"
"done = true;\n" % unionArgumentObj)
object = CGGeneric("if (!%s.SetToObject(cx, &${val}.toObject(), ${passedToJSImpl})) {\n"
"%s"
"}\n"
"done = true;\n" % (unionArgumentObj, indent(exceptionCode)))
names.append(objectMemberTypes[0].name)
else:
object = None
@ -4425,7 +4445,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if descriptor.nativeType == 'JSObject':
# XXXbz Workers code does this sometimes
assert descriptor.workers
return handleJSObjectType(type, isMember, failureCode)
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
if descriptor.interface.isCallback():
name = descriptor.interface.identifier.name
@ -4507,7 +4527,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
isCallbackReturnValue,
firstCap(sourceDescription)))
elif descriptor.workers:
return handleJSObjectType(type, isMember, failureCode)
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
else:
# Either external, or new-binding non-castable. We always have a
# holder for these, because we don't actually know whether we have
@ -4826,6 +4846,19 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isOptional
templateBody = "${declName} = ${val};\n"
# For JS-implemented APIs, we refuse to allow passing objects that the
# API consumer does not subsume.
if not isinstance(descriptorProvider, Descriptor) or descriptorProvider.interface.isJSImplemented():
templateBody = fill("""
if ($${passedToJSImpl} && !CallerSubsumes($${val})) {
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "${sourceDescription}");
$*{exceptionCode}
}
""",
sourceDescription=sourceDescription,
exceptionCode=exceptionCode) + templateBody
# We may not have a default value if we're being converted for
# a setter, say.
if defaultValue:
@ -4841,7 +4874,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.isObject():
assert not isEnforceRange and not isClamp
return handleJSObjectType(type, isMember, failureCode)
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
if type.isDictionary():
# There are no nullable dictionaries
@ -4891,7 +4924,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.nullable():
dictLoc += ".SetValue()"
template += ('if (!%s.Init(cx, %s, "%s")) {\n'
template += ('if (!%s.Init(cx, %s, "%s", ${passedToJSImpl})) {\n'
"%s"
"}\n" % (dictLoc, val, firstCap(sourceDescription),
exceptionCodeIndented.define()))
@ -5167,7 +5200,8 @@ class CGArgumentConverter(CGThing):
self.replacementVariables = {
"declName": "arg%d" % index,
"holderName": ("arg%d" % index) + "_holder",
"obj": "obj"
"obj": "obj",
"passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptorProvider))
}
self.replacementVariables["val"] = string.Template(
"args[${index}]").substitute(replacer)
@ -5245,7 +5279,8 @@ class CGArgumentConverter(CGThing):
# conversion even when forceOwningType ends up true.
"holderName": "tempHolder",
# Use the same ${obj} as for the variadic arg itself
"obj": replacer["obj"]
"obj": replacer["obj"],
"passedToJSImpl": toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
}), 4)
variadicConversion += (" }\n"
@ -6741,7 +6776,8 @@ class CGMethodCall(CGThing):
"holderName": ("arg%d" % distinguishingIndex) + "_holder",
"val": distinguishingArg,
"obj": "obj",
"haveValue": "args.hasDefined(%d)" % distinguishingIndex
"haveValue": "args.hasDefined(%d)" % distinguishingIndex,
"passedToJSImpl": toStringBool(isJSImplementedDescriptor(descriptor))
},
checkForValue=argIsOptional)
caseBody.append(CGIndenter(testCode, indent))
@ -8316,9 +8352,22 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
mUnion.mValue.mObject.SetValue(cx, obj);
mUnion.mType = mUnion.eObject;
""")
setter = ClassMethod("SetToObject", "void",
# It's a bit sketchy to do the security check after setting the value,
# but it keeps the code cleaner and lets us avoid rooting |obj| over the
# call to CallerSubsumes().
body = body + dedent("""
if (passedToJSImpl && !CallerSubsumes(obj)) {
ThrowErrorMessage(cx, MSG_PERMISSION_DENIED_TO_PASS_ARG, "%s");
return false;
}
return true;
""")
setter = ClassMethod("SetToObject", "bool",
[Argument("JSContext*", "cx"),
Argument("JSObject*", "obj")],
Argument("JSObject*", "obj"),
Argument("bool", "passedToJSImpl", default="false")],
inline=True, bodyInHeader=True,
body=body)
@ -8338,7 +8387,8 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
val="value",
declName="memberSlot",
holderName=(holderName if ownsMembers else "%s.ref()" % holderName),
destroyHolder=destroyHolder)
destroyHolder=destroyHolder,
passedToJSImpl="passedToJSImpl")
jsConversion = fill(
"""
@ -8357,7 +8407,8 @@ def getUnionTypeTemplateVars(unionType, type, descriptorProvider,
setter = ClassMethod("TrySetTo" + name, "bool",
[Argument("JSContext*", "cx"),
Argument("JS::Handle<JS::Value>", "value"),
Argument("bool&", "tryNext")],
Argument("bool&", "tryNext"),
Argument("bool", "passedToJSImpl", default="false")],
inline=not ownsMembers,
bodyInHeader=not ownsMembers,
body=jsConversion)
@ -9463,7 +9514,8 @@ class CGProxySpecialOperation(CGPerSignatureCall):
"declName": argument.identifier.name,
"holderName": argument.identifier.name + "_holder",
"val": argumentMutableValue,
"obj": "obj"
"obj": "obj",
"passedToJSImpl": "false"
}
self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
elif operation.isGetter() or operation.isDeleter():
@ -11087,7 +11139,8 @@ class CGDictionary(CGThing):
return ClassMethod("Init", "bool", [
Argument('JSContext*', 'cx'),
Argument('JS::Handle<JS::Value>', 'val'),
Argument('const char*', 'sourceDescription', default='"Value"')
Argument('const char*', 'sourceDescription', default='"Value"'),
Argument('bool', 'passedToJSImpl', default='false')
], body=body)
def initFromJSONMethod(self):
@ -11322,7 +11375,8 @@ class CGDictionary(CGThing):
# We need a holder name for external interfaces, but
# it's scoped down to the conversion so we can just use
# anything we want.
"holderName": "holder"
"holderName": "holder",
"passedToJSImpl": "passedToJSImpl"
}
# We can't handle having a holderType here
assert conversionInfo.holderType is None
@ -11458,6 +11512,11 @@ class CGDictionary(CGThing):
trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData)
if type.nullable():
trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable)
elif type.isMozMap():
# If you implement this, add a MozMap<object> to
# TestInterfaceJSDictionary and test it in test_bug1036214.html
# to make sure we end up with the correct security properties.
assert False
else:
assert False # unknown type
@ -13389,7 +13448,8 @@ class CallbackMember(CGNativeMember):
# We actually want to pass in a null scope object here, because
# wrapping things into our current compartment (that of mCallback)
# is what we want.
"obj": "nullptr"
"obj": "nullptr",
"passedToJSImpl": "false"
}
if isJSImplementedDescriptor(self.descriptorProvider):

View File

@ -58,3 +58,4 @@ MSG_DEF(MSG_HEADERS_IMMUTABLE, 0, "Headers are immutable and cannot be modified.
MSG_DEF(MSG_INVALID_HEADER_NAME, 1, "{0} is an invalid header name.")
MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, "{0} is an invalid header value.")
MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, "Headers require name/value tuples when being initialized by a sequence.")
MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, "Permission denied to pass cross-origin object as {0}.")

View File

@ -9,17 +9,6 @@ const Ci = Components.interfaces;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var gGlobal = this;
function checkGlobal(obj) {
if (Object(obj) === obj && Cu.getGlobalForObject(obj) != gGlobal) {
// This message may not make it to the caller in a useful form, so dump
// as well.
var msg = "TestInterfaceJS received an object from a different scope!";
dump(msg + "\n");
throw new Error(msg);
}
}
function TestInterfaceJS(anyArg, objectArg) {}
TestInterfaceJS.prototype = {
@ -27,23 +16,32 @@ TestInterfaceJS.prototype = {
contractID: "@mozilla.org/dom/test-interface-js;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
__init: function (anyArg, objectArg) {
__init: function (anyArg, objectArg, dictionaryArg) {
this._anyAttr = undefined;
this._objectAttr = null;
this._anyArg = anyArg;
this._objectArg = objectArg;
checkGlobal(anyArg);
checkGlobal(objectArg);
this._dictionaryArg = dictionaryArg;
},
get anyArg() { return this._anyArg; },
get objectArg() { return this._objectArg; },
get dictionaryArg() { return this._dictionaryArg; },
get anyAttr() { return this._anyAttr; },
set anyAttr(val) { checkGlobal(val); this._anyAttr = val; },
set anyAttr(val) { this._anyAttr = val; },
get objectAttr() { return this._objectAttr; },
set objectAttr(val) { checkGlobal(val); this._objectAttr = val; },
pingPongAny: function(any) { checkGlobal(any); return any; },
pingPongObject: function(obj) { checkGlobal(obj); return obj; },
set objectAttr(val) { this._objectAttr = val; },
get dictionaryAttr() { return this._dictionaryAttr; },
set dictionaryAttr(val) { this._dictionaryAttr = val; },
pingPongAny: function(any) { return any; },
pingPongObject: function(obj) { return obj; },
pingPongObjectOrString: function(objectOrString) { return objectOrString; },
pingPongDictionary: function(dict) { return dict; },
pingPongDictionaryOrLong: function(dictOrLong) { return dictOrLong.anyMember || dictOrLong; },
pingPongMap: function(map) { return JSON.stringify(map); },
objectSequenceLength: function(seq) { return seq.length; },
anySequenceLength: function(seq) { return seq.length; },
getCallerPrincipal: function() { return Cu.getWebIDLCallerPrincipal().origin; },

View File

@ -17,10 +17,8 @@ support-files =
[test_bug788369.html]
[test_bug852846.html]
[test_bug862092.html]
# When bug 923904 lands, this test can be turned on, but only for debug builds
# where we have our test component. So this should become skip-if = debug == false.
[test_bug923904.html]
skip-if = true
[test_bug1036214.html]
skip-if = debug == false
[test_bug1041646.html]
[test_barewordGetsWindow.html]
[test_callback_default_thisval.html]

View File

@ -0,0 +1,123 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1036214
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1036214</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for subsumes-checking |any| and |object| for js-implemented WebIDL. **/
SimpleTest.waitForExplicitFinish();
var xoObjects = [];
function setup() {
xoObjects.push(window[0]);
xoObjects.push(window[0].location);
xoObjects.push(SpecialPowers.unwrap(SpecialPowers.wrap(window[0]).document));
xoObjects.push(SpecialPowers);
xoObjects.push(SpecialPowers.wrap);
SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, go);
}
function checkThrows(f, msg) {
try {
f();
ok(false, "Should have thrown: " + msg);
} catch (e) {
ok(true, "Threw correctly: " + msg);
ok(/denied|insecure/.test(e), "Threw security exception: " + e);
}
}
function go() {
//
// Test the basics of the test interface.
//
var any = { a: 11 };
var obj = { b: 22, c: "str" };
var obj2 = { foo: "baz" };
var myDict = { anyMember: 42, objectMember: { answer: 42 }, objectOrStringMember: { answer: "anobject" },
anySequenceMember: [{}, 1, "thirdinsequence"],
innerDictionary: { innerObject: { answer: "rabbithole" } } };
var t = new TestInterfaceJS(any, obj, myDict);
is(Object.getPrototypeOf(t), TestInterfaceJS.prototype, "Prototype setup works correctly");
is(t.anyArg, any, "anyArg is correct");
is(t.objectArg, obj, "objectArg is correct");
is(t.dictionaryArg.anyMember, 42, "dictionaryArg looks correct");
is(t.dictionaryArg.objectMember.answer, 42, "dictionaryArg looks correct");
t.anyAttr = 2;
is(t.anyAttr, 2, "ping-pong any attribute works");
t.objAttr = obj2;
is(t.objAttr, obj2, "ping-pong object attribute works");
t.dictionaryAttr = myDict;
is(t.dictionaryAttr.anyMember, 42, "ping-pong dictionary attribute works");
is(t.dictionaryAttr.objectMember.answer, 42, "ping-pong dictionary attribute works");
is(any, t.pingPongAny(any), "ping-pong works with any");
is(obj, t.pingPongObject(obj), "ping-pong works with obj");
is(obj, t.pingPongObjectOrString(obj), "ping-pong works with obj or string");
is("foo", t.pingPongObjectOrString("foo"), "ping-pong works with obj or string");
is(t.pingPongDictionary(myDict).anyMember, 42, "ping pong works with dict");
is(t.pingPongDictionary(myDict).objectMember.answer, 42, "ping pong works with dict");
is(t.pingPongDictionary(myDict).objectOrStringMember.answer, "anobject", "ping pong works with dict");
is(t.pingPongDictionary(myDict).anySequenceMember[2], "thirdinsequence", "ping pong works with dict");
is(t.pingPongDictionary(myDict).innerDictionary.innerObject.answer, "rabbithole", "ping pong works with layered dicts");
is(t.pingPongDictionaryOrLong({anyMember: 42}), 42, "ping pong (dict or long) works with dict");
is(t.pingPongDictionaryOrLong(42), 42, "ping pong (dict or long) works with long");
ok(/canary/.test(t.pingPongMap({ someVal: 42, someOtherVal: "canary" })), "ping pong works with mozmap");
is(t.objectSequenceLength([{}, {}, {}]), 3, "ping pong works with object sequence");
is(t.anySequenceLength([42, 'string', {}, undefined]), 4, "ping pong works with any sequence");
//
// Test that we throw in the cross-origin cases.
//
xoObjects.forEach(function(xoObj) {
var blank = new TestInterfaceJS();
checkThrows(() => new TestInterfaceJS(xoObj, undefined), "any param for constructor");
checkThrows(() => new TestInterfaceJS(undefined, xoObj), "obj param for constructor");
checkThrows(() => new TestInterfaceJS(undefined, undefined, { anyMember: xoObj }), "any dict param for constructor");
checkThrows(() => new TestInterfaceJS(undefined, undefined, { objectMember: xoObj }), "object dict param for constructor");
checkThrows(() => new TestInterfaceJS(undefined, undefined, { objectOrStringMember: xoObj }), "union dict param for constructor");
checkThrows(() => new TestInterfaceJS(undefined, undefined, { anySequenceMember: [0, xoObj, 'hi' ] }), "sequence dict param for constructor");
checkThrows(() => new TestInterfaceJS(undefined, undefined, { innerDictionary: { innerObject: xoObj } }), "inner dict param for constructor");
checkThrows(() => t.anyAttr = xoObj, "anyAttr");
checkThrows(() => t.objectAttr = xoObj, "objAttr");
checkThrows(() => t.dictionaryAttr = { anyMember: xoObj }, "dictionaryAttr any");
checkThrows(() => t.dictionaryAttr = { objectMember: xoObj }, "dictionaryAttr object");
checkThrows(() => t.pingPongAny(xoObj), "pingpong any");
checkThrows(() => t.pingPongObject(xoObj), "pingpong obj");
checkThrows(() => t.pingPongObjectOrString(xoObj), "pingpong union");
checkThrows(() => t.pingPongDictionary({ anyMember: xoObj }), "dictionary pingpong any");
checkThrows(() => t.pingPongDictionary({ objectMember: xoObj }), "dictionary pingpong object");
checkThrows(() => t.pingPongDictionary({ anyMember: xoObj, objectMember: xoObj }), "dictionary pingpong both");
checkThrows(() => t.pingPongDictionary({ objectOrStringMember: xoObj }), "dictionary pingpong objectorstring");
checkThrows(() => t.pingPongDictionaryOrLong({ objectMember: xoObj }), "unionable dictionary");
checkThrows(() => t.pingPongDictionaryOrLong({ anyMember: xoObj }), "unionable dictionary");
checkThrows(() => t.pingPongMap({ someMember: 42, someOtherMember: {}, crossOriginMember: xoObj }), "mozmap");
checkThrows(() => t.objectSequenceLength([{}, {}, xoObj, {}]), "object sequence");
checkThrows(() => t.anySequenceLength([42, 'someString', xoObj, {}]), "any sequence");
});
SimpleTest.finish();
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1036214">Mozilla Bug 1036214</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<iframe id="ifr" onload="setup();" src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html"></iframe>
</body>
</html>

View File

@ -1,66 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=923904
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 923904</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for cloning of |any| and |object| for JS-Implemented WebIDL. **/
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, go);
function go() {
var someAny = { a: 11 };
var someObj = { b: 22, c: "str" };
var t = new TestInterfaceJS(someAny, someObj);
is(Object.getPrototypeOf(t), TestInterfaceJS.prototype, "Prototype setup works correctly");
is(t.anyArg.toSource(), someAny.toSource(), "anyArg comes back looking like what we sent");
is(t.objectArg.toSource(), someObj.toSource(), "objectArg comes back looking like what we sent");
isnot(t.anyArg, t.anyArg, "get a new anyArg each time");
isnot(t.objectArg, t.objectArg, "get a new objectArg each time");
t.anyAttr = 2;
is(t.anyAttr, 2, "ping-pong works");
testObjectCloned(t, 'anyAttr');
testObjectCloned(t, 'objectAttr');
is(someAny.toSource(), t.pingPongAny(someAny).toSource(), "ping-pong works with any");
is(someObj.toSource(), t.pingPongObject(someObj).toSource(), "ping-pong works with obj");
isnot(someAny, t.pingPongAny(someAny), "Clone works for ping-pong any");
isnot(someObj, t.pingPongObject(someObj), "Clone works for ping-pong obj");
SimpleTest.finish();
}
function testObjectCloned(iface, propname) {
var obj = { prop: 42 };
iface[propname] = obj;
is(iface[propname].prop, 42, "objects come back as well");
is(iface[propname].__proto__, Object.prototype, "vanilla object");
isnot(iface[propname], obj, "Should not be the original object");
isnot(iface[propname], iface[propname], "Should get cloned each time");
try {
iface[propname] = { stringProp: "hi", reflectorProp: document };
ok(false, "Should throw when trying to clone reflector");
} catch (e) {
ok(/cloned/.test(e), "Should throw clone error: " + e);
}
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=923904">Mozilla Bug 923904</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -1985,7 +1985,7 @@ CanvasRenderingContext2D::ArcTo(double x1, double y1, double x2,
}
// Check for colinearity
dir = (p2.x - p1.x) * (p0.y - p1.y) + (p2.y - p1.y) * (p1.x - p0.x);
dir = (p2.x - p1.x).value * (p0.y - p1.y).value + (p2.y - p1.y).value * (p1.x - p0.x).value;
if (dir == 0) {
LineTo(p1.x, p1.y);
return;
@ -4500,7 +4500,7 @@ CanvasPath::ArcTo(double x1, double y1, double x2, double y2, double radius,
}
// Check for colinearity
dir = (p2.x - p1.x) * (p0.y - p1.y) + (p2.y - p1.y) * (p1.x - p0.x);
dir = (p2.x - p1.x).value * (p0.y - p1.y).value + (p2.y - p1.y).value * (p1.x - p0.x).value;
if (dir == 0) {
LineTo(p1.x, p1.y);
return;

View File

@ -790,7 +790,7 @@ protected:
// The spec says we should not draw shadows if the operator is OVER.
// If it's over and the alpha value is zero, nothing needs to be drawn.
return NS_GET_A(state.shadowColor) != 0 &&
(state.shadowBlur != 0 || state.shadowOffset.x != 0 || state.shadowOffset.y != 0);
(state.shadowBlur != 0.f || state.shadowOffset.x != 0.f || state.shadowOffset.y != 0.f);
}
mozilla::gfx::CompositionOp UsedOperation()

View File

@ -1595,8 +1595,9 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
// fire drag gesture if mouse has moved enough
LayoutDeviceIntPoint pt = aEvent->refPoint +
LayoutDeviceIntPoint::FromUntyped(aEvent->widget->WidgetToScreenOffset());
if (DeprecatedAbs(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
DeprecatedAbs(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
if (Abs(distance.x.value) > SafeCast<uint32_t>(pixelThresholdX) ||
Abs(distance.y.value) > SafeCast<uint32_t>(pixelThresholdY)) {
if (Prefs::ClickHoldContextMenu()) {
// stop the click-hold before we fire off the drag gesture, in case
// it takes a long time

View File

@ -8,7 +8,7 @@
interface nsIDocument;
interface nsIURI;
[uuid(cc539f1e-1ce6-4af5-bf94-195b30bde010)]
[uuid(9b5acea4-2601-4ac7-8836-4352ceb88178)]
interface nsIServiceWorkerManager : nsISupports
{
// Returns a Promise
@ -17,9 +17,9 @@ interface nsIServiceWorkerManager : nsISupports
// Returns a Promise
nsISupports unregister(in nsIDOMWindow aWindow, in DOMString aScope);
// aTarget MUST be a ServiceWorkerContainer.
[noscript] void AddContainerEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
[noscript] void RemoveContainerEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
// aTarget MUST be a ServiceWorkerRegistration.
[noscript] void AddRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
[noscript] void RemoveRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
/**
* Call this to request that document `aDoc` be controlled by a ServiceWorker

View File

@ -2102,12 +2102,12 @@ MediaManager::MediaCaptureWindowStateInternal(nsIDOMWindow* aWindow, bool* aVide
// results.
nsCOMPtr<nsPIDOMWindow> piWin = do_QueryInterface(aWindow);
if (piWin) {
if (piWin->GetCurrentInnerWindow() || piWin->IsInnerWindow()) {
if (piWin->IsInnerWindow() || piWin->GetCurrentInnerWindow()) {
uint64_t windowID;
if (piWin->GetCurrentInnerWindow()) {
windowID = piWin->GetCurrentInnerWindow()->WindowID();
} else {
if (piWin->IsInnerWindow()) {
windowID = piWin->WindowID();
} else {
windowID = piWin->GetCurrentInnerWindow()->WindowID();
}
StreamListeners* listeners = GetActiveWindows()->Get(windowID);
if (listeners) {

View File

@ -55,14 +55,14 @@ var SMILUtil =
},
// Smart wrapper for getComputedStyle, which will generate a "fake" computed
// style for recognized shorthand properties (font, overflow, marker)
// style for recognized shorthand properties (font, font-variant, overflow, marker)
getComputedStyleWrapper : function(elem, propName)
{
// Special cases for shorthand properties (which aren't directly queriable
// via getComputedStyle)
var computedStyle;
if (propName == "font") {
var subProps = ["font-style", "font-variant", "font-weight",
var subProps = ["font-style", "font-variant-caps", "font-weight",
"font-size", "line-height", "font-family"];
for (var i in subProps) {
var subPropStyle = SMILUtil.getComputedStyleSimple(elem, subProps[i]);
@ -78,6 +78,10 @@ var SMILUtil =
}
}
}
} else if (propName == "font-variant") {
// xxx - this isn't completely correct but it's sufficient for what's
// being tested here
computedStyle = SMILUtil.getComputedStyleSimple(elem, "font-variant-caps");
} else if (propName == "marker") {
var subProps = ["marker-end", "marker-mid", "marker-start"];
for (var i in subProps) {

View File

@ -8,29 +8,27 @@
*
*/
[Pref="dom.serviceWorkers.enabled"]
interface ServiceWorkerContainer {
[Pref="dom.serviceWorkers.enabled",
Exposed=Window]
interface ServiceWorkerContainer : EventTarget {
// FIXME(nsm):
// https://github.com/slightlyoff/ServiceWorker/issues/198
// and discussion at https://etherpad.mozilla.org/serviceworker07apr
[Unforgeable] readonly attribute ServiceWorker? installing;
[Unforgeable] readonly attribute ServiceWorker? waiting;
[Unforgeable] readonly attribute ServiceWorker? active;
[Unforgeable] readonly attribute ServiceWorker? controller;
[Throws]
readonly attribute Promise<any> ready;
readonly attribute Promise<ServiceWorkerRegistration> ready;
[Throws]
Promise<any> getAll();
Promise<ServiceWorkerRegistration> register(ScalarValueString scriptURL,
optional RegistrationOptionList options);
[Throws]
Promise<ServiceWorker> register(DOMString url, optional RegistrationOptionList options);
Promise<ServiceWorkerRegistration> getRegistration(optional ScalarValueString documentURL = "");
[Throws]
Promise<any> unregister(DOMString? scope);
Promise<sequence<ServiceWorkerRegistration>> getRegistrations();
attribute EventHandler onupdatefound;
attribute EventHandler oncontrollerchange;
attribute EventHandler onreloadpage;
attribute EventHandler onerror;
@ -49,5 +47,5 @@ partial interface ServiceWorkerContainer {
};
dictionary RegistrationOptionList {
DOMString scope = "/*";
ScalarValueString scope = "/*";
};

View File

@ -0,0 +1,25 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
*
*/
[Pref="dom.serviceWorkers.enabled",
Exposed=Window]
interface ServiceWorkerRegistration : EventTarget {
[Unforgeable] readonly attribute ServiceWorker? installing;
[Unforgeable] readonly attribute ServiceWorker? waiting;
[Unforgeable] readonly attribute ServiceWorker? active;
readonly attribute ScalarValueString scope;
[Throws]
Promise<boolean> unregister();
// event
attribute EventHandler onupdatefound;
};

View File

@ -4,16 +4,29 @@
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
dictionary TestInterfaceJSUnionableDictionary {
object objectMember;
any anyMember;
};
[JSImplementation="@mozilla.org/dom/test-interface-js;1",
Pref="dom.expose_test_interfaces",
Constructor(optional any anyArg, optional object objectArg)]
Constructor(optional any anyArg, optional object objectArg, optional TestInterfaceJSDictionary dictionaryArg)]
interface TestInterfaceJS {
readonly attribute any anyArg;
readonly attribute object objectArg;
[Cached, Pure] readonly attribute TestInterfaceJSDictionary dictionaryArg;
attribute any anyAttr;
attribute object objectAttr;
[Cached, Pure] attribute TestInterfaceJSDictionary dictionaryAttr;
any pingPongAny(any arg);
object pingPongObject(any obj);
object pingPongObject(object obj);
any pingPongObjectOrString((object or DOMString) objOrString);
TestInterfaceJSDictionary pingPongDictionary(optional TestInterfaceJSDictionary dict);
long pingPongDictionaryOrLong(optional (TestInterfaceJSUnionableDictionary or long) dictOrLong);
DOMString pingPongMap(MozMap<any> map);
long objectSequenceLength(sequence<object> seq);
long anySequenceLength(sequence<any> seq);
// For testing bug 968335.
DOMString getCallerPrincipal();

View File

@ -0,0 +1,27 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
//
// These dictionaries are in a separate WebIDL file to avoid circular include
// problems. One of the dictionary includes a union as a member, so that
// dictionary's header needs to include UnionTypes.h. But the API in
// TestInterfaceJS also declares a union of dictionaries, so _that_
// dictionary's header needs to be included _by_ UnionTypes.h. The solution
// is to separate those two dictionaries into separate header files.
//
dictionary TestInterfaceJSDictionary2 {
object innerObject;
};
dictionary TestInterfaceJSDictionary {
TestInterfaceJSDictionary2 innerDictionary;
object objectMember;
any anyMember;
(object or DOMString) objectOrStringMember;
sequence<any> anySequenceMember;
};

View File

@ -326,6 +326,7 @@ WEBIDL_FILES = [
'ServiceWorker.webidl',
'ServiceWorkerContainer.webidl',
'ServiceWorkerGlobalScope.webidl',
'ServiceWorkerRegistration.webidl',
'SettingsManager.webidl',
'ShadowRoot.webidl',
'SharedWorker.webidl',
@ -563,7 +564,7 @@ WEBIDL_FILES += [
# We only expose our prefable test interfaces in debug builds, just to be on
# the safe side.
if CONFIG['MOZ_DEBUG']:
WEBIDL_FILES += ['TestInterfaceJS.webidl']
WEBIDL_FILES += ['TestInterfaceJS.webidl', 'TestInterfaceJSDictionaries.webidl']
if CONFIG['MOZ_B2G_BT']:
if CONFIG['MOZ_B2G_BT_API_V2']:

View File

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_ServiceWorkerCommon_h
#define mozilla_dom_ServiceWorkerCommon_h
namespace mozilla {
namespace dom {
// Use multiples of 2 since they can be bitwise ORed when calling
// InvalidateServiceWorkerRegistrationWorker.
MOZ_BEGIN_ENUM_CLASS(WhichServiceWorker)
INSTALLING_WORKER = 1,
WAITING_WORKER = 2,
ACTIVE_WORKER = 4,
MOZ_END_ENUM_CLASS(WhichServiceWorker)
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(WhichServiceWorker)
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_ServiceWorkerCommon_h

View File

@ -22,7 +22,6 @@
namespace mozilla {
namespace dom {
namespace workers {
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
@ -31,21 +30,16 @@ NS_IMPL_ADDREF_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper,
mInstallingWorker,
mWaitingWorker,
mActiveWorker,
mControllerWorker)
ServiceWorkerContainer::ServiceWorkerContainer(nsPIDOMWindow* aWindow)
: mWindow(aWindow)
{
SetIsDOMBinding();
StartListeningForEvents();
}
ServiceWorkerContainer::~ServiceWorkerContainer()
{
StopListeningForEvents();
}
JSObject*
@ -77,61 +71,6 @@ ServiceWorkerContainer::Register(const nsAString& aScriptURL,
return ret.forget();
}
already_AddRefed<Promise>
ServiceWorkerContainer::Unregister(const nsAString& aScope,
ErrorResult& aRv)
{
nsCOMPtr<nsISupports> promise;
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (!swm) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
aRv = swm->Unregister(mWindow, aScope, getter_AddRefs(promise));
if (aRv.Failed()) {
return nullptr;
}
nsRefPtr<Promise> ret = static_cast<Promise*>(promise.get());
MOZ_ASSERT(ret);
return ret.forget();
}
already_AddRefed<workers::ServiceWorker>
ServiceWorkerContainer::GetInstalling()
{
if (!mInstallingWorker) {
mInstallingWorker = GetWorkerReference(WhichServiceWorker::INSTALLING_WORKER);
}
nsRefPtr<ServiceWorker> ret = mInstallingWorker;
return ret.forget();
}
already_AddRefed<workers::ServiceWorker>
ServiceWorkerContainer::GetWaiting()
{
if (!mWaitingWorker) {
mWaitingWorker = GetWorkerReference(WhichServiceWorker::WAITING_WORKER);
}
nsRefPtr<ServiceWorker> ret = mWaitingWorker;
return ret.forget();
}
already_AddRefed<workers::ServiceWorker>
ServiceWorkerContainer::GetActive()
{
if (!mActiveWorker) {
mActiveWorker = GetWorkerReference(WhichServiceWorker::ACTIVE_WORKER);
}
nsRefPtr<ServiceWorker> ret = mActiveWorker;
return ret.forget();
}
already_AddRefed<workers::ServiceWorker>
ServiceWorkerContainer::GetController()
{
@ -148,15 +87,25 @@ ServiceWorkerContainer::GetController()
return nullptr;
}
mControllerWorker = static_cast<ServiceWorker*>(serviceWorker.get());
mControllerWorker =
static_cast<workers::ServiceWorker*>(serviceWorker.get());
}
nsRefPtr<ServiceWorker> ref = mControllerWorker;
nsRefPtr<workers::ServiceWorker> ref = mControllerWorker;
return ref.forget();
}
already_AddRefed<Promise>
ServiceWorkerContainer::GetAll(ErrorResult& aRv)
ServiceWorkerContainer::GetRegistrations(ErrorResult& aRv)
{
// FIXME(nsm): Bug 1002571
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
already_AddRefed<Promise>
ServiceWorkerContainer::GetRegistration(const nsAString& aDocumentURL,
ErrorResult& aRv)
{
// FIXME(nsm): Bug 1002571
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
@ -171,74 +120,6 @@ ServiceWorkerContainer::GetReady(ErrorResult& aRv)
return Promise::Create(global, aRv);
}
// XXXnsm, maybe this can be optimized to only add when a event handler is
// registered.
void
ServiceWorkerContainer::StartListeningForEvents()
{
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (swm) {
swm->AddContainerEventListener(mWindow->GetDocumentURI(), this);
}
}
void
ServiceWorkerContainer::StopListeningForEvents()
{
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (swm) {
swm->RemoveContainerEventListener(mWindow->GetDocumentURI(), this);
}
}
void
ServiceWorkerContainer::InvalidateWorkerReference(WhichServiceWorker aWhichOnes)
{
if (aWhichOnes & WhichServiceWorker::INSTALLING_WORKER) {
mInstallingWorker = nullptr;
}
if (aWhichOnes & WhichServiceWorker::WAITING_WORKER) {
mWaitingWorker = nullptr;
}
if (aWhichOnes & WhichServiceWorker::ACTIVE_WORKER) {
mActiveWorker = nullptr;
}
}
already_AddRefed<workers::ServiceWorker>
ServiceWorkerContainer::GetWorkerReference(WhichServiceWorker aWhichOne)
{
nsresult rv;
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
if (!swm) {
return nullptr;
}
nsCOMPtr<nsISupports> serviceWorker;
switch(aWhichOne) {
case WhichServiceWorker::INSTALLING_WORKER:
rv = swm->GetInstalling(mWindow, getter_AddRefs(serviceWorker));
break;
case WhichServiceWorker::WAITING_WORKER:
rv = swm->GetWaiting(mWindow, getter_AddRefs(serviceWorker));
break;
case WhichServiceWorker::ACTIVE_WORKER:
rv = swm->GetActive(mWindow, getter_AddRefs(serviceWorker));
break;
default:
MOZ_CRASH("Invalid enum value");
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsRefPtr<ServiceWorker> ref = static_cast<ServiceWorker*>(serviceWorker.get());
return ref.forget();
}
// Testing only.
already_AddRefed<Promise>
ServiceWorkerContainer::ClearAllServiceWorkerData(ErrorResult& aRv)
@ -271,6 +152,5 @@ ServiceWorkerContainer::GetControllingWorkerScriptURLForPath(
{
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
} // namespace workers
} // namespace dom
} // namespace mozilla

View File

@ -4,13 +4,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_workers_serviceworkercontainer_h__
#define mozilla_dom_workers_serviceworkercontainer_h__
#ifndef mozilla_dom_serviceworkercontainer_h__
#define mozilla_dom_serviceworkercontainer_h__
#include "mozilla/DOMEventTargetHelper.h"
#include "ServiceWorkerManager.h"
class nsPIDOMWindow;
namespace mozilla {
@ -20,8 +18,8 @@ class Promise;
struct RegistrationOptionList;
namespace workers {
class ServiceWorker;
}
// Lightweight serviceWorker APIs collection.
class ServiceWorkerContainer MOZ_FINAL : public DOMEventTargetHelper
@ -30,7 +28,6 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerContainer, DOMEventTargetHelper)
IMPL_EVENT_HANDLER(updatefound)
IMPL_EVENT_HANDLER(controllerchange)
IMPL_EVENT_HANDLER(reloadpage)
IMPL_EVENT_HANDLER(error)
@ -51,39 +48,19 @@ public:
const RegistrationOptionList& aOptions,
ErrorResult& aRv);
already_AddRefed<Promise>
Unregister(const nsAString& scope, ErrorResult& aRv);
already_AddRefed<ServiceWorker>
GetInstalling();
already_AddRefed<ServiceWorker>
GetWaiting();
already_AddRefed<ServiceWorker>
GetActive();
already_AddRefed<ServiceWorker>
already_AddRefed<workers::ServiceWorker>
GetController();
already_AddRefed<Promise>
GetAll(ErrorResult& aRv);
GetRegistration(const nsAString& aDocumentURL,
ErrorResult& aRv);
already_AddRefed<Promise>
GetRegistrations(ErrorResult& aRv);
already_AddRefed<Promise>
GetReady(ErrorResult& aRv);
nsIURI*
GetDocumentURI() const
{
return mWindow->GetDocumentURI();
}
void
InvalidateWorkerReference(WhichServiceWorker aWhichOnes);
already_AddRefed<workers::ServiceWorker>
GetWorkerReference(WhichServiceWorker aWhichOne);
// Testing only.
already_AddRefed<Promise>
ClearAllServiceWorkerData(ErrorResult& aRv);
@ -100,28 +77,14 @@ public:
private:
~ServiceWorkerContainer();
void
StartListeningForEvents();
void
StopListeningForEvents();
nsCOMPtr<nsPIDOMWindow> mWindow;
// The following properties are cached here to ensure JS equality is satisfied
// instead of acquiring a new worker instance from the ServiceWorkerManager
// for every access. A null value is considered a cache miss.
// These three may change to a new worker at any time.
nsRefPtr<ServiceWorker> mInstallingWorker;
nsRefPtr<ServiceWorker> mWaitingWorker;
nsRefPtr<ServiceWorker> mActiveWorker;
// This only changes when a worker hijacks everything in its scope by calling
// replace().
// FIXME(nsm): Bug 982711. Provide API to let SWM invalidate this.
nsRefPtr<ServiceWorker> mControllerWorker;
nsRefPtr<workers::ServiceWorker> mControllerWorker;
};
} // namespace workers
} // namespace dom
} // namespace mozilla

View File

@ -24,7 +24,7 @@
#include "RuntimeService.h"
#include "ServiceWorker.h"
#include "ServiceWorkerContainer.h"
#include "ServiceWorkerRegistration.h"
#include "ServiceWorkerEvents.h"
#include "WorkerInlines.h"
#include "WorkerPrivate.h"
@ -36,7 +36,7 @@ using namespace mozilla::dom;
BEGIN_WORKERS_NAMESPACE
NS_IMPL_ISUPPORTS0(ServiceWorkerRegistration)
NS_IMPL_ISUPPORTS0(ServiceWorkerRegistrationInfo)
UpdatePromise::UpdatePromise()
: mState(Pending)
@ -80,6 +80,7 @@ UpdatePromise::ResolveAllPromises(const nsACString& aScriptSpec, const nsACStrin
GlobalObject domGlobal(cx, global);
// The service worker is created and kept alive as a SharedWorker.
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv = rs->CreateServiceWorker(domGlobal,
NS_ConvertUTF8toUTF16(aScriptSpec),
@ -90,7 +91,14 @@ UpdatePromise::ResolveAllPromises(const nsACString& aScriptSpec, const nsACStrin
continue;
}
pendingPromise->MaybeResolve(serviceWorker);
// Since ServiceWorkerRegistration is only exposed to windows we can be
// certain about this cast.
nsCOMPtr<nsPIDOMWindow> window =
do_QueryInterface(pendingPromise->GetParentObject());
nsRefPtr<ServiceWorkerRegistration> swr =
new ServiceWorkerRegistration(window, NS_ConvertUTF8toUTF16(aScope));
pendingPromise->MaybeResolve(swr);
}
}
}
@ -107,7 +115,7 @@ UpdatePromise::RejectAllPromises(nsresult aRv)
for (uint32_t i = 0; i < array.Length(); ++i) {
WeakPtr<Promise>& pendingPromise = array.ElementAt(i);
if (pendingPromise) {
// Since ServiceWorkerContainer is only exposed to windows we can be
// Since ServiceWorkerRegistration is only exposed to windows we can be
// certain about this cast.
nsCOMPtr<nsPIDOMWindow> window =
do_QueryInterface(pendingPromise->GetParentObject());
@ -129,7 +137,7 @@ UpdatePromise::RejectAllPromises(const ErrorEventInit& aErrorDesc)
for (uint32_t i = 0; i < array.Length(); ++i) {
WeakPtr<Promise>& pendingPromise = array.ElementAt(i);
if (pendingPromise) {
// Since ServiceWorkerContainer is only exposed to windows we can be
// Since ServiceWorkerRegistration is only exposed to windows we can be
// certain about this cast.
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(pendingPromise->GetParentObject());
MOZ_ASSERT(go);
@ -208,7 +216,7 @@ public:
class ServiceWorkerUpdateInstance MOZ_FINAL : public nsISupports
{
// Owner of this instance.
ServiceWorkerRegistration* mRegistration;
ServiceWorkerRegistrationInfo* mRegistration;
nsCString mScriptSpec;
nsCOMPtr<nsPIDOMWindow> mWindow;
@ -219,7 +227,7 @@ class ServiceWorkerUpdateInstance MOZ_FINAL : public nsISupports
public:
NS_DECL_ISUPPORTS
ServiceWorkerUpdateInstance(ServiceWorkerRegistration *aRegistration,
ServiceWorkerUpdateInstance(ServiceWorkerRegistrationInfo *aRegistration,
nsPIDOMWindow* aWindow)
: mRegistration(aRegistration),
// Capture the current script spec in case register() gets called.
@ -297,13 +305,13 @@ FinishFetchOnMainThreadRunnable::Run()
return NS_OK;
}
ServiceWorkerRegistration::ServiceWorkerRegistration(const nsACString& aScope)
ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& aScope)
: mControlledDocumentsCounter(0),
mScope(aScope),
mPendingUninstall(false)
{ }
ServiceWorkerRegistration::~ServiceWorkerRegistration()
ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
{
MOZ_ASSERT(!IsControllingDocuments());
}
@ -339,7 +347,7 @@ ServiceWorkerManager::CleanupServiceWorkerInformation(const nsACString& aDomain,
ServiceWorkerDomainInfo* aDomainInfo,
void *aUnused)
{
aDomainInfo->mServiceWorkerRegistrations.Clear();
aDomainInfo->mServiceWorkerRegistrationInfos.Clear();
return PL_DHASH_NEXT;
}
@ -376,7 +384,7 @@ public:
swm->mDomainMap.Put(domain, domainInfo);
}
nsRefPtr<ServiceWorkerRegistration> registration =
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
domainInfo->GetRegistration(mScope);
nsCString spec;
@ -412,7 +420,11 @@ public:
return NS_ERROR_FAILURE;
}
mPromise->MaybeResolve(serviceWorker);
nsRefPtr<ServiceWorkerRegistration> swr =
new ServiceWorkerRegistration(mWindow,
NS_ConvertUTF8toUTF16(registration->mScope));
mPromise->MaybeResolve(swr);
return NS_OK;
}
}
@ -528,7 +540,7 @@ ServiceWorkerManager::Register(nsIDOMWindow* aWindow, const nsAString& aScope,
}
void
ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration,
ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistrationInfo* aRegistration,
nsresult aRv)
{
AssertIsOnMainThread();
@ -538,7 +550,7 @@ ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistration* aR
}
void
ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration,
ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistrationInfo* aRegistration,
const ErrorEventInit& aErrorDesc)
{
AssertIsOnMainThread();
@ -552,7 +564,7 @@ ServiceWorkerManager::RejectUpdatePromiseObservers(ServiceWorkerRegistration* aR
* may access the registration's (new) Promise after calling this method.
*/
NS_IMETHODIMP
ServiceWorkerManager::Update(ServiceWorkerRegistration* aRegistration,
ServiceWorkerManager::Update(ServiceWorkerRegistrationInfo* aRegistration,
nsPIDOMWindow* aWindow)
{
if (aRegistration->HasUpdatePromise()) {
@ -571,8 +583,8 @@ ServiceWorkerManager::Update(ServiceWorkerRegistration* aRegistration,
// instance.
// FIXME(nsm): Fire "statechange" on installing worker instance.
aRegistration->mInstallingWorker = nullptr;
InvalidateServiceWorkerContainerWorker(aRegistration,
WhichServiceWorker::INSTALLING_WORKER);
InvalidateServiceWorkerRegistrationWorker(aRegistration,
WhichServiceWorker::INSTALLING_WORKER);
}
aRegistration->mUpdatePromise = new UpdatePromise();
@ -587,7 +599,7 @@ ServiceWorkerManager::Update(ServiceWorkerRegistration* aRegistration,
return NS_OK;
}
// If we return an error, ServiceWorkerContainer will reject the Promise.
// If we return an error, ServiceWorkerREgistration will reject the Promise.
NS_IMETHODIMP
ServiceWorkerManager::Unregister(nsIDOMWindow* aWindow, const nsAString& aScope,
nsISupports** aPromise)
@ -613,7 +625,7 @@ ServiceWorkerManager::GetInstance()
}
void
ServiceWorkerManager::ResolveRegisterPromises(ServiceWorkerRegistration* aRegistration,
ServiceWorkerManager::ResolveRegisterPromises(ServiceWorkerRegistrationInfo* aRegistration,
const nsACString& aWorkerScriptSpec)
{
AssertIsOnMainThread();
@ -630,7 +642,7 @@ ServiceWorkerManager::ResolveRegisterPromises(ServiceWorkerRegistration* aRegist
// Must NS_Free() aString
void
ServiceWorkerManager::FinishFetch(ServiceWorkerRegistration* aRegistration,
ServiceWorkerManager::FinishFetch(ServiceWorkerRegistrationInfo* aRegistration,
nsPIDOMWindow* aWindow)
{
AssertIsOnMainThread();
@ -688,7 +700,7 @@ ServiceWorkerManager::HandleError(JSContext* aCx,
nsCString scope;
scope.Assign(aScope);
nsRefPtr<ServiceWorkerRegistration> registration = domainInfo->GetRegistration(scope);
nsRefPtr<ServiceWorkerRegistrationInfo> registration = domainInfo->GetRegistration(scope);
MOZ_ASSERT(registration);
RootedDictionary<ErrorEventInit> init(aCx);
@ -717,11 +729,11 @@ ServiceWorkerManager::HandleError(JSContext* aCx,
class FinishInstallRunnable MOZ_FINAL : public nsRunnable
{
nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
public:
explicit FinishInstallRunnable(
const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
: mRegistration(aRegistration)
{
MOZ_ASSERT(!NS_IsMainThread());
@ -740,10 +752,10 @@ public:
class FinishActivationRunnable : public nsRunnable
{
nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
public:
FinishActivationRunnable(const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
FinishActivationRunnable(const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
: mRegistration(aRegistration)
{
MOZ_ASSERT(!NS_IsMainThread());
@ -763,11 +775,11 @@ public:
class CancelServiceWorkerInstallationRunnable MOZ_FINAL : public nsRunnable
{
nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
public:
explicit CancelServiceWorkerInstallationRunnable(
const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
: mRegistration(aRegistration)
{
}
@ -780,8 +792,8 @@ public:
// FIXME(nsm): Fire statechange.
mRegistration->mInstallingWorker = nullptr;
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
swm->InvalidateServiceWorkerContainerWorker(mRegistration,
WhichServiceWorker::INSTALLING_WORKER);
swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
WhichServiceWorker::INSTALLING_WORKER);
return NS_OK;
}
};
@ -791,7 +803,7 @@ public:
*/
class FinishInstallHandler MOZ_FINAL : public PromiseNativeHandler
{
nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
virtual
~FinishInstallHandler()
@ -799,7 +811,7 @@ class FinishInstallHandler MOZ_FINAL : public PromiseNativeHandler
public:
explicit FinishInstallHandler(
const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
: mRegistration(aRegistration)
{
MOZ_ASSERT(!NS_IsMainThread());
@ -827,10 +839,10 @@ public:
class FinishActivateHandler : public PromiseNativeHandler
{
nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
public:
FinishActivateHandler(const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
FinishActivateHandler(const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
: mRegistration(aRegistration)
{
MOZ_ASSERT(!NS_IsMainThread());
@ -866,13 +878,13 @@ public:
*/
class InstallEventRunnable MOZ_FINAL : public WorkerRunnable
{
nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
nsCString mScope;
public:
InstallEventRunnable(
WorkerPrivate* aWorkerPrivate,
const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
mRegistration(aRegistration),
mScope(aRegistration.get()->mScope) // copied for access on worker thread.
@ -935,11 +947,11 @@ private:
class ActivateEventRunnable : public WorkerRunnable
{
nsMainThreadPtrHandle<ServiceWorkerRegistration> mRegistration;
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
public:
ActivateEventRunnable(WorkerPrivate* aWorkerPrivate,
const nsMainThreadPtrHandle<ServiceWorkerRegistration>& aRegistration)
const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
mRegistration(aRegistration)
{
@ -998,17 +1010,17 @@ private:
};
void
ServiceWorkerManager::Install(ServiceWorkerRegistration* aRegistration,
ServiceWorkerManager::Install(ServiceWorkerRegistrationInfo* aRegistration,
ServiceWorkerInfo* aServiceWorkerInfo)
{
AssertIsOnMainThread();
aRegistration->mInstallingWorker = aServiceWorkerInfo;
MOZ_ASSERT(aRegistration->mInstallingWorker);
InvalidateServiceWorkerContainerWorker(aRegistration,
WhichServiceWorker::INSTALLING_WORKER);
InvalidateServiceWorkerRegistrationWorker(aRegistration,
WhichServiceWorker::INSTALLING_WORKER);
nsMainThreadPtrHandle<ServiceWorkerRegistration> handle(
new nsMainThreadPtrHolder<ServiceWorkerRegistration>(aRegistration));
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle(
new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(aRegistration));
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv =
@ -1042,15 +1054,15 @@ ServiceWorkerManager::Install(ServiceWorkerRegistration* aRegistration,
// a wait is likely to be required only when performing networking or storage
// transactions in the first place.
FireEventOnServiceWorkerContainers(aRegistration,
NS_LITERAL_STRING("updatefound"));
FireEventOnServiceWorkerRegistrations(aRegistration,
NS_LITERAL_STRING("updatefound"));
}
class ActivationRunnable : public nsRunnable
{
nsRefPtr<ServiceWorkerRegistration> mRegistration;
nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
public:
explicit ActivationRunnable(ServiceWorkerRegistration* aRegistration)
explicit ActivationRunnable(ServiceWorkerRegistrationInfo* aRegistration)
: mRegistration(aRegistration)
{
}
@ -1065,13 +1077,13 @@ public:
mRegistration->mCurrentWorker = mRegistration->mWaitingWorker.forget();
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
swm->InvalidateServiceWorkerContainerWorker(mRegistration,
WhichServiceWorker::ACTIVE_WORKER | WhichServiceWorker::WAITING_WORKER);
swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
WhichServiceWorker::ACTIVE_WORKER | WhichServiceWorker::WAITING_WORKER);
// FIXME(nsm): Steps 7 of the algorithm.
swm->FireEventOnServiceWorkerContainers(mRegistration,
NS_LITERAL_STRING("controllerchange"));
swm->FireEventOnServiceWorkerRegistrations(mRegistration,
NS_LITERAL_STRING("controllerchange"));
MOZ_ASSERT(mRegistration->mCurrentWorker);
nsRefPtr<ServiceWorker> serviceWorker;
@ -1083,8 +1095,8 @@ public:
return rv;
}
nsMainThreadPtrHandle<ServiceWorkerRegistration> handle(
new nsMainThreadPtrHolder<ServiceWorkerRegistration>(mRegistration));
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle(
new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(mRegistration));
nsRefPtr<ActivateEventRunnable> r =
new ActivateEventRunnable(serviceWorker->GetWorkerPrivate(), handle);
@ -1099,7 +1111,7 @@ public:
};
void
ServiceWorkerManager::FinishInstall(ServiceWorkerRegistration* aRegistration)
ServiceWorkerManager::FinishInstall(ServiceWorkerRegistrationInfo* aRegistration)
{
AssertIsOnMainThread();
@ -1118,8 +1130,8 @@ ServiceWorkerManager::FinishInstall(ServiceWorkerRegistration* aRegistration)
aRegistration->mWaitingWorker = aRegistration->mInstallingWorker.forget();
MOZ_ASSERT(aRegistration->mWaitingWorker);
InvalidateServiceWorkerContainerWorker(aRegistration,
WhichServiceWorker::WAITING_WORKER | WhichServiceWorker::INSTALLING_WORKER);
InvalidateServiceWorkerRegistrationWorker(aRegistration,
WhichServiceWorker::WAITING_WORKER | WhichServiceWorker::INSTALLING_WORKER);
// FIXME(nsm): Actually update state of active ServiceWorker instances to
// installed.
@ -1140,7 +1152,7 @@ ServiceWorkerManager::FinishInstall(ServiceWorkerRegistration* aRegistration)
}
void
ServiceWorkerManager::FinishActivate(ServiceWorkerRegistration* aRegistration)
ServiceWorkerManager::FinishActivate(ServiceWorkerRegistrationInfo* aRegistration)
{
// FIXME(nsm): Set aRegistration->mCurrentWorker state to activated.
// Fire statechange.
@ -1178,22 +1190,22 @@ ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
return rv;
}
already_AddRefed<ServiceWorkerRegistration>
ServiceWorkerManager::GetServiceWorkerRegistration(nsPIDOMWindow* aWindow)
already_AddRefed<ServiceWorkerRegistrationInfo>
ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsPIDOMWindow* aWindow)
{
nsCOMPtr<nsIDocument> document = aWindow->GetExtantDoc();
return GetServiceWorkerRegistration(document);
return GetServiceWorkerRegistrationInfo(document);
}
already_AddRefed<ServiceWorkerRegistration>
ServiceWorkerManager::GetServiceWorkerRegistration(nsIDocument* aDoc)
already_AddRefed<ServiceWorkerRegistrationInfo>
ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIDocument* aDoc)
{
nsCOMPtr<nsIURI> documentURI = aDoc->GetDocumentURI();
return GetServiceWorkerRegistration(documentURI);
return GetServiceWorkerRegistrationInfo(documentURI);
}
already_AddRefed<ServiceWorkerRegistration>
ServiceWorkerManager::GetServiceWorkerRegistration(nsIURI* aURI)
already_AddRefed<ServiceWorkerRegistrationInfo>
ServiceWorkerManager::GetServiceWorkerRegistrationInfo(nsIURI* aURI)
{
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aURI);
if (!domainInfo) {
@ -1211,8 +1223,8 @@ ServiceWorkerManager::GetServiceWorkerRegistration(nsIURI* aURI)
return nullptr;
}
nsRefPtr<ServiceWorkerRegistration> registration;
domainInfo->mServiceWorkerRegistrations.Get(scope, getter_AddRefs(registration));
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
domainInfo->mServiceWorkerRegistrationInfos.Get(scope, getter_AddRefs(registration));
// ordered scopes and registrations better be in sync.
MOZ_ASSERT(registration);
@ -1357,8 +1369,8 @@ ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc)
return;
}
nsRefPtr<ServiceWorkerRegistration> registration =
GetServiceWorkerRegistration(aDoc);
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetServiceWorkerRegistrationInfo(aDoc);
if (registration && registration->mCurrentWorker) {
MOZ_ASSERT(!domainInfo->mControlledDocuments.Contains(aDoc));
registration->StartControllingADocument();
@ -1381,7 +1393,7 @@ ServiceWorkerManager::MaybeStopControlling(nsIDocument* aDoc)
return;
}
nsRefPtr<ServiceWorkerRegistration> registration;
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
domainInfo->mControlledDocuments.Remove(aDoc, getter_AddRefs(registration));
// A document which was uncontrolled does not maintain that state itself, so
// it will always call MaybeStopControlling() even if there isn't an
@ -1400,7 +1412,7 @@ ServiceWorkerManager::GetScopeForUrl(const nsAString& aUrl, nsAString& aScope)
return NS_ERROR_FAILURE;
}
nsRefPtr<ServiceWorkerRegistration> r = GetServiceWorkerRegistration(uri);
nsRefPtr<ServiceWorkerRegistrationInfo> r = GetServiceWorkerRegistrationInfo(uri);
if (!r) {
return NS_ERROR_FAILURE;
}
@ -1410,7 +1422,7 @@ ServiceWorkerManager::GetScopeForUrl(const nsAString& aUrl, nsAString& aScope)
}
NS_IMETHODIMP
ServiceWorkerManager::AddContainerEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
ServiceWorkerManager::AddRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
{
MOZ_ASSERT(aDocumentURI);
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
@ -1427,13 +1439,14 @@ ServiceWorkerManager::AddContainerEventListener(nsIURI* aDocumentURI, nsIDOMEven
MOZ_ASSERT(domainInfo);
ServiceWorkerContainer* container = static_cast<ServiceWorkerContainer*>(aListener);
domainInfo->mServiceWorkerContainers.AppendElement(container);
// TODO: this is very very bad:
ServiceWorkerRegistration* registration = static_cast<ServiceWorkerRegistration*>(aListener);
domainInfo->mServiceWorkerRegistrations.AppendElement(registration);
return NS_OK;
}
NS_IMETHODIMP
ServiceWorkerManager::RemoveContainerEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
ServiceWorkerManager::RemoveRegistrationEventListener(nsIURI* aDocumentURI, nsIDOMEventTarget* aListener)
{
MOZ_ASSERT(aDocumentURI);
nsRefPtr<ServiceWorkerDomainInfo> domainInfo = GetDomainInfo(aDocumentURI);
@ -1441,14 +1454,14 @@ ServiceWorkerManager::RemoveContainerEventListener(nsIURI* aDocumentURI, nsIDOME
return NS_OK;
}
ServiceWorkerContainer* container = static_cast<ServiceWorkerContainer*>(aListener);
domainInfo->mServiceWorkerContainers.RemoveElement(container);
ServiceWorkerRegistration* registration = static_cast<ServiceWorkerRegistration*>(aListener);
domainInfo->mServiceWorkerRegistrations.RemoveElement(registration);
return NS_OK;
}
void
ServiceWorkerManager::FireEventOnServiceWorkerContainers(
ServiceWorkerRegistration* aRegistration,
ServiceWorkerManager::FireEventOnServiceWorkerRegistrations(
ServiceWorkerRegistrationInfo* aRegistration,
const nsAString& aName)
{
AssertIsOnMainThread();
@ -1456,9 +1469,9 @@ ServiceWorkerManager::FireEventOnServiceWorkerContainers(
GetDomainInfo(aRegistration->mScriptSpec);
if (domainInfo) {
nsTObserverArray<ServiceWorkerContainer*>::ForwardIterator it(domainInfo->mServiceWorkerContainers);
nsTObserverArray<ServiceWorkerRegistration*>::ForwardIterator it(domainInfo->mServiceWorkerRegistrations);
while (it.HasMore()) {
nsRefPtr<ServiceWorkerContainer> target = it.GetNext();
nsRefPtr<ServiceWorkerRegistration> target = it.GetNext();
nsIURI* targetURI = target->GetDocumentURI();
if (!targetURI) {
NS_WARNING("Controlled domain cannot have page with null URI!");
@ -1494,8 +1507,8 @@ ServiceWorkerManager::GetServiceWorkerForWindow(nsIDOMWindow* aWindow,
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
MOZ_ASSERT(window);
nsRefPtr<ServiceWorkerRegistration> registration =
GetServiceWorkerRegistration(window);
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
GetServiceWorkerRegistrationInfo(window);
if (!registration) {
return NS_ERROR_FAILURE;
@ -1549,7 +1562,7 @@ ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports**
return NS_ERROR_FAILURE;
}
nsRefPtr<ServiceWorkerRegistration> registration;
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
if (!domainInfo->mControlledDocuments.Get(doc, getter_AddRefs(registration))) {
return NS_ERROR_FAILURE;
}
@ -1615,7 +1628,7 @@ ServiceWorkerManager::CreateServiceWorker(const nsACString& aScriptSpec,
// FIXME(nsm): Create correct principal based on app-ness.
// Would it make sense to store the nsIPrincipal of the first register() in
// the ServiceWorkerRegistration and use that?
// the ServiceWorkerRegistrationInfo and use that?
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
rv = ssm->GetNoAppCodebasePrincipal(info.mBaseURI, getter_AddRefs(info.mPrincipal));
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -1642,17 +1655,17 @@ ServiceWorkerManager::CreateServiceWorker(const nsACString& aScriptSpec,
}
void
ServiceWorkerManager::InvalidateServiceWorkerContainerWorker(ServiceWorkerRegistration* aRegistration,
WhichServiceWorker aWhichOnes)
ServiceWorkerManager::InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
WhichServiceWorker aWhichOnes)
{
AssertIsOnMainThread();
nsRefPtr<ServiceWorkerDomainInfo> domainInfo =
GetDomainInfo(aRegistration->mScriptSpec);
if (domainInfo) {
nsTObserverArray<ServiceWorkerContainer*>::ForwardIterator it(domainInfo->mServiceWorkerContainers);
nsTObserverArray<ServiceWorkerRegistration*>::ForwardIterator it(domainInfo->mServiceWorkerRegistrations);
while (it.HasMore()) {
nsRefPtr<ServiceWorkerContainer> target = it.GetNext();
nsRefPtr<ServiceWorkerRegistration> target = it.GetNext();
nsIURI* targetURI = target->GetDocumentURI();
nsCString path;

View File

@ -16,6 +16,7 @@
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ServiceWorkerCommon.h"
#include "nsRefPtrHashtable.h"
#include "nsTArrayForwardDeclare.h"
#include "nsTObserverArray.h"
@ -24,10 +25,12 @@ class nsIScriptError;
namespace mozilla {
namespace dom {
class ServiceWorkerRegistration;
namespace workers {
class ServiceWorker;
class ServiceWorkerContainer;
class ServiceWorkerUpdateInstance;
/**
@ -95,22 +98,13 @@ public:
{ }
};
// Use multiples of 2 since they can be bitwise ORed when calling
// InvalidateServiceWorkerContainerWorker.
MOZ_BEGIN_ENUM_CLASS(WhichServiceWorker)
INSTALLING_WORKER = 1,
WAITING_WORKER = 2,
ACTIVE_WORKER = 4,
MOZ_END_ENUM_CLASS(WhichServiceWorker)
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(WhichServiceWorker)
// Needs to inherit from nsISupports because NS_ProxyRelease() does not support
// non-ISupports classes.
class ServiceWorkerRegistration MOZ_FINAL : public nsISupports
class ServiceWorkerRegistrationInfo MOZ_FINAL : public nsISupports
{
uint32_t mControlledDocumentsCounter;
virtual ~ServiceWorkerRegistration();
virtual ~ServiceWorkerRegistrationInfo();
public:
NS_DECL_ISUPPORTS
@ -145,7 +139,7 @@ public:
// pendingUninstall and when all controlling documents go away, removed.
bool mPendingUninstall;
explicit ServiceWorkerRegistration(const nsACString& aScope);
explicit ServiceWorkerRegistrationInfo(const nsACString& aScope);
already_AddRefed<ServiceWorkerInfo>
Newest()
@ -236,35 +230,35 @@ public:
nsTArray<nsCString> mOrderedScopes;
// Scope to registration.
nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerRegistration> mServiceWorkerRegistrations;
nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerRegistrationInfo> mServiceWorkerRegistrationInfos;
// This array can't be stored in ServiceWorkerRegistration because one may
// not exist when a certain window is opened, but we still want that
// window's container to be notified if it's in scope.
// The containers inform the SWM on creation and destruction.
nsTObserverArray<ServiceWorkerContainer*> mServiceWorkerContainers;
nsTObserverArray<ServiceWorkerRegistration*> mServiceWorkerRegistrations;
nsRefPtrHashtable<nsISupportsHashKey, ServiceWorkerRegistration> mControlledDocuments;
nsRefPtrHashtable<nsISupportsHashKey, ServiceWorkerRegistrationInfo> mControlledDocuments;
ServiceWorkerDomainInfo()
{ }
already_AddRefed<ServiceWorkerRegistration>
already_AddRefed<ServiceWorkerRegistrationInfo>
GetRegistration(const nsCString& aScope) const
{
nsRefPtr<ServiceWorkerRegistration> reg;
mServiceWorkerRegistrations.Get(aScope, getter_AddRefs(reg));
nsRefPtr<ServiceWorkerRegistrationInfo> reg;
mServiceWorkerRegistrationInfos.Get(aScope, getter_AddRefs(reg));
return reg.forget();
}
ServiceWorkerRegistration*
ServiceWorkerRegistrationInfo*
CreateNewRegistration(const nsCString& aScope)
{
ServiceWorkerRegistration* registration =
new ServiceWorkerRegistration(aScope);
ServiceWorkerRegistrationInfo* registration =
new ServiceWorkerRegistrationInfo(aScope);
// From now on ownership of registration is with
// mServiceWorkerRegistrations.
mServiceWorkerRegistrations.Put(aScope, registration);
// mServiceWorkerRegistrationInfos.
mServiceWorkerRegistrationInfos.Put(aScope, registration);
ServiceWorkerManager::AddScope(mOrderedScopes, aScope);
return registration;
}
@ -279,26 +273,26 @@ public:
nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerDomainInfo> mDomainMap;
void
ResolveRegisterPromises(ServiceWorkerRegistration* aRegistration,
ResolveRegisterPromises(ServiceWorkerRegistrationInfo* aRegistration,
const nsACString& aWorkerScriptSpec);
void
RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration,
RejectUpdatePromiseObservers(ServiceWorkerRegistrationInfo* aRegistration,
nsresult aResult);
void
RejectUpdatePromiseObservers(ServiceWorkerRegistration* aRegistration,
RejectUpdatePromiseObservers(ServiceWorkerRegistrationInfo* aRegistration,
const ErrorEventInit& aErrorDesc);
void
FinishFetch(ServiceWorkerRegistration* aRegistration,
FinishFetch(ServiceWorkerRegistrationInfo* aRegistration,
nsPIDOMWindow* aWindow);
void
FinishInstall(ServiceWorkerRegistration* aRegistration);
FinishInstall(ServiceWorkerRegistrationInfo* aRegistration);
void
FinishActivate(ServiceWorkerRegistration* aRegistration);
FinishActivate(ServiceWorkerRegistrationInfo* aRegistration);
void
HandleError(JSContext* aCx,
@ -319,10 +313,10 @@ private:
~ServiceWorkerManager();
NS_IMETHOD
Update(ServiceWorkerRegistration* aRegistration, nsPIDOMWindow* aWindow);
Update(ServiceWorkerRegistrationInfo* aRegistration, nsPIDOMWindow* aWindow);
void
Install(ServiceWorkerRegistration* aRegistration,
Install(ServiceWorkerRegistrationInfo* aRegistration,
ServiceWorkerInfo* aServiceWorkerInfo);
NS_IMETHOD
@ -356,17 +350,17 @@ private:
nsISupports** aServiceWorker);
void
InvalidateServiceWorkerContainerWorker(ServiceWorkerRegistration* aRegistration,
WhichServiceWorker aWhichOnes);
InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
WhichServiceWorker aWhichOnes);
already_AddRefed<ServiceWorkerRegistration>
GetServiceWorkerRegistration(nsPIDOMWindow* aWindow);
already_AddRefed<ServiceWorkerRegistrationInfo>
GetServiceWorkerRegistrationInfo(nsPIDOMWindow* aWindow);
already_AddRefed<ServiceWorkerRegistration>
GetServiceWorkerRegistration(nsIDocument* aDoc);
already_AddRefed<ServiceWorkerRegistrationInfo>
GetServiceWorkerRegistrationInfo(nsIDocument* aDoc);
already_AddRefed<ServiceWorkerRegistration>
GetServiceWorkerRegistration(nsIURI* aURI);
already_AddRefed<ServiceWorkerRegistrationInfo>
GetServiceWorkerRegistrationInfo(nsIURI* aURI);
static void
AddScope(nsTArray<nsCString>& aList, const nsACString& aScope);
@ -378,8 +372,8 @@ private:
RemoveScope(nsTArray<nsCString>& aList, const nsACString& aScope);
void
FireEventOnServiceWorkerContainers(ServiceWorkerRegistration* aRegistration,
const nsAString& aName);
FireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
const nsAString& aName);
};

View File

@ -0,0 +1,197 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ServiceWorkerRegistration.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "nsServiceManagerUtils.h"
#include "ServiceWorker.h"
#include "nsIServiceWorkerManager.h"
#include "nsPIDOMWindow.h"
using namespace mozilla::dom::workers;
namespace mozilla {
namespace dom {
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistration)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(ServiceWorkerRegistration, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorkerRegistration,
DOMEventTargetHelper,
mWindow,
mInstallingWorker,
mWaitingWorker,
mActiveWorker)
ServiceWorkerRegistration::ServiceWorkerRegistration(nsPIDOMWindow* aWindow,
const nsAString& aScope)
: mWindow(aWindow)
, mScope(aScope)
{
MOZ_ASSERT(aWindow);
SetIsDOMBinding();
StartListeningForEvents();
}
ServiceWorkerRegistration::~ServiceWorkerRegistration()
{
StopListeningForEvents();
}
JSObject*
ServiceWorkerRegistration::WrapObject(JSContext* aCx)
{
return ServiceWorkerRegistrationBinding::Wrap(aCx, this);
}
already_AddRefed<workers::ServiceWorker>
ServiceWorkerRegistration::GetInstalling()
{
if (!mInstallingWorker) {
mInstallingWorker = GetWorkerReference(WhichServiceWorker::INSTALLING_WORKER);
}
nsRefPtr<ServiceWorker> ret = mInstallingWorker;
return ret.forget();
}
already_AddRefed<workers::ServiceWorker>
ServiceWorkerRegistration::GetWaiting()
{
if (!mWaitingWorker) {
mWaitingWorker = GetWorkerReference(WhichServiceWorker::WAITING_WORKER);
}
nsRefPtr<ServiceWorker> ret = mWaitingWorker;
return ret.forget();
}
already_AddRefed<workers::ServiceWorker>
ServiceWorkerRegistration::GetActive()
{
if (!mActiveWorker) {
mActiveWorker = GetWorkerReference(WhichServiceWorker::ACTIVE_WORKER);
}
nsRefPtr<ServiceWorker> ret = mActiveWorker;
return ret.forget();
}
already_AddRefed<Promise>
ServiceWorkerRegistration::Unregister(ErrorResult& aRv)
{
nsCOMPtr<nsISupports> promise;
nsresult rv;
nsCOMPtr<nsIServiceWorkerManager> swm =
do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return nullptr;
}
aRv = swm->Unregister(mWindow, mScope, getter_AddRefs(promise));
if (aRv.Failed()) {
return nullptr;
}
nsRefPtr<Promise> ret = static_cast<Promise*>(promise.get());
MOZ_ASSERT(ret);
return ret.forget();
}
already_AddRefed<workers::ServiceWorker>
ServiceWorkerRegistration::GetWorkerReference(WhichServiceWorker aWhichOne)
{
nsresult rv;
nsCOMPtr<nsIServiceWorkerManager> swm =
do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsCOMPtr<nsISupports> serviceWorker;
switch(aWhichOne) {
case WhichServiceWorker::INSTALLING_WORKER:
rv = swm->GetInstalling(mWindow, getter_AddRefs(serviceWorker));
break;
case WhichServiceWorker::WAITING_WORKER:
rv = swm->GetWaiting(mWindow, getter_AddRefs(serviceWorker));
break;
case WhichServiceWorker::ACTIVE_WORKER:
rv = swm->GetActive(mWindow, getter_AddRefs(serviceWorker));
break;
default:
MOZ_CRASH("Invalid enum value");
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
nsRefPtr<ServiceWorker> ref =
static_cast<ServiceWorker*>(serviceWorker.get());
return ref.forget();
}
void
ServiceWorkerRegistration::InvalidateWorkerReference(WhichServiceWorker aWhichOnes)
{
if (aWhichOnes & WhichServiceWorker::INSTALLING_WORKER) {
mInstallingWorker = nullptr;
}
if (aWhichOnes & WhichServiceWorker::WAITING_WORKER) {
mWaitingWorker = nullptr;
}
if (aWhichOnes & WhichServiceWorker::ACTIVE_WORKER) {
mActiveWorker = nullptr;
}
}
// XXXnsm, maybe this can be optimized to only add when a event handler is
// registered.
void
ServiceWorkerRegistration::StartListeningForEvents()
{
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
MOZ_ASSERT(mWindow);
if (swm) {
swm->AddRegistrationEventListener(GetDocumentURI(), this);
}
}
void
ServiceWorkerRegistration::StopListeningForEvents()
{
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID);
// StopListeningForEvents is called in the dtor, and it can happen that
// SnowWhite had already set to null mWindow.
if (swm && mWindow) {
swm->RemoveRegistrationEventListener(GetDocumentURI(), this);
}
}
nsIURI*
ServiceWorkerRegistration::GetDocumentURI() const
{
MOZ_ASSERT(mWindow);
return mWindow->GetDocumentURI();
}
} // dom namespace
} // mozilla namespace

View File

@ -0,0 +1,99 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_ServiceWorkerRegistration_h
#define mozilla_dom_ServiceWorkerRegistration_h
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/dom/ServiceWorkerCommon.h"
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class Promise;
namespace workers {
class ServiceWorker;
}
class ServiceWorkerRegistration MOZ_FINAL : public DOMEventTargetHelper
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerRegistration,
DOMEventTargetHelper)
IMPL_EVENT_HANDLER(updatefound)
ServiceWorkerRegistration(nsPIDOMWindow* aWindow,
const nsAString& aScope);
nsPIDOMWindow*
GetParentObject() const
{
return mWindow;
}
JSObject*
WrapObject(JSContext* aCx);
already_AddRefed<workers::ServiceWorker>
GetInstalling();
already_AddRefed<workers::ServiceWorker>
GetWaiting();
already_AddRefed<workers::ServiceWorker>
GetActive();
void
GetScope(nsAString& aScope) const
{
aScope = mScope;
}
already_AddRefed<Promise>
Unregister(ErrorResult& aRv);
// Useful methods for ServiceWorkerManager:
nsIURI*
GetDocumentURI() const;
void
InvalidateWorkerReference(WhichServiceWorker aWhichOnes);
private:
~ServiceWorkerRegistration();
already_AddRefed<workers::ServiceWorker>
GetWorkerReference(WhichServiceWorker aWhichOne);
void
StartListeningForEvents();
void
StopListeningForEvents();
nsCOMPtr<nsPIDOMWindow> mWindow;
// The following properties are cached here to ensure JS equality is satisfied
// instead of acquiring a new worker instance from the ServiceWorkerManager
// for every access. A null value is considered a cache miss.
// These three may change to a new worker at any time.
nsRefPtr<workers::ServiceWorker> mInstallingWorker;
nsRefPtr<workers::ServiceWorker> mWaitingWorker;
nsRefPtr<workers::ServiceWorker> mActiveWorker;
const nsString mScope;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_ServiceWorkerRegistration_h */

View File

@ -6,7 +6,9 @@
# Public stuff.
EXPORTS.mozilla.dom += [
'ServiceWorkerCommon.h',
'ServiceWorkerContainer.h',
'ServiceWorkerRegistration.h',
'WorkerPrivate.h',
'WorkerRunnable.h',
'WorkerScope.h',
@ -50,6 +52,7 @@ SOURCES += [
'ServiceWorkerContainer.cpp',
'ServiceWorkerEvents.cpp',
'ServiceWorkerManager.cpp',
'ServiceWorkerRegistration.cpp',
'SharedWorker.cpp',
'URL.cpp',
'WorkerPrivate.cpp',

View File

@ -32,9 +32,21 @@
// We are controlled.
// Register a new worker for this sub-scope. After that, controller should still be for upper level, but active should change to be this scope's.
navigator.serviceWorker.register("../worker2.js", { scope: "./*" }).then(function(e) {
my_ok(navigator.serviceWorker.installing &&
navigator.serviceWorker.installing.scope.match(/controller\/\*$/),
my_ok("installing" in e, "ServiceWorkerRegistration.installing exists.");
my_ok(e.installing instanceof ServiceWorker, "ServiceWorkerRegistration.installing is a ServiceWorker.");
my_ok("waiting" in e, "ServiceWorkerRegistration.waiting exists.");
my_ok("active" in e, "ServiceWorkerRegistration.active exists.");
my_ok(e.installing &&
e.installing.scope.match(/controller\/\*$/),
"Installing is serviceworker/controller/*");
my_ok("scope" in e, "ServiceWorkerRegistration.scope exists.");
my_ok(e.scope.match(/serviceworkers\/controller\/\*$/), "Scope is serviceworker/*: " + e.scope);
my_ok("unregister" in e, "ServiceWorkerRegistration.unregister exists.");
my_ok(navigator.serviceWorker.controller.scope.match(/serviceworkers\/control\*$/),
"Controller is still serviceworker/*");
finish();

View File

@ -20,11 +20,11 @@
return p;
}
function nextRegister() {
function nextRegister(reg) {
var p = navigator.serviceWorker.register("install_event_worker.js", { scope: "./*" });
return new Promise(function(resolve, reject) {
navigator.serviceWorker.onupdatefound = function(e) {
reg.onupdatefound = function(e) {
ok(true, "Received onupdatefound");
resolve();
};

View File

@ -57,11 +57,12 @@
function realWorker() {
var p = navigator.serviceWorker.register("worker.js", { scope: "realworker*" });
return p.then(function(w) {
ok(w instanceof ServiceWorker, "Register a ServiceWorker");
info(w.scope);
ok(w.scope == (new URL("realworker*", document.baseURI)).href, "Scope should match");
ok(w.url == (new URL("worker.js", document.baseURI)).href, "URL should be of the worker");
return p.then(function(wr) {
ok(wr instanceof ServiceWorkerRegistration, "Register a ServiceWorker");
info(wr.scope);
ok(wr.scope == (new URL("realworker*", document.baseURI)).href, "Scope should match");
}, function(e) {
info("Error: " + e.name);
ok(false, "realWorker Registration should have succeeded!");
@ -73,14 +74,14 @@
var q = navigator.serviceWorker.register("worker3.js", { scope: "foo/*" });
return Promise.all([
p.then(function(w) {
p.then(function(wr) {
ok(false, "First registration should fail with AbortError");
}, function(e) {
ok(e.name === "AbortError", "First registration should fail with AbortError");
}),
q.then(function(w) {
ok(w instanceof ServiceWorker, "Second registration should succeed");
q.then(function(wr) {
ok(wr instanceof ServiceWorkerRegistration, "Second registration should succeed");
}, function(e) {
ok(false, "Second registration should succeed");
})
@ -97,7 +98,7 @@
function parseError() {
var p = navigator.serviceWorker.register("parse_error_worker.js");
return p.then(function(w) {
return p.then(function(wr) {
ok(false, "Registration should fail with parse error");
}, function(e) {
info("NSM " + e.name);
@ -107,6 +108,7 @@
// FIXME(nsm): test for parse error when Update step doesn't happen (directly from register).
/* FIXME bug 1002571 - re-enable this test when GetRegistration is implemented.
function updatefound() {
var frame = document.createElement("iframe");
frame.setAttribute("id", "simpleregister-frame");
@ -137,6 +139,7 @@
}
return p;
}
*/
function runTest() {
simpleRegister()
@ -147,7 +150,6 @@
.then(abortPrevious)
.then(networkError404)
.then(parseError)
.then(updatefound)
// put more tests here.
.then(function() {
SimpleTest.finish();

View File

@ -18,12 +18,9 @@
function checkEnabled() {
ok(navigator.serviceWorker, "navigator.serviceWorker should exist when ServiceWorkers are enabled.");
ok(typeof navigator.serviceWorker.register === "function", "navigator.serviceWorker.register() should be a function.");
ok(typeof navigator.serviceWorker.unregister === "function", "navigator.serviceWorker.unregister() should be a function.");
ok(typeof navigator.serviceWorker.getAll === "function", "navigator.serviceWorker.getAll() should be a function.");
ok(typeof navigator.serviceWorker.getRegistration === "function", "navigator.serviceWorker.getAll() should be a function.");
ok(typeof navigator.serviceWorker.getRegistrations === "function", "navigator.serviceWorker.getAll() should be a function.");
ok(navigator.serviceWorker.ready instanceof Promise, "navigator.serviceWorker.ready should be a Promise.");
ok(navigator.serviceWorker.installing === null, "There should be no installing worker for an uncontrolled scope.");
ok(navigator.serviceWorker.waiting === null, "There should be no waiting worker for an uncontrolled scope.");
// ok(navigator.serviceWorker.active === null, "There should be no active worker for an uncontrolled scope.");
ok(navigator.serviceWorker.controller === null, "There should be no controller worker for an uncontrolled document.");
}

View File

@ -302,8 +302,7 @@ XMLDocument::Load(const nsAString& aUrl, ErrorResult& aRv)
WarnOnceAbout(nsIDocument::eUseOfDOM3LoadMethod);
nsCOMPtr<nsIDocument> callingDoc = nsContentUtils::GetDocumentFromContext();
nsCOMPtr<nsIDocument> callingDoc = GetEntryDocument();
nsIURI *baseURI = mDocumentURI;
nsAutoCString charset;

View File

@ -65,6 +65,7 @@
#endif
using namespace mozilla;
using namespace mozilla::dom;
/****************************************************************
******************** nsWatcherWindowEntry **********************
@ -886,7 +887,7 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow *aParent,
}
nsCOMPtr<nsPIDOMWindow> referrerWindow =
do_QueryInterface(dom::BrokenGetEntryGlobal());
do_QueryInterface(GetEntryGlobal());
if (!referrerWindow) {
referrerWindow = do_QueryInterface(aParent);
}
@ -1345,18 +1346,8 @@ nsWindowWatcher::URIfromURL(const char *aURL,
nsIDOMWindow *aParent,
nsIURI **aURI)
{
nsCOMPtr<nsIDOMWindow> baseWindow;
/* build the URI relative to the calling JS Context, if any.
(note this is the same context used to make the security check
in nsGlobalWindow.cpp.) */
JSContext *cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
if (scriptcx) {
baseWindow = do_QueryInterface(scriptcx->GetGlobalObject());
}
}
// Build the URI relative to the entry global.
nsCOMPtr<nsIDOMWindow> baseWindow = do_QueryInterface(GetEntryGlobal());
// failing that, build it relative to the parent window, if possible
if (!baseWindow)
@ -1726,16 +1717,8 @@ nsWindowWatcher::FindItemWithName(const char16_t* aName,
already_AddRefed<nsIDocShellTreeItem>
nsWindowWatcher::GetCallerTreeItem(nsIDocShellTreeItem* aParentItem)
{
JSContext *cx = nsContentUtils::GetCurrentJSContext();
nsCOMPtr<nsIDocShellTreeItem> callerItem;
if (cx) {
nsCOMPtr<nsIWebNavigation> callerWebNav =
do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
callerItem = do_QueryInterface(callerWebNav);
}
nsCOMPtr<nsIWebNavigation> callerWebNav = do_GetInterface(GetEntryGlobal());
nsCOMPtr<nsIDocShellTreeItem> callerItem = do_QueryInterface(callerWebNav);
if (!callerItem) {
callerItem = aParentItem;
}

110
gfx/2d/BaseCoord.h Normal file
View File

@ -0,0 +1,110 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_GFX_BASECOORD_H_
#define MOZILLA_GFX_BASECOORD_H_
#include "mozilla/Attributes.h"
namespace mozilla {
namespace gfx {
/**
* Do not use this class directly. Subclass it, pass that subclass as the
* Sub parameter, and only use that subclass. This allows methods to safely
* cast 'this' to 'Sub*'.
*/
template <class T, class Sub>
struct BaseCoord {
T value;
// Constructors
MOZ_CONSTEXPR BaseCoord() : value(0) {}
explicit MOZ_CONSTEXPR BaseCoord(T aValue) : value(aValue) {}
// Note that '=' isn't defined so we'll get the
// compiler generated default assignment operator
operator T() const { return value; }
friend bool operator==(Sub aA, Sub aB) {
return aA.value == aB.value;
}
friend bool operator!=(Sub aA, Sub aB) {
return aA.value != aB.value;
}
friend Sub operator+(Sub aA, Sub aB) {
return Sub(aA.value + aB.value);
}
friend Sub operator-(Sub aA, Sub aB) {
return Sub(aA.value - aB.value);
}
friend Sub operator*(Sub aCoord, T aScale) {
return Sub(aCoord.value * aScale);
}
friend Sub operator*(T aScale, Sub aCoord) {
return Sub(aScale * aCoord.value);
}
friend Sub operator/(Sub aCoord, T aScale) {
return Sub(aCoord.value / aScale);
}
// 'scale / coord' is intentionally omitted because it doesn't make sense.
Sub& operator+=(Sub aCoord) {
value += aCoord.value;
return *static_cast<Sub*>(this);
}
Sub& operator-=(Sub aCoord) {
value -= aCoord.value;
return *static_cast<Sub*>(this);
}
Sub& operator*=(T aScale) {
value *= aScale;
return *static_cast<Sub*>(this);
}
Sub& operator/=(T aScale) {
value /= aScale;
return *static_cast<Sub*>(this);
}
// Since BaseCoord is implicitly convertible to its value type T, we need
// mixed-type operator overloads to avoid ambiguities at mixed-type call
// sites. As we transition more of our code to strongly-typed classes, we
// may be able to remove some or all of these overloads.
friend bool operator==(Sub aA, T aB) {
return aA.value == aB;
}
friend bool operator==(T aA, Sub aB) {
return aA == aB.value;
}
friend bool operator!=(Sub aA, T aB) {
return aA.value != aB;
}
friend bool operator!=(T aA, Sub aB) {
return aA != aB.value;
}
friend T operator+(Sub aA, T aB) {
return aA.value + aB;
}
friend T operator+(T aA, Sub aB) {
return aA + aB.value;
}
friend T operator-(Sub aA, T aB) {
return aA.value - aB;
}
friend T operator-(T aA, Sub aB) {
return aA - aB.value;
}
Sub operator-() const {
return Sub(-value);
}
};
}
}
#endif /* MOZILLA_GFX_BASECOORD_H_ */

View File

@ -17,13 +17,13 @@ namespace gfx {
* Sub parameter, and only use that subclass. This allows methods to safely
* cast 'this' to 'Sub*'.
*/
template <class T, class Sub>
template <class T, class Sub, class Coord = T>
struct BasePoint {
T x, y;
Coord x, y;
// Constructors
MOZ_CONSTEXPR BasePoint() : x(0), y(0) {}
MOZ_CONSTEXPR BasePoint(T aX, T aY) : x(aX), y(aY) {}
MOZ_CONSTEXPR BasePoint(Coord aX, Coord aY) : x(aX), y(aY) {}
void MoveTo(T aX, T aY) { x = aX; y = aY; }
void MoveBy(T aDx, T aDy) { x += aDx; y += aDy; }
@ -67,15 +67,15 @@ struct BasePoint {
}
T Length() const {
return hypot(x, y);
return hypot(x.value, y.value);
}
// Round() is *not* rounding to nearest integer if the values are negative.
// They are always rounding as floor(n + 0.5).
// See https://bugzilla.mozilla.org/show_bug.cgi?id=410748#c14
Sub& Round() {
x = static_cast<T>(floor(x + 0.5));
y = static_cast<T>(floor(y + 0.5));
x = Coord(floor(T(x) + T(0.5)));
y = Coord(floor(T(y) + T(0.5)));
return *static_cast<Sub*>(this);
}

View File

@ -734,8 +734,8 @@ static const Float GAUSSIAN_SCALE_FACTOR = Float((3 * sqrt(2 * M_PI) / 4) * 1.5)
IntSize
AlphaBoxBlur::CalculateBlurRadius(const Point& aStd)
{
IntSize size(static_cast<int32_t>(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5)),
static_cast<int32_t>(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5)));
IntSize size(static_cast<int32_t>(floor(aStd.x * GAUSSIAN_SCALE_FACTOR + 0.5f)),
static_cast<int32_t>(floor(aStd.y * GAUSSIAN_SCALE_FACTOR + 0.5f)));
return size;
}

142
gfx/2d/Coord.h Normal file
View File

@ -0,0 +1,142 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_GFX_COORD_H_
#define MOZILLA_GFX_COORD_H_
#include "mozilla/Attributes.h"
#include "Types.h"
#include "BaseCoord.h"
#include <cmath>
namespace mozilla {
template <typename> struct IsPixel;
namespace gfx {
template <class units> struct IntCoordTyped;
template <class units> struct CoordTyped;
// CommonType<coord, primitive> is a metafunction that returns the type of the
// result of an arithmetic operation on the underlying type of a strongly-typed
// coordinate type 'coord', and a primitive type 'primitive'. C++ rules for
// arithmetic conversions are designed to avoid losing information - for
// example, the result of adding an int and a float is a float - and we want
// the same behaviour when mixing our coordinate types with primitive types.
// We get C++ to compute the desired result type using 'decltype'.
template <class coord, class primitive>
struct CommonType;
template <class units, class primitive>
struct CommonType<IntCoordTyped<units>, primitive> {
typedef decltype(int32_t() + primitive()) type;
};
template <class units, class primitive>
struct CommonType<CoordTyped<units>, primitive> {
typedef decltype(Float() + primitive()) type;
};
// This is a base class that provides mixed-type operator overloads between
// a strongly-typed Coord and a primitive value. It is needed to avoid
// ambiguities at mixed-type call sites, because Coord classes are implicitly
// convertible to their underlying value type. As we transition more of our code
// to strongly-typed classes, we may be able to remove some or all of these
// overloads.
template <class coord, class primitive>
struct CoordOperatorsHelper {
friend bool operator==(coord aA, primitive aB) {
return aA.value == aB;
}
friend bool operator==(primitive aA, coord aB) {
return aA == aB.value;
}
friend bool operator!=(coord aA, primitive aB) {
return aA.value != aB;
}
friend bool operator!=(primitive aA, coord aB) {
return aA != aB.value;
}
typedef typename CommonType<coord, primitive>::type result_type;
friend result_type operator+(coord aA, primitive aB) {
return aA.value + aB;
}
friend result_type operator+(primitive aA, coord aB) {
return aA + aB.value;
}
friend result_type operator-(coord aA, primitive aB) {
return aA.value - aB;
}
friend result_type operator-(primitive aA, coord aB) {
return aA - aB.value;
}
friend result_type operator*(coord aCoord, primitive aScale) {
return aCoord.value * aScale;
}
friend result_type operator*(primitive aScale, coord aCoord) {
return aScale * aCoord.value;
}
friend result_type operator/(coord aCoord, primitive aScale) {
return aCoord.value / aScale;
}
// 'scale / coord' is intentionally omitted because it doesn't make sense.
};
// Note: 'IntCoordTyped<units>' and 'CoordTyped<units>' do not derive from
// 'units' to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61959.
template<class units>
struct IntCoordTyped :
public BaseCoord< int32_t, IntCoordTyped<units> >,
public CoordOperatorsHelper< IntCoordTyped<units>, float >,
public CoordOperatorsHelper< IntCoordTyped<units>, double > {
static_assert(IsPixel<units>::value,
"'units' must be a coordinate system tag");
typedef BaseCoord< int32_t, IntCoordTyped<units> > Super;
MOZ_CONSTEXPR IntCoordTyped() : Super() {}
MOZ_CONSTEXPR IntCoordTyped(int32_t aValue) : Super(aValue) {}
};
template<class units>
struct CoordTyped :
public BaseCoord< Float, CoordTyped<units> >,
public CoordOperatorsHelper< CoordTyped<units>, int32_t >,
public CoordOperatorsHelper< CoordTyped<units>, uint32_t >,
public CoordOperatorsHelper< CoordTyped<units>, double > {
static_assert(IsPixel<units>::value,
"'units' must be a coordinate system tag");
typedef BaseCoord< Float, CoordTyped<units> > Super;
MOZ_CONSTEXPR CoordTyped() : Super() {}
MOZ_CONSTEXPR CoordTyped(Float aValue) : Super(aValue) {}
explicit MOZ_CONSTEXPR CoordTyped(const IntCoordTyped<units>& aCoord) : Super(float(aCoord.value)) {}
void Round() {
this->value = floor(this->value + 0.5);
}
void Truncate() {
this->value = int32_t(this->value);
}
IntCoordTyped<units> Rounded() const {
return IntCoordTyped<units>(int32_t(floor(this->value + 0.5)));
}
IntCoordTyped<units> Truncated() const {
return IntCoordTyped<units>(int32_t(this->value));
}
};
}
}
#endif /* MOZILLA_GFX_COORD_H_ */

View File

@ -2599,7 +2599,7 @@ DrawTargetD2D::SetupEffectForRadialGradient(const RadialGradientPattern *aPatter
mPrivateData->mEffect->GetVariableByName("DeviceSpaceToUserSpace")->
AsMatrix()->SetMatrix(matrix);
float A = dc.x * dc.x + dc.y * dc.y - dr * dr;
float A = dc.x.value * dc.x.value + dc.y.value * dc.y.value - dr * dr;
uint32_t offset = 0;
switch (stops->mStopCollection->GetExtendMode()) {

View File

@ -35,8 +35,8 @@ DrawTargetTiled::Init(const TileSet& aTiles)
mTiles[i].mTileOrigin.x + mTiles[i].mDrawTarget->GetSize().width);
uint32_t newYMost = max(mRect.YMost(),
mTiles[i].mTileOrigin.y + mTiles[i].mDrawTarget->GetSize().height);
mRect.x = min(mRect.x, mTiles[i].mTileOrigin.x);
mRect.y = min(mRect.y, mTiles[i].mTileOrigin.y);
mRect.x = min(mRect.x, mTiles[i].mTileOrigin.x.value);
mRect.y = min(mRect.y, mTiles[i].mTileOrigin.y.value);
mRect.width = newXMost - mRect.x;
mRect.height = newYMost - mRect.y;
}

View File

@ -239,7 +239,7 @@ static inline bool IsPatternSupportedByD2D(const Pattern &aPattern)
Point diff = pat->mCenter2 - pat->mCenter1;
if (sqrt(diff.x * diff.x + diff.y * diff.y) >= pat->mRadius2) {
if (sqrt(diff.x.value * diff.x.value + diff.y.value * diff.y.value) >= pat->mRadius2) {
// Inner point lies outside the circle.
return false;
}

View File

@ -107,7 +107,7 @@ FlattenedPath::QuadraticBezierTo(const Point &aCP1,
const Point &aCP2)
{
MOZ_ASSERT(!mCalculatedLength);
// We need to elevate the degree of this quadratic Bézier to cubic, so we're
// We need to elevate the degree of this quadratic B<EFBFBD>zier to cubic, so we're
// going to add an intermediate control point, and recompute control point 1.
// The first and last control points remain the same.
// This formula can be found on http://fontforge.sourceforge.net/bezier.html
@ -250,7 +250,7 @@ FlattenBezierCurveSegment(const BezierControlPoints &aControlPoints,
Point cp21 = currentCP.mCP2 - currentCP.mCP3;
Point cp31 = currentCP.mCP3 - currentCP.mCP1;
Float s3 = (cp31.x * cp21.y - cp31.y * cp21.x) / hypotf(cp21.x, cp21.y);
Float s3 = (cp31.x.value * cp21.y.value - cp31.y.value * cp21.x.value) / hypotf(cp21.x, cp21.y);
t = 2 * Float(sqrt(aTolerance / (3. * abs(s3))));
@ -276,7 +276,7 @@ FindInflectionApproximationRange(BezierControlPoints aControlPoints,
Point cp21 = aControlPoints.mCP2 - aControlPoints.mCP1;
Point cp41 = aControlPoints.mCP4 - aControlPoints.mCP1;
if (cp21.x == 0 && cp21.y == 0) {
if (cp21.x == 0.f && cp21.y == 0.f) {
// In this case s3 becomes lim[n->0] (cp41.x * n) / n - (cp41.y * n) / n = cp41.x - cp41.y.
// Use the absolute value so that Min and Max will correspond with the
@ -286,7 +286,7 @@ FindInflectionApproximationRange(BezierControlPoints aControlPoints,
return;
}
Float s3 = (cp41.x * cp21.y - cp41.y * cp21.x) / hypotf(cp21.x, cp21.y);
Float s3 = (cp41.x.value * cp21.y.value - cp41.y.value * cp21.x.value) / hypotf(cp21.x, cp21.y);
if (s3 == 0) {
// This means within the precision we have it can be approximated

View File

@ -16,8 +16,8 @@ template <typename T>
void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius,
float aStartAngle, float aEndAngle, bool aAntiClockwise)
{
Point startPoint(aOrigin.x + cos(aStartAngle) * aRadius.width,
aOrigin.y + sin(aStartAngle) * aRadius.height);
Point startPoint(aOrigin.x + cosf(aStartAngle) * aRadius.width,
aOrigin.y + sinf(aStartAngle) * aRadius.height);
aSink->LineTo(startPoint);
@ -56,10 +56,10 @@ void ArcToBezier(T* aSink, const Point &aOrigin, const Size &aRadius,
currentEndAngle = currentStartAngle + arcSweepLeft * sweepDirection;
}
Point currentStartPoint(aOrigin.x + cos(currentStartAngle) * aRadius.width,
aOrigin.y + sin(currentStartAngle) * aRadius.height);
Point currentEndPoint(aOrigin.x + cos(currentEndAngle) * aRadius.width,
aOrigin.y + sin(currentEndAngle) * aRadius.height);
Point currentStartPoint(aOrigin.x + cosf(currentStartAngle) * aRadius.width,
aOrigin.y + sinf(currentStartAngle) * aRadius.height);
Point currentEndPoint(aOrigin.x + cosf(currentEndAngle) * aRadius.width,
aOrigin.y + sinf(currentEndAngle) * aRadius.height);
// Calculate kappa constant for partial curve. The sign of angle in the
// tangent will actually ensure this is negative for a counter clockwise

View File

@ -141,10 +141,10 @@ PathSkia::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
}
SkRegion pointRect;
pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1)),
int32_t(SkFloatToScalar(transformed.y - 1)),
int32_t(SkFloatToScalar(transformed.x + 1)),
int32_t(SkFloatToScalar(transformed.y + 1)));
pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1.f)),
int32_t(SkFloatToScalar(transformed.y - 1.f)),
int32_t(SkFloatToScalar(transformed.x + 1.f)),
int32_t(SkFloatToScalar(transformed.y + 1.f)));
SkRegion pathRegion;
@ -174,10 +174,10 @@ PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
}
SkRegion pointRect;
pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1)),
int32_t(SkFloatToScalar(transformed.y - 1)),
int32_t(SkFloatToScalar(transformed.x + 1)),
int32_t(SkFloatToScalar(transformed.y + 1)));
pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1.f)),
int32_t(SkFloatToScalar(transformed.y - 1.f)),
int32_t(SkFloatToScalar(transformed.x + 1.f)),
int32_t(SkFloatToScalar(transformed.y + 1.f)));
SkRegion pathRegion;

View File

@ -8,6 +8,8 @@
#include "mozilla/Attributes.h"
#include "Types.h"
#include "Coord.h"
#include "BaseCoord.h"
#include "BasePoint.h"
#include "BasePoint3D.h"
#include "BasePoint4D.h"
@ -33,15 +35,21 @@ namespace gfx {
template<class units>
struct IntPointTyped :
public BasePoint< int32_t, IntPointTyped<units> >,
public BasePoint< int32_t, IntPointTyped<units>, IntCoordTyped<units> >,
public units {
static_assert(IsPixel<units>::value,
"'units' must be a coordinate system tag");
typedef BasePoint< int32_t, IntPointTyped<units> > Super;
typedef IntCoordTyped<units> Coord;
typedef BasePoint< int32_t, IntPointTyped<units>, IntCoordTyped<units> > Super;
MOZ_CONSTEXPR IntPointTyped() : Super() {}
MOZ_CONSTEXPR IntPointTyped(int32_t aX, int32_t aY) : Super(aX, aY) {}
MOZ_CONSTEXPR IntPointTyped(int32_t aX, int32_t aY) : Super(Coord(aX), Coord(aY)) {}
// The mixed-type constructors (int, Coord) and (Coord, int) are needed to
// avoid ambiguities because Coord is implicitly convertible to int.
MOZ_CONSTEXPR IntPointTyped(int32_t aX, Coord aY) : Super(Coord(aX), aY) {}
MOZ_CONSTEXPR IntPointTyped(Coord aX, int32_t aY) : Super(aX, Coord(aY)) {}
MOZ_CONSTEXPR IntPointTyped(Coord aX, Coord aY) : Super(aX, aY) {}
// XXX When all of the code is ported, the following functions to convert to and from
// unknown types should be removed.
@ -58,15 +66,21 @@ typedef IntPointTyped<UnknownUnits> IntPoint;
template<class units>
struct PointTyped :
public BasePoint< Float, PointTyped<units> >,
public BasePoint< Float, PointTyped<units>, CoordTyped<units> >,
public units {
static_assert(IsPixel<units>::value,
"'units' must be a coordinate system tag");
typedef BasePoint< Float, PointTyped<units> > Super;
typedef CoordTyped<units> Coord;
typedef BasePoint< Float, PointTyped<units>, CoordTyped<units> > Super;
MOZ_CONSTEXPR PointTyped() : Super() {}
MOZ_CONSTEXPR PointTyped(Float aX, Float aY) : Super(aX, aY) {}
MOZ_CONSTEXPR PointTyped(Float aX, Float aY) : Super(Coord(aX), Coord(aY)) {}
// The mixed-type constructors (Float, Coord) and (Coord, Float) are needed to
// avoid ambiguities because Coord is implicitly convertible to Float.
MOZ_CONSTEXPR PointTyped(Float aX, Coord aY) : Super(Coord(aX), aY) {}
MOZ_CONSTEXPR PointTyped(Coord aX, Float aY) : Super(aX, Coord(aY)) {}
MOZ_CONSTEXPR PointTyped(Coord aX, Coord aY) : Super(aX.value, aY.value) {}
MOZ_CONSTEXPR MOZ_IMPLICIT PointTyped(const IntPointTyped<units>& point) : Super(float(point.x), float(point.y)) {}
// XXX When all of the code is ported, the following functions to convert to and from
@ -84,8 +98,14 @@ typedef PointTyped<UnknownUnits> Point;
template<class units>
IntPointTyped<units> RoundedToInt(const PointTyped<units>& aPoint) {
return IntPointTyped<units>(int32_t(floorf(aPoint.x + 0.5f)),
int32_t(floorf(aPoint.y + 0.5f)));
return IntPointTyped<units>(aPoint.x.Rounded(),
aPoint.y.Rounded());
}
template<class units>
IntPointTyped<units> TruncatedToInt(const PointTyped<units>& aPoint) {
return IntPointTyped<units>(aPoint.x.Truncated(),
aPoint.y.Truncated());
}
template<class units>

View File

@ -240,15 +240,15 @@ SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::Noise2(Point aVec, c
uint8_t i = mLatticeSelector[b0.x & sBM];
uint8_t j = mLatticeSelector[b1.x & sBM];
const f32x4_t* qua = mGradient[(i + b0.y) & sBM];
const f32x4_t* qub = mGradient[(i + b1.y) & sBM];
const f32x4_t* qva = mGradient[(j + b0.y) & sBM];
const f32x4_t* qvb = mGradient[(j + b1.y) & sBM];
const f32x4_t* qua = mGradient[(i + b0.y.value) & sBM];
const f32x4_t* qub = mGradient[(i + b1.y.value) & sBM];
const f32x4_t* qva = mGradient[(j + b0.y.value) & sBM];
const f32x4_t* qvb = mGradient[(j + b1.y.value) & sBM];
return BiMix(simd::WSumF32(qua[0], qua[1], r.x, r.y),
simd::WSumF32(qva[0], qva[1], r.x - 1, r.y),
simd::WSumF32(qub[0], qub[1], r.x, r.y - 1),
simd::WSumF32(qvb[0], qvb[1], r.x - 1, r.y - 1),
simd::WSumF32(qva[0], qva[1], r.x - 1.f, r.y),
simd::WSumF32(qub[0], qub[1], r.x, r.y - 1.f),
simd::WSumF32(qvb[0], qvb[1], r.x - 1.f, r.y - 1.f),
SCurve(r));
}

View File

@ -10,6 +10,7 @@ EXPORTS.mozilla += [
EXPORTS.mozilla.gfx += [
'2D.h',
'BaseCoord.h',
'BaseMargin.h',
'BasePoint.h',
'BasePoint3D.h',
@ -18,6 +19,7 @@ EXPORTS.mozilla.gfx += [
'BaseSize.h',
'Blur.h',
'BorrowedContext.h',
'Coord.h',
'DataSurfaceHelpers.h',
'Filters.h',
'Helpers.h',

View File

@ -26,8 +26,8 @@ TestPoint::Addition()
a += b;
VERIFY(a.x == 7);
VERIFY(a.y == -3);
VERIFY(a.x == 7.f);
VERIFY(a.y == -3.f);
}
void
@ -41,6 +41,6 @@ TestPoint::Subtraction()
a -= b;
VERIFY(a.x == -3);
VERIFY(a.y == 7);
VERIFY(a.x == -3.f);
VERIFY(a.y == 7.f);
}

View File

@ -507,6 +507,38 @@ struct ParamTraits<nsIntSize>
}
};
template<class T>
struct ParamTraits< mozilla::gfx::CoordTyped<T> >
{
typedef mozilla::gfx::CoordTyped<T> paramType;
static void Write(Message* msg, const paramType& param)
{
WriteParam(msg, param.value);
}
static bool Read(const Message* msg, void** iter, paramType* result)
{
return (ReadParam(msg, iter, &result->value));
}
};
template<class T>
struct ParamTraits< mozilla::gfx::IntCoordTyped<T> >
{
typedef mozilla::gfx::IntCoordTyped<T> paramType;
static void Write(Message* msg, const paramType& param)
{
WriteParam(msg, param.value);
}
static bool Read(const Message* msg, void** iter, paramType* result)
{
return (ReadParam(msg, iter, &result->value));
}
};
template<class T, class U>
struct ParamTraits< mozilla::gfx::ScaleFactor<T, U> >
{

View File

@ -197,7 +197,7 @@ protected:
public:
NS_INLINE_DECL_REFCOUNTING(Compositor)
Compositor(PCompositorParent* aParent = nullptr)
explicit Compositor(PCompositorParent* aParent = nullptr)
: mCompositorID(0)
, mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC)
, mParent(aParent)

View File

@ -42,7 +42,7 @@ struct Effect
{
NS_INLINE_DECL_REFCOUNTING(Effect)
Effect(EffectTypes aType) : mType(aType) {}
explicit Effect(EffectTypes aType) : mType(aType) {}
EffectTypes mType;
@ -98,7 +98,7 @@ struct EffectMask : public Effect
struct EffectBlendMode : public Effect
{
EffectBlendMode(gfx::CompositionOp aBlendMode)
explicit EffectBlendMode(gfx::CompositionOp aBlendMode)
: Effect(EffectTypes::BLEND_MODE)
, mBlendMode(aBlendMode)
{ }
@ -112,7 +112,7 @@ struct EffectBlendMode : public Effect
// Render to a render target rather than the screen.
struct EffectRenderTarget : public TexturedEffect
{
EffectRenderTarget(CompositingRenderTarget *aRenderTarget)
explicit EffectRenderTarget(CompositingRenderTarget *aRenderTarget)
: TexturedEffect(EffectTypes::RENDER_TARGET, aRenderTarget, true, gfx::Filter::LINEAR)
, mRenderTarget(aRenderTarget)
{}
@ -183,7 +183,7 @@ struct EffectComponentAlpha : public TexturedEffect
struct EffectSolidColor : public Effect
{
EffectSolidColor(const gfx::Color &aColor)
explicit EffectSolidColor(const gfx::Color &aColor)
: Effect(EffectTypes::SOLID_COLOR)
, mColor(aColor)
{}

View File

@ -563,6 +563,22 @@ struct ScrollableLayerGuid {
{
return !(*this == other);
}
bool operator<(const ScrollableLayerGuid& other) const
{
if (mLayersId < other.mLayersId) {
return true;
}
if (mLayersId == other.mLayersId) {
if (mPresShellId < other.mPresShellId) {
return true;
}
if (mPresShellId == other.mPresShellId) {
return mScrollId < other.mScrollId;
}
}
return false;
}
};
template <int LogLevel>

View File

@ -57,7 +57,7 @@ public:
*/
class SurfaceReleaser : public nsRunnable {
public:
SurfaceReleaser(RawRef aRef) : mRef(aRef) {}
explicit SurfaceReleaser(RawRef aRef) : mRef(aRef) {}
NS_IMETHOD Run() {
mRef->Release();
return NS_OK;
@ -350,7 +350,7 @@ public:
enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 };
ImageContainer(int flag = 0);
explicit ImageContainer(int flag = 0);
/**
* Create an Image in one of the given formats.
@ -666,7 +666,7 @@ private:
class AutoLockImage
{
public:
AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); }
explicit AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); }
AutoLockImage(ImageContainer *aContainer, RefPtr<gfx::SourceSurface> *aSurface) : mContainer(aContainer) {
*aSurface = mContainer->LockCurrentAsSourceSurface(&mSize, getter_AddRefs(mImage));
}
@ -821,7 +821,7 @@ public:
virtual gfx::IntSize GetSize() { return mSize; }
PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
explicit PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
virtual SharedPlanarYCbCrImage *AsSharedPlanarYCbCrImage() { return nullptr; }

Some files were not shown because too many files have changed in this diff Show More