mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 12:25:53 +00:00
Merge m-c to elm.
This commit is contained in:
commit
f8b82bf7ff
@ -23,6 +23,7 @@
|
||||
#include "Relation.h"
|
||||
#include "RootAccessible.h"
|
||||
#include "States.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
#include "nsXPCOMStrings.h"
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nsFontMetrics.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "HyperTextAccessible.h"
|
||||
#include "mozilla/AppUnits.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
@ -504,7 +505,7 @@ TextAttrsMgr::FontSizeTextAttr::
|
||||
//
|
||||
// XXX todo: consider sharing this code with layout module? (bug 474621)
|
||||
float px =
|
||||
NSAppUnitsToFloatPixels(aValue, nsDeviceContext::AppUnitsPerCSSPixel());
|
||||
NSAppUnitsToFloatPixels(aValue, mozilla::AppUnitsPerCSSPixel());
|
||||
// Each pt is 4/3 of a CSS pixel.
|
||||
int pts = NS_lround(px*3/4);
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "nsIAccessibleStates.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
|
@ -74,10 +74,11 @@ DocAccessible::
|
||||
DocAccessible(nsIDocument* aDocument, nsIContent* aRootContent,
|
||||
nsIPresShell* aPresShell) :
|
||||
HyperTextAccessibleWrap(aRootContent, this),
|
||||
mDocumentNode(aDocument), mScrollPositionChangedTicks(0),
|
||||
// XXX aaronl should we use an algorithm for the initial cache size?
|
||||
mAccessibleCache(kDefaultCacheSize),
|
||||
mNodeToAccessibleMap(kDefaultCacheSize),
|
||||
mDocumentNode(aDocument),
|
||||
mScrollPositionChangedTicks(0),
|
||||
mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
|
||||
mVirtualCursor(nullptr),
|
||||
mPresShell(aPresShell)
|
||||
|
@ -498,90 +498,30 @@ var Output = {
|
||||
speechHelper: {
|
||||
EARCONS: ['chrome://global/content/accessibility/tick.wav'],
|
||||
|
||||
delayedActions: [],
|
||||
|
||||
earconsToLoad: -1, // -1: not inited, 1 or more: initing, 0: inited
|
||||
|
||||
earconBuffers: {},
|
||||
|
||||
webaudioEnabled: false,
|
||||
inited: false,
|
||||
|
||||
webspeechEnabled: false,
|
||||
|
||||
doDelayedActionsIfLoaded: function doDelayedActionsIfLoaded(aToLoadCount) {
|
||||
if (aToLoadCount === 0) {
|
||||
this.outputActions(this.delayedActions);
|
||||
this.delayedActions = [];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
init: function init() {
|
||||
if (this.earconsToLoad === 0) {
|
||||
// Already inited.
|
||||
return;
|
||||
}
|
||||
|
||||
let window = Utils.win;
|
||||
this.webaudioEnabled = !!window.AudioContext;
|
||||
this.webspeechEnabled = !!window.speechSynthesis;
|
||||
|
||||
this.earconsToLoad = this.webaudioEnabled ? this.EARCONS.length : 0;
|
||||
|
||||
if (this.doDelayedActionsIfLoaded(this.earconsToLoad)) {
|
||||
// Nothing to load
|
||||
return;
|
||||
}
|
||||
|
||||
this.audioContext = new window.AudioContext();
|
||||
|
||||
for (let earcon of this.EARCONS) {
|
||||
let xhr = new window.XMLHttpRequest();
|
||||
xhr.open('GET', earcon);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.onerror = () => {
|
||||
Logger.error('Error getting earcon:', xhr.statusText);
|
||||
this.doDelayedActionsIfLoaded(--this.earconsToLoad);
|
||||
};
|
||||
xhr.onload = () => {
|
||||
this.audioContext.decodeAudioData(
|
||||
xhr.response,
|
||||
(audioBuffer) => {
|
||||
try {
|
||||
let earconName = /.*\/(.*)\..*$/.exec(earcon)[1];
|
||||
this.earconBuffers[earconName] = new WeakMap();
|
||||
this.earconBuffers[earconName].set(window, audioBuffer);
|
||||
this.doDelayedActionsIfLoaded(--this.earconsToLoad);
|
||||
} catch (x) {
|
||||
Logger.logException(x);
|
||||
}
|
||||
},
|
||||
() => {
|
||||
this.doDelayedActionsIfLoaded(--this.earconsToLoad);
|
||||
Logger.error('Error decoding earcon');
|
||||
});
|
||||
};
|
||||
xhr.send();
|
||||
let earconName = /.*\/(.*)\..*$/.exec(earcon)[1];
|
||||
this.earconBuffers[earconName] = new WeakMap();
|
||||
this.earconBuffers[earconName].set(window, new window.Audio(earcon));
|
||||
}
|
||||
|
||||
this.inited = true;
|
||||
},
|
||||
|
||||
output: function output(aActions) {
|
||||
if (this.earconsToLoad !== 0) {
|
||||
// We did not load the earcons yet.
|
||||
this.delayedActions.push.apply(this.delayedActions, aActions);
|
||||
if (this.earconsToLoad < 0) {
|
||||
// Loading did not start yet, start it.
|
||||
this.init();
|
||||
}
|
||||
return;
|
||||
if (!this.inited) {
|
||||
this.init();
|
||||
}
|
||||
|
||||
this.outputActions(aActions);
|
||||
},
|
||||
|
||||
outputActions: function outputActions(aActions) {
|
||||
for (let action of aActions) {
|
||||
let window = Utils.win;
|
||||
Logger.info('tts.' + action.method,
|
||||
@ -595,13 +535,10 @@ var Output = {
|
||||
if (action.method === 'speak' && this.webspeechEnabled) {
|
||||
window.speechSynthesis.speak(
|
||||
new window.SpeechSynthesisUtterance(action.data));
|
||||
} else if (action.method === 'playEarcon' && this.webaudioEnabled) {
|
||||
} else if (action.method === 'playEarcon') {
|
||||
let audioBufferWeakMap = this.earconBuffers[action.data];
|
||||
if (audioBufferWeakMap) {
|
||||
let node = this.audioContext.createBufferSource();
|
||||
node.connect(this.audioContext.destination);
|
||||
node.buffer = audioBufferWeakMap.get(window);
|
||||
node.start(0);
|
||||
audioBufferWeakMap.get(window).cloneNode(false).play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -798,6 +735,9 @@ var Input = {
|
||||
case 'swipeleft1':
|
||||
this.moveCursor('movePrevious', 'Simple', 'gesture');
|
||||
break;
|
||||
case 'exploreend1':
|
||||
this.activateCurrent(null, true);
|
||||
break;
|
||||
case 'swiperight2':
|
||||
this.sendScrollMessage(-1, true);
|
||||
break;
|
||||
@ -938,12 +878,13 @@ var Input = {
|
||||
mm.sendAsyncMessage(type, aDetails);
|
||||
},
|
||||
|
||||
activateCurrent: function activateCurrent(aData) {
|
||||
activateCurrent: function activateCurrent(aData, aActivateIfKey = false) {
|
||||
let mm = Utils.getMessageManager(Utils.CurrentBrowser);
|
||||
let offset = aData && typeof aData.keyIndex === 'number' ?
|
||||
aData.keyIndex - Output.brailleState.startOffset : -1;
|
||||
|
||||
mm.sendAsyncMessage('AccessFu:Activate', {offset: offset});
|
||||
mm.sendAsyncMessage('AccessFu:Activate',
|
||||
{offset: offset, activateIfKey: aActivateIfKey});
|
||||
},
|
||||
|
||||
sendContextMenuMessage: function sendContextMenuMessage() {
|
||||
|
@ -428,10 +428,10 @@ TouchPoint.prototype = {
|
||||
}
|
||||
|
||||
// To be considered an explore...
|
||||
if (!this.done &&
|
||||
duration > TouchAdapter.SWIPE_MAX_DURATION &&
|
||||
if (duration > TouchAdapter.SWIPE_MAX_DURATION &&
|
||||
(this.distanceTraveled / this.dpi) > TouchAdapter.TAP_MAX_RADIUS) {
|
||||
return {type: 'explore', x: this.x, y: this.y};
|
||||
return {type: this.done ? 'exploreend' : 'explore',
|
||||
x: this.x, y: this.y};
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -31,6 +31,7 @@ const ROLE_CHECK_MENU_ITEM = Ci.nsIAccessibleRole.ROLE_CHECK_MENU_ITEM;
|
||||
const ROLE_PASSWORD_TEXT = Ci.nsIAccessibleRole.ROLE_PASSWORD_TEXT;
|
||||
const ROLE_RADIO_MENU_ITEM = Ci.nsIAccessibleRole.ROLE_RADIO_MENU_ITEM;
|
||||
const ROLE_TOGGLE_BUTTON = Ci.nsIAccessibleRole.ROLE_TOGGLE_BUTTON;
|
||||
const ROLE_KEY = Ci.nsIAccessibleRole.ROLE_KEY;
|
||||
const ROLE_ENTRY = Ci.nsIAccessibleRole.ROLE_ENTRY;
|
||||
const ROLE_LIST = Ci.nsIAccessibleRole.ROLE_LIST;
|
||||
const ROLE_DEFINITION_LIST = Ci.nsIAccessibleRole.ROLE_DEFINITION_LIST;
|
||||
@ -104,6 +105,7 @@ var gSimpleTraversalRoles =
|
||||
ROLE_RADIO_MENU_ITEM,
|
||||
ROLE_TOGGLE_BUTTON,
|
||||
ROLE_ENTRY,
|
||||
ROLE_KEY,
|
||||
ROLE_HEADER,
|
||||
ROLE_HEADING,
|
||||
// Used for traversing in to child OOP frames.
|
||||
|
@ -164,6 +164,12 @@ function forwardToChild(aMessage, aListener, aVCPosition) {
|
||||
function activateCurrent(aMessage) {
|
||||
Logger.debug('activateCurrent');
|
||||
function activateAccessible(aAccessible) {
|
||||
if (aMessage.json.activateIfKey &&
|
||||
aAccessible.role != Ci.nsIAccessibleRole.ROLE_KEY) {
|
||||
// Only activate keys, don't do anything on other objects.
|
||||
return;
|
||||
}
|
||||
|
||||
if (aAccessible.actionCount > 0) {
|
||||
aAccessible.doAction(0);
|
||||
} else {
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "oleacc.h"
|
||||
#include "nsIAccessibleTypes.h"
|
||||
#include "nsIPersistentProperties2.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
|
@ -31,7 +31,7 @@ this.Keyboard = {
|
||||
if (this._messageManager && !Cu.isDeadWrapper(this._messageManager))
|
||||
return this._messageManager;
|
||||
|
||||
throw Error('no message manager set');
|
||||
return null;
|
||||
},
|
||||
|
||||
set messageManager(mm) {
|
||||
@ -92,6 +92,10 @@ this.Keyboard = {
|
||||
// If we get a 'Keyboard:XXX' message, check that the sender has the
|
||||
// keyboard permission.
|
||||
if (msg.name.indexOf("Keyboard:") != -1) {
|
||||
if (!this.messageManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mm;
|
||||
try {
|
||||
mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
|
@ -199,15 +199,51 @@ MozKeyboard.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
const TESTING_ENABLED_PREF = "dom.mozInputMethod.testing";
|
||||
|
||||
/*
|
||||
* A WeakMap to map input method iframe window to its active status.
|
||||
*/
|
||||
let WindowMap = {
|
||||
// WeakMap of <window, boolean> pairs.
|
||||
_map: null,
|
||||
|
||||
/*
|
||||
* Check if the given window is active.
|
||||
*/
|
||||
isActive: function(win) {
|
||||
if (!this._map || !win) {
|
||||
return false;
|
||||
}
|
||||
return this._map.get(win, false);
|
||||
},
|
||||
|
||||
/*
|
||||
* Set the active status of the given window.
|
||||
*/
|
||||
setActive: function(win, isActive) {
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
if (!this._map) {
|
||||
this._map = new WeakMap();
|
||||
}
|
||||
this._map.set(win, isActive);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ==============================================
|
||||
* InputMethodManager
|
||||
* ==============================================
|
||||
*/
|
||||
function MozInputMethodManager() { }
|
||||
function MozInputMethodManager(win) {
|
||||
this._window = win;
|
||||
}
|
||||
|
||||
MozInputMethodManager.prototype = {
|
||||
_supportsSwitching: false,
|
||||
_window: null,
|
||||
|
||||
classID: Components.ID("{7e9d7280-ef86-11e2-b778-0800200c9a66}"),
|
||||
|
||||
@ -224,18 +260,30 @@ MozInputMethodManager.prototype = {
|
||||
}),
|
||||
|
||||
showAll: function() {
|
||||
if (!WindowMap.isActive(this._window)) {
|
||||
return;
|
||||
}
|
||||
cpmm.sendAsyncMessage('Keyboard:ShowInputMethodPicker', {});
|
||||
},
|
||||
|
||||
next: function() {
|
||||
if (!WindowMap.isActive(this._window)) {
|
||||
return;
|
||||
}
|
||||
cpmm.sendAsyncMessage('Keyboard:SwitchToNextInputMethod', {});
|
||||
},
|
||||
|
||||
supportsSwitching: function() {
|
||||
if (!WindowMap.isActive(this._window)) {
|
||||
return false;
|
||||
}
|
||||
return this._supportsSwitching;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (!WindowMap.isActive(this._window)) {
|
||||
return;
|
||||
}
|
||||
cpmm.sendAsyncMessage('Keyboard:RemoveFocus', {});
|
||||
}
|
||||
};
|
||||
@ -250,6 +298,7 @@ function MozInputMethod() { }
|
||||
MozInputMethod.prototype = {
|
||||
_inputcontext: null,
|
||||
_layouts: {},
|
||||
_window: null,
|
||||
|
||||
classID: Components.ID("{4607330d-e7d2-40a4-9eb8-43967eae0142}"),
|
||||
|
||||
@ -268,17 +317,26 @@ MozInputMethod.prototype = {
|
||||
}),
|
||||
|
||||
init: function mozInputMethodInit(win) {
|
||||
let principal = win.document.nodePrincipal;
|
||||
let perm = Services.perms
|
||||
.testExactPermissionFromPrincipal(principal, "keyboard");
|
||||
if (perm != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
dump("No permission to use the keyboard API for " +
|
||||
principal.origin + "\n");
|
||||
return null;
|
||||
// Check if we're in testing mode.
|
||||
let isTesting = false;
|
||||
try {
|
||||
isTesting = Services.prefs.getBoolPref(TESTING_ENABLED_PREF);
|
||||
} catch (e) {}
|
||||
|
||||
// Don't bypass the permission check if not in testing mode.
|
||||
if (!isTesting) {
|
||||
let principal = win.document.nodePrincipal;
|
||||
let perm = Services.perms
|
||||
.testExactPermissionFromPrincipal(principal, "keyboard");
|
||||
if (perm != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
dump("No permission to use the keyboard API for " +
|
||||
principal.origin + "\n");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
this._window = win;
|
||||
this._mgmt = new MozInputMethodManager();
|
||||
this._mgmt = new MozInputMethodManager(win);
|
||||
this.innerWindowID = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.currentInnerWindowID;
|
||||
@ -288,11 +346,6 @@ MozInputMethod.prototype = {
|
||||
cpmm.addMessageListener('Keyboard:SelectionChange', this);
|
||||
cpmm.addMessageListener('Keyboard:GetContext:Result:OK', this);
|
||||
cpmm.addMessageListener('Keyboard:LayoutsChange', this);
|
||||
|
||||
// If there already is an active context, then this will trigger
|
||||
// a GetContext:Result:OK event, and we can initialize ourselves.
|
||||
// Otherwise silently ignored.
|
||||
cpmm.sendAsyncMessage("Keyboard:GetContext", {});
|
||||
},
|
||||
|
||||
uninit: function mozInputMethodUninit() {
|
||||
@ -307,6 +360,10 @@ MozInputMethod.prototype = {
|
||||
},
|
||||
|
||||
receiveMessage: function mozInputMethodReceiveMsg(msg) {
|
||||
if (!WindowMap.isActive(this._window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let json = msg.json;
|
||||
|
||||
switch(msg.name) {
|
||||
@ -338,11 +395,18 @@ MozInputMethod.prototype = {
|
||||
},
|
||||
|
||||
get mgmt() {
|
||||
if (!WindowMap.isActive(this._window)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._mgmt;
|
||||
},
|
||||
|
||||
get inputcontext() {
|
||||
return this._inputcontext;
|
||||
if (!WindowMap.isActive(this._window)) {
|
||||
return null;
|
||||
}
|
||||
return this._inputcontext;
|
||||
},
|
||||
|
||||
set oninputcontextchange(handler) {
|
||||
@ -372,6 +436,27 @@ MozInputMethod.prototype = {
|
||||
let event = new this._window.Event("inputcontextchange",
|
||||
ObjectWrapper.wrap({}, this._window));
|
||||
this.__DOM_IMPL__.dispatchEvent(event);
|
||||
},
|
||||
|
||||
setActive: function mozInputMethodSetActive(isActive) {
|
||||
if (WindowMap.isActive(this._window) === isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
WindowMap.setActive(this._window, isActive);
|
||||
|
||||
if (isActive) {
|
||||
// Activate current input method.
|
||||
// If there is already an active context, then this will trigger
|
||||
// a GetContext:Result:OK event, and we can initialize ourselves.
|
||||
// Otherwise silently ignored.
|
||||
cpmm.sendAsyncMessage("Keyboard:GetContext", {});
|
||||
} else {
|
||||
// Deactive current input method.
|
||||
if (this._inputcontext) {
|
||||
this.setInputContext(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -400,6 +485,7 @@ function MozInputContext(ctx) {
|
||||
MozInputContext.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
_window: null,
|
||||
_context: null,
|
||||
_contextId: -1,
|
||||
|
||||
@ -452,6 +538,8 @@ MozInputContext.prototype = {
|
||||
this._context[k] = null;
|
||||
}
|
||||
}
|
||||
|
||||
this._window = null;
|
||||
},
|
||||
|
||||
receiveMessage: function ic_receiveMessage(msg) {
|
||||
@ -558,8 +646,7 @@ MozInputContext.prototype = {
|
||||
|
||||
getText: function ic_getText(offset, length) {
|
||||
let self = this;
|
||||
return this.createPromise(function(resolve, reject) {
|
||||
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
return this._sendPromise(function(resolverId) {
|
||||
cpmm.sendAsyncMessage('Keyboard:GetText', {
|
||||
contextId: self._contextId,
|
||||
requestId: resolverId,
|
||||
@ -587,8 +674,7 @@ MozInputContext.prototype = {
|
||||
|
||||
setSelectionRange: function ic_setSelectionRange(start, length) {
|
||||
let self = this;
|
||||
return this.createPromise(function(resolve, reject) {
|
||||
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
return this._sendPromise(function(resolverId) {
|
||||
cpmm.sendAsyncMessage("Keyboard:SetSelectionRange", {
|
||||
contextId: self._contextId,
|
||||
requestId: resolverId,
|
||||
@ -616,8 +702,7 @@ MozInputContext.prototype = {
|
||||
|
||||
replaceSurroundingText: function ic_replaceSurrText(text, offset, length) {
|
||||
let self = this;
|
||||
return this.createPromise(function(resolve, reject) {
|
||||
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
return this._sendPromise(function(resolverId) {
|
||||
cpmm.sendAsyncMessage('Keyboard:ReplaceSurroundingText', {
|
||||
contextId: self._contextId,
|
||||
requestId: resolverId,
|
||||
@ -634,8 +719,7 @@ MozInputContext.prototype = {
|
||||
|
||||
sendKey: function ic_sendKey(keyCode, charCode, modifiers) {
|
||||
let self = this;
|
||||
return this.createPromise(function(resolve, reject) {
|
||||
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
return this._sendPromise(function(resolverId) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SendKey', {
|
||||
contextId: self._contextId,
|
||||
requestId: resolverId,
|
||||
@ -648,8 +732,7 @@ MozInputContext.prototype = {
|
||||
|
||||
setComposition: function ic_setComposition(text, cursor, clauses) {
|
||||
let self = this;
|
||||
return this.createPromise(function(resolve, reject) {
|
||||
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
return this._sendPromise(function(resolverId) {
|
||||
cpmm.sendAsyncMessage('Keyboard:SetComposition', {
|
||||
contextId: self._contextId,
|
||||
requestId: resolverId,
|
||||
@ -662,14 +745,26 @@ MozInputContext.prototype = {
|
||||
|
||||
endComposition: function ic_endComposition(text) {
|
||||
let self = this;
|
||||
return this.createPromise(function(resolve, reject) {
|
||||
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
return this._sendPromise(function(resolverId) {
|
||||
cpmm.sendAsyncMessage('Keyboard:EndComposition', {
|
||||
contextId: self._contextId,
|
||||
requestId: resolverId,
|
||||
text: text || ''
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_sendPromise: function(callback) {
|
||||
let self = this;
|
||||
return this.createPromise(function(resolve, reject) {
|
||||
let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
|
||||
if (!WindowMap.isActive(self._window)) {
|
||||
self.removePromiseResolver(resolverId);
|
||||
reject('Input method is not active.');
|
||||
return;
|
||||
}
|
||||
callback(resolverId);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "c062ff36671ed3b1249428ad098dc70615e5e612",
|
||||
"revision": "e03c317f861e6c01078b358321ef8f576ca81377",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -378,6 +378,8 @@
|
||||
@BINPATH@/components/PeerConnection.js
|
||||
@BINPATH@/components/PeerConnection.manifest
|
||||
#endif
|
||||
@BINPATH@/components/HttpDataUsage.manifest
|
||||
@BINPATH@/components/HttpDataUsage.js
|
||||
@BINPATH@/components/SiteSpecificUserAgent.js
|
||||
@BINPATH@/components/SiteSpecificUserAgent.manifest
|
||||
@BINPATH@/components/storage-Legacy.js
|
||||
|
@ -549,6 +549,7 @@ let gHistorySwipeAnimation = {
|
||||
this.isLTR = document.documentElement.mozMatchesSelector(
|
||||
":-moz-locale-dir(ltr)");
|
||||
this._trackedSnapshots = [];
|
||||
this._startingIndex = -1;
|
||||
this._historyIndex = -1;
|
||||
this._boxWidth = -1;
|
||||
this._maxSnapshots = this._getMaxSnapshots();
|
||||
@ -561,6 +562,7 @@ let gHistorySwipeAnimation = {
|
||||
gBrowser.addEventListener("pagehide", this, false);
|
||||
gBrowser.addEventListener("pageshow", this, false);
|
||||
gBrowser.addEventListener("popstate", this, false);
|
||||
gBrowser.addEventListener("DOMModalDialogClosed", this, false);
|
||||
gBrowser.tabContainer.addEventListener("TabClose", this, false);
|
||||
}
|
||||
},
|
||||
@ -572,6 +574,7 @@ let gHistorySwipeAnimation = {
|
||||
gBrowser.removeEventListener("pagehide", this, false);
|
||||
gBrowser.removeEventListener("pageshow", this, false);
|
||||
gBrowser.removeEventListener("popstate", this, false);
|
||||
gBrowser.removeEventListener("DOMModalDialogClosed", this, false);
|
||||
gBrowser.tabContainer.removeEventListener("TabClose", this, false);
|
||||
|
||||
this.active = false;
|
||||
@ -591,7 +594,8 @@ let gHistorySwipeAnimation = {
|
||||
this._handleFastSwiping();
|
||||
}
|
||||
else {
|
||||
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
|
||||
this._startingIndex = gBrowser.webNavigation.sessionHistory.index;
|
||||
this._historyIndex = this._startingIndex;
|
||||
this._canGoBack = this.canGoBack();
|
||||
this._canGoForward = this.canGoForward();
|
||||
if (this.active) {
|
||||
@ -622,20 +626,24 @@ let gHistorySwipeAnimation = {
|
||||
if (!this.isAnimationRunning())
|
||||
return;
|
||||
|
||||
// We use the following value to decrease the bounce effect when swiping
|
||||
// back/forward past the browsing history. This value was determined
|
||||
// experimentally.
|
||||
let dampValue = 4;
|
||||
if ((aVal >= 0 && this.isLTR) ||
|
||||
(aVal <= 0 && !this.isLTR)) {
|
||||
if (aVal > 1)
|
||||
aVal = 1; // Cap value to avoid sliding the page further than allowed.
|
||||
|
||||
let tempDampValue = 1;
|
||||
if (this._canGoBack)
|
||||
this._prevBox.collapsed = false;
|
||||
else
|
||||
else {
|
||||
tempDampValue = dampValue;
|
||||
this._prevBox.collapsed = true;
|
||||
}
|
||||
|
||||
// The current page is pushed to the right (LTR) or left (RTL),
|
||||
// the intention is to go back.
|
||||
// If there is a page to go back to, it should show in the background.
|
||||
this._positionBox(this._curBox, aVal);
|
||||
this._positionBox(this._curBox, aVal / tempDampValue);
|
||||
|
||||
// The forward page should be pushed offscreen all the way to the right.
|
||||
this._positionBox(this._nextBox, 1);
|
||||
@ -651,13 +659,14 @@ let gHistorySwipeAnimation = {
|
||||
// For the backdrop to be visible in that case, the previous page needs
|
||||
// to be hidden (if it exists).
|
||||
if (this._canGoForward) {
|
||||
this._nextBox.collapsed = false;
|
||||
let offset = this.isLTR ? 1 : -1;
|
||||
this._positionBox(this._curBox, 0);
|
||||
this._positionBox(this._nextBox, offset + aVal); // aVal is negative
|
||||
this._positionBox(this._nextBox, offset + aVal);
|
||||
}
|
||||
else {
|
||||
this._prevBox.collapsed = true;
|
||||
this._positionBox(this._curBox, aVal);
|
||||
this._positionBox(this._curBox, aVal / dampValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -674,13 +683,14 @@ let gHistorySwipeAnimation = {
|
||||
let browser = gBrowser.getBrowserForTab(aEvent.target);
|
||||
this._removeTrackedSnapshot(-1, browser);
|
||||
break;
|
||||
case "DOMModalDialogClosed":
|
||||
this.stopAnimation();
|
||||
break;
|
||||
case "pageshow":
|
||||
case "popstate":
|
||||
if (this.isAnimationRunning()) {
|
||||
if (aEvent.target != gBrowser.selectedBrowser.contentDocument)
|
||||
break;
|
||||
this.stopAnimation();
|
||||
}
|
||||
if (aEvent.target != gBrowser.selectedBrowser.contentDocument)
|
||||
break;
|
||||
this.stopAnimation();
|
||||
this._historyIndex = gBrowser.webNavigation.sessionHistory.index;
|
||||
break;
|
||||
case "pagehide":
|
||||
@ -748,7 +758,7 @@ let gHistorySwipeAnimation = {
|
||||
* any. This will also result in the animation overlay to be torn down.
|
||||
*/
|
||||
swipeEndEventReceived: function HSA_swipeEndEventReceived() {
|
||||
if (this._lastSwipeDir != "")
|
||||
if (this._lastSwipeDir != "" && this._historyIndex != this._startingIndex)
|
||||
this._navigateToHistoryIndex();
|
||||
else
|
||||
this.stopAnimation();
|
||||
@ -776,9 +786,10 @@ let gHistorySwipeAnimation = {
|
||||
* |this|.
|
||||
*/
|
||||
_navigateToHistoryIndex: function HSA__navigateToHistoryIndex() {
|
||||
if (this._doesIndexExistInHistory(this._historyIndex)) {
|
||||
if (this._doesIndexExistInHistory(this._historyIndex))
|
||||
gBrowser.webNavigation.gotoIndex(this._historyIndex);
|
||||
}
|
||||
else
|
||||
this.stopAnimation();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1004,12 +1015,17 @@ let gHistorySwipeAnimation = {
|
||||
return aBlob;
|
||||
|
||||
let img = new Image();
|
||||
let url = URL.createObjectURL(aBlob);
|
||||
img.onload = function() {
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
img.src = url;
|
||||
return img;
|
||||
let url = "";
|
||||
try {
|
||||
url = URL.createObjectURL(aBlob);
|
||||
img.onload = function() {
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
}
|
||||
finally {
|
||||
img.src = url;
|
||||
return img;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -912,7 +912,7 @@ var gBrowserInit = {
|
||||
defaultHeight = screen.availHeight * .75;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK2
|
||||
#if MOZ_WIDGET_GTK == 2
|
||||
// On X, we're not currently able to account for the size of the window
|
||||
// border. Use 28px as a guess (titlebar + bottom window border)
|
||||
defaultHeight -= 28;
|
||||
|
7
browser/base/content/test/chrome/Makefile.in
Normal file
7
browser/base/content/test/chrome/Makefile.in
Normal file
@ -0,0 +1,7 @@
|
||||
# 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/.
|
||||
|
||||
MOCHITEST_CHROME_FILES = \
|
||||
test_aboutCrashed.xul \
|
||||
$(NULL)
|
6
browser/base/content/test/chrome/moz.build
Normal file
6
browser/base/content/test/chrome/moz.build
Normal file
@ -0,0 +1,6 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
86
browser/base/content/test/chrome/test_aboutCrashed.xul
Normal file
86
browser/base/content/test/chrome/test_aboutCrashed.xul
Normal file
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<iframe type="content" id="frame1"/>
|
||||
<iframe type="content" id="frame2" onload="doTest()"/>
|
||||
<script type="application/javascript"><![CDATA[
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Load error pages do not fire "load" events, so let's use a progressListener.
|
||||
function waitForErrorPage(frame) {
|
||||
let errorPageDeferred = Promise.defer();
|
||||
|
||||
let progressListener = {
|
||||
onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
|
||||
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
|
||||
frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress)
|
||||
.removeProgressListener(progressListener,
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION);
|
||||
|
||||
errorPageDeferred.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress)
|
||||
.addProgressListener(progressListener,
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION);
|
||||
|
||||
return errorPageDeferred.promise;
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
Task.spawn(function test_aboutCrashed() {
|
||||
let frame1 = document.getElementById("frame1");
|
||||
let frame2 = document.getElementById("frame2");
|
||||
let uri1 = Services.io.newURI("http://www.example.com/1", null, null);
|
||||
let uri2 = Services.io.newURI("http://www.example.com/2", null, null);
|
||||
|
||||
let errorPageReady = waitForErrorPage(frame1);
|
||||
frame1.docShell.chromeEventHandler.setAttribute("crashedPageTitle", "pageTitle");
|
||||
frame1.docShell.displayLoadError(Components.results.NS_ERROR_CONTENT_CRASHED, uri1, null);
|
||||
|
||||
yield errorPageReady;
|
||||
frame1.docShell.chromeEventHandler.removeAttribute("crashedPageTitle");
|
||||
|
||||
SimpleTest.is(frame1.contentDocument.documentURI,
|
||||
"about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/1&c=UTF-8&d=pageTitle",
|
||||
"Correct about:tabcrashed displayed for page with title.");
|
||||
|
||||
errorPageReady = waitForErrorPage(frame2);
|
||||
frame2.docShell.displayLoadError(Components.results.NS_ERROR_CONTENT_CRASHED, uri2, null);
|
||||
|
||||
yield errorPageReady;
|
||||
|
||||
SimpleTest.is(frame2.contentDocument.documentURI,
|
||||
"about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/2&c=UTF-8&d=%20",
|
||||
"Correct about:tabcrashed displayed for page with no title.");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
]]></script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;" />
|
||||
</window>
|
@ -4,5 +4,5 @@
|
||||
# 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/.
|
||||
|
||||
DIRS += ['general', 'newtab', 'social']
|
||||
DIRS += ['chrome', 'general', 'newtab', 'social']
|
||||
|
||||
|
@ -66,7 +66,7 @@ const PREF_AUDIO_FEED_SELECTED_READER = "browser.audioFeeds.handler.default";
|
||||
const kActionUsePlugin = 5;
|
||||
|
||||
/*
|
||||
#ifdef MOZ_WIDGET_GTK2
|
||||
#if MOZ_WIDGET_GTK == 2
|
||||
*/
|
||||
const ICON_URL_APP = "moz-icon://dummy.exe?size=16";
|
||||
/*
|
||||
|
@ -36,6 +36,9 @@ const DEFAULT_EDITOR_CONFIG = {
|
||||
showOverviewRuler: true
|
||||
};
|
||||
|
||||
//For telemetry
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
|
||||
/**
|
||||
* Object defining the debugger view components.
|
||||
*/
|
||||
@ -276,6 +279,13 @@ let DebuggerView = {
|
||||
if (this._editorSource.url == aSource.url && !aFlags.force) {
|
||||
return this._editorSource.promise;
|
||||
}
|
||||
let transportType = DebuggerController.client.localTransport
|
||||
? "_LOCAL"
|
||||
: "_REMOTE";
|
||||
//Telemetry probe
|
||||
let histogramId = "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE" + transportType + "_MS";
|
||||
let histogram = Services.telemetry.getHistogramById(histogramId);
|
||||
let startTime = +new Date();
|
||||
|
||||
let deferred = promise.defer();
|
||||
|
||||
@ -296,6 +306,8 @@ let DebuggerView = {
|
||||
DebuggerView.Sources.selectedValue = aSource.url;
|
||||
DebuggerController.Breakpoints.updateEditorBreakpoints();
|
||||
|
||||
histogram.add(+new Date() - startTime);
|
||||
|
||||
// Resolve and notify that a source file was shown.
|
||||
window.emit(EVENTS.SOURCE_SHOWN, aSource);
|
||||
deferred.resolve([aSource, aText]);
|
||||
|
@ -40,9 +40,6 @@ function OptionsPanel(iframeWindow, toolbox) {
|
||||
this.toolbox = toolbox;
|
||||
this.isReady = false;
|
||||
|
||||
// Make restart method available from xul
|
||||
this.panelWin.restart = this.restart;
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
};
|
||||
|
||||
@ -57,7 +54,6 @@ OptionsPanel.prototype = {
|
||||
|
||||
this.setupToolsList();
|
||||
this.populatePreferences();
|
||||
this.prepareRestartPreferences();
|
||||
|
||||
this._disableJSClicked = this._disableJSClicked.bind(this);
|
||||
|
||||
@ -201,34 +197,6 @@ OptionsPanel.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles checkbox click inside hbox with class "hidden-labels-box". The
|
||||
* labels inside the hbox are shown again when the user click on the checkbox
|
||||
* in the box.
|
||||
*/
|
||||
prepareRestartPreferences: function() {
|
||||
let checkboxes = this.panelDoc.querySelectorAll(".hidden-labels-box > checkbox");
|
||||
for (let checkbox of checkboxes) {
|
||||
checkbox.addEventListener("command", function(target) {
|
||||
target.parentNode.classList.toggle("visible");
|
||||
}.bind(null, checkbox));
|
||||
}
|
||||
},
|
||||
|
||||
restart: function() {
|
||||
let canceled = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
|
||||
if (canceled.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// restart
|
||||
Cc['@mozilla.org/toolkit/app-startup;1']
|
||||
.getService(Ci.nsIAppStartup)
|
||||
.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables JavaScript for the currently loaded tab. We force a page refresh
|
||||
* here because setting docShell.allowJavascript to true fails to block JS
|
||||
|
@ -74,21 +74,11 @@
|
||||
<checkbox label="&options.enableChrome.label3;"
|
||||
tooltiptext="&options.enableChrome.tooltip;"
|
||||
data-pref="devtools.chrome.enabled"/>
|
||||
<label class="options-citation-label"
|
||||
value="&options.context.requiresRestart2;"/>
|
||||
<label class="text-link"
|
||||
onclick="restart()"
|
||||
value="&options.restartButton.label;"/>
|
||||
</hbox>
|
||||
<hbox class="hidden-labels-box">
|
||||
<checkbox label="&options.enableRemote.label3;"
|
||||
tooltiptext="&options.enableRemote.tooltip;"
|
||||
data-pref="devtools.debugger.remote-enabled"/>
|
||||
<label class="options-citation-label"
|
||||
value="&options.context.requiresRestart2;"/>
|
||||
<label class="text-link"
|
||||
onclick="restart()"
|
||||
value="&options.restartButton.label;"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
@ -729,6 +729,15 @@ InspectorPanel.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger a high-priority layout change for things that need to be
|
||||
* updated immediately
|
||||
*/
|
||||
immediateLayoutChange: function Inspector_immediateLayoutChange()
|
||||
{
|
||||
this.emit("layout-change");
|
||||
},
|
||||
|
||||
/**
|
||||
* Schedule a low-priority change event for things like paint
|
||||
* and resize.
|
||||
|
@ -17,7 +17,7 @@ function test() {
|
||||
}
|
||||
|
||||
|
||||
function getInspectorProp(aName)
|
||||
function getInspectorComputedProp(aName)
|
||||
{
|
||||
let computedview = inspector.sidebar.getWindowForTab("computedview").computedview.view;
|
||||
for each (let view in computedview.propertyViews) {
|
||||
@ -27,6 +27,18 @@ function test() {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function getInspectorRuleProp(aName)
|
||||
{
|
||||
let ruleview = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
let inlineStyles = ruleview._elementStyle.rules[0];
|
||||
|
||||
for each (let prop in inlineStyles.textProps) {
|
||||
if (prop.name == aName) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function runInspectorTests(aInspector)
|
||||
{
|
||||
@ -40,50 +52,93 @@ function test() {
|
||||
testDiv.style.fontSize = "10px";
|
||||
|
||||
// Start up the style inspector panel...
|
||||
inspector.once("computed-view-refreshed", stylePanelTests);
|
||||
inspector.once("computed-view-refreshed", computedStylePanelTests);
|
||||
|
||||
inspector.selection.setNode(testDiv);
|
||||
});
|
||||
}
|
||||
|
||||
function stylePanelTests()
|
||||
function computedStylePanelTests()
|
||||
{
|
||||
let computedview = inspector.sidebar.getWindowForTab("computedview").computedview;
|
||||
ok(computedview, "Style Panel has a cssHtmlTree");
|
||||
|
||||
let propView = getInspectorProp("font-size");
|
||||
let propView = getInspectorComputedProp("font-size");
|
||||
is(propView.value, "10px", "Style inspector should be showing the correct font size.");
|
||||
|
||||
inspector.once("computed-view-refreshed", stylePanelAfterChange);
|
||||
inspector.once("computed-view-refreshed", computedStylePanelAfterChange);
|
||||
|
||||
testDiv.style.fontSize = "15px";
|
||||
inspector.emit("layout-change");
|
||||
testDiv.style.cssText = "font-size: 15px; color: red;";
|
||||
}
|
||||
|
||||
function stylePanelAfterChange()
|
||||
function computedStylePanelAfterChange()
|
||||
{
|
||||
let propView = getInspectorProp("font-size");
|
||||
let propView = getInspectorComputedProp("font-size");
|
||||
is(propView.value, "15px", "Style inspector should be showing the new font size.");
|
||||
|
||||
stylePanelNotActive();
|
||||
let propView = getInspectorComputedProp("color");
|
||||
is(propView.value, "#F00", "Style inspector should be showing the new color.");
|
||||
|
||||
computedStylePanelNotActive();
|
||||
}
|
||||
|
||||
function stylePanelNotActive()
|
||||
function computedStylePanelNotActive()
|
||||
{
|
||||
// Tests changes made while the style panel is not active.
|
||||
inspector.sidebar.select("ruleview");
|
||||
|
||||
executeSoon(function() {
|
||||
inspector.once("computed-view-refreshed", stylePanelAfterSwitch);
|
||||
testDiv.style.fontSize = "20px";
|
||||
inspector.sidebar.select("computedview");
|
||||
});
|
||||
testDiv.style.fontSize = "20px";
|
||||
testDiv.style.color = "blue";
|
||||
testDiv.style.textAlign = "center";
|
||||
inspector.once("computed-view-refreshed", computedStylePanelAfterSwitch);
|
||||
inspector.sidebar.select("computedview");
|
||||
}
|
||||
|
||||
function stylePanelAfterSwitch()
|
||||
function computedStylePanelAfterSwitch()
|
||||
{
|
||||
let propView = getInspectorProp("font-size");
|
||||
is(propView.value, "20px", "Style inspector should be showing the newest font size.");
|
||||
let propView = getInspectorComputedProp("font-size");
|
||||
is(propView.value, "20px", "Style inspector should be showing the new font size.");
|
||||
|
||||
let propView = getInspectorComputedProp("color");
|
||||
is(propView.value, "#00F", "Style inspector should be showing the new color.");
|
||||
|
||||
let propView = getInspectorComputedProp("text-align");
|
||||
is(propView.value, "center", "Style inspector should be showing the new text align.");
|
||||
|
||||
rulePanelTests();
|
||||
}
|
||||
|
||||
function rulePanelTests()
|
||||
{
|
||||
inspector.sidebar.select("ruleview");
|
||||
let ruleview = inspector.sidebar.getWindowForTab("ruleview").ruleview;
|
||||
ok(ruleview, "Style Panel has a ruleview");
|
||||
|
||||
let propView = getInspectorRuleProp("text-align");
|
||||
is(propView.value, "center", "Style inspector should be showing the new text align.");
|
||||
|
||||
testDiv.style.textAlign = "right";
|
||||
testDiv.style.color = "lightgoldenrodyellow";
|
||||
testDiv.style.fontSize = "3em";
|
||||
testDiv.style.textTransform = "uppercase";
|
||||
|
||||
|
||||
inspector.once("rule-view-refreshed", rulePanelAfterChange);
|
||||
|
||||
}
|
||||
|
||||
function rulePanelAfterChange()
|
||||
{
|
||||
let propView = getInspectorRuleProp("text-align");
|
||||
is(propView.value, "right", "Style inspector should be showing the new text align.");
|
||||
|
||||
let propView = getInspectorRuleProp("color");
|
||||
is(propView.value, "#FAFAD2", "Style inspector should be showing the new color.")
|
||||
|
||||
let propView = getInspectorRuleProp("font-size");
|
||||
is(propView.value, "3em", "Style inspector should be showing the new font size.");
|
||||
|
||||
let propView = getInspectorRuleProp("text-transform");
|
||||
is(propView.value, "uppercase", "Style inspector should be showing the new text transform.");
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
@ -397,6 +397,7 @@ MarkupView.prototype = {
|
||||
*/
|
||||
_mutationObserver: function MT__mutationObserver(aMutations)
|
||||
{
|
||||
let requiresLayoutChange = false;
|
||||
for (let mutation of aMutations) {
|
||||
let type = mutation.type;
|
||||
let target = mutation.target;
|
||||
@ -419,6 +420,11 @@ MarkupView.prototype = {
|
||||
}
|
||||
if (type === "attributes" || type === "characterData") {
|
||||
container.update(false);
|
||||
|
||||
// Auto refresh style properties on selected node when they change.
|
||||
if (type === "attributes" && container.selected) {
|
||||
requiresLayoutChange = true;
|
||||
}
|
||||
} else if (type === "childList") {
|
||||
container.childrenDirty = true;
|
||||
// Update the children to take care of changes in the DOM
|
||||
@ -427,6 +433,10 @@ MarkupView.prototype = {
|
||||
this._updateChildren(container, {flash: true});
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresLayoutChange) {
|
||||
this._inspector.immediateLayoutChange();
|
||||
}
|
||||
this._waitForChildren().then(() => {
|
||||
this._flashMutatedNodes(aMutations);
|
||||
this._inspector.emit("markupmutation");
|
||||
|
@ -1283,13 +1283,13 @@ CssRuleView.prototype = {
|
||||
{
|
||||
// Ignore refreshes during editing or when no element is selected.
|
||||
if (this.isEditing || !this._elementStyle) {
|
||||
return promise.resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this._clearRules();
|
||||
|
||||
// Repopulate the element style.
|
||||
return this._populate();
|
||||
this._populate();
|
||||
},
|
||||
|
||||
_populate: function() {
|
||||
|
@ -7,6 +7,7 @@ let doc;
|
||||
let inspector;
|
||||
let ruleView;
|
||||
let testElement;
|
||||
let rule;
|
||||
|
||||
function startTest(aInspector, aRuleView)
|
||||
{
|
||||
@ -43,25 +44,29 @@ function testRuleChanges()
|
||||
is(selectors[2].textContent.indexOf(".testclass"), 0, "Third item is class rule.");
|
||||
|
||||
// Change the id and refresh.
|
||||
inspector.once("rule-view-refreshed", testRuleChange1);
|
||||
testElement.setAttribute("id", "differentid");
|
||||
promiseDone(ruleView.nodeChanged().then(() => {
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 2, "Two rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf(".testclass"), 0, "Second item is class rule.");
|
||||
}
|
||||
|
||||
testElement.setAttribute("id", "testid");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
// Put the id back.
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 3, "Three rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf("#testid"), 0, "Second item is id rule.");
|
||||
is(selectors[2].textContent.indexOf(".testclass"), 0, "Third item is class rule.");
|
||||
function testRuleChange1()
|
||||
{
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 2, "Two rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf(".testclass"), 0, "Second item is class rule.");
|
||||
|
||||
testPropertyChanges();
|
||||
}));
|
||||
inspector.once("rule-view-refreshed", testRuleChange2);
|
||||
testElement.setAttribute("id", "testid");
|
||||
}
|
||||
function testRuleChange2()
|
||||
{
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 3, "Three rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf("#testid"), 0, "Second item is id rule.");
|
||||
is(selectors[2].textContent.indexOf(".testclass"), 0, "Third item is class rule.");
|
||||
|
||||
testPropertyChanges();
|
||||
}
|
||||
|
||||
function validateTextProp(aProp, aEnabled, aName, aValue, aDesc)
|
||||
@ -77,65 +82,86 @@ function validateTextProp(aProp, aEnabled, aName, aValue, aDesc)
|
||||
|
||||
function testPropertyChanges()
|
||||
{
|
||||
// Add a second margin-top value, just to make things interesting.
|
||||
let rule = ruleView._elementStyle.rules[0];
|
||||
rule = ruleView._elementStyle.rules[0];
|
||||
let ruleEditor = ruleView._elementStyle.rules[0].editor;
|
||||
inspector.once("rule-view-refreshed", testPropertyChange0);
|
||||
|
||||
// Add a second margin-top value, just to make things interesting.
|
||||
ruleEditor.addProperty("margin-top", "5px", "");
|
||||
promiseDone(expectRuleChange(rule).then(() => {
|
||||
// Set the element style back to a 1px margin-top.
|
||||
testElement.setAttribute("style", "margin-top: 1px; padding-top: 5px");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], true, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], false, "margin-top", "5px", "Second margin property disabled");
|
||||
}
|
||||
|
||||
// Now set it back to 5px, the 5px value should be re-enabled.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 5px;");
|
||||
return ruleView.nodeChanged();
|
||||
function testPropertyChange0()
|
||||
{
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "Original margin property active");
|
||||
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "5px", "Second margin property disabled");
|
||||
inspector.once("rule-view-refreshed", testPropertyChange1);
|
||||
testElement.setAttribute("style", "margin-top: 1px; padding-top: 5px");
|
||||
}
|
||||
function testPropertyChange1()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], true, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], false, "margin-top", "5px", "Second margin property disabled");
|
||||
|
||||
// Set the margin property to a value that doesn't exist in the editor.
|
||||
// Should reuse the currently-enabled element (the second one.)
|
||||
testElement.setAttribute("style", "margin-top: 15px; padding-top: 5px;");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "15px", "Second margin property disabled");
|
||||
inspector.once("rule-view-refreshed", testPropertyChange2);
|
||||
|
||||
// Remove the padding-top attribute. Should disable the padding property but not remove it.
|
||||
testElement.setAttribute("style", "margin-top: 5px;");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], false, "padding-top", "5px", "Padding property disabled");
|
||||
// Now set it back to 5px, the 5px value should be re-enabled.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 5px;");
|
||||
}
|
||||
function testPropertyChange2()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "5px", "Second margin property disabled");
|
||||
|
||||
// Put the padding-top attribute back in, should re-enable the padding property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], true, "padding-top", "25px", "Padding property enabled");
|
||||
inspector.once("rule-view-refreshed", testPropertyChange3);
|
||||
|
||||
// Add an entirely new property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px; padding-left: 20px;");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 4, "Added a property");
|
||||
validateTextProp(rule.textProps[3], true, "padding-left", "20px", "Padding property enabled");
|
||||
// Set the margin property to a value that doesn't exist in the editor.
|
||||
// Should reuse the currently-enabled element (the second one.)
|
||||
testElement.setAttribute("style", "margin-top: 15px; padding-top: 5px;");
|
||||
}
|
||||
function testPropertyChange3()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "15px", "Second margin property disabled");
|
||||
|
||||
finishTest();
|
||||
}));
|
||||
inspector.once("rule-view-refreshed", testPropertyChange4);
|
||||
|
||||
// Remove the padding-top attribute. Should disable the padding property but not remove it.
|
||||
testElement.setAttribute("style", "margin-top: 5px;");
|
||||
}
|
||||
function testPropertyChange4()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], false, "padding-top", "5px", "Padding property disabled");
|
||||
|
||||
inspector.once("rule-view-refreshed", testPropertyChange5);
|
||||
|
||||
// Put the padding-top attribute back in, should re-enable the padding property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px");
|
||||
}
|
||||
function testPropertyChange5()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], true, "padding-top", "25px", "Padding property enabled");
|
||||
|
||||
inspector.once("rule-view-refreshed", testPropertyChange6);
|
||||
|
||||
// Add an entirely new property
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px; padding-left: 20px;");
|
||||
}
|
||||
function testPropertyChange6()
|
||||
{
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 4, "Added a property");
|
||||
validateTextProp(rule.textProps[3], true, "padding-left", "20px", "Padding property enabled");
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
inspector = ruleView = null;
|
||||
inspector = ruleView = rule = null;
|
||||
doc = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
@ -224,12 +224,10 @@ function testGen() {
|
||||
|
||||
eventHandlers.push(variablesViewShown);
|
||||
|
||||
// Send the mousedown, mouseup and click events to check if the variables
|
||||
// view opens.
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" }, messageBody, window);
|
||||
EventUtils.sendMouseEvent({ type: "click" }, messageBody, window);
|
||||
EventUtils.synthesizeMouse(messageBody, 2, 2, {}, HUD.iframeWindow);
|
||||
|
||||
if (showsVariablesView) {
|
||||
info("messageBody tagName '" + messageBody.tagName + "' className '" + messageBody.className + "'");
|
||||
yield undefined; // wait for the panel to open if we need to.
|
||||
}
|
||||
|
||||
|
@ -544,6 +544,9 @@
|
||||
@BINPATH@/components/PeerConnection.manifest
|
||||
#endif
|
||||
|
||||
@BINPATH@/components/HttpDataUsage.manifest
|
||||
@BINPATH@/components/HttpDataUsage.js
|
||||
|
||||
@BINPATH@/chrome/marionette@JAREXT@
|
||||
@BINPATH@/chrome/marionette.manifest
|
||||
@BINPATH@/components/MarionetteComponents.manifest
|
||||
|
@ -76,7 +76,7 @@
|
||||
|
||||
<!ENTITY help.title "App Manager">
|
||||
<!ENTITY help.close "Close">
|
||||
<!ENTITY help.intro "This tool will help you build and install web apps on compatible devices (i.e Firefox OS). The <strong>Apps</strong> tab will assist you in the validation and installation process of your app. The <strong>Device</strong> tab will give you information about the connected device. Use the bottom toolbar to connect to a device or start the simulator.">
|
||||
<!ENTITY help.intro "This tool will help you build and install web apps on compatible devices (i.e. Firefox OS). The <strong>Apps</strong> tab will assist you in the validation and installation process of your app. The <strong>Device</strong> tab will give you information about the connected device. Use the bottom toolbar to connect to a device or start the simulator.">
|
||||
<!ENTITY help.usefullLinks "Useful links:">
|
||||
<!ENTITY help.appMgrDoc "Documentation: Using the App Manager">
|
||||
<!ENTITY help.configuringDevice "How to setup your Firefox OS device">
|
||||
|
@ -52,15 +52,6 @@
|
||||
- -->
|
||||
<!ENTITY options.defaultColorUnit.name "Color Names">
|
||||
|
||||
<!-- LOCALIZATION NOTE (options.context.requiresRestart2): This is the requires
|
||||
- restart label at right of settings that require a browser restart to be
|
||||
- effective. -->
|
||||
<!ENTITY options.context.requiresRestart2 "Requires browser restart">
|
||||
|
||||
<!-- LOCALIZATION NOTE (options.restartButton.label): This is the label for the
|
||||
- restart button next to options.context.requiresRestart2 label. -->
|
||||
<!ENTITY options.restartButton.label "Restart now">
|
||||
|
||||
<!-- LOCALIZATION NOTE (options.context.triggersPageRefresh2): This is the
|
||||
- triggers page refresh label next to the settings in the advanced settings
|
||||
- group in the options panel which trigger page reload. -->
|
||||
|
@ -92,19 +92,18 @@ function removeMockSearchDefault(aTimeoutMs) {
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
Task.spawn(function(){
|
||||
yield addTab("about:blank");
|
||||
}).then(runTests);
|
||||
runTests();
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
if (!gEdit)
|
||||
gEdit = document.getElementById("urlbar-edit");
|
||||
|
||||
yield addTab("about:blank");
|
||||
yield showNavBar();
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
yield removeMockSearchDefault();
|
||||
Browser.closeTab(Browser.selectedTab, { forceClose: true });
|
||||
}
|
||||
|
||||
@ -272,15 +271,17 @@ gTests.push({
|
||||
let searchSubmission = gEngine.getSubmission(search, null);
|
||||
let trimmedSubmission = gEdit.trimValue(searchSubmission.uri.spec);
|
||||
is(gEdit.value, trimmedSubmission, "tap search option: search conducted");
|
||||
|
||||
yield removeMockSearchDefault();
|
||||
}
|
||||
});
|
||||
|
||||
gTests.push({
|
||||
desc: "bug 897131 - url bar update after content tap + edge swipe",
|
||||
setUp: setUp,
|
||||
tearDown: tearDown,
|
||||
run: function testUrlbarTyping() {
|
||||
let tab = yield addTab("about:mozilla");
|
||||
yield showNavBar();
|
||||
|
||||
sendElementTap(window, gEdit);
|
||||
ok(gEdit.isEditing, "focus urlbar: in editing mode");
|
||||
@ -305,3 +306,62 @@ gTests.push({
|
||||
}
|
||||
});
|
||||
|
||||
gTests.push({
|
||||
desc: "Bug 916383 - Invisible autocomplete items selectable by keyboard when 'your results' not shown",
|
||||
tearDown: tearDown,
|
||||
run: function testBug916383() {
|
||||
yield addTab("about:start");
|
||||
yield showNavBar();
|
||||
|
||||
sendElementTap(window, gEdit);
|
||||
|
||||
let bookmarkItem = Browser.selectedBrowser.contentWindow.BookmarksStartView._grid.querySelector("richgriditem");
|
||||
// Get the first bookmark item label to make sure it will show up in 'your results'
|
||||
let label = bookmarkItem.getAttribute("label");
|
||||
|
||||
EventUtils.sendString(label, window);
|
||||
|
||||
let opened = yield waitForCondition(() => gEdit.popup.popupOpen);
|
||||
yield waitForCondition(() => gEdit.popup._results.itemCount > 0);
|
||||
|
||||
ok(!gEdit.popup._resultsContainer.hidden, "'Your results' are visible");
|
||||
ok(gEdit.popup._results.itemCount > 0, "'Your results' are populated");
|
||||
|
||||
// Append a string to make sure it doesn't match anything in 'your results'
|
||||
EventUtils.sendString("zzzzzzzzzzzzzzzzzz", window);
|
||||
|
||||
yield waitForCondition(() => gEdit.popup._resultsContainer.hidden);
|
||||
|
||||
ok(gEdit.popup._resultsContainer.hidden, "'Your results' are hidden");
|
||||
ok(gEdit.popup._results.itemCount === 0, "'Your results' are empty");
|
||||
|
||||
EventUtils.synthesizeKey("VK_DOWN", {}, window);
|
||||
is(gEdit.popup._searches.selectedIndex, 0, "key select search: first search selected");
|
||||
}
|
||||
});
|
||||
|
||||
gTests.push({
|
||||
desc: "Bug 891667 - Use up arrow too",
|
||||
tearDown: tearDown,
|
||||
run: function testBug891667() {
|
||||
yield addTab("about:start");
|
||||
yield showNavBar();
|
||||
|
||||
sendElementTap(window, gEdit);
|
||||
|
||||
let bookmarkItem = Browser.selectedBrowser.contentWindow.BookmarksStartView._grid.querySelector("richgriditem");
|
||||
// Get the first bookmark item label to make sure it will show up in 'your results'
|
||||
let label = bookmarkItem.getAttribute("label");
|
||||
|
||||
EventUtils.sendString(label, window);
|
||||
|
||||
yield waitForCondition(() => gEdit.popup.popupOpen);
|
||||
yield waitForCondition(() => gEdit.popup._results.itemCount > 0);
|
||||
|
||||
ok(gEdit.popup._results.itemCount > 0, "'Your results' populated");
|
||||
|
||||
EventUtils.synthesizeKey("VK_UP", {}, window);
|
||||
is(gEdit.popup._results.selectedIndex, 0, "Pressing arrow up selects first item.");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -396,11 +396,12 @@ function waitForCondition(aCondition, aTimeoutMs, aIntervalMs) {
|
||||
let timeoutMs = aTimeoutMs || kDefaultWait;
|
||||
let intervalMs = aIntervalMs || kDefaultInterval;
|
||||
let startTime = Date.now();
|
||||
let stack = new Error().stack;
|
||||
|
||||
function testCondition() {
|
||||
let now = Date.now();
|
||||
if((now - startTime) > timeoutMs) {
|
||||
deferred.reject( new Error("Timed out waiting for condition to be true") );
|
||||
deferred.reject( new Error("Timed out waiting for condition to be true at " + stack) );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,9 @@ this.TabCrashReporter = {
|
||||
},
|
||||
|
||||
onAboutTabCrashedLoad: function (aBrowser) {
|
||||
if (!this.childMap)
|
||||
return;
|
||||
|
||||
let dumpID = this.childMap.get(this.browserMap.get(aBrowser));
|
||||
if (!dumpID)
|
||||
return;
|
||||
|
@ -87,7 +87,7 @@ browser.jar:
|
||||
skin/classic/browser/downloads/download-notification-start.png (downloads/download-notification-start.png)
|
||||
skin/classic/browser/downloads/download-summary.png (downloads/download-summary.png)
|
||||
* skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
* skin/classic/browser/downloads/indicator.css (downloads/indicator.css)
|
||||
skin/classic/browser/downloads/indicator.css (downloads/indicator.css)
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png)
|
||||
|
@ -294,7 +294,7 @@ case "$target" in
|
||||
# The build tools got moved around to different directories in
|
||||
# SDK Tools r22. Try to locate them.
|
||||
android_build_tools=""
|
||||
for suffix in android-4.3 18.0.1 18.0.0 17.0.0 android-4.2.2; do
|
||||
for suffix in android-4.3 18.1.0 18.0.1 18.0.0 17.0.0 android-4.2.2; do
|
||||
tools_directory="$android_sdk/../../build-tools/$suffix"
|
||||
if test -d "$tools_directory" ; then
|
||||
android_build_tools="$tools_directory"
|
||||
|
@ -8,6 +8,28 @@ import glob, logging, os, platform, shutil, subprocess, sys, tempfile, urllib2,
|
||||
import re
|
||||
from urlparse import urlparse
|
||||
|
||||
try:
|
||||
import mozinfo
|
||||
except ImportError:
|
||||
# Stub out fake mozinfo since this is not importable on Android 4.0 Opt.
|
||||
# This should be fixed; see
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=650881
|
||||
mozinfo = type('mozinfo', (), dict(info={}))()
|
||||
mozinfo.isWin = mozinfo.isLinux = mozinfo.isUnix = mozinfo.isMac = False
|
||||
|
||||
# TODO! FILE: localautomation :/
|
||||
# mapping from would-be mozinfo attr <-> sys.platform
|
||||
mapping = {'isMac': ['mac', 'darwin'],
|
||||
'isLinux': ['linux', 'linux2'],
|
||||
'isWin': ['win32', 'win64'],
|
||||
}
|
||||
mapping = dict(sum([[(value, key) for value in values] for key, values in mapping.items()], []))
|
||||
attr = mapping.get(sys.platform)
|
||||
if attr:
|
||||
setattr(mozinfo, attr, True)
|
||||
if mozinfo.isLinux:
|
||||
mozinfo.isUnix = True
|
||||
|
||||
__all__ = [
|
||||
"ZipFileReader",
|
||||
"addCommonOptions",
|
||||
@ -18,6 +40,10 @@ __all__ = [
|
||||
"DEBUGGER_INFO",
|
||||
"replaceBackSlashes",
|
||||
"wrapCommand",
|
||||
'KeyValueParseError',
|
||||
'parseKeyValue',
|
||||
'systemMemory',
|
||||
'environment'
|
||||
]
|
||||
|
||||
# Map of debugging programs to information about them, like default arguments
|
||||
@ -345,3 +371,105 @@ def wrapCommand(cmd):
|
||||
return ["arch", "-arch", "i386"] + cmd
|
||||
# otherwise just execute the command normally
|
||||
return cmd
|
||||
|
||||
class KeyValueParseError(Exception):
|
||||
"""error when parsing strings of serialized key-values"""
|
||||
def __init__(self, msg, errors=()):
|
||||
self.errors = errors
|
||||
Exception.__init__(self, msg)
|
||||
|
||||
def parseKeyValue(strings, separator='=', context='key, value: '):
|
||||
"""
|
||||
parse string-serialized key-value pairs in the form of
|
||||
`key = value`. Returns a list of 2-tuples.
|
||||
Note that whitespace is not stripped.
|
||||
"""
|
||||
|
||||
# syntax check
|
||||
missing = [string for string in strings if separator not in string]
|
||||
if missing:
|
||||
raise KeyValueParseError("Error: syntax error in %s" % (context,
|
||||
','.join(missing)),
|
||||
errors=missing)
|
||||
return [string.split(separator, 1) for string in strings]
|
||||
|
||||
def systemMemory():
|
||||
"""
|
||||
Returns total system memory in kilobytes.
|
||||
Works only on unix-like platforms where `free` is in the path.
|
||||
"""
|
||||
return int(os.popen("free").readlines()[1].split()[1])
|
||||
|
||||
def environment(xrePath, env=None, crashreporter=True):
|
||||
"""populate OS environment variables for mochitest"""
|
||||
|
||||
env = os.environ.copy() if env is None else env
|
||||
|
||||
assert os.path.isabs(xrePath)
|
||||
|
||||
ldLibraryPath = xrePath
|
||||
|
||||
envVar = None
|
||||
if mozinfo.isUnix:
|
||||
envVar = "LD_LIBRARY_PATH"
|
||||
env['MOZILLA_FIVE_HOME'] = xrePath
|
||||
elif mozinfo.isMac:
|
||||
envVar = "DYLD_LIBRARY_PATH"
|
||||
elif mozinfo.isWin:
|
||||
envVar = "PATH"
|
||||
if envVar:
|
||||
envValue = ((env.get(envVar), str(ldLibraryPath))
|
||||
if mozinfo.isWin
|
||||
else (ldLibraryPath, env.get(envVar)))
|
||||
env[envVar] = os.path.pathsep.join([path for path in envValue if path])
|
||||
|
||||
# crashreporter
|
||||
env['GNOME_DISABLE_CRASH_DIALOG'] = '1'
|
||||
env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
|
||||
env['NS_TRACE_MALLOC_DISABLE_STACKS'] = '1'
|
||||
|
||||
if crashreporter:
|
||||
env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
|
||||
env['MOZ_CRASHREPORTER'] = '1'
|
||||
else:
|
||||
env['MOZ_CRASHREPORTER_DISABLE'] = '1'
|
||||
|
||||
# Additional temporary logging while we try to debug some intermittent
|
||||
# WebRTC conditions. This is necessary to troubleshoot bugs 841496,
|
||||
# 841150, and 839677 (at least)
|
||||
# Also (temporary) bug 870002 (mediastreamgraph)
|
||||
env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:3')
|
||||
env['R_LOG_LEVEL'] = '5'
|
||||
env['R_LOG_DESTINATION'] = 'stderr'
|
||||
env['R_LOG_VERBOSE'] = '1'
|
||||
|
||||
# ASan specific environment stuff
|
||||
asan = bool(mozinfo.info.get("asan"))
|
||||
if asan and (mozinfo.isLinux or mozinfo.isMac):
|
||||
try:
|
||||
totalMemory = systemMemory()
|
||||
|
||||
# Only 2 GB RAM or less available? Use custom ASan options to reduce
|
||||
# the amount of resources required to do the tests. Standard options
|
||||
# will otherwise lead to OOM conditions on the current test slaves.
|
||||
#
|
||||
# If we have more than 2 GB or RAM but still less than 4 GB, we need
|
||||
# another set of options to prevent OOM in some memory-intensive
|
||||
# tests.
|
||||
message = "INFO | runtests.py | ASan running in %s configuration"
|
||||
if totalMemory <= 1024 * 1024 * 2:
|
||||
message = message % 'low-memory'
|
||||
env["ASAN_OPTIONS"] = "quarantine_size=50331648:redzone=64"
|
||||
elif totalMemory <= 1024 * 1024 * 4:
|
||||
message = message % 'mid-memory'
|
||||
env["ASAN_OPTIONS"] = "quarantine_size=100663296:redzone=64"
|
||||
else:
|
||||
message = message % 'default memory'
|
||||
except OSError,err:
|
||||
log.info("Failed determine available memory, disabling ASan low-memory configuration: %s", err.strerror)
|
||||
except:
|
||||
log.info("Failed determine available memory, disabling ASan low-memory configuration")
|
||||
else:
|
||||
log.info(message)
|
||||
|
||||
return env
|
||||
|
108
build/docs/build-overview.rst
Normal file
108
build/docs/build-overview.rst
Normal file
@ -0,0 +1,108 @@
|
||||
.. _build_overview:
|
||||
|
||||
=====================
|
||||
Build System Overview
|
||||
=====================
|
||||
|
||||
This document provides an overview on how the build system works. It is
|
||||
targeted at people wanting to learn about internals of the build system.
|
||||
It is not meant for persons who casually interact with the build system.
|
||||
That being said, knowledge empowers, so consider reading on.
|
||||
|
||||
The build system is composed of many different components working in
|
||||
harmony to build the source tree. We begin with a graphic overview.
|
||||
|
||||
.. graphviz::
|
||||
|
||||
digraph build_components {
|
||||
rankdir="LR";
|
||||
"configure" -> "config.status" -> "build backend" -> "build output"
|
||||
}
|
||||
|
||||
Phase 1: Configuration
|
||||
======================
|
||||
|
||||
Phase 1 centers around the configure script, which is a bash shell script.
|
||||
The file is generated from a file called configure.in which is written in M4
|
||||
and processed using Autoconf 2.13 to create the final configure script.
|
||||
You don't have to worry about how you obtain a configure file: the build system
|
||||
does this for you.
|
||||
|
||||
The primary job of configure is to determine characteristics of the system and
|
||||
compiler, apply options passed into it, and validate everything looks OK to
|
||||
build. The primary output of the configure script is an executable file in the
|
||||
object directory called config.status. configure also produces some additional
|
||||
files (like autoconf.mk). However, the most important file in terms of
|
||||
architecture is config.status.
|
||||
|
||||
The existence of a config.status file may be familiar to those who have worked
|
||||
with Autoconf before. However, Mozilla's config.status is different from almost
|
||||
any other config.status you've ever seen: it's written in Python! Instead of
|
||||
having our configure script produce a shell script, we have it generating Python.
|
||||
|
||||
Now is as good a time as any to mention that Python is prevalent in our build
|
||||
system. If we need to write code for the build system, we do it in Python.
|
||||
That's just how we roll.
|
||||
|
||||
config.status contains 2 parts: data structures representing the output of
|
||||
configure and a command-line interface for preparing/configuring/generating
|
||||
an appropriate build backend. (A build backend is merely a tool used to build
|
||||
the tree - like GNU Make or Tup). These data structures essentially describe
|
||||
the current state of the system and what the existing build configuration looks
|
||||
like. For example, it defines which compiler to use, how to invoke it, which
|
||||
application features are enabled, etc. You are encouraged to open up
|
||||
config.status to have a look for yourself!
|
||||
|
||||
Once we have emitted a config.status file, we pass into the realm of phase 2.
|
||||
|
||||
Phase 2: Build Backend Preparation and the Build Definition
|
||||
===========================================================
|
||||
|
||||
Once configure has determined what the current build configuration is, we need
|
||||
to apply this to the source tree so we can actually build.
|
||||
|
||||
What essentially happens is the automatically-produced config.status Python
|
||||
script is executed as soon as configure has generated it. config.status is charged
|
||||
with the task of tell a tool had to build the tree. To do this, config.status
|
||||
must first scan the build system definition.
|
||||
|
||||
The build system definition consists of various moz.build files in the tree.
|
||||
There is roughly one moz.build file per directory or pet set of related directories.
|
||||
Each moz.build files defines how its part of the build config works. For example it
|
||||
says I want these C++ files compiled or look for additional information in these
|
||||
directories. config.status starts with the main moz.build file and then recurses
|
||||
into all referenced files and directories. As the moz.build files are read, data
|
||||
structures describing the overall build system definition are emitted. These data
|
||||
structures are then read by a build backend generator which then converts them
|
||||
into files, function calls, etc. In the case of a `make` backend, the generator
|
||||
writes out Makefiles.
|
||||
|
||||
When config.status runs, you'll see the following output::
|
||||
|
||||
Reticulating splines...
|
||||
Finished reading 1096 moz.build files into 1276 descriptors in 2.40s
|
||||
Backend executed in 2.39s
|
||||
2188 total backend files. 0 created; 1 updated; 2187 unchanged
|
||||
Total wall time: 5.03s; CPU time: 3.79s; Efficiency: 75%
|
||||
|
||||
What this is saying is that a total of 1096 moz.build files were read. Altogether,
|
||||
1276 data structures describing the build configuration were derived from them.
|
||||
It took 2.40s wall time to just read these files and produce the data structures.
|
||||
The 1276 data structures were fed into the build backend which then determined it
|
||||
had to manage 2188 files derived from those data structures. Most of them
|
||||
already existed and didn't need changed. However, 1 was updated as a result of
|
||||
the new configuration. The whole process took 5.03s. Although, only 3.79s was in
|
||||
CPU time. That likely means we spent roughly 25% of the time waiting on I/O.
|
||||
|
||||
Phase 3: Invokation of the Build Backend
|
||||
========================================
|
||||
|
||||
When most people think of the build system, they think of phase 3. This is
|
||||
where we take all the code in the tree and produce Firefox or whatever
|
||||
application you are creating. Phase 3 effectively takes whatever was
|
||||
generated by phase 2 and runs it. Since the dawn of Mozilla, this has been
|
||||
make consuming Makefiles. However, with the transition to moz.build files,
|
||||
you may soon see non-Make build backends, such as Tup or Visual Studio.
|
||||
|
||||
When building the tree, most of the time is spent in phase 3. This is when
|
||||
header files are installed, C++ files are compiled, files are preprocessed, etc.
|
@ -17,6 +17,7 @@ import mdn_theme
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.graphviz',
|
||||
]
|
||||
|
||||
templates_path = ['_templates']
|
||||
|
44
build/docs/environment-variables.rst
Normal file
44
build/docs/environment-variables.rst
Normal file
@ -0,0 +1,44 @@
|
||||
.. _environment_variables:
|
||||
|
||||
================================================
|
||||
Environment Variables Impacting the Build System
|
||||
================================================
|
||||
|
||||
Various environment variables have an impact on the behavior of the
|
||||
build system. This document attempts to document them.
|
||||
|
||||
AUTOCLOBBER
|
||||
If defines, the build system will automatically clobber as needed.
|
||||
The default behavior is to print a message and error out when a
|
||||
clobber is needed.
|
||||
|
||||
This variable is typically defined in a :ref:`mozconfig <mozconfig>`
|
||||
file via ``mk_add_options``.
|
||||
|
||||
REBUILD_CHECK
|
||||
If defined, the build system will print information about why
|
||||
certain files were rebuilt.
|
||||
|
||||
This feature is disabled by default because it makes the build slower.
|
||||
|
||||
MACH_NO_TERMINAL_FOOTER
|
||||
If defined, the terminal footer displayed when building with mach in
|
||||
a TTY is disabled.
|
||||
|
||||
MACH_NO_WRITE_TIMES
|
||||
If defined, mach commands will not prefix output lines with the
|
||||
elapsed time since program start. This option is equivalent to
|
||||
passing ``--log-no-times`` to mach.
|
||||
|
||||
MOZ_PSEUDO_DERECURSE
|
||||
Activate an *experimental* build mode where make directory traversal
|
||||
is derecursified. This mode should result in faster build times at
|
||||
the expense of busted builds from time-to-time. The end goal is for
|
||||
this build mode to be the default. At which time, this variable will
|
||||
likely go away.
|
||||
|
||||
A value of ``1`` activates the mode with full optimizations.
|
||||
|
||||
A value of ``no-parallel-export`` activates the mode without
|
||||
optimizations to the *export* tier, which are known to be slightly
|
||||
buggy.
|
@ -26,3 +26,19 @@ Glossary
|
||||
generated build config and writes out files used to build the
|
||||
tree. Traditionally, config.status writes out a bunch of
|
||||
Makefiles.
|
||||
|
||||
install manifest
|
||||
A file containing metadata describing file installation rules.
|
||||
A large part of the build system consists of copying files
|
||||
around to appropriate places. We write out special files
|
||||
describing the set of required operations so we can process the
|
||||
actions effeciently. These files are install manifests.
|
||||
|
||||
clobber build
|
||||
A build performed with an initially empty object directory. All
|
||||
build actions must be performed.
|
||||
|
||||
incremental build
|
||||
A build performed with the result of a previous build in an
|
||||
object directory. The build should not have to work as hard because
|
||||
it will be able to reuse the work from previous builds.
|
||||
|
@ -15,8 +15,11 @@ Important Concepts
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
build-overview
|
||||
Mozconfig Files <mozconfigs>
|
||||
Profile Guided Optimization <pgo>
|
||||
slow
|
||||
environment-variables
|
||||
|
||||
mozbuild
|
||||
========
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _mozconfig:
|
||||
|
||||
===============
|
||||
mozconfig Files
|
||||
===============
|
||||
|
156
build/docs/slow.rst
Normal file
156
build/docs/slow.rst
Normal file
@ -0,0 +1,156 @@
|
||||
.. _slow:
|
||||
|
||||
============================
|
||||
Why the Build System is Slow
|
||||
============================
|
||||
|
||||
A common complaint about the build system is that it's slow. There are
|
||||
many reasons contributing to its slowness. We will attempt to document
|
||||
them here.
|
||||
|
||||
First, it is important to distinguish between a :term:`clobber build`
|
||||
and an :term:`incremental build`. The reasons for why each are slow can
|
||||
be different.
|
||||
|
||||
The build does a lot of work
|
||||
============================
|
||||
|
||||
It may not be obvious, but the main reason the build system is slow is
|
||||
because it does a lot of work! The source tree consists of a few
|
||||
thousand C++ files. On a modern machine, we spend over 120 minutes of CPU
|
||||
core time compiling files! So, if you are looking for the root cause of
|
||||
slow clobber builds, look at the sheer volume of C++ files in the tree.
|
||||
|
||||
You don't have enough CPU cores and MHz
|
||||
=======================================
|
||||
|
||||
The build should be CPU bound. If the build system maintainers are
|
||||
optimizing the build system perfectly, every CPU core in your machine
|
||||
should be 100% saturated during a build. While this isn't currently the
|
||||
case (keep reading below), generally speaking, the more CPU cores you
|
||||
have in your machine and the more total MHz in your machine, the better.
|
||||
|
||||
**We highly recommend building with no fewer than 4 physical CPU
|
||||
cores.** Please note the *physical* in this sentence. Hyperthreaded
|
||||
cores (an Intel Core i7 will report 8 CPU cores but only 4 are physical
|
||||
for example) only yield at most a 1.25x speedup per core.
|
||||
|
||||
We also recommend using the most modern CPU model possible. Haswell
|
||||
chips deliver much more performance per CPU cycle than say Sandy Bridge
|
||||
CPUs.
|
||||
|
||||
This cause impacts both clobber and incremental builds.
|
||||
|
||||
You are building with a slow I/O layer
|
||||
======================================
|
||||
|
||||
The build system can be I/O bound if your I/O layer is slow. Linking
|
||||
libxul on some platforms and build architectures can perform gigabytes
|
||||
of I/O.
|
||||
|
||||
To minimize the impact of slow I/O on build performance, **we highly
|
||||
recommend building with an SSD.** Power users with enough memory may opt
|
||||
to build from a RAM disk. Mechanical disks should be avoided if at all
|
||||
possible.
|
||||
|
||||
This cause impacts both clobber and incremental builds.
|
||||
|
||||
You don't have enough memory
|
||||
============================
|
||||
|
||||
The build system allocates a lot of memory, especially when building
|
||||
many things in parallel. If you don't have enough free system memory,
|
||||
the build will cause swap activity, slowing down your system and the
|
||||
build. Even if you never get to the point of swapping, the build system
|
||||
performs a lot of I/O and having all accessed files in memory and the
|
||||
page cache can significantly reduce the influence of the I/O layer on
|
||||
the build system.
|
||||
|
||||
**We recommend building with no less than 8 GB of system memory.** As
|
||||
always, the more memory you have, the better. For a bare bones machine
|
||||
doing nothing more than building the source tree, anything more than 16
|
||||
GB is likely entering the point of diminishing returns.
|
||||
|
||||
This cause impacts both clobber and incremental builds.
|
||||
|
||||
You are building with pymake
|
||||
============================
|
||||
|
||||
Pymake is slower than GNU make. One reason is Python is generally slower
|
||||
than C. The build system maintainers are consistently looking at
|
||||
optimizing pymake. However, it is death by a thousand cuts.
|
||||
|
||||
This cause impacts both clobber and incremental builds.
|
||||
|
||||
You are building on Windows
|
||||
===========================
|
||||
|
||||
Builds on Windows are slow for a few reasons. First, Windows builds use
|
||||
pymake, not GNU make (because of compatibility issues with GNU make).
|
||||
But, there are other sources of slowness.
|
||||
|
||||
New processes on Windows are about a magnitude slower to spawn than on
|
||||
UNIX-y systems such as Linux. This is because Windows has optimized new
|
||||
threads while the \*NIX platforms typically optimize new processes.
|
||||
Anyway, the build system spawns thousands of new processes during a
|
||||
build. Parts of the build that rely on rapid spawning of new processes
|
||||
are slow on Windows as a result. This is most pronounced when running
|
||||
*configure*. The configure file is a giant shell script and shell
|
||||
scripts rely heavily on new processes. This is why configure on Windows
|
||||
can run over a minute slower on Windows.
|
||||
|
||||
Another reason Windows builds are slower is because Windows lacks proper
|
||||
symlink support. On systems that support symlinks, we can generate a
|
||||
file into a staging area then symlink it into the final directory very
|
||||
quickly. On Windows, we have to perform a full file copy. This incurs
|
||||
much more I/O. And if done poorly, can muck with file modification
|
||||
times, messing up build dependencies. As of the summer of 2013, the
|
||||
impact of symlinks is being mitigated through the use
|
||||
of an :term:`install manifest`.
|
||||
|
||||
These issues impact both clobber and incremental builds.
|
||||
|
||||
Recursive make traversal is slow
|
||||
================================
|
||||
|
||||
The build system has traditionally been built by employing recursive
|
||||
make. Recursive make involves make iterating through directories / make
|
||||
files sequentially and executing each in turn. This is inefficient for
|
||||
directories containing few targets/tasks because make could be *starved*
|
||||
for work when processing these directories. Any time make is starved,
|
||||
the build isn't using all available CPU cycles and the build is slower
|
||||
as a result.
|
||||
|
||||
Work has started in bug 907365 to fix this issue by changing the way
|
||||
make traverses all the make files.
|
||||
|
||||
The impact of slow recursive make traversal is mostly felt on
|
||||
incremental builds. Traditionally, most of the wall time during a
|
||||
no-op build is spent in make traversal.
|
||||
|
||||
make is inefficient
|
||||
===================
|
||||
|
||||
Compared to modern build backends like Tup or Ninja, make is slow and
|
||||
inefficient. We can only make make so fast. At some point, we'll hit a
|
||||
performance plateau and will need to use a different tool to make builds
|
||||
faster.
|
||||
|
||||
Please note that clobber and incremental builds are different. A clobber
|
||||
build with make will likely be as fast as a clobber build with e.g. Tup.
|
||||
However, Tup should vastly outperform make when it comes to incremental
|
||||
builds. Therefore, this issue is mostly seen when performing incremental
|
||||
builds.
|
||||
|
||||
C++ header dependency hell
|
||||
==========================
|
||||
|
||||
Modifying a *.h* file can have significant impact on the build system.
|
||||
If you modify a *.h* that is used by 1000 C++ files, all of those 1000
|
||||
C++ files will be recompiled.
|
||||
|
||||
Our code base has traditionally been sloppy managing the impact of
|
||||
changed headers on build performance. Bug 785103 tracks improving the
|
||||
situation.
|
||||
|
||||
This issue mostly impacts the times of an :term:`incremental build`.
|
@ -14,7 +14,7 @@ JAVAFILES = \
|
||||
R.java \
|
||||
$(NULL)
|
||||
|
||||
RES_FILES = \
|
||||
ANDROID_RESFILES = \
|
||||
res/values/strings.xml \
|
||||
$(NULL)
|
||||
|
||||
|
@ -21,7 +21,7 @@ JAVAFILES = \
|
||||
R.java \
|
||||
$(NULL)
|
||||
|
||||
RES_FILES = \
|
||||
ANDROID_RESFILES = \
|
||||
res/drawable/icon.png \
|
||||
res/drawable/ateamlogo.png \
|
||||
res/drawable/ic_stat_first.png \
|
||||
|
@ -12,7 +12,7 @@ JAVAFILES = \
|
||||
R.java \
|
||||
$(NULL)
|
||||
|
||||
RES_FILES = \
|
||||
ANDROID_RESFILES = \
|
||||
res/drawable-hdpi/icon.png \
|
||||
res/drawable-ldpi/icon.png \
|
||||
res/drawable-mdpi/icon.png \
|
||||
|
@ -12,7 +12,7 @@ JAVAFILES = \
|
||||
R.java \
|
||||
$(NULL)
|
||||
|
||||
RES_FILES = \
|
||||
ANDROID_RESFILES = \
|
||||
res/drawable-hdpi/icon.png \
|
||||
res/drawable-ldpi/icon.png \
|
||||
res/drawable-mdpi/icon.png \
|
||||
|
@ -13,7 +13,7 @@ JAVAFILES = \
|
||||
WatcherService.java \
|
||||
$(NULL)
|
||||
|
||||
RES_FILES = \
|
||||
ANDROID_RESFILES = \
|
||||
res/drawable-hdpi/icon.png \
|
||||
res/drawable-hdpi/ateamlogo.png \
|
||||
res/drawable-ldpi/icon.png \
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsPrincipal.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
|
||||
class nsIURI;
|
||||
|
||||
@ -54,7 +53,6 @@ public:
|
||||
virtual ~nsNullPrincipal();
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
|
||||
};
|
||||
|
||||
#endif // nsNullPrincipal_h__
|
||||
|
@ -149,7 +149,8 @@ nsNullPrincipal::GetHashValue(uint32_t *aResult)
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::GetSecurityPolicy(void** aSecurityPolicy)
|
||||
{
|
||||
// We don't actually do security policy caching.
|
||||
// We don't actually do security policy caching. And it's not like anyone
|
||||
// can set a security policy for us anyway.
|
||||
*aSecurityPolicy = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -157,7 +158,8 @@ nsNullPrincipal::GetSecurityPolicy(void** aSecurityPolicy)
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
|
||||
{
|
||||
// We don't actually do security policy caching.
|
||||
// We don't actually do security policy caching. And it's not like anyone
|
||||
// can set a security policy for us anyway.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -170,20 +172,16 @@ nsNullPrincipal::GetURI(nsIURI** aURI)
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
|
||||
{
|
||||
NS_IF_ADDREF(*aCsp = mCSP);
|
||||
// CSP on a null principal makes no sense
|
||||
*aCsp = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
|
||||
{
|
||||
// If CSP was already set, it should not be destroyed! Instead, it should
|
||||
// get set anew when a new principal is created.
|
||||
if (mCSP)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
mCSP = aCsp;
|
||||
return NS_OK;
|
||||
// CSP on a null principal makes no sense
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define mozilla_RegistryMessageUtils_h
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsString.h"
|
||||
|
||||
struct SerializedURI
|
||||
{
|
||||
|
@ -10,32 +10,20 @@
|
||||
|
||||
*/
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsChromeProtocolHandler.h"
|
||||
#include "nsChromeRegistry.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentCID.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIChromeRegistry.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "nsIFileChannel.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIJARChannel.h"
|
||||
#include "nsIJARURI.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIStandardURL.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsString.h"
|
||||
#include "prlog.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -8,33 +8,23 @@
|
||||
#include "nsChromeRegistryChrome.h"
|
||||
#include "nsChromeRegistryContent.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "prio.h"
|
||||
#include "prprf.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsLayoutCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsString.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
#include "nsCSSStyleSheet.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMLocation.h"
|
||||
#include "nsIDOMWindowCollection.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIJARProtocolHandler.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
|
||||
|
@ -6,31 +6,24 @@
|
||||
#ifndef nsChromeRegistry_h
|
||||
#define nsChromeRegistry_h
|
||||
|
||||
#include "nsIChromeRegistry.h"
|
||||
#include "nsIToolkitChromeRegistry.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsIXULOverlayProvider.h"
|
||||
#endif
|
||||
|
||||
#include "pldhash.h"
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsURIHashKey.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsIResProtocolHandler.h"
|
||||
#include "nsIXPConnect.h"
|
||||
|
||||
#include "mozilla/Omnijar.h"
|
||||
#include "mozilla/FileLocation.h"
|
||||
|
||||
class nsIDOMWindow;
|
||||
class nsIPrefBranch;
|
||||
class nsIURL;
|
||||
|
||||
// The chrome registry is actually split between nsChromeRegistryChrome and
|
||||
|
@ -13,35 +13,27 @@
|
||||
#include <windows.h>
|
||||
#elif defined(XP_MACOSX)
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsComponentManager.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsStringEnumerator.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsZipArchive.h"
|
||||
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
|
||||
#include "nsICommandLine.h"
|
||||
#include "nsILocaleService.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIResProtocolHandler.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIVersionComparator.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIXULAppInfo.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
|
||||
#define UILOCALE_CMD_LINE_ARG "UILocale"
|
||||
|
@ -6,6 +6,7 @@
|
||||
#ifndef nsChromeRegistryChrome_h
|
||||
#define nsChromeRegistryChrome_h
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsChromeRegistry.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
@ -4,11 +4,10 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "RegistryMessageUtils.h"
|
||||
#include "nsChromeRegistry.h"
|
||||
#include "nsChromeRegistryContent.h"
|
||||
#include "nsString.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsResProtocolHandler.h"
|
||||
#include "nsIResProtocolHandler.h"
|
||||
|
||||
nsChromeRegistryContent::nsChromeRegistryContent()
|
||||
{
|
||||
|
@ -7,10 +7,8 @@
|
||||
#define nsChromeRegistryContent_h
|
||||
|
||||
#include "nsChromeRegistry.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
class nsCString;
|
||||
struct ChromePackage;
|
||||
struct ResourceMapping;
|
||||
struct OverrideMapping;
|
||||
|
@ -797,8 +797,8 @@ PLY_INCLUDE = -I$(topsrcdir)/other-licenses/ply
|
||||
|
||||
export CL_INCLUDES_PREFIX
|
||||
|
||||
ifeq ($(MOZ_WIDGET_GTK),2)
|
||||
MOZ_GTK2_CFLAGS := -I$(topsrcdir)/widget/gtk2/compat $(MOZ_GTK2_CFLAGS)
|
||||
ifdef MOZ_GTK2_CFLAGS
|
||||
MOZ_GTK2_CFLAGS := -I$(topsrcdir)/widget/gtk/compat $(MOZ_GTK2_CFLAGS)
|
||||
endif
|
||||
|
||||
DEFINES += -DNO_NSPR_10_SUPPORT
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
ifndef INCLUDED_JAVA_BUILD_MK #{
|
||||
|
||||
ifdef RES_FILES #{
|
||||
ifdef ANDROID_RESFILES #{
|
||||
res-dep := .deps-copy-java-res
|
||||
|
||||
GENERATED_DIRS += res
|
||||
@ -16,7 +16,7 @@ GARBAGE += $(res-dep)
|
||||
export:: $(res-dep)
|
||||
|
||||
res-dep-preqs := \
|
||||
$(addprefix $(srcdir)/,$(RES_FILES)) \
|
||||
$(addprefix $(srcdir)/,$(ANDROID_RESFILES)) \
|
||||
$(call mkdir_deps,res) \
|
||||
$(if $(IS_LANGUAGE_REPACK),FORCE) \
|
||||
$(NULL)
|
||||
|
@ -1225,7 +1225,7 @@ endif
|
||||
###############################################################################
|
||||
# Java rules
|
||||
###############################################################################
|
||||
ifneq (,$(value JAVAFILES)$(value RESFILES))
|
||||
ifneq (,$(value JAVAFILES)$(value ANDROID_RESFILES))
|
||||
include $(topsrcdir)/config/makefiles/java-build.mk
|
||||
endif
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIDOMDocument;
|
||||
|
||||
|
@ -49,9 +49,9 @@ function ContentSecurityPolicy() {
|
||||
|
||||
this._request = "";
|
||||
this._requestOrigin = "";
|
||||
this._weakRequestPrincipal = null;
|
||||
this._requestPrincipal = "";
|
||||
this._referrer = "";
|
||||
this._weakDocRequest = { get : function() { return null; } };
|
||||
this._docRequest = null;
|
||||
CSPdebug("CSP object initialized, no policies to enforce yet");
|
||||
|
||||
this._cache = { };
|
||||
@ -249,7 +249,7 @@ ContentSecurityPolicy.prototype = {
|
||||
return;
|
||||
|
||||
// Save the docRequest for fetching a policy-uri
|
||||
this._weakDocRequest = Cu.getWeakReference(aChannel);
|
||||
this._docRequest = aChannel;
|
||||
|
||||
// save the document URI (minus <fragment>) and referrer for reporting
|
||||
let uri = aChannel.URI.cloneIgnoringRef();
|
||||
@ -260,9 +260,8 @@ ContentSecurityPolicy.prototype = {
|
||||
this._requestOrigin = uri;
|
||||
|
||||
//store a reference to the principal, that can later be used in shouldLoad
|
||||
this._weakRequestPrincipal = Cu.getWeakReference(Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager)
|
||||
.getChannelPrincipal(aChannel));
|
||||
this._requestPrincipal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
|
||||
getService(Components.interfaces.nsIScriptSecurityManager).getChannelPrincipal(aChannel);
|
||||
|
||||
if (aChannel.referrer) {
|
||||
let referrer = aChannel.referrer.cloneIgnoringRef();
|
||||
@ -311,13 +310,13 @@ ContentSecurityPolicy.prototype = {
|
||||
if (aSpecCompliant) {
|
||||
newpolicy = CSPRep.fromStringSpecCompliant(aPolicy,
|
||||
selfURI,
|
||||
this._weakDocRequest.get(),
|
||||
this._docRequest,
|
||||
this,
|
||||
aReportOnly);
|
||||
} else {
|
||||
newpolicy = CSPRep.fromString(aPolicy,
|
||||
selfURI,
|
||||
this._weakDocRequest.get(),
|
||||
this._docRequest,
|
||||
this,
|
||||
aReportOnly);
|
||||
}
|
||||
@ -435,8 +434,8 @@ ContentSecurityPolicy.prototype = {
|
||||
// we need to set an nsIChannelEventSink on the channel object
|
||||
// so we can tell it to not follow redirects when posting the reports
|
||||
chan.notificationCallbacks = new CSPReportRedirectSink(policy);
|
||||
if (this._weakDocRequest.get()) {
|
||||
chan.loadGroup = this._weakDocRequest.get().loadGroup;
|
||||
if (this._docRequest) {
|
||||
chan.loadGroup = this._docRequest.loadGroup;
|
||||
}
|
||||
|
||||
chan.QueryInterface(Ci.nsIUploadChannel)
|
||||
@ -455,7 +454,7 @@ ContentSecurityPolicy.prototype = {
|
||||
.getService(Ci.nsIContentPolicy);
|
||||
if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_CSP_REPORT,
|
||||
chan.URI, this._requestOrigin,
|
||||
null, null, null, this._weakRequestPrincipal.get())
|
||||
null, null, null, this._requestPrincipal)
|
||||
!= Ci.nsIContentPolicy.ACCEPT) {
|
||||
continue; // skip unauthorized URIs
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
#define nsAttrValue_h___
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsCaseTreatment.h"
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "nsContentListDeclarations.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIHTMLCollection.h"
|
||||
#include "nsIDOMNodeList.h"
|
||||
#include "nsINodeList.h"
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
// image copy stuff
|
||||
#include "nsIImageLoadingContent.h"
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDOMMozNamedAttrMap.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsIAtom;
|
||||
|
@ -2681,8 +2681,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
if (csp) {
|
||||
// Copy into principal
|
||||
nsIPrincipal* principal = GetPrincipal();
|
||||
rv = principal->SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
principal->SetCsp(csp);
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gCspPRLog, PR_LOG_DEBUG,
|
||||
("Inserted CSP into principal %p", principal));
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "nsIMozBrowserFrame.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "mozilla/dom/StructuredCloneUtils.h"
|
||||
#include "js/StructuredClone.h"
|
||||
|
||||
using mozilla::dom::StructuredCloneData;
|
||||
using mozilla::dom::StructuredCloneClosure;
|
||||
|
@ -97,19 +97,6 @@ MOCHITEST_FILES := \
|
||||
file_bug836922_npolicies.html^headers^ \
|
||||
file_bug836922_npolicies_violation.sjs \
|
||||
file_bug836922_npolicies_ro_violation.sjs \
|
||||
test_bug886164.html \
|
||||
file_bug886164.html \
|
||||
file_bug886164.html^headers^ \
|
||||
file_bug886164_2.html \
|
||||
file_bug886164_2.html^headers^ \
|
||||
file_bug886164_3.html \
|
||||
file_bug886164_3.html^headers^ \
|
||||
file_bug886164_4.html \
|
||||
file_bug886164_4.html^headers^ \
|
||||
file_bug886164_5.html \
|
||||
file_bug886164_5.html^headers^ \
|
||||
file_bug886164_6.html \
|
||||
file_bug886164_6.html^headers^ \
|
||||
test_CSP_bug916446.html \
|
||||
file_CSP_bug916446.html \
|
||||
file_CSP_bug916446.html^headers^ \
|
||||
|
@ -1,15 +0,0 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox="allow-same-origin" -->
|
||||
<!-- Content-Security-Policy: default-src 'self' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img_bad&type=img/png"> </img>
|
||||
|
||||
<!-- these should load ok -->
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img_good&type=img/png" />
|
||||
<script src='/tests/content/base/test/csp/file_CSP.sjs?testid=scripta_bad&type=text/javascript'></script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
Content-Security-Policy: default-src 'self'
|
@ -1,14 +0,0 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox -->
|
||||
<!-- Content-Security-Policy: default-src 'self' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img2_bad&type=img/png"> </img>
|
||||
|
||||
<!-- these should load ok -->
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img2a_good&type=img/png" />
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
Content-Security-Policy: default-src 'self'
|
@ -1,12 +0,0 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox -->
|
||||
<!-- Content-Security-Policy: default-src 'none' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img3_bad&type=img/png"> </img>
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img3a_bad&type=img/png" />
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
Content-Security-Policy: default-src 'none'
|
@ -1,12 +0,0 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox -->
|
||||
<!-- Content-Security-Policy: default-src 'none' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img4_bad&type=img/png"> </img>
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img4a_bad&type=img/png" />
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
Content-Security-Policy: default-src 'none'
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<script type="text/javascript">
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
|
||||
function doStuff() {
|
||||
ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
|
||||
}
|
||||
</script>
|
||||
<script src='file_iframe_sandbox_pass.js'></script>
|
||||
<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
|
||||
I am sandboxed but with only inline "allow-scripts"
|
||||
|
||||
<!-- sandbox="allow-scripts" -->
|
||||
<!-- Content-Security-Policy: default-src 'none' 'unsafe-inline'-->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img5_bad&type=img/png" />
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img5a_bad&type=img/png"> </img>
|
||||
<script src='/tests/content/base/test/csp/file_CSP.sjs?testid=script5_bad&type=text/javascript'></script>
|
||||
<script src='http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=script5a_bad&type=text/javascript'></script>
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
Content-Security-Policy: default-src 'none' 'unsafe-inline';
|
@ -1,35 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
</head>
|
||||
<script type="text/javascript">
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
|
||||
function doStuff() {
|
||||
ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
|
||||
|
||||
document.getElementById('a_form').submit();
|
||||
|
||||
// trigger the javascript: url test
|
||||
sendMouseEvent({type:'click'}, 'a_link');
|
||||
}
|
||||
</script>
|
||||
<script src='file_iframe_sandbox_pass.js'></script>
|
||||
<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
|
||||
I am sandboxed but with "allow-scripts"
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img6_bad&type=img/png"> </img>
|
||||
<script src='http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=script6_bad&type=text/javascript'></script>
|
||||
|
||||
<form method="get" action="file_iframe_sandbox_form_fail.html" id="a_form">
|
||||
First name: <input type="text" name="firstname">
|
||||
Last name: <input type="text" name="lastname">
|
||||
<input type="submit" onclick="doSubmit()" id="a_button">
|
||||
</form>
|
||||
|
||||
<a href = 'javascript:ok(true, "documents sandboxed with allow-scripts should be able to run script from javascript: URLs");' id='a_link'>click me</a>
|
||||
</body>
|
||||
</html>
|
@ -1 +0,0 @@
|
||||
Content-Security-Policy: default-src 'self' 'unsafe-inline';
|
@ -1,185 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 886164 - Enforce CSP in sandboxed iframe</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<iframe style="width:200px;height:200px;" id='cspframe' sandbox="allow-same-origin"></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe2' sandbox></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe3' sandbox="allow-same-origin"></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe4' sandbox></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe5' sandbox="allow-scripts"></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe6' sandbox="allow-same-origin allow-scripts"></iframe>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
|
||||
var path = "/tests/content/base/test/csp/";
|
||||
|
||||
// These are test results: -1 means it hasn't run,
|
||||
// true/false is the pass/fail result.
|
||||
window.tests = {
|
||||
// sandbox allow-same-origin; 'self'
|
||||
img_good: -1, // same origin
|
||||
img_bad: -1, //example.com
|
||||
|
||||
// sandbox; 'self'
|
||||
img2_bad: -1, //example.com
|
||||
img2a_good: -1, // same origin & is image
|
||||
|
||||
// sandbox allow-same-origin; 'none'
|
||||
img3_bad: -1,
|
||||
img3a_bad: -1,
|
||||
|
||||
// sandbox; 'none'
|
||||
img4_bad: -1,
|
||||
img4a_bad: -1,
|
||||
|
||||
// sandbox allow-scripts; 'none' 'unsafe-inline'
|
||||
img5_bad: -1,
|
||||
img5a_bad: -1,
|
||||
script5_bad: -1,
|
||||
script5a_bad: -1,
|
||||
|
||||
// sandbox allow-same-origin allow-scripts; 'self' 'unsafe-inline'
|
||||
img6_bad: -1,
|
||||
script6_bad: -1,
|
||||
};
|
||||
|
||||
// a postMessage handler that is used by sandboxed iframes without
|
||||
// 'allow-same-origin' to communicate pass/fail back to this main page.
|
||||
// it expects to be called with an object like {ok: true/false, desc:
|
||||
// <description of the test> which it then forwards to ok()
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
||||
function receiveMessage(event)
|
||||
{
|
||||
ok_wrapper(event.data.ok, event.data.desc);
|
||||
}
|
||||
|
||||
var cspTestsDone = false;
|
||||
var iframeSandboxTestsDone = false;
|
||||
|
||||
// iframe related
|
||||
var completedTests = 0;
|
||||
var passedTests = 0;
|
||||
|
||||
function ok_wrapper(result, desc) {
|
||||
ok(result, desc);
|
||||
|
||||
completedTests++;
|
||||
|
||||
if (result) {
|
||||
passedTests++;
|
||||
}
|
||||
|
||||
if (completedTests === 5) {
|
||||
iframeSandboxTestsDone = true;
|
||||
if (cspTestsDone) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//csp related
|
||||
|
||||
// This is used to watch the blocked data bounce off CSP and allowed data
|
||||
// get sent out to the wire.
|
||||
function examiner() {
|
||||
SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
|
||||
SpecialPowers.addObserver(this, "http-on-modify-request", false);
|
||||
}
|
||||
examiner.prototype = {
|
||||
observe: function(subject, topic, data) {
|
||||
// subject should be an nsURI, and should be either allowed or blocked.
|
||||
if (!SpecialPowers.can_QI(subject))
|
||||
return;
|
||||
|
||||
var testpat = new RegExp("testid=([a-z0-9_]+)");
|
||||
|
||||
//_good things better be allowed!
|
||||
//_bad things better be stopped!
|
||||
|
||||
if (topic === "http-on-modify-request") {
|
||||
//these things were allowed by CSP
|
||||
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
|
||||
if (!testpat.test(asciiSpec)) return;
|
||||
var testid = testpat.exec(asciiSpec)[1];
|
||||
|
||||
window.testResult(testid,
|
||||
/_good/.test(testid),
|
||||
asciiSpec + " allowed by csp");
|
||||
}
|
||||
|
||||
if(topic === "csp-on-violate-policy") {
|
||||
//these were blocked... record that they were blocked
|
||||
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
|
||||
if (!testpat.test(asciiSpec)) return;
|
||||
var testid = testpat.exec(asciiSpec)[1];
|
||||
window.testResult(testid,
|
||||
/_bad/.test(testid),
|
||||
asciiSpec + " blocked by \"" + data + "\"");
|
||||
}
|
||||
},
|
||||
|
||||
// must eventually call this to remove the listener,
|
||||
// or mochitests might get borked.
|
||||
remove: function() {
|
||||
SpecialPowers.removeObserver(this, "csp-on-violate-policy");
|
||||
SpecialPowers.removeObserver(this, "http-on-modify-request");
|
||||
}
|
||||
}
|
||||
|
||||
window.examiner = new examiner();
|
||||
|
||||
window.testResult = function(testname, result, msg) {
|
||||
//test already complete.... forget it... remember the first result.
|
||||
if (window.tests[testname] != -1)
|
||||
return;
|
||||
|
||||
window.tests[testname] = result;
|
||||
is(result, true, testname + ' test: ' + msg);
|
||||
|
||||
// if any test is incomplete, keep waiting
|
||||
for (var v in window.tests)
|
||||
if(tests[v] == -1) {
|
||||
console.log(v + " is not complete");
|
||||
return;
|
||||
}
|
||||
|
||||
// ... otherwise, finish
|
||||
window.examiner.remove();
|
||||
cspTestsDone = true;
|
||||
if (iframeSandboxTestsDone) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{'set':[["security.csp.speccompliant", true]]},
|
||||
function() {
|
||||
// save this for last so that our listeners are registered.
|
||||
// ... this loads the testbed of good and bad requests.
|
||||
document.getElementById('cspframe').src = 'file_bug886164.html';
|
||||
document.getElementById('cspframe2').src = 'file_bug886164_2.html';
|
||||
document.getElementById('cspframe3').src = 'file_bug886164_3.html';
|
||||
document.getElementById('cspframe4').src = 'file_bug886164_4.html';
|
||||
document.getElementById('cspframe5').src = 'file_bug886164_5.html';
|
||||
document.getElementById('cspframe6').src = 'file_bug886164_6.html';
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -23,6 +23,7 @@
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsDeviceContext.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -12,7 +12,8 @@
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsEvent.h"
|
||||
#include "mozilla/dom/UIEventBinding.h"
|
||||
#include "Units.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsDeviceContext.h"
|
||||
|
||||
class nsDOMUIEvent : public nsDOMEvent,
|
||||
public nsIDOMUIEvent
|
||||
|
@ -530,6 +530,12 @@ public:
|
||||
mTextTracks->AddTextTrack(aTextTrack);
|
||||
}
|
||||
|
||||
void RemoveTextTrack(TextTrack* aTextTrack) {
|
||||
if (mTextTracks) {
|
||||
mTextTracks->RemoveTextTrack(*aTextTrack);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
class MediaLoadListener;
|
||||
class StreamListener;
|
||||
|
@ -290,8 +290,15 @@ HTMLTrackElement::BindToTree(nsIDocument* aDocument,
|
||||
void
|
||||
HTMLTrackElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
if (mMediaParent && aNullParent) {
|
||||
mMediaParent = nullptr;
|
||||
if (mMediaParent) {
|
||||
// mTrack can be null if HTMLTrackElement::LoadResource has never been
|
||||
// called.
|
||||
if (mTrack) {
|
||||
mMediaParent->RemoveTextTrack(mTrack);
|
||||
}
|
||||
if (aNullParent) {
|
||||
mMediaParent = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
@ -73,15 +73,13 @@ TextTrack::SetMode(TextTrackMode aValue)
|
||||
void
|
||||
TextTrack::AddCue(TextTrackCue& aCue)
|
||||
{
|
||||
//XXX: If cue exists, remove. Bug 867823.
|
||||
mCueList->AddCue(aCue);
|
||||
}
|
||||
|
||||
void
|
||||
TextTrack::RemoveCue(TextTrackCue& aCue)
|
||||
TextTrack::RemoveCue(TextTrackCue& aCue, ErrorResult& aRv)
|
||||
{
|
||||
//XXX: If cue does not exists throw NotFoundError. Bug 867823.
|
||||
mCueList->RemoveCue(aCue);
|
||||
mCueList->RemoveCue(aCue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -99,7 +99,7 @@ public:
|
||||
void Update(double aTime);
|
||||
|
||||
void AddCue(TextTrackCue& aCue);
|
||||
void RemoveCue(TextTrackCue& aCue);
|
||||
void RemoveCue(TextTrackCue& aCue, ErrorResult& aRv);
|
||||
void CueChanged(TextTrackCue& aCue);
|
||||
|
||||
IMPL_EVENT_HANDLER(cuechange)
|
||||
|
@ -116,6 +116,21 @@ public:
|
||||
CueChanged();
|
||||
}
|
||||
|
||||
void GetRegionId(nsAString& aRegionId) const
|
||||
{
|
||||
aRegionId = mRegionId;
|
||||
}
|
||||
|
||||
void SetRegionId(const nsAString& aRegionId)
|
||||
{
|
||||
if (mRegionId == aRegionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRegionId = aRegionId;
|
||||
CueChanged();
|
||||
}
|
||||
|
||||
DirectionSetting Vertical() const
|
||||
{
|
||||
return mVertical;
|
||||
@ -304,6 +319,7 @@ private:
|
||||
int32_t mSize;
|
||||
bool mPauseOnExit;
|
||||
bool mSnapToLines;
|
||||
nsString mRegionId;
|
||||
DirectionSetting mVertical;
|
||||
int mLine;
|
||||
TextTrackCueAlign mAlign;
|
||||
|
@ -66,12 +66,19 @@ TextTrackCueList::GetCueById(const nsAString& aId)
|
||||
void
|
||||
TextTrackCueList::AddCue(TextTrackCue& cue)
|
||||
{
|
||||
if (mList.Contains(&cue)) {
|
||||
return;
|
||||
}
|
||||
mList.AppendElement(&cue);
|
||||
}
|
||||
|
||||
void
|
||||
TextTrackCueList::RemoveCue(TextTrackCue& cue)
|
||||
TextTrackCueList::RemoveCue(TextTrackCue& cue, ErrorResult& aRv)
|
||||
{
|
||||
if (!mList.Contains(&cue)) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
|
||||
return;
|
||||
}
|
||||
mList.RemoveElement(&cue);
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -47,7 +48,7 @@ public:
|
||||
TextTrackCue* GetCueById(const nsAString& aId);
|
||||
|
||||
void AddCue(TextTrackCue& cue);
|
||||
void RemoveCue(TextTrackCue& cue);
|
||||
void RemoveCue(TextTrackCue& cue, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "mozilla/dom/TextTrack.h"
|
||||
#include "mozilla/dom/TextTrackRegion.h"
|
||||
#include "mozilla/dom/TextTrackRegionBinding.h"
|
||||
#include "mozilla/dom/VTTRegionBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -22,7 +22,7 @@ NS_INTERFACE_MAP_END
|
||||
JSObject*
|
||||
TextTrackRegion::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return TextTrackRegionBinding::Wrap(aCx, aScope, this);
|
||||
return VTTRegionBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
already_AddRefed<TextTrackRegion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include "mozilla/dom/TextTrackRegion.h"
|
||||
#include "mozilla/dom/TextTrackRegionList.h"
|
||||
#include "mozilla/dom/TextTrackRegionListBinding.h"
|
||||
#include "mozilla/dom/VTTRegionListBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -23,7 +23,7 @@ NS_INTERFACE_MAP_END
|
||||
JSObject*
|
||||
TextTrackRegionList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return TextTrackRegionListBinding::Wrap(aCx, aScope, this);
|
||||
return VTTRegionListBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
TextTrackRegionList::TextTrackRegionList(nsISupports* aGlobal)
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include "WebVTTListener.h"
|
||||
#include "mozilla/dom/TextTrackCue.h"
|
||||
#include "mozilla/dom/TextTrackRegion.h"
|
||||
#include "mozilla/dom/VTTRegionBinding.h"
|
||||
#include "mozilla/dom/HTMLTrackElement.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIWebVTTParserWrapper.h"
|
||||
@ -172,7 +174,17 @@ WebVTTListener::OnCue(const JS::Value &aCue, JSContext* aCx)
|
||||
NS_IMETHODIMP
|
||||
WebVTTListener::OnRegion(const JS::Value &aRegion, JSContext* aCx)
|
||||
{
|
||||
// TODO: Implement VTTRegions see bug 897504
|
||||
if (!aRegion.isObject()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
TextTrackRegion* region;
|
||||
nsresult rv = UNWRAP_OBJECT(VTTRegion, aCx, &aRegion.toObject(),
|
||||
region);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mElement->mTrack->AddRegion(*region);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -140,6 +140,7 @@ MOCHITEST_FILES = \
|
||||
$(filter disabled-for-intermittent-failures--bug-608634, test_error_in_video_document.html) \
|
||||
test_texttrack.html \
|
||||
test_texttrackcue.html \
|
||||
test_texttrackregion.html \
|
||||
test_timeupdate_small_files.html \
|
||||
test_unseekable.html \
|
||||
test_VideoPlaybackQuality.html \
|
||||
@ -272,6 +273,7 @@ MOCHITEST_FILES += \
|
||||
notags.mp3 \
|
||||
id3tags.mp3 \
|
||||
basic.vtt \
|
||||
region.vtt \
|
||||
long.vtt \
|
||||
$(NULL)
|
||||
|
||||
|
5
content/media/test/region.vtt
Normal file
5
content/media/test/region.vtt
Normal file
@ -0,0 +1,5 @@
|
||||
WEBVTT
|
||||
Region: id=fred width=62% lines=5 regionanchor=4%,78% viewportanchor=10%,90% scroll=up
|
||||
|
||||
00:01.000 --> 00:02.000 region:fred
|
||||
Test here.
|
@ -84,40 +84,29 @@ SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
|
||||
is(cue.text, "foo", "Cue's text should be foo.");
|
||||
|
||||
// Adding the same cue again should not increase the cue count.
|
||||
// TODO: https://bugzilla.mozilla.org/show_bug.cgi?id=867823
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrack-addcue
|
||||
trackElement.track.addCue(vttCue);
|
||||
todo_is(cueList.length, 5, "Cue list length should be 5.");
|
||||
is(cueList.length, 5, "Cue list length should be 5.");
|
||||
|
||||
// Check that we are able to remove cues.
|
||||
trackElement.track.removeCue(cue);
|
||||
// TODO: Marked as todo as incorrect addition up top increases cue count
|
||||
// to 4 -- https://bugzilla.mozilla.org/show_bug.cgi?id=867823
|
||||
todo_is(cueList.length, 4, "Cue list length should be 4.");
|
||||
is(cueList.length, 4, "Cue list length should be 4.");
|
||||
|
||||
var exceptionHappened = false;
|
||||
try {
|
||||
// We should not be able to remove a cue that is not in the list.
|
||||
cue = new VTTCue(1, 2, "foo");
|
||||
trackElement.removeCue(cue);
|
||||
trackElement.track.removeCue(cue);
|
||||
} catch (e) {
|
||||
// "NotFoundError" should be thrown when trying to remove a cue that is
|
||||
// not in the list.
|
||||
// TODO: https://bugzilla.mozilla.org/show_bug.cgi?id=867823
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#dom-texttrack-removecue
|
||||
todo_is(e.name, "NotFoundError", "We should have caught an error.");
|
||||
is(e.name, "NotFoundError", "Should have thrown NotFoundError.");
|
||||
exceptionHappened = true;
|
||||
}
|
||||
// If this is false then we did not throw an error and probably removed a cue
|
||||
// when we shouln't have.
|
||||
ok(exceptionHappened, "Exception should have happened.");
|
||||
|
||||
// We should not have removed a cue so the cue list length should not
|
||||
// have changed.
|
||||
// TODO: Marked as todo as incorrect addition of cue up top increases
|
||||
// count erroneously.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=867823
|
||||
todo_is(cueList.length, 4, "Cue list length should be 4.");
|
||||
is(cueList.length, 4, "Cue list length should be 4.");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user