diff --git a/accessible/src/jsat/AccessFu.jsm b/accessible/src/jsat/AccessFu.jsm
index 8a4834e840a0..7c80d7580b76 100644
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -918,10 +918,18 @@ var Input = {
},
moveToPoint: function moveToPoint(aRule, aX, aY) {
- let mm = Utils.getMessageManager(Utils.CurrentBrowser);
- mm.sendAsyncMessage('AccessFu:MoveToPoint', {rule: aRule,
- x: aX, y: aY,
- origin: 'top'});
+ // XXX: Bug 1013408 - There is no alignment between the chrome window's
+ // viewport size and the content viewport size in Android. This makes
+ // sending mouse events beyond its bounds impossible.
+ if (Utils.MozBuildApp === 'mobile/android') {
+ let mm = Utils.getMessageManager(Utils.CurrentBrowser);
+ mm.sendAsyncMessage('AccessFu:MoveToPoint',
+ {rule: aRule, x: aX, y: aY, origin: 'top'});
+ } else {
+ let win = Utils.win;
+ Utils.winUtils.sendMouseEvent('mousemove',
+ aX - win.mozInnerScreenX, aY - win.mozInnerScreenY, 0, 0, 0);
+ }
},
moveCursor: function moveCursor(aAction, aRule, aInputType) {
@@ -999,11 +1007,9 @@ var Input = {
let page = aDetails.page;
let p = AccessFu.adjustContentBounds(aDetails.bounds, Utils.CurrentBrowser,
true, true).center();
- let wu = Utils.win.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDOMWindowUtils);
- wu.sendWheelEvent(p.x, p.y,
- horizontal ? page : 0, horizontal ? 0 : page, 0,
- Utils.win.WheelEvent.DOM_DELTA_PAGE, 0, 0, 0, 0);
+ Utils.winUtils.sendWheelEvent(p.x, p.y,
+ horizontal ? page : 0, horizontal ? 0 : page, 0,
+ Utils.win.WheelEvent.DOM_DELTA_PAGE, 0, 0, 0, 0);
},
get keyMap() {
diff --git a/accessible/src/jsat/ContentControl.jsm b/accessible/src/jsat/ContentControl.jsm
index 28018d1b924f..14eb4a506368 100644
--- a/accessible/src/jsat/ContentControl.jsm
+++ b/accessible/src/jsat/ContentControl.jsm
@@ -45,6 +45,7 @@ this.ContentControl.prototype = {
for (let message of this.messagesOfInterest) {
cs.addMessageListener(message, this);
}
+ cs.addEventListener('mousemove', this);
},
stop: function cc_stop() {
@@ -52,6 +53,7 @@ this.ContentControl.prototype = {
for (let message of this.messagesOfInterest) {
cs.removeMessageListener(message, this);
}
+ cs.removeEventListener('mousemove', this);
},
get document() {
@@ -124,18 +126,22 @@ this.ContentControl.prototype = {
}
},
+ handleEvent: function cc_handleEvent(aEvent) {
+ if (aEvent.type === 'mousemove') {
+ this.handleMoveToPoint(
+ { json: { x: aEvent.screenX, y: aEvent.screenY, rule: 'Simple' } });
+ }
+ if (!Utils.getMessageManager(aEvent.target)) {
+ aEvent.preventDefault();
+ }
+ },
+
handleMoveToPoint: function cc_handleMoveToPoint(aMessage) {
let [x, y] = [aMessage.json.x, aMessage.json.y];
let rule = TraversalRules[aMessage.json.rule];
- let vc = this.vc;
- let win = this.window;
- let dpr = win.devicePixelRatio;
+ let dpr = this.window.devicePixelRatio;
this.vc.moveToPoint(rule, x * dpr, y * dpr, true);
-
- let delta = Utils.isContentProcess ?
- { x: x - win.mozInnerScreenX, y: y - win.mozInnerScreenY } : {};
- this.sendToChild(vc, aMessage, delta);
},
handleClearCursor: function cc_handleClearCursor(aMessage) {
diff --git a/accessible/src/jsat/PointerAdapter.jsm b/accessible/src/jsat/PointerAdapter.jsm
index 151e798e7fad..15a3aa0f38aa 100644
--- a/accessible/src/jsat/PointerAdapter.jsm
+++ b/accessible/src/jsat/PointerAdapter.jsm
@@ -110,36 +110,14 @@ let PointerRelay = { // jshint ignore:line
}
},
- _suppressPointerMove: function PointerRelay__suppressPointerMove(aChangedTouches) {
- if (!this.lastPointerMove) {
- return false;
- }
- for (let i = 0; i < aChangedTouches.length; ++i) {
- let touch = aChangedTouches[i];
- let lastTouch;
- try {
- lastTouch = this.lastPointerMove.identifiedTouch ?
- this.lastPointerMove.identifiedTouch(touch.identifier) :
- this.lastPointerMove[i];
- } catch (x) {
- // Sometimes touch object can't be accessed after page navigation.
- }
- if (!lastTouch || lastTouch.target !== touch.target ||
- Math.hypot(touch.screenX - lastTouch.screenX, touch.screenY -
- lastTouch.screenY) / Utils.dpi >= GestureSettings.travelThreshold) {
- return false;
- }
- }
- return true;
- },
-
handleEvent: function PointerRelay_handleEvent(aEvent) {
// Don't bother with chrome mouse events.
if (Utils.MozBuildApp === 'browser' &&
aEvent.view.top instanceof Ci.nsIDOMChromeWindow) {
return;
}
- if (aEvent.mozInputSource === Ci.nsIDOMMouseEvent.MOZ_SOURCE_UNKNOWN) {
+ if (aEvent.mozInputSource === Ci.nsIDOMMouseEvent.MOZ_SOURCE_UNKNOWN ||
+ aEvent.isSynthesized) {
// Ignore events that are scripted or clicks from the a11y API.
return;
}
@@ -164,13 +142,6 @@ let PointerRelay = { // jshint ignore:line
return;
}
let pointerType = this._eventMap[type];
- if (pointerType === 'pointermove') {
- if (this._suppressPointerMove(changedTouches)) {
- // Do not fire pointermove more than every POINTERMOVE_THROTTLE.
- return;
- }
- this.lastPointerMove = changedTouches;
- }
this.onPointerEvent({
type: pointerType,
points: Array.prototype.map.call(changedTouches,
diff --git a/accessible/src/jsat/TraversalRules.jsm b/accessible/src/jsat/TraversalRules.jsm
index 48791e1aa037..954e9b7a8ab2 100644
--- a/accessible/src/jsat/TraversalRules.jsm
+++ b/accessible/src/jsat/TraversalRules.jsm
@@ -113,6 +113,11 @@ var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) {
function isFlatSubtree(acc) {
for (let child = acc.firstChild; child; child = child.nextSibling) {
+ // text leafs inherit the actionCount of any ancestor that has a click
+ // listener.
+ if ([Roles.TEXT_LEAF, Roles.STATICTEXT].indexOf(child.role) >= 0) {
+ continue;
+ }
if (child.childCount > 0 || child.actionCount > 0) {
return false;
}
diff --git a/accessible/src/jsat/Utils.jsm b/accessible/src/jsat/Utils.jsm
index e273dc141f7a..59775132b797 100644
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -54,6 +54,15 @@ this.Utils = {
return this._win.get();
},
+ get winUtils() {
+ let win = this.win;
+ if (!win) {
+ return null;
+ }
+ return win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(
+ Ci.nsIDOMWindowUtils);
+ },
+
get AccRetrieval() {
if (!this._AccRetrieval) {
this._AccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1'].
@@ -181,7 +190,6 @@ this.Utils = {
return aBrowser.QueryInterface(Ci.nsIFrameLoaderOwner).
frameLoader.messageManager;
} catch (x) {
- Logger.logException(x);
return null;
}
},
@@ -252,8 +260,7 @@ this.Utils = {
*/
get dpi() {
delete this.dpi;
- this.dpi = this.win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(
- Ci.nsIDOMWindowUtils).displayDPI;
+ this.dpi = this.winUtils.displayDPI;
return this.dpi;
},
diff --git a/accessible/tests/mochitest/jsat/doc_traversal.html b/accessible/tests/mochitest/jsat/doc_traversal.html
index 31d83e95eca2..4465250c4533 100644
--- a/accessible/tests/mochitest/jsat/doc_traversal.html
+++ b/accessible/tests/mochitest/jsat/doc_traversal.html
@@ -60,7 +60,7 @@
A esoteric weapon wielded by only the most formidable warriors,
for its unrelenting strict power is unfathomable.
-
+
- Lists of Programming Languages
- Lisp
diff --git a/b2g/components/B2GComponents.manifest b/b2g/components/B2GComponents.manifest
index 61d0be1ebc02..6bffaa7a081b 100644
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -29,11 +29,6 @@ component {1a94c87a-5ece-4d11-91e1-d29c29f21b28} ProcessGlobal.js
contract @mozilla.org/b2g-process-global;1 {1a94c87a-5ece-4d11-91e1-d29c29f21b28}
category app-startup ProcessGlobal service,@mozilla.org/b2g-process-global;1
-# ContentHandler.js
-component {d18d0216-d50c-11e1-ba54-efb18d0ef0ac} ContentHandler.js
-contract @mozilla.org/b2g/activities-content-handler;1 {d18d0216-d50c-11e1-ba54-efb18d0ef0ac}
-category app-startup ContentHandler service,@mozilla.org/b2g/activities-content-handler;1
-
# PaymentGlue.js
component {8b83eabc-7929-47f4-8b48-4dea8d887e4b} PaymentGlue.js
contract @mozilla.org/payment/ui-glue;1 {8b83eabc-7929-47f4-8b48-4dea8d887e4b}
diff --git a/b2g/components/ContentHandler.js b/b2g/components/ContentHandler.js
deleted file mode 100644
index 4f77d7c6e71f..000000000000
--- a/b2g/components/ContentHandler.js
+++ /dev/null
@@ -1,145 +0,0 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-"use strict";
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
- return Cc["@mozilla.org/childprocessmessagemanager;1"]
- .getService(Ci.nsIMessageSender);
-});
-
-function debug(aMsg) {
- //dump("--*-- ContentHandler: " + aMsg + "\n");
-}
-
-const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
-
-let ActivityContentFactory = {
- createInstance: function createInstance(outer, iid) {
- if (outer != null) {
- throw Cr.NS_ERROR_NO_AGGREGATION;
- }
- return new ActivityContentHandler().QueryInterface(iid);
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
-}
-
-function ActivityContentHandler() {
-}
-
-ActivityContentHandler.prototype = {
- handleContent: function handleContent(aMimetype, aContext, aRequest) {
- if (!(aRequest instanceof Ci.nsIChannel))
- throw NS_ERROR_WONT_HANDLE_CONTENT;
-
- let detail = {
- "type": aMimetype,
- "url": aRequest.URI.spec
- };
- cpmm.sendAsyncMessage("content-handler", detail);
-
- aRequest.cancel(Cr.NS_BINDING_ABORTED);
- },
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler])
-}
-
-function ContentHandler() {
- this.classIdMap = {};
-}
-
-ContentHandler.prototype = {
- observe: function(aSubject, aTopic, aData) {
- if (aTopic == "app-startup") {
- // We only want to register these from content processes.
- let appInfo = Cc["@mozilla.org/xre/app-info;1"];
- if (appInfo.getService(Ci.nsIXULRuntime)
- .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
- return;
- }
- }
-
- cpmm.addMessageListener("Activities:RegisterContentTypes", this);
- cpmm.addMessageListener("Activities:UnregisterContentTypes", this);
- cpmm.sendAsyncMessage("Activities:GetContentTypes", { });
- },
-
- /**
- * Do the component registration for a content type.
- * We only need to register one component per content type, even if several
- * apps provide it, so we keep track of the number of providers for each
- * content type.
- */
- registerContentHandler: function registerContentHandler(aContentType) {
- debug("Registering " + aContentType);
-
- // We already have a provider for this content type, just increase the
- // tracking count.
- if (this.classIdMap[aContentType]) {
- this.classIdMap[aContentType].count++;
- return;
- }
-
- let contractID = "@mozilla.org/uriloader/content-handler;1?type=" +
- aContentType;
- let uuidGen = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
- let id = Components.ID(uuidGen.generateUUID().toString());
- this.classIdMap[aContentType] = { count: 1, id: id };
- let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
- cr.registerFactory(Components.ID(id), "Activity Content Handler", contractID,
- ActivityContentFactory);
- },
-
- /**
- * Do the component unregistration for a content type.
- */
- unregisterContentHandler: function registerContentHandler(aContentType) {
- debug("Unregistering " + aContentType);
-
- let record = this.classIdMap[aContentType];
- if (!record) {
- return;
- }
-
- // Bail out if we still have providers left for this content type.
- if (--record.count > 0) {
- return;
- }
-
- let contractID = "@mozilla.org/uriloader/content-handler;1?type=" +
- aContentType;
- let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
- cr.unregisterFactory(record.id, ActivityContentFactory);
- delete this.classIdMap[aContentType]
- },
-
- receiveMessage: function(aMessage) {
- let data = aMessage.data;
-
- switch (aMessage.name) {
- case "Activities:RegisterContentTypes":
- data.contentTypes.forEach(this.registerContentHandler, this);
- break;
- case "Activities:UnregisterContentTypes":
- data.contentTypes.forEach(this.unregisterContentHandler, this);
- break;
- }
- },
-
- classID: Components.ID("{d18d0216-d50c-11e1-ba54-efb18d0ef0ac}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler,
- Ci.nsIObserver,
- Ci.nsISupportsWeakReference])
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentHandler]);
diff --git a/b2g/components/moz.build b/b2g/components/moz.build
index 88248f6bce2d..66296e4998b5 100644
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -10,7 +10,6 @@ EXTRA_COMPONENTS += [
'ActivitiesGlue.js',
'AlertsService.js',
'B2GAboutRedirector.js',
- 'ContentHandler.js',
'ContentPermissionPrompt.js',
'FilePicker.js',
'HelperAppDialog.js',
diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index c8d78864411a..d0a6737def5b 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index d18705daaa03..83f09231c913 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index 37e3d5a9b6f9..9d917ec322af 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index c8d78864411a..d0a6737def5b 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml
index 632e231901f9..55afdbeb1d71 100644
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -18,7 +18,7 @@
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index 8bcee7d236d3..5884e5e068d9 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
- "revision": "2f15fe97023bf41e29660a2d427bd43a3ff181b0",
+ "revision": "9b29b2b76fa9038d3162261c174a92dd5ef704d2",
"repo_path": "/integration/gaia-central"
}
diff --git a/b2g/config/hamachi/sources.xml b/b2g/config/hamachi/sources.xml
index 9f545593c126..7ffe5693c2b2 100644
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/helix/sources.xml b/b2g/config/helix/sources.xml
index 77230dfeae57..08693889b41e 100644
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/b2g/config/inari/sources.xml b/b2g/config/inari/sources.xml
index 52147da4b4ff..bcdbe7d8e1fa 100644
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/leo/sources.xml b/b2g/config/leo/sources.xml
index 19aa10ffc2e9..7d16654e4323 100644
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/mako/sources.xml b/b2g/config/mako/sources.xml
index 3864a5da4345..a70297ddecc4 100644
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/b2g/config/tooltool-manifests/linux32/releng.manifest b/b2g/config/tooltool-manifests/linux32/releng.manifest
index c4db9be28b78..15901d073db7 100644
--- a/b2g/config/tooltool-manifests/linux32/releng.manifest
+++ b/b2g/config/tooltool-manifests/linux32/releng.manifest
@@ -6,8 +6,8 @@
"filename": "setup.sh"
},
{
-"size": 165464,
-"digest": "ee87db68eb63e417a366333e34a32d9220232bfb9c3e91b9941513acf0551f2603a836537ffef41a240430200970d83fa9271f55b8b5168d6967be595cdb50db",
+"size": 165226,
+"digest": "79280f7595bc9e1613e05f8b2f0db3798ac739b96191e0f133e8ccd8ad149fedc84a1046e59863574189db28363a01712ae7b368ad1714e30ff88e7ebd5dad23",
"algorithm": "sha512",
"filename": "sccache.tar.bz2"
}
diff --git a/b2g/config/tooltool-manifests/linux64/releng.manifest b/b2g/config/tooltool-manifests/linux64/releng.manifest
index c4db9be28b78..15901d073db7 100644
--- a/b2g/config/tooltool-manifests/linux64/releng.manifest
+++ b/b2g/config/tooltool-manifests/linux64/releng.manifest
@@ -6,8 +6,8 @@
"filename": "setup.sh"
},
{
-"size": 165464,
-"digest": "ee87db68eb63e417a366333e34a32d9220232bfb9c3e91b9941513acf0551f2603a836537ffef41a240430200970d83fa9271f55b8b5168d6967be595cdb50db",
+"size": 165226,
+"digest": "79280f7595bc9e1613e05f8b2f0db3798ac739b96191e0f133e8ccd8ad149fedc84a1046e59863574189db28363a01712ae7b368ad1714e30ff88e7ebd5dad23",
"algorithm": "sha512",
"filename": "sccache.tar.bz2"
}
diff --git a/b2g/config/tooltool-manifests/macosx64/releng.manifest b/b2g/config/tooltool-manifests/macosx64/releng.manifest
index 9ff54b36efed..eb5c54499c32 100644
--- a/b2g/config/tooltool-manifests/macosx64/releng.manifest
+++ b/b2g/config/tooltool-manifests/macosx64/releng.manifest
@@ -15,8 +15,8 @@
"filename": "clang.tar.bz2"
},
{
-"size": 165464,
-"digest": "ee87db68eb63e417a366333e34a32d9220232bfb9c3e91b9941513acf0551f2603a836537ffef41a240430200970d83fa9271f55b8b5168d6967be595cdb50db",
+"size": 165226,
+"digest": "79280f7595bc9e1613e05f8b2f0db3798ac739b96191e0f133e8ccd8ad149fedc84a1046e59863574189db28363a01712ae7b368ad1714e30ff88e7ebd5dad23",
"algorithm": "sha512",
"filename": "sccache.tar.bz2"
}
diff --git a/b2g/config/wasabi/sources.xml b/b2g/config/wasabi/sources.xml
index 3dee95d83c5c..199664205dd5 100644
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -17,7 +17,7 @@
-
+
diff --git a/browser/base/content/aboutneterror/netError.css b/browser/base/content/aboutneterror/netError.css
index 30ae7e924184..69fbd10f3bd6 100644
--- a/browser/base/content/aboutneterror/netError.css
+++ b/browser/base/content/aboutneterror/netError.css
@@ -32,13 +32,14 @@ ul {
max-width: 512px;
}
-#errorTitle {
+#errorTitleText {
background: url("info.svg") left 0 no-repeat;
- -moz-margin-start: -5em;
- -moz-padding-start: 5em;
+ background-size: 1.2em;
+ -moz-margin-start: -2em;
+ -moz-padding-start: 2em;
}
-#errorTitle:-moz-dir(rtl) {
+#errorTitleText:-moz-dir(rtl) {
background-position: right 0;
}
diff --git a/browser/config/tooltool-manifests/linux32/releng.manifest b/browser/config/tooltool-manifests/linux32/releng.manifest
index e9fc525d0d41..88752c57fd32 100644
--- a/browser/config/tooltool-manifests/linux32/releng.manifest
+++ b/browser/config/tooltool-manifests/linux32/releng.manifest
@@ -12,8 +12,8 @@
"filename": "gcc.tar.xz"
},
{
-"size": 165464,
-"digest": "ee87db68eb63e417a366333e34a32d9220232bfb9c3e91b9941513acf0551f2603a836537ffef41a240430200970d83fa9271f55b8b5168d6967be595cdb50db",
+"size": 165226,
+"digest": "79280f7595bc9e1613e05f8b2f0db3798ac739b96191e0f133e8ccd8ad149fedc84a1046e59863574189db28363a01712ae7b368ad1714e30ff88e7ebd5dad23",
"algorithm": "sha512",
"filename": "sccache.tar.bz2"
}
diff --git a/browser/config/tooltool-manifests/linux64/releng.manifest b/browser/config/tooltool-manifests/linux64/releng.manifest
index e9fc525d0d41..88752c57fd32 100644
--- a/browser/config/tooltool-manifests/linux64/releng.manifest
+++ b/browser/config/tooltool-manifests/linux64/releng.manifest
@@ -12,8 +12,8 @@
"filename": "gcc.tar.xz"
},
{
-"size": 165464,
-"digest": "ee87db68eb63e417a366333e34a32d9220232bfb9c3e91b9941513acf0551f2603a836537ffef41a240430200970d83fa9271f55b8b5168d6967be595cdb50db",
+"size": 165226,
+"digest": "79280f7595bc9e1613e05f8b2f0db3798ac739b96191e0f133e8ccd8ad149fedc84a1046e59863574189db28363a01712ae7b368ad1714e30ff88e7ebd5dad23",
"algorithm": "sha512",
"filename": "sccache.tar.bz2"
}
diff --git a/browser/config/tooltool-manifests/macosx64/releng.manifest b/browser/config/tooltool-manifests/macosx64/releng.manifest
index 868b54d8ac96..14f19b3fd801 100644
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -15,8 +15,8 @@
"filename": "clang.tar.bz2"
},
{
-"size": 165464,
-"digest": "ee87db68eb63e417a366333e34a32d9220232bfb9c3e91b9941513acf0551f2603a836537ffef41a240430200970d83fa9271f55b8b5168d6967be595cdb50db",
+"size": 165226,
+"digest": "79280f7595bc9e1613e05f8b2f0db3798ac739b96191e0f133e8ccd8ad149fedc84a1046e59863574189db28363a01712ae7b368ad1714e30ff88e7ebd5dad23",
"algorithm": "sha512",
"filename": "sccache.tar.bz2"
}
diff --git a/browser/config/tooltool-manifests/win32/releng.manifest b/browser/config/tooltool-manifests/win32/releng.manifest
index b8b8c38ae124..267d9cc44fc1 100644
--- a/browser/config/tooltool-manifests/win32/releng.manifest
+++ b/browser/config/tooltool-manifests/win32/releng.manifest
@@ -12,8 +12,8 @@
"filename": "setup.sh"
},
{
-"size": 165464,
-"digest": "ee87db68eb63e417a366333e34a32d9220232bfb9c3e91b9941513acf0551f2603a836537ffef41a240430200970d83fa9271f55b8b5168d6967be595cdb50db",
+"size": 165226,
+"digest": "79280f7595bc9e1613e05f8b2f0db3798ac739b96191e0f133e8ccd8ad149fedc84a1046e59863574189db28363a01712ae7b368ad1714e30ff88e7ebd5dad23",
"algorithm": "sha512",
"filename": "sccache.tar.bz2"
}
diff --git a/browser/devtools/debugger/debugger-controller.js b/browser/devtools/debugger/debugger-controller.js
index 9551174c73af..8205d27b08a7 100644
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -474,6 +474,13 @@ ThreadState.prototype = {
* Update the UI after a thread state change.
*/
_update: function(aEvent) {
+ // Ignore "interrupted" events, which are generated by the slow script
+ // dialog and internal events such as setting breakpoints, to avoid UI
+ // flicker.
+ if (aEvent == "interrupted") {
+ return;
+ }
+
DebuggerView.Toolbar.toggleResumeButtonState(this.activeThread.state);
if (gTarget && (aEvent == "paused" || aEvent == "resumed")) {
@@ -580,6 +587,11 @@ StackFrames.prototype = {
this._currentReturnedValue = aPacket.why.frameFinished.return;
}
break;
+ // If paused by an explicit interrupt, which are generated by the slow
+ // script dialog and internal events such as setting breakpoints, ignore
+ // the event to avoid UI flicker.
+ case "interrupted":
+ return;
}
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
diff --git a/browser/devtools/debugger/test/browser.ini b/browser/devtools/debugger/test/browser.ini
index a58822e47c99..6586c31f73b3 100644
--- a/browser/devtools/debugger/test/browser.ini
+++ b/browser/devtools/debugger/test/browser.ini
@@ -78,6 +78,7 @@ support-files =
doc_script-switching-01.html
doc_script-switching-02.html
doc_step-out.html
+ doc_terminate-on-tab-close.html
doc_tracing-01.html
doc_watch-expressions.html
doc_watch-expression-button.html
@@ -237,6 +238,7 @@ skip-if = true # Bug 933950 (leaky test)
[browser_dbg_step-out.js]
[browser_dbg_tabactor-01.js]
[browser_dbg_tabactor-02.js]
+[browser_dbg_terminate-on-tab-close.js]
[browser_dbg_tracing-01.js]
[browser_dbg_tracing-02.js]
[browser_dbg_tracing-03.js]
diff --git a/browser/devtools/debugger/test/browser_dbg_terminate-on-tab-close.js b/browser/devtools/debugger/test/browser_dbg_terminate-on-tab-close.js
new file mode 100644
index 000000000000..10e7493bf413
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_terminate-on-tab-close.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that debuggee scripts are terminated on tab closure.
+ */
+
+const TAB_URL = EXAMPLE_URL + "doc_terminate-on-tab-close.html";
+
+let gTab, gDebuggee, gDebugger, gPanel;
+
+function test() {
+ initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
+ gTab = aTab;
+ gDebuggee = aDebuggee;
+ gPanel = aPanel;
+ gDebugger = gPanel.panelWin;
+
+ testTerminate();
+ });
+}
+
+function testTerminate() {
+ gDebugger.gThreadClient.addOneTimeListener("paused", () => {
+ resumeDebuggerThenCloseAndFinish(gPanel).then(function () {
+ ok(true, "should not throw after this point");
+ });
+ });
+
+ gDebuggee.debuggerThenThrow();
+}
+
+registerCleanupFunction(function() {
+ gTab = null;
+ gDebuggee = null;
+ gPanel = null;
+ gDebugger = null;
+});
diff --git a/browser/devtools/debugger/test/doc_terminate-on-tab-close.html b/browser/devtools/debugger/test/doc_terminate-on-tab-close.html
new file mode 100644
index 000000000000..2101b31034db
--- /dev/null
+++ b/browser/devtools/debugger/test/doc_terminate-on-tab-close.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Debugger test page
+
+
+
+
+
+
+
diff --git a/browser/devtools/framework/gDevTools.jsm b/browser/devtools/framework/gDevTools.jsm
index e598f524615d..7e9d7672585b 100644
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -580,6 +580,79 @@ let gDevToolsBrowser = {
mainKeyset.parentNode.insertBefore(devtoolsKeyset, mainKeyset);
},
+ /**
+ * Hook the JS debugger tool to the "Debug Script" button of the slow script
+ * dialog.
+ */
+ setSlowScriptDebugHandler: function DT_setSlowScriptDebugHandler() {
+ let debugService = Cc["@mozilla.org/dom/slow-script-debug;1"]
+ .getService(Ci.nsISlowScriptDebug);
+ let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
+
+ debugService.activationHandler = function(aWindow) {
+ let chromeWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow)
+ .QueryInterface(Ci.nsIDOMChromeWindow);
+ let target = devtools.TargetFactory.forTab(chromeWindow.gBrowser.selectedTab);
+
+ let setupFinished = false;
+ gDevTools.showToolbox(target, "jsdebugger").then(toolbox => {
+ let threadClient = toolbox.getCurrentPanel().panelWin.gThreadClient;
+
+ // Break in place, which means resuming the debuggee thread and pausing
+ // right before the next step happens.
+ switch (threadClient.state) {
+ case "paused":
+ // When the debugger is already paused.
+ threadClient.breakOnNext();
+ setupFinished = true;
+ break;
+ case "attached":
+ // When the debugger is already open.
+ threadClient.interrupt(() => {
+ threadClient.breakOnNext();
+ setupFinished = true;
+ });
+ break;
+ case "resuming":
+ // The debugger is newly opened.
+ threadClient.addOneTimeListener("resumed", () => {
+ threadClient.interrupt(() => {
+ threadClient.breakOnNext();
+ setupFinished = true;
+ });
+ });
+ break;
+ default:
+ throw Error("invalid thread client state in slow script debug handler: " +
+ threadClient.state);
+ }
+ });
+
+ // Don't return from the interrupt handler until the debugger is brought
+ // up; no reason to continue executing the slow script.
+ let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ utils.enterModalState();
+ while (!setupFinished) {
+ tm.currentThread.processNextEvent(true);
+ }
+ utils.leaveModalState();
+ };
+ },
+
+ /**
+ * Unset the slow script debug handler.
+ */
+ unsetSlowScriptDebugHandler: function DT_unsetSlowScriptDebugHandler() {
+ let debugService = Cc["@mozilla.org/dom/slow-script-debug;1"]
+ .getService(Ci.nsISlowScriptDebug);
+ debugService.activationHandler = undefined;
+ },
/**
* Detect the presence of a Firebug.
@@ -669,6 +742,10 @@ let gDevToolsBrowser = {
}
}
}
+
+ if (toolDefinition.id === "jsdebugger") {
+ gDevToolsBrowser.setSlowScriptDebugHandler();
+ }
},
/**
@@ -844,6 +921,10 @@ let gDevToolsBrowser = {
for (let win of gDevToolsBrowser._trackedBrowserWindows) {
gDevToolsBrowser._removeToolFromMenu(toolId, win.document);
}
+
+ if (toolId === "jsdebugger") {
+ gDevToolsBrowser.unsetSlowScriptDebugHandler();
+ }
},
/**
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index 8bff930388a7..3c9cd240c8a5 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -531,6 +531,9 @@
@BINPATH@/components/Push.manifest
@BINPATH@/components/PushServiceLauncher.js
+@BINPATH@/components/SlowScriptDebug.manifest
+@BINPATH@/components/SlowScriptDebug.js
+
#ifndef RELEASE_BUILD
@BINPATH@/components/InterAppComm.manifest
@BINPATH@/components/InterAppCommService.js
diff --git a/build/unix/elfhack/inject/moz.build b/build/unix/elfhack/inject/moz.build
index 3b069ef337a6..d0edb3ae7750 100644
--- a/build/unix/elfhack/inject/moz.build
+++ b/build/unix/elfhack/inject/moz.build
@@ -20,3 +20,5 @@ GENERATED_SOURCES += [
DEFINES['ELFHACK_BUILD'] = True
NO_PGO = True
+
+NO_VISIBILITY_FLAGS = True
diff --git a/config/gcc_hidden_dso_handle.h b/config/gcc_hidden_dso_handle.h
new file mode 100644
index 000000000000..b42c50e75fe9
--- /dev/null
+++ b/config/gcc_hidden_dso_handle.h
@@ -0,0 +1,11 @@
+/* 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/. */
+
+#ifdef __cplusplus
+extern "C"
+#endif
+void *__dso_handle;
+
+/* Begin all files as hidden visibility */
+#pragma GCC visibility push(hidden)
diff --git a/config/system-headers b/config/system-headers
index afe126a429f4..6c0049395ecc 100644
--- a/config/system-headers
+++ b/config/system-headers
@@ -407,9 +407,6 @@ DriverServices.h
DriverSynchronization.h
DropInPanel.h
dvidef.h
-#ifdef ANDROID
-EffectApi.h
-#endif
elf.h
endian.h
Entry.h
@@ -516,6 +513,8 @@ gtk/gtkprinter.h
gtk/gtkprintjob.h
gtk/gtkprintunixdialog.h
#ifdef ANDROID
+gui/BufferQueue.h
+gui/ConsumerBase.h
gui/GraphicBufferAlloc.h
gui/IConsumerListener.h
gui/IGraphicBufferAlloc.h
@@ -542,14 +541,6 @@ hlink.h
HTTPBase.h
#endif
ia64/sys/inline.h
-#ifdef ANDROID
-IAudioFlingerClient.h
-IAudioFlinger.h
-IAudioRecord.h
-IAudioTrack.h
-IEffect.h
-IEffectClient.h
-#endif
Icons.h
iconv.h
ieeefp.h
@@ -911,6 +902,7 @@ rpc/types.h
sane/sane.h
sane/sanei.h
sane/saneopts.h
+sched.h
Scrap.h
Screen.h
Script.h
diff --git a/configure.in b/configure.in
index d0a305a691a8..4e17a2ad3e81 100644
--- a/configure.in
+++ b/configure.in
@@ -2550,17 +2550,19 @@ dnl ===============================================================
if test "$GNU_CC" -a "$OS_TARGET" != WINNT; then
AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
- if test -n "$gonkdir"; then
- visibility_target=Gonk
- else
- visibility_target=$OS_TARGET
- fi
- case "$visibility_target" in
- Darwin|Gonk)
+ case "$OS_TARGET" in
+ Darwin)
VISIBILITY_FLAGS='-fvisibility=hidden'
;;
*)
- VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h'
+ case $GCC_VERSION in
+ 4.4*)
+ VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden_dso_handle.h'
+ ;;
+ *)
+ VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h'
+ ;;
+ esac
WRAP_SYSTEM_INCLUDES=1
;;
esac
diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h
index d2b59b1d2516..6e43b9be6355 100644
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1334,6 +1334,12 @@ public:
*/
static nsIPrincipal* GetSystemPrincipal();
+ /**
+ * Gets the null subject principal singleton. This is only useful for
+ * assertions.
+ */
+ static nsIPrincipal* GetNullSubjectPrincipal() { return sNullSubjectPrincipal; }
+
/**
* *aResourcePrincipal is a principal describing who may access the contents
* of a resource. The resource can only be consumed by a principal that
@@ -2169,6 +2175,7 @@ private:
static nsIScriptSecurityManager *sSecurityManager;
static nsIPrincipal *sSystemPrincipal;
+ static nsIPrincipal *sNullSubjectPrincipal;
static nsIParserService *sParserService;
diff --git a/content/base/src/nsCSPContext.cpp b/content/base/src/nsCSPContext.cpp
index 1101d7fff718..2bec183a1533 100644
--- a/content/base/src/nsCSPContext.cpp
+++ b/content/base/src/nsCSPContext.cpp
@@ -18,6 +18,7 @@
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMHTMLElement.h"
#include "nsIHttpChannel.h"
+#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
@@ -26,6 +27,7 @@
#include "nsIPrincipal.h"
#include "nsIPropertyBag2.h"
#include "nsIScriptError.h"
+#include "nsIWebNavigation.h"
#include "nsIWritablePropertyBag2.h"
#include "nsString.h"
#include "prlog.h"
@@ -45,6 +47,47 @@ GetCspContextLog()
#define CSPCONTEXTLOG(args) PR_LOG(GetCspContextLog(), 4, args)
+static const uint32_t CSP_CACHE_URI_CUTOFF_SIZE = 512;
+
+/**
+ * Creates a key for use in the ShouldLoad cache.
+ * Looks like: !
+ */
+nsresult
+CreateCacheKey_Internal(nsIURI* aContentLocation,
+ nsContentPolicyType aContentType,
+ nsACString& outCacheKey)
+{
+ if (!aContentLocation) {
+ return NS_ERROR_FAILURE;
+ }
+
+ bool isDataScheme = false;
+ nsresult rv = aContentLocation->SchemeIs("data", &isDataScheme);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ outCacheKey.Truncate();
+ if (aContentType != nsIContentPolicy::TYPE_SCRIPT && isDataScheme) {
+ // For non-script data: URI, use ("data:", aContentType) as the cache key.
+ outCacheKey.Append(NS_LITERAL_CSTRING("data:"));
+ outCacheKey.AppendInt(aContentType);
+ return NS_OK;
+ }
+
+ nsAutoCString spec;
+ rv = aContentLocation->GetSpec(spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Don't cache for a URI longer than the cutoff size.
+ if (spec.Length() <= CSP_CACHE_URI_CUTOFF_SIZE) {
+ outCacheKey.Append(spec);
+ outCacheKey.Append(NS_LITERAL_CSTRING("!"));
+ outCacheKey.AppendInt(aContentType);
+ }
+
+ return NS_OK;
+}
+
/* ===== nsIContentSecurityPolicy impl ====== */
NS_IMETHODIMP
@@ -74,6 +117,16 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
// * Content Type is not whitelisted (CSP Reports, TYPE_DOCUMENT, etc).
// * Fast Path for Apps
+ nsAutoCString cacheKey;
+ rv = CreateCacheKey_Internal(aContentLocation, aContentType, cacheKey);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool isCached = mShouldLoadCache.Get(cacheKey, outDecision);
+ if (isCached && cacheKey.Length() > 0) {
+ // this is cached, use the cached value.
+ return NS_OK;
+ }
+
// Default decision, CSP can revise it if there's a policy to enforce
*outDecision = nsIContentPolicy::ACCEPT;
@@ -137,6 +190,11 @@ nsCSPContext::ShouldLoad(nsContentPolicyType aContentType,
// * Console error reporting, bug 994322
}
}
+ // Done looping, cache any relevant result
+ if (cacheKey.Length() > 0 && !isPreload) {
+ mShouldLoadCache.Put(cacheKey, *outDecision);
+ }
+
#ifdef PR_LOGGING
{
nsAutoCString spec;
@@ -183,6 +241,7 @@ nsCSPContext::~nsCSPContext()
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
delete mPolicies[i];
}
+ mShouldLoadCache.Clear();
}
NS_IMETHODIMP
@@ -215,6 +274,8 @@ nsCSPContext::RemovePolicy(uint32_t aIndex)
return NS_ERROR_ILLEGAL_VALUE;
}
mPolicies.RemoveElementAt(aIndex);
+ // reset cache since effective policy changes
+ mShouldLoadCache.Clear();
return NS_OK;
}
@@ -237,6 +298,8 @@ nsCSPContext::AppendPolicy(const nsAString& aPolicyString,
nsCSPPolicy* policy = nsCSPParser::parseContentSecurityPolicy(aPolicyString, mSelfURI, aReportOnly, 0);
if (policy) {
mPolicies.AppendElement(policy);
+ // reset cache since effective policy changes
+ mShouldLoadCache.Clear();
}
return NS_OK;
}
@@ -378,11 +441,118 @@ nsCSPContext::SetRequestContext(nsIURI* aSelfURI,
return NS_OK;
}
+/**
+ * Based on the given docshell, determines if this CSP context allows the
+ * ancestry.
+ *
+ * In order to determine the URI of the parent document (one causing the load
+ * of this protected document), this function obtains the docShellTreeItem,
+ * then walks up the hierarchy until it finds a privileged (chrome) tree item.
+ * Getting the parent's URI looks like this in pseudocode:
+ *
+ * nsIDocShell->QI(nsIInterfaceRequestor)
+ * ->GI(nsIDocShellTreeItem)
+ * ->QI(nsIInterfaceRequestor)
+ * ->GI(nsIWebNavigation)
+ * ->GetCurrentURI();
+ *
+ * aDocShell is the docShell for the protected document.
+ */
NS_IMETHODIMP
nsCSPContext::PermitsAncestry(nsIDocShell* aDocShell, bool* outPermitsAncestry)
{
- // For now, we allows permitsAncestry, this will be fixed in Bug 994320
+ nsresult rv;
+
+ // Can't check ancestry without a docShell.
+ if (aDocShell == nullptr) {
+ return NS_ERROR_FAILURE;
+ }
+
*outPermitsAncestry = true;
+
+ // extract the ancestry as an array
+ nsCOMArray ancestorsArray;
+
+ nsCOMPtr ir(do_QueryInterface(aDocShell));
+ nsCOMPtr treeItem(do_GetInterface(ir));
+ nsCOMPtr parentTreeItem;
+ nsCOMPtr webNav;
+ nsCOMPtr currentURI;
+ nsCOMPtr uriClone;
+
+ // iterate through each docShell parent item
+ while (NS_SUCCEEDED(treeItem->GetParent(getter_AddRefs(parentTreeItem))) &&
+ parentTreeItem != nullptr) {
+ ir = do_QueryInterface(parentTreeItem);
+ NS_ASSERTION(ir, "Could not QI docShellTreeItem to nsIInterfaceRequestor");
+
+ webNav = do_GetInterface(ir);
+ NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
+
+ rv = webNav->GetCurrentURI(getter_AddRefs(currentURI));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (currentURI) {
+ // stop when reaching chrome
+ bool isChrome = false;
+ rv = currentURI->SchemeIs("chrome", &isChrome);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (isChrome) { break; }
+
+ // delete the userpass from the URI.
+ rv = currentURI->CloneIgnoringRef(getter_AddRefs(uriClone));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = uriClone->SetUserPass(EmptyCString());
+ NS_ENSURE_SUCCESS(rv, rv);
+#ifdef PR_LOGGING
+ {
+ nsAutoCString spec;
+ uriClone->GetSpec(spec);
+ CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, found ancestor: %s", spec.get()));
+ }
+#endif
+ ancestorsArray.AppendElement(uriClone);
+ }
+
+ // next ancestor
+ treeItem = parentTreeItem;
+ }
+
+ nsAutoString violatedDirective;
+
+ // Now that we've got the ancestry chain in ancestorsArray, time to check
+ // them against any CSP.
+ for (uint32_t i = 0; i < mPolicies.Length(); i++) {
+ for (uint32_t a = 0; a < ancestorsArray.Length(); a++) {
+ // TODO(sid) the mapping from frame-ancestors context to TYPE_DOCUMENT is
+ // forced. while this works for now, we will implement something in
+ // bug 999656.
+#ifdef PR_LOGGING
+ {
+ nsAutoCString spec;
+ ancestorsArray[a]->GetSpec(spec);
+ CSPCONTEXTLOG(("nsCSPContext::PermitsAncestry, checking ancestor: %s", spec.get()));
+ }
+#endif
+ if (!mPolicies[i]->permits(nsIContentPolicy::TYPE_DOCUMENT,
+ ancestorsArray[a],
+ EmptyString(), // no nonce
+ violatedDirective)) {
+ // Policy is violated
+ nsCOMPtr observerService =
+ mozilla::services::GetObserverService();
+ NS_ENSURE_TRUE(observerService, NS_ERROR_NOT_AVAILABLE);
+
+ observerService->NotifyObservers(ancestorsArray[a],
+ CSP_VIOLATION_TOPIC,
+ violatedDirective.get());
+ // TODO(sid) generate violation reports and remove NotifyObservers
+ // call. (in bug 994322)
+ // TODO(sid) implement logic for report-only (in bug 994322)
+ *outPermitsAncestry = false;
+ }
+ }
+ }
return NS_OK;
}
diff --git a/content/base/src/nsCSPContext.h b/content/base/src/nsCSPContext.h
index 8855e502b5a5..5c44e9a28fbb 100644
--- a/content/base/src/nsCSPContext.h
+++ b/content/base/src/nsCSPContext.h
@@ -7,6 +7,7 @@
#define nsCSPContext_h___
#include "nsCSPUtils.h"
+#include "nsDataHashtable.h"
#include "nsIChannel.h"
#include "nsIClassInfo.h"
#include "nsIContentSecurityPolicy.h"
@@ -36,8 +37,9 @@ class nsCSPContext : public nsIContentSecurityPolicy
bool* outShouldReportViolations,
bool* outIsAllowed) const;
- nsTArray mPolicies;
- nsCOMPtr mSelfURI;
+ nsTArray mPolicies;
+ nsCOMPtr mSelfURI;
+ nsDataHashtable mShouldLoadCache;
};
#endif /* nsCSPContext_h___ */
diff --git a/content/base/src/nsCSPUtils.cpp b/content/base/src/nsCSPUtils.cpp
index 6d4493a3461b..85c5e33c5008 100644
--- a/content/base/src/nsCSPUtils.cpp
+++ b/content/base/src/nsCSPUtils.cpp
@@ -636,6 +636,8 @@ CSP_DirectiveToContentType(enum CSPDirective aDir)
case CSP_MEDIA_SRC: return nsIContentPolicy::TYPE_MEDIA;
case CSP_OBJECT_SRC: return nsIContentPolicy::TYPE_OBJECT;
case CSP_FRAME_SRC: return nsIContentPolicy::TYPE_SUBDOCUMENT;
+ // TODO(sid): fix this mapping to be more precise (bug 999656)
+ case CSP_FRAME_ANCESTORS: return nsIContentPolicy::TYPE_DOCUMENT;
// Fall through to error for the following Directives:
case CSP_DEFAULT_SRC:
diff --git a/content/base/src/nsCSPUtils.h b/content/base/src/nsCSPUtils.h
index 50be4b21337b..a0aeb41832bb 100644
--- a/content/base/src/nsCSPUtils.h
+++ b/content/base/src/nsCSPUtils.h
@@ -49,22 +49,24 @@ enum CSPDirective {
CSP_FONT_SRC,
CSP_CONNECT_SRC,
CSP_REPORT_URI,
+ CSP_FRAME_ANCESTORS,
// CSP_LAST_DIRECTIVE_VALUE always needs to be the last element in the enum
// because we use it to calculate the size for the char* array.
CSP_LAST_DIRECTIVE_VALUE
};
static const char* CSPStrDirectives[] = {
- "default-src", // CSP_DEFAULT_SRC = 0
- "script-src", // CSP_SCRIPT_SRC
- "object-src", // CSP_OBJECT_SRC
- "style-src", // CSP_STYLE_SRC
- "img-src", // CSP_IMG_SRC
- "media-src", // CSP_MEDIA_SRC
- "frame-src", // CSP_FRAME_SRC
- "font-src", // CSP_FONT_SRC
- "connect-src", // CSP_CONNECT_SRC
- "report-uri", // CSP_REPORT_URI
+ "default-src", // CSP_DEFAULT_SRC = 0
+ "script-src", // CSP_SCRIPT_SRC
+ "object-src", // CSP_OBJECT_SRC
+ "style-src", // CSP_STYLE_SRC
+ "img-src", // CSP_IMG_SRC
+ "media-src", // CSP_MEDIA_SRC
+ "frame-src", // CSP_FRAME_SRC
+ "font-src", // CSP_FONT_SRC
+ "connect-src", // CSP_CONNECT_SRC
+ "report-uri", // CSP_REPORT_URI
+ "frame-ancestors" // CSP_FRAME_ANCESTORS
};
inline const char* CSP_EnumToDirective(enum CSPDirective aDir)
diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp
index 5fba7423afad..ee656e1a6714 100644
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -196,6 +196,7 @@ const char kLoadAsData[] = "loadAsData";
nsIXPConnect *nsContentUtils::sXPConnect;
nsIScriptSecurityManager *nsContentUtils::sSecurityManager;
nsIPrincipal *nsContentUtils::sSystemPrincipal;
+nsIPrincipal *nsContentUtils::sNullSubjectPrincipal;
nsIParserService *nsContentUtils::sParserService = nullptr;
nsNameSpaceManager *nsContentUtils::sNameSpaceManager;
nsIIOService *nsContentUtils::sIOService;
@@ -379,6 +380,7 @@ nsContentUtils::Init()
sSecurityManager->GetSystemPrincipal(&sSystemPrincipal);
MOZ_ASSERT(sSystemPrincipal);
+ NS_ADDREF(sNullSubjectPrincipal = new nsNullPrincipal());
nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
if (NS_FAILED(rv)) {
@@ -1436,6 +1438,7 @@ nsContentUtils::Shutdown()
sXPConnect = nullptr;
NS_IF_RELEASE(sSecurityManager);
NS_IF_RELEASE(sSystemPrincipal);
+ NS_IF_RELEASE(sNullSubjectPrincipal);
NS_IF_RELEASE(sParserService);
NS_IF_RELEASE(sIOService);
NS_IF_RELEASE(sLineBreaker);
@@ -2322,9 +2325,33 @@ nsContentUtils::SubjectPrincipal()
return GetSystemPrincipal();
}
- JSCompartment* compartment = js::GetContextCompartment(cx);
- MOZ_ASSERT(compartment);
- JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
+ JSCompartment *compartment = js::GetContextCompartment(cx);
+
+ // When an AutoJSAPI is instantiated, we are in a null compartment until the
+ // first JSAutoCompartment, which is kind of a purgatory as far as permissions
+ // go. It would be nice to just hard-abort if somebody does a security check
+ // in this purgatory zone, but that would be too fragile, since it could be
+ // triggered by random IsCallerChrome() checks 20-levels deep.
+ //
+ // So we want to return _something_ here - and definitely not the System
+ // Principal, since that would make an AutoJSAPI a very dangerous thing to
+ // instantiate.
+ //
+ // The natural thing to return is a null principal. Ideally, we'd return a
+ // different null principal each time, to avoid any unexpected interactions
+ // when the principal accidentally gets inherited somewhere. But
+ // GetSubjectPrincipal doesn't return strong references, so there's no way to
+ // sanely manage the lifetime of multiple null principals.
+ //
+ // So we use a singleton null principal. To avoid it being accidentally
+ // inherited and becoming a "real" subject or object principal, we do a
+ // release-mode assert during compartment creation against using this
+ // principal on an actual global.
+ if (!compartment) {
+ return sNullSubjectPrincipal;
+ }
+
+ JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
return nsJSPrincipals::get(principals);
}
diff --git a/content/base/test/TestCSPParser.cpp b/content/base/test/TestCSPParser.cpp
index 533ac37a5730..7e29b1f97b80 100644
--- a/content/base/test/TestCSPParser.cpp
+++ b/content/base/test/TestCSPParser.cpp
@@ -667,6 +667,28 @@ nsresult TestGoodGeneratedPolicies() {
"script-src http://policy-uri" },
{ "img-src 'self'; ",
"img-src http://www.selfuri.com" },
+ { "frame-ancestors foo-bar.com",
+ "frame-ancestors http://foo-bar.com" },
+ { "frame-ancestors http://a.com",
+ "frame-ancestors http://a.com" },
+ { "frame-ancestors 'self'",
+ "frame-ancestors http://www.selfuri.com" },
+ { "frame-ancestors http://self.com:88",
+ "frame-ancestors http://self.com:88" },
+ { "frame-ancestors http://a.b.c.d.e.f.g.h.i.j.k.l.x.com",
+ "frame-ancestors http://a.b.c.d.e.f.g.h.i.j.k.l.x.com" },
+ { "frame-ancestors https://self.com:34",
+ "frame-ancestors https://self.com:34" },
+ { "default-src 'none'; frame-ancestors 'self'",
+ "default-src 'none'; frame-ancestors http://www.selfuri.com" },
+ { "frame-ancestors http://self:80",
+ "frame-ancestors http://self:80" },
+ { "frame-ancestors http://self.com/bar",
+ "frame-ancestors http://self.com" },
+ { "default-src 'self'; frame-ancestors 'self'",
+ "default-src http://www.selfuri.com; frame-ancestors http://www.selfuri.com" },
+ { "frame-ancestors http://bar.com/foo.png",
+ "frame-ancestors http://bar.com" },
};
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
diff --git a/content/canvas/test/reftest/reftest.list b/content/canvas/test/reftest/reftest.list
index ce27ccf2b4f2..dca01879c844 100644
--- a/content/canvas/test/reftest/reftest.list
+++ b/content/canvas/test/reftest/reftest.list
@@ -154,15 +154,6 @@ fuzzy(1,65536) random-if(gtk2Widget) fails-if(B2G) fuzzy-if(Android,9,65536) fai
# random-if(B2G) from bug 983650
fuzzy(1,65536) random-if(B2G) fuzzy-if(Android,9,65536) random-if(Android&&AndroidVersion<15) == webgl-color-alpha-test.html?colorVal=0.5&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png
-# Test over-bright premult:
-# random-if(B2G) from bug 983650
-# This test assumes that the compositor is able to correctly handle superluminant
-# pixels in a WebGL canvas with premultiplied alpha. This is not handled by
-# Skia's software blending code. Consequently, this test is random on
-# basic-layers when using skia. See bug 1004483.
-fuzzy(1,65536) random-if(B2G) fuzzy-if(Android,9,65536) random-if(Android&&AndroidVersion<15) random-if(skiaContent&&!layersGPUAccelerated) == webgl-color-alpha-test.html?colorVal=1.0&alphaVal=0.5&alpha&premult wrapper.html?colors-half-alpha.png
-
-
# Check for hanging framebuffer bindings:
random-if(Android&&AndroidVersion<15) == webgl-hanging-fb-test.html?__&________ wrapper.html?green.png
random-if(Android&&AndroidVersion<15) == webgl-hanging-fb-test.html?aa&________ wrapper.html?green.png
diff --git a/content/html/document/src/HTMLAllCollection.cpp b/content/html/document/src/HTMLAllCollection.cpp
index bcc052b1f5fb..38f7b9a007d1 100644
--- a/content/html/document/src/HTMLAllCollection.cpp
+++ b/content/html/document/src/HTMLAllCollection.cpp
@@ -6,43 +6,10 @@
#include "mozilla/dom/HTMLAllCollection.h"
-#include "jsapi.h"
-#include "mozilla/HoldDropJSObjects.h"
-#include "nsContentUtils.h"
-#include "nsDOMClassInfo.h"
+#include "mozilla/dom/HTMLAllCollectionBinding.h"
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/dom/UnionTypes.h"
#include "nsHTMLDocument.h"
-#include "nsJSUtils.h"
-#include "nsWrapperCacheInlines.h"
-#include "xpcpublic.h"
-
-using namespace mozilla;
-using namespace mozilla::dom;
-
-class nsHTMLDocumentSH
-{
-public:
- static bool DocumentAllGetProperty(JSContext *cx, JS::Handle obj, JS::Handle id,
- JS::MutableHandle vp);
- static bool DocumentAllNewResolve(JSContext *cx, JS::Handle obj, JS::Handle id,
- JS::MutableHandle objp);
- static void ReleaseDocument(JSFreeOp *fop, JSObject *obj);
- static bool CallToGetPropMapper(JSContext *cx, unsigned argc, JS::Value *vp);
-};
-
-const JSClass sHTMLDocumentAllClass = {
- "HTML document.all class",
- JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_NEW_RESOLVE |
- JSCLASS_EMULATES_UNDEFINED,
- JS_PropertyStub, /* addProperty */
- JS_DeletePropertyStub, /* delProperty */
- nsHTMLDocumentSH::DocumentAllGetProperty, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- (JSResolveOp)nsHTMLDocumentSH::DocumentAllNewResolve,
- JS_ConvertStub,
- nsHTMLDocumentSH::ReleaseDocument,
- nsHTMLDocumentSH::CallToGetPropMapper
-};
namespace mozilla {
namespace dom {
@@ -51,37 +18,31 @@ HTMLAllCollection::HTMLAllCollection(nsHTMLDocument* aDocument)
: mDocument(aDocument)
{
MOZ_ASSERT(mDocument);
- mozilla::HoldJSObjects(this);
+ SetIsDOMBinding();
}
HTMLAllCollection::~HTMLAllCollection()
{
- mObject = nullptr;
- mozilla::DropJSObjects(this);
}
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(HTMLAllCollection, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(HTMLAllCollection, Release)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLAllCollection,
+ mDocument,
+ mCollection,
+ mNamedMap)
-NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLAllCollection)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLAllCollection)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLAllCollection)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HTMLAllCollection)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCollection)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNamedMap)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLAllCollection)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HTMLAllCollection)
- tmp->mObject = nullptr;
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mCollection)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mNamedMap)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(HTMLAllCollection)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mObject)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
+nsINode*
+HTMLAllCollection::GetParentObject() const
+{
+ return mDocument;
+}
uint32_t
HTMLAllCollection::Length()
@@ -95,32 +56,6 @@ HTMLAllCollection::Item(uint32_t aIndex)
return Collection()->Item(aIndex);
}
-JSObject*
-HTMLAllCollection::GetObject(JSContext* aCx, ErrorResult& aRv)
-{
- MOZ_ASSERT(aCx);
-
- if (!mObject) {
- JS::Rooted wrapper(aCx, mDocument->GetWrapper());
- MOZ_ASSERT(wrapper);
-
- JSAutoCompartment ac(aCx, wrapper);
- JS::Rooted global(aCx, JS_GetGlobalForObject(aCx, wrapper));
- mObject = JS_NewObject(aCx, &sHTMLDocumentAllClass, JS::NullPtr(), global);
- if (!mObject) {
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return nullptr;
- }
-
- // Make the JSObject hold a reference to the document.
- JS_SetPrivate(mObject, ToSupports(mDocument));
- NS_ADDREF(mDocument);
- }
-
- JS::ExposeObjectToActiveJS(mObject);
- return mObject;
-}
-
nsContentList*
HTMLAllCollection::Collection()
{
@@ -186,197 +121,43 @@ HTMLAllCollection::GetDocumentAllList(const nsAString& aID)
return docAllList;
}
-nsISupports*
-HTMLAllCollection::GetNamedItem(const nsAString& aID,
- nsWrapperCache** aCache)
+void
+HTMLAllCollection::NamedGetter(const nsAString& aID,
+ bool& aFound,
+ Nullable& aResult)
{
nsContentList* docAllList = GetDocumentAllList(aID);
if (!docAllList) {
- return nullptr;
+ aFound = false;
+ aResult.SetNull();
+ return;
}
// Check if there are more than 1 entries. Do this by getting the second one
// rather than the length since getting the length always requires walking
// the entire document.
-
- nsIContent* cont = docAllList->Item(1, true);
- if (cont) {
- *aCache = docAllList;
- return static_cast(docAllList);
+ if (docAllList->Item(1, true)) {
+ aFound = true;
+ aResult.SetValue().SetAsHTMLCollection() = docAllList;
+ return;
}
// There's only 0 or 1 items. Return the first one or null.
- *aCache = cont = docAllList->Item(0, true);
- return cont;
+ if (nsIContent* node = docAllList->Item(0, true)) {
+ aFound = true;
+ aResult.SetValue().SetAsNode() = node;
+ return;
+ }
+
+ aFound = false;
+ aResult.SetNull();
+}
+
+JSObject*
+HTMLAllCollection::WrapObject(JSContext* aCx)
+{
+ return HTMLAllCollectionBinding::Wrap(aCx, this);
}
} // namespace dom
} // namespace mozilla
-
-static nsHTMLDocument*
-GetDocument(JSObject *obj)
-{
- MOZ_ASSERT(js::GetObjectJSClass(obj) == &sHTMLDocumentAllClass);
- return static_cast(
- static_cast(JS_GetPrivate(obj)));
-}
-
-bool
-nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JS::Handle obj_,
- JS::Handle id, JS::MutableHandle vp)
-{
- JS::Rooted obj(cx, obj_);
-
- // document.all.item and .namedItem get their value in the
- // newResolve hook, so nothing to do for those properties here. And
- // we need to return early to prevent from shadowing
- // document.all.item(), etc.
- if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
- return true;
- }
-
- JS::Rooted
proto(cx);
- while (js::GetObjectJSClass(obj) != &sHTMLDocumentAllClass) {
- if (!js::GetObjectProto(cx, obj, &proto)) {
- return false;
- }
-
- if (!proto) {
- NS_ERROR("The JS engine lies!");
- return true;
- }
-
- obj = proto;
- }
-
- HTMLAllCollection* allCollection = GetDocument(obj)->All();
- nsISupports *result;
- nsWrapperCache *cache;
-
- if (JSID_IS_STRING(id)) {
- if (nsDOMClassInfo::sLength_id == id) {
- // Make sure doesn't shadow document.all.length.
- vp.setNumber(allCollection->Length());
- return true;
- }
-
- // For all other strings, look for an element by id or name.
- nsDependentJSString str(id);
- result = allCollection->GetNamedItem(str, &cache);
- } else if (JSID_IS_INT(id) && JSID_TO_INT(id) >= 0) {
- // Map document.all[n] (where n is a number) to the n:th item in
- // the document.all node list.
-
- nsIContent* node = allCollection->Item(SafeCast
(JSID_TO_INT(id)));
-
- result = node;
- cache = node;
- } else {
- result = nullptr;
- }
-
- if (result) {
- nsresult rv = nsContentUtils::WrapNative(cx, result, cache, vp);
- if (NS_FAILED(rv)) {
- xpc::Throw(cx, rv);
-
- return false;
- }
- } else {
- vp.setUndefined();
- }
-
- return true;
-}
-
-bool
-nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JS::Handle obj,
- JS::Handle id,
- JS::MutableHandle objp)
-{
- JS::Rooted v(cx);
-
- if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
- // Define the item() or namedItem() method.
-
- JSFunction *fnc = ::JS_DefineFunctionById(cx, obj, id, CallToGetPropMapper,
- 0, JSPROP_ENUMERATE);
- objp.set(obj);
-
- return fnc != nullptr;
- }
-
- if (nsDOMClassInfo::sLength_id == id) {
- // document.all.length. Any jsval other than undefined would do
- // here, all we need is to get into the code below that defines
- // this propery on obj, the rest happens in
- // DocumentAllGetProperty().
-
- v = JSVAL_ONE;
- } else {
- if (!DocumentAllGetProperty(cx, obj, id, &v)) {
- return false;
- }
- }
-
- bool ok = true;
-
- if (v.get() != JSVAL_VOID) {
- ok = ::JS_DefinePropertyById(cx, obj, id, v, 0);
- objp.set(obj);
- }
-
- return ok;
-}
-
-void
-nsHTMLDocumentSH::ReleaseDocument(JSFreeOp *fop, JSObject *obj)
-{
- nsIHTMLDocument* doc = GetDocument(obj);
- if (doc) {
- nsContentUtils::DeferredFinalize(doc);
- }
-}
-
-bool
-nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp)
-{
- JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
- // Handle document.all("foo") style access to document.all.
-
- if (args.length() != 1) {
- // XXX: Should throw NS_ERROR_XPC_NOT_ENOUGH_ARGS for argc < 1,
- // and create a new NS_ERROR_XPC_TOO_MANY_ARGS for argc > 1? IE
- // accepts nothing other than one arg.
- xpc::Throw(cx, NS_ERROR_INVALID_ARG);
-
- return false;
- }
-
- // Convert all types to string.
- JS::Rooted str(cx, JS::ToString(cx, args[0]));
- if (!str) {
- return false;
- }
-
- // If we are called via document.all(id) instead of document.all.item(i) or
- // another method, use the document.all callee object as self.
- JS::Rooted self(cx);
- if (args.calleev().isObject() &&
- JS_GetClass(&args.calleev().toObject()) == &sHTMLDocumentAllClass) {
- self = &args.calleev().toObject();
- } else {
- self = JS_THIS_OBJECT(cx, vp);
- if (!self)
- return false;
- }
-
- size_t length;
- JS::Anchor anchor(str);
- const jschar *chars = ::JS_GetStringCharsAndLength(cx, str, &length);
- if (!chars) {
- return false;
- }
-
- return ::JS_GetUCProperty(cx, self, chars, length, args.rval());
-}
diff --git a/content/html/document/src/HTMLAllCollection.h b/content/html/document/src/HTMLAllCollection.h
index 096018619592..c922700a5739 100644
--- a/content/html/document/src/HTMLAllCollection.h
+++ b/content/html/document/src/HTMLAllCollection.h
@@ -7,49 +7,84 @@
#ifndef mozilla_dom_HTMLAllCollection_h
#define mozilla_dom_HTMLAllCollection_h
-#include "js/RootingAPI.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupportsImpl.h"
#include "nsRefPtrHashtable.h"
+#include "nsWrapperCache.h"
#include
class nsContentList;
class nsHTMLDocument;
class nsIContent;
-class nsWrapperCache;
+class nsINode;
namespace mozilla {
+
class ErrorResult;
namespace dom {
-class HTMLAllCollection
+class OwningNodeOrHTMLCollection;
+template class Nullable;
+
+class HTMLAllCollection MOZ_FINAL : public nsISupports
+ , public nsWrapperCache
{
public:
HTMLAllCollection(nsHTMLDocument* aDocument);
~HTMLAllCollection();
- NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(HTMLAllCollection)
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(HTMLAllCollection)
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(HTMLAllCollection)
+
+ virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+ nsINode* GetParentObject() const;
uint32_t Length();
nsIContent* Item(uint32_t aIndex);
+ void Item(const nsAString& aName, Nullable& aResult)
+ {
+ NamedItem(aName, aResult);
+ }
+ nsIContent* IndexedGetter(uint32_t aIndex, bool& aFound)
+ {
+ nsIContent* result = Item(aIndex);
+ aFound = !!result;
+ return result;
+ }
- JSObject* GetObject(JSContext* aCx, ErrorResult& aRv);
-
- nsISupports* GetNamedItem(const nsAString& aID, nsWrapperCache** aCache);
+ void NamedItem(const nsAString& aName,
+ Nullable& aResult)
+ {
+ bool found = false;
+ NamedGetter(aName, found, aResult);
+ }
+ void NamedGetter(const nsAString& aName,
+ bool& aFound,
+ Nullable& aResult);
+ void GetSupportedNames(unsigned flags, nsTArray& aNames)
+ {
+ }
+ bool NameIsEnumerable(const nsAString& aName)
+ {
+ return false;
+ }
+ void LegacyCall(JS::Handle, const nsAString& aName,
+ Nullable& aResult)
+ {
+ NamedItem(aName, aResult);
+ }
private:
nsContentList* Collection();
/**
- * Returns the NodeList for document.all[aID], or null if there isn't one.
+ * Returns the HTMLCollection for document.all[aID], or null if there isn't one.
*/
nsContentList* GetDocumentAllList(const nsAString& aID);
- JS::Heap mObject;
nsRefPtr mDocument;
nsRefPtr mCollection;
nsRefPtrHashtable mNamedMap;
diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp
index a47e0d0e4eb9..21b48f9d5fad 100644
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -2564,12 +2564,6 @@ nsHTMLDocument::All()
return mAll;
}
-JSObject*
-nsHTMLDocument::GetAll(JSContext* aCx, ErrorResult& aRv)
-{
- return All()->GetObject(aCx, aRv);
-}
-
static void
NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument)
{
diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h
index fccd1c05ab8f..6d894d48f60e 100644
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -104,7 +104,6 @@ public:
NS_DECL_NSIDOMHTMLDOCUMENT
mozilla::dom::HTMLAllCollection* All();
- JSObject* GetAll(JSContext* aCx, mozilla::ErrorResult& aRv);
nsISupports* ResolveName(const nsAString& aName, nsWrapperCache **aCache);
diff --git a/content/media/MediaDecoderReader.h b/content/media/MediaDecoderReader.h
index cc970c1f08a1..cbb06a68cdac 100644
--- a/content/media/MediaDecoderReader.h
+++ b/content/media/MediaDecoderReader.h
@@ -78,16 +78,17 @@ public:
int64_t aEndTime,
int64_t aCurrentTime) = 0;
- // Called to move the reader into idle/active state. When the reader is
+ // Called to move the reader into idle state. When the reader is
// created it is assumed to be active (i.e. not idle). When the media
// element is paused and we don't need to decode any more data, the state
// machine calls SetIdle() to inform the reader that its decoder won't be
- // needed for a while. When we need to decode data again, the state machine
- // calls SetActive() to activate the decoder. The reader can use these
- // notifications to enter/exit a low power state when the decoder isn't
- // needed, if desired. This is most useful on mobile.
+ // needed for a while. The reader can use these notifications to enter
+ // a low power state when the decoder isn't needed, if desired.
+ // This is most useful on mobile.
+ // Note: DecodeVideoFrame, DecodeAudioData, ReadMetadata and Seek should
+ // activate the decoder if necessary. The state machine only needs to know
+ // when to call SetIdle().
virtual void SetIdle() { }
- virtual void SetActive() { }
// Tell the reader that the data decoded are not for direct playback, so it
// can accept more files, in particular those which have more channels than
diff --git a/content/media/MediaDecoderStateMachine.cpp b/content/media/MediaDecoderStateMachine.cpp
index cdd9c9d91909..dc99cb344943 100644
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -194,7 +194,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mAmpleAudioThresholdUsecs(AMPLE_AUDIO_USECS),
mDispatchedAudioDecodeTask(false),
mDispatchedVideoDecodeTask(false),
- mIsReaderIdle(false),
mAudioCaptured(false),
mTransportSeekable(true),
mMediaSeekable(true),
@@ -573,7 +572,6 @@ MediaDecoderStateMachine::DecodeVideo()
mDispatchedVideoDecodeTask = false;
return;
}
- EnsureActive();
// We don't want to consider skipping to the next keyframe if we've
// only just started up the decode loop, so wait until we've decoded
@@ -667,7 +665,6 @@ MediaDecoderStateMachine::DecodeAudio()
mDispatchedAudioDecodeTask = false;
return;
}
- EnsureActive();
// We don't want to consider skipping to the next keyframe if we've
// only just started up the decode loop, so wait until we've decoded
@@ -1499,21 +1496,6 @@ MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
return NS_OK;
}
-void
-MediaDecoderStateMachine::EnsureActive()
-{
- AssertCurrentThreadInMonitor();
- MOZ_ASSERT(OnDecodeThread());
- if (!mIsReaderIdle) {
- return;
- }
- mIsReaderIdle = false;
- {
- ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
- SetReaderActive();
- }
-}
-
void
MediaDecoderStateMachine::SetReaderIdle()
{
@@ -1529,14 +1511,6 @@ MediaDecoderStateMachine::SetReaderIdle()
mReader->SetIdle();
}
-void
-MediaDecoderStateMachine::SetReaderActive()
-{
- DECODER_LOG(PR_LOG_DEBUG, "SetReaderActive()");
- MOZ_ASSERT(OnDecodeThread());
- mReader->SetActive();
-}
-
void
MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
{
@@ -1575,19 +1549,13 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
EnsureVideoDecodeTaskQueued();
}
- if (mIsReaderIdle == needIdle) {
- return;
- }
- mIsReaderIdle = needIdle;
- RefPtr event;
- if (mIsReaderIdle) {
- event = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SetReaderIdle);
- } else {
- event = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SetReaderActive);
- }
- if (NS_FAILED(mDecodeTaskQueue->Dispatch(event.forget())) &&
- mState != DECODER_STATE_SHUTDOWN) {
- NS_WARNING("Failed to dispatch event to set decoder idle state");
+ if (needIdle) {
+ RefPtr event = NS_NewRunnableMethod(
+ this, &MediaDecoderStateMachine::SetReaderIdle);
+ nsresult rv = mDecodeTaskQueue->Dispatch(event.forget());
+ if (NS_FAILED(rv) && mState != DECODER_STATE_SHUTDOWN) {
+ NS_WARNING("Failed to dispatch event to set decoder idle state");
+ }
}
}
@@ -1828,7 +1796,6 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
if (mState != DECODER_STATE_DECODING_METADATA) {
return NS_ERROR_FAILURE;
}
- EnsureActive();
nsresult res;
MediaInfo info;
@@ -1930,7 +1897,6 @@ void MediaDecoderStateMachine::DecodeSeek()
if (mState != DECODER_STATE_SEEKING) {
return;
}
- EnsureActive();
// During the seek, don't have a lock on the decoder state,
// otherwise long seek operations can block the main thread.
diff --git a/content/media/MediaDecoderStateMachine.h b/content/media/MediaDecoderStateMachine.h
index 64e00f3e3aea..549d895a9339 100644
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -565,11 +565,9 @@ protected:
// The decoder monitor must be held.
nsresult EnqueueDecodeSeekTask();
- // Calls the reader's SetIdle(), with aIsIdle as parameter. This is only
- // called in a task dispatched to the decode task queue, don't call it
- // directly.
+ // Calls the reader's SetIdle(). This is only called in a task dispatched to
+ // the decode task queue, don't call it directly.
void SetReaderIdle();
- void SetReaderActive();
// Re-evaluates the state and determines whether we need to dispatch
// events to run the decode, or if not whether we should set the reader
@@ -577,11 +575,6 @@ protected:
// The decoder monitor must be held.
void DispatchDecodeTasksIfNeeded();
- // Called before we do anything on the decode task queue to set the reader
- // as not idle if it was idle. This is called before we decode, seek, or
- // decode metadata (in case we were dormant or awaiting resources).
- void EnsureActive();
-
// Queries our state to see whether the decode has finished for all streams.
// If so, we move into DECODER_STATE_COMPLETED and schedule the state machine
// to run.
@@ -851,12 +844,6 @@ protected:
// the video decode.
bool mDispatchedVideoDecodeTask;
- // True when the reader is initialized, but has been ordered "idle" by the
- // state machine. This happens when the MediaQueue's of decoded data are
- // "full" and playback is paused. The reader may choose to use the idle
- // notification to enter a low power state.
- bool mIsReaderIdle;
-
// If the video decode is falling behind the audio, we'll start dropping the
// inter-frames up until the next keyframe which is at or before the current
// playback position. skipToNextKeyframe is true if we're currently
diff --git a/content/media/mediasource/MediaSourceDecoder.cpp b/content/media/mediasource/MediaSourceDecoder.cpp
index fc4461599f95..30793b2c51dc 100644
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -147,7 +147,6 @@ private:
mActiveVideoDecoder = i;
MSE_DEBUG("%p MSR::DecodeVF switching to %d", this, mActiveVideoDecoder);
- GetVideoReader()->SetActive();
return true;
}
}
@@ -326,7 +325,6 @@ MediaSourceReader::CallDecoderInitialization()
MediaDecoderReader* reader = decoder->GetReader();
MSE_DEBUG("%p: Initializating subdecoder %p reader %p", this, decoder.get(), reader);
- reader->SetActive();
MediaInfo mi;
nsAutoPtr tags; // TODO: Handle metadata.
nsresult rv;
@@ -456,8 +454,6 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
MediaDecoderReader* reader = mDecoders[i]->GetReader();
- reader->SetActive(); // XXX check where this should be called
-
MediaInfo mi = reader->GetMediaInfo();
if (mi.HasVideo() && !mInfo.HasVideo()) {
diff --git a/content/media/omx/MediaOmxReader.cpp b/content/media/omx/MediaOmxReader.cpp
index 738cfc9529fb..8960fa80b428 100644
--- a/content/media/omx/MediaOmxReader.cpp
+++ b/content/media/omx/MediaOmxReader.cpp
@@ -47,9 +47,6 @@ MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
, mVideoSeekTimeUs(-1)
, mAudioSeekTimeUs(-1)
, mSkipCount(0)
-#ifdef DEBUG
- , mIsActive(true)
-#endif
{
#ifdef PR_LOGGING
if (!gMediaDecoderLog) {
@@ -135,7 +132,7 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags)
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
- MOZ_ASSERT(mIsActive);
+ EnsureActive();
*aTags = nullptr;
@@ -211,7 +208,8 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
int64_t aTimeThreshold)
{
- MOZ_ASSERT(mIsActive);
+ NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
+ EnsureActive();
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
@@ -341,7 +339,7 @@ void MediaOmxReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, in
bool MediaOmxReader::DecodeAudioData()
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
- MOZ_ASSERT(mIsActive);
+ EnsureActive();
// This is the approximate byte position in the stream.
int64_t pos = mDecoder->GetResource()->Tell();
@@ -375,7 +373,7 @@ bool MediaOmxReader::DecodeAudioData()
nsresult MediaOmxReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime)
{
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
- MOZ_ASSERT(mIsActive);
+ EnsureActive();
ResetDecode();
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
@@ -410,19 +408,13 @@ static uint64_t BytesToTime(int64_t offset, uint64_t length, uint64_t durationUs
}
void MediaOmxReader::SetIdle() {
-#ifdef DEBUG
- mIsActive = false;
-#endif
if (!mOmxDecoder.get()) {
return;
}
mOmxDecoder->Pause();
}
-void MediaOmxReader::SetActive() {
-#ifdef DEBUG
- mIsActive = true;
-#endif
+void MediaOmxReader::EnsureActive() {
if (!mOmxDecoder.get()) {
return;
}
diff --git a/content/media/omx/MediaOmxReader.h b/content/media/omx/MediaOmxReader.h
index ca47b29bce11..7daa3450ca6f 100644
--- a/content/media/omx/MediaOmxReader.h
+++ b/content/media/omx/MediaOmxReader.h
@@ -49,6 +49,10 @@ protected:
// information used for creating OMX decoder such as video/audio codec.
virtual nsresult InitOmxDecoder();
+ // Called inside DecodeVideoFrame, DecodeAudioData, ReadMetadata and Seek
+ // to activate the decoder automatically.
+ virtual void EnsureActive();
+
public:
MediaOmxReader(AbstractMediaDecoder* aDecoder);
~MediaOmxReader();
@@ -83,7 +87,6 @@ public:
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime);
virtual void SetIdle() MOZ_OVERRIDE;
- virtual void SetActive() MOZ_OVERRIDE;
void SetAudioChannel(dom::AudioChannel aAudioChannel) {
mAudioChannel = aAudioChannel;
@@ -99,12 +102,6 @@ public:
// ANDROID_VERSION < 19
void CheckAudioOffload();
#endif
-
-private:
- // This flag is true when SetActive() has been called without a matching
- // SetIdle(). This is used to sanity check the SetIdle/SetActive calls, to
- // ensure SetActive has been called before a decode call.
- DebugOnly mIsActive;
};
} // namespace mozilla
diff --git a/content/media/omx/OmxDecoder.cpp b/content/media/omx/OmxDecoder.cpp
index 02eda270bac5..12b4f4bf9cca 100644
--- a/content/media/omx/OmxDecoder.cpp
+++ b/content/media/omx/OmxDecoder.cpp
@@ -779,6 +779,7 @@ bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs,
if (aDoSeek) {
{
Mutex::Autolock autoLock(mSeekLock);
+ ReleaseAllPendingVideoBuffersLocked();
mIsVideoSeeking = true;
}
MediaSource::ReadOptions options;
diff --git a/content/media/omx/RtspOmxReader.cpp b/content/media/omx/RtspOmxReader.cpp
index 07d81d1286d0..91cede16986e 100644
--- a/content/media/omx/RtspOmxReader.cpp
+++ b/content/media/omx/RtspOmxReader.cpp
@@ -299,18 +299,6 @@ nsresult RtspOmxReader::Seek(int64_t aTime, int64_t aStartTime,
return MediaOmxReader::Seek(aTime, aStartTime, aEndTime, aCurrentTime);
}
-nsresult
-RtspOmxReader::ReadMetadata(MediaInfo* aInfo,
- MetadataTags** aTags)
-{
- SetActive();
-
- nsresult rv = MediaOmxReader::ReadMetadata(aInfo, aTags);
- NS_ENSURE_SUCCESS(rv, rv);
-
- return NS_OK;
-}
-
void RtspOmxReader::SetIdle() {
// Call parent class to set OMXCodec idle.
MediaOmxReader::SetIdle();
@@ -326,7 +314,7 @@ void RtspOmxReader::SetIdle() {
}
}
-void RtspOmxReader::SetActive() {
+void RtspOmxReader::EnsureActive() {
// Need to start RTSP streaming OMXCodec decoding.
if (mRtspResource) {
nsIStreamingProtocolController* controller =
@@ -338,7 +326,7 @@ void RtspOmxReader::SetActive() {
}
// Call parent class to set OMXCodec active.
- MediaOmxReader::SetActive();
+ MediaOmxReader::EnsureActive();
}
} // namespace mozilla
diff --git a/content/media/omx/RtspOmxReader.h b/content/media/omx/RtspOmxReader.h
index 9c811fe96c4c..341367973c27 100644
--- a/content/media/omx/RtspOmxReader.h
+++ b/content/media/omx/RtspOmxReader.h
@@ -28,6 +28,7 @@ class RtspOmxReader : public MediaOmxReader
protected:
// Provide a Rtsp extractor.
nsresult InitOmxDecoder() MOZ_FINAL MOZ_OVERRIDE;
+ virtual void EnsureActive() MOZ_OVERRIDE;
public:
RtspOmxReader(AbstractMediaDecoder* aDecoder)
@@ -44,9 +45,6 @@ public:
MOZ_COUNT_DTOR(RtspOmxReader);
}
- virtual nsresult ReadMetadata(MediaInfo* aInfo,
- MetadataTags** aTags) MOZ_OVERRIDE;
-
// Implement a time-based seek instead of byte-based..
virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
int64_t aCurrentTime) MOZ_FINAL MOZ_OVERRIDE;
@@ -66,7 +64,6 @@ public:
}
virtual void SetIdle() MOZ_OVERRIDE;
- virtual void SetActive() MOZ_OVERRIDE;
private:
// A pointer to RtspMediaResource for calling the Rtsp specific function.
diff --git a/content/svg/content/src/SVGTransformableElement.cpp b/content/svg/content/src/SVGTransformableElement.cpp
index 07dfbcf04e5a..f72123189440 100644
--- a/content/svg/content/src/SVGTransformableElement.cpp
+++ b/content/svg/content/src/SVGTransformableElement.cpp
@@ -5,6 +5,7 @@
#include "gfx2DGlue.h"
#include "mozilla/dom/SVGAnimatedTransformList.h"
+#include "mozilla/dom/SVGGraphicsElementBinding.h"
#include "mozilla/dom/SVGTransformableElement.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGSVGElement.h"
@@ -182,7 +183,8 @@ SVGTransformableElement::GetFarthestViewportElement()
}
already_AddRefed
-SVGTransformableElement::GetBBox(ErrorResult& rv)
+SVGTransformableElement::GetBBox(const SVGBoundingBoxOptions& aOptions,
+ ErrorResult& rv)
{
nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
@@ -190,14 +192,37 @@ SVGTransformableElement::GetBBox(ErrorResult& rv)
rv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
-
nsISVGChildFrame* svgframe = do_QueryFrame(frame);
if (!svgframe) {
rv.Throw(NS_ERROR_NOT_IMPLEMENTED); // XXX: outer svg
return nullptr;
}
- return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame)));
+ if (!NS_SVGNewGetBBoxEnabled()) {
+ return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame)));
+ } else {
+ uint32_t aFlags = 0;
+ if (aOptions.mFill) {
+ aFlags |= nsSVGUtils::eBBoxIncludeFill;
+ }
+ if (aOptions.mStroke) {
+ aFlags |= nsSVGUtils::eBBoxIncludeStroke;
+ }
+ if (aOptions.mMarkers) {
+ aFlags |= nsSVGUtils::eBBoxIncludeMarkers;
+ }
+ if (aOptions.mClipped) {
+ aFlags |= nsSVGUtils::eBBoxIncludeClipped;
+ }
+ if (aFlags == 0) {
+ return NS_NewSVGRect(this,0,0,0,0);
+ }
+ if (aFlags == nsSVGUtils::eBBoxIncludeMarkers ||
+ aFlags == nsSVGUtils::eBBoxIncludeClipped) {
+ aFlags |= nsSVGUtils::eBBoxIncludeFill;
+ }
+ return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame, aFlags)));
+ }
}
already_AddRefed
diff --git a/content/svg/content/src/SVGTransformableElement.h b/content/svg/content/src/SVGTransformableElement.h
index 13dba659d7d3..33787ac9ce3d 100644
--- a/content/svg/content/src/SVGTransformableElement.h
+++ b/content/svg/content/src/SVGTransformableElement.h
@@ -19,6 +19,7 @@ class SVGAnimatedTransformList;
class SVGGraphicsElement;
class SVGMatrix;
class SVGIRect;
+class SVGBoundingBoxOptions;
class SVGTransformableElement : public nsSVGElement
{
@@ -33,7 +34,8 @@ public:
already_AddRefed Transform();
nsSVGElement* GetNearestViewportElement();
nsSVGElement* GetFarthestViewportElement();
- already_AddRefed GetBBox(ErrorResult& rv);
+ already_AddRefed GetBBox(const SVGBoundingBoxOptions& aOptions,
+ ErrorResult& rv);
already_AddRefed GetCTM();
already_AddRefed GetScreenCTM();
already_AddRefed GetTransformToElement(SVGGraphicsElement& aElement,
diff --git a/content/svg/content/test/getBBox-method-helper.svg b/content/svg/content/test/getBBox-method-helper.svg
new file mode 100644
index 000000000000..acf8c8365b25
--- /dev/null
+++ b/content/svg/content/test/getBBox-method-helper.svg
@@ -0,0 +1,299 @@
+
+
diff --git a/content/svg/content/test/mochitest.ini b/content/svg/content/test/mochitest.ini
index bf2f6d3109d8..6f38a9d10247 100644
--- a/content/svg/content/test/mochitest.ini
+++ b/content/svg/content/test/mochitest.ini
@@ -9,6 +9,7 @@ support-files =
animated-svg-image-helper.svg
bbox-helper.svg
bounds-helper.svg
+ getBBox-method-helper.svg
dataTypes-helper.svg
fragments-helper.svg
getCTM-helper.svg
@@ -34,6 +35,7 @@ support-files =
[test_bbox.xhtml]
[test_bounds.html]
[test_bug872812.html]
+[test_getBBox-method.html]
[test_dataTypes.html]
[test_dataTypesModEvents.html]
[test_fragments.html]
diff --git a/content/svg/content/test/test_getBBox-method.html b/content/svg/content/test/test_getBBox-method.html
new file mode 100644
index 000000000000..0f200634cd7a
--- /dev/null
+++ b/content/svg/content/test/test_getBBox-method.html
@@ -0,0 +1,249 @@
+
+
+
+
+ Test case for Bug 999964
+
+
+
+
+
+Mozilla Bug 999964
+
+
+
+
+
+
+
+
+
+