This commit is contained in:
Richard Newman 2012-02-17 19:04:00 -08:00
Родитель b611868ba2 66f0fb03f2
Коммит 8381eca623
606 изменённых файлов: 20007 добавлений и 8388 удалений

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

@ -1494,28 +1494,24 @@ nsHTMLTableAccessible::IsProbablyForLayout(bool *aIsProbablyForLayout)
* Rules for non-bordered tables with 2-4 columns and 2+ rows from here on forward * Rules for non-bordered tables with 2-4 columns and 2+ rows from here on forward
*/ */
// Check for styled background color across the row // Check for styled background color across rows (alternating background
// Alternating background color is a common way // color is a common feature for data tables).
nsCOMPtr<nsIDOMNodeList> nodeList; PRUint32 childCount = GetChildCount();
nsCOMPtr<nsIDOMElement> tableElt(do_QueryInterface(mContent)); nsAutoString rowColor, prevRowColor;
tableElt->GetElementsByTagName(NS_LITERAL_STRING("tr"), getter_AddRefs(nodeList)); for (PRUint32 childIdx = 0; childIdx < childCount; childIdx++) {
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE); nsAccessible* child = GetChildAt(childIdx);
PRUint32 length; if (child->Role() == roles::ROW) {
nodeList->GetLength(&length); nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl =
nsAutoString color, lastRowColor; nsCoreUtils::GetComputedStyleDeclaration(EmptyString(),
for (PRUint32 rowCount = 0; rowCount < length; rowCount ++) { child->GetContent());
nsCOMPtr<nsIDOMNode> rowNode; if (styleDecl) {
nodeList->Item(rowCount, getter_AddRefs(rowNode)); prevRowColor = rowColor;
nsCOMPtr<nsIContent> rowContent(do_QueryInterface(rowNode)); styleDecl->GetPropertyValue(NS_LITERAL_STRING("background-color"),
rowColor);
nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl = if (childIdx > 0 && !prevRowColor.Equals(rowColor)) {
nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), rowContent); RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
NS_ENSURE_TRUE(styleDecl, NS_ERROR_FAILURE); }
}
lastRowColor = color;
styleDecl->GetPropertyValue(NS_LITERAL_STRING("background-color"), color);
if (rowCount > 0 && false == lastRowColor.Equals(color)) {
RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
} }
} }

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

@ -1631,6 +1631,9 @@ nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
NS_ENSURE_ARG_POINTER(aCaretOffset); NS_ENSURE_ARG_POINTER(aCaretOffset);
*aCaretOffset = -1; *aCaretOffset = -1;
if (IsDefunct())
return NS_ERROR_FAILURE;
// Not focused focusable accessible except document accessible doesn't have // Not focused focusable accessible except document accessible doesn't have
// a caret. // a caret.
if (!IsDoc() && !FocusMgr()->IsFocused(this) && if (!IsDoc() && !FocusMgr()->IsFocused(this) &&

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

@ -48,6 +48,7 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES =\ _TEST_FILES =\
test_ariadialog.html \ test_ariadialog.html \
test_colorpicker.xul \ test_colorpicker.xul \
test_cssoverflow.html \
test_contextmenu.xul \ test_contextmenu.xul \
test_doc.html \ test_doc.html \
test_gencontent.html \ test_gencontent.html \

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

@ -0,0 +1,141 @@
<html>
<head>
<title>Testing HTML scrollable frames (css overflow style)</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
////////////////////////////////////////////////////////////////////////////
// Invokers
////////////////////////////////////////////////////////////////////////////
/**
* Change scroll range to not empty size and inserts a child into container
* to trigger tree update of the container. Prior to bug 677154 not empty
* size resulted to accessible creation for scroll area, container tree
* update picked up that accessible unattaching scroll area accessible
* subtree.
*/
function changeScrollRange(aContainerID, aScrollAreaID)
{
this.containerNode = getNode(aContainerID);
this.container = getAccessible(this.containerNode);
this.scrollAreaNode = getNode(aScrollAreaID);
this.eventSeq = [
new invokerChecker(EVENT_REORDER, this.container)
];
this.invoke = function changeScrollRange_invoke()
{
this.scrollAreaNode.style.width = "20px";
this.containerNode.appendChild(document.createElement("input"));
}
this.finalCheck = function changeScrollRange_finalCheck()
{
var accTree =
{ SECTION: [ // container
{ SECTION: [ // scroll area
{ ENTRY: [] } // child content
] },
{ ENTRY: [] } // inserted input
] };
testAccessibleTree(this.container, accTree);
}
this.getID = function changeScrollRange_getID()
{
return "change scroll range for " + prettyName(aScrollAreaID);
}
}
/**
* Change scrollbar styles from hidden to auto. That makes us to create an
* accessible for scroll area.
*/
function changeScrollbarStyles(aContainerID, aScrollAreaID)
{
this.container = getAccessible(aContainerID);
this.scrollAreaNode = getNode(aScrollAreaID);
this.eventSeq = [
new invokerChecker(EVENT_SHOW, getAccessible, this.scrollAreaNode),
new invokerChecker(EVENT_REORDER, this.container)
];
this.invoke = function changeScrollbarStyles_invoke()
{
var accTree =
{ SECTION: [] };
testAccessibleTree(this.container, accTree);
this.scrollAreaNode.style.overflow = "auto";
}
this.finalCheck = function changeScrollbarStyles_finalCheck()
{
var accTree =
{ SECTION: [ // container
{ SECTION: [] } // scroll area
] };
testAccessibleTree(this.container, accTree);
}
this.getID = function changeScrollbarStyles_getID()
{
return "change scrollbar styles " + prettyName(aScrollAreaID);
}
}
////////////////////////////////////////////////////////////////////////////
// Do tests
////////////////////////////////////////////////////////////////////////////
var gQueue = null;
//gA11yEventDumpID = "eventdump"; // debug stuff
//gA11yEventDumpToConsole = true;
function doTests()
{
gQueue = new eventQueue();
gQueue.push(new changeScrollRange("container", "scrollarea"));
gQueue.push(new changeScrollbarStyles("container2", "scrollarea2"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=677154"
title="Detached document accessibility tree">
Mozilla Bug 677154</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="eventdump"></div>
<div id="container"><div id="scrollarea" style="overflow:auto;"><input></div></div>
<div id="container2"><div id="scrollarea2" style="overflow:hidden;"></div></div>
</body>
</html>

1
aclocal.m4 поставляемый
Просмотреть файл

@ -17,6 +17,7 @@ builtin(include, build/autoconf/acwinpaths.m4)dnl
builtin(include, build/autoconf/lto.m4)dnl builtin(include, build/autoconf/lto.m4)dnl
builtin(include, build/autoconf/gcc-pr49911.m4)dnl builtin(include, build/autoconf/gcc-pr49911.m4)dnl
builtin(include, build/autoconf/frameptr.m4)dnl builtin(include, build/autoconf/frameptr.m4)dnl
builtin(include, build/autoconf/compiler-opts.m4)dnl
MOZ_PROG_CHECKMSYS() MOZ_PROG_CHECKMSYS()

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

@ -426,7 +426,13 @@ pref("media.realtime_decoder.enabled", true);
// by bug 710563. // by bug 710563.
pref("layout.frame_rate.precise", true); pref("layout.frame_rate.precise", true);
// Temporary remote js console hack
pref("b2g.remote-js.enabled", true);
pref("b2g.remote-js.port", 9999);
// Screen timeout in minutes // Screen timeout in minutes
pref("power.screen.timeout", 60); pref("power.screen.timeout", 60);
pref("full-screen-api.enabled", true); pref("full-screen-api.enabled", true);
pref("media.volume.steps", 10);

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

@ -8,6 +8,7 @@ const Cc = Components.classes;
const Ci = Components.interfaces; const Ci = Components.interfaces;
const Cu = Components.utils; const Cu = Components.utils;
const CC = Components.Constructor; const CC = Components.Constructor;
const Cr = Components.results;
const LocalFile = CC('@mozilla.org/file/local;1', const LocalFile = CC('@mozilla.org/file/local;1',
'nsILocalFile', 'nsILocalFile',
@ -25,11 +26,18 @@ XPCOMUtils.defineLazyGetter(Services, 'ss', function() {
return Cc['@mozilla.org/content/style-sheet-service;1'] return Cc['@mozilla.org/content/style-sheet-service;1']
.getService(Ci.nsIStyleSheetService); .getService(Ci.nsIStyleSheetService);
}); });
XPCOMUtils.defineLazyGetter(Services, 'idle', function() { XPCOMUtils.defineLazyGetter(Services, 'idle', function() {
return Cc['@mozilla.org/widget/idleservice;1'] return Cc['@mozilla.org/widget/idleservice;1']
.getService(Ci.nsIIdleService); .getService(Ci.nsIIdleService);
}); });
XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function(){
return Cc['@mozilla.org/focus-managr;1']
.getService(Ci.nsFocusManager);
});
// In order to use http:// scheme instead of file:// scheme // In order to use http:// scheme instead of file:// scheme
// (that is much more restricted) the following code kick-off // (that is much more restricted) the following code kick-off
// a local http server listening on http://127.0.0.1:7777 and // a local http server listening on http://127.0.0.1:7777 and
@ -105,6 +113,7 @@ var shell = {
window.addEventListener('keypress', this); window.addEventListener('keypress', this);
window.addEventListener('MozApplicationManifest', this); window.addEventListener('MozApplicationManifest', this);
window.addEventListener("AppCommand", this); window.addEventListener("AppCommand", this);
window.addEventListener('mozfullscreenchange', this);
this.contentBrowser.addEventListener('load', this, true); this.contentBrowser.addEventListener('load', this, true);
try { try {
@ -186,6 +195,24 @@ var shell = {
Services.prefs.setBoolPref("nglayout.debug.paint_flashing", false); Services.prefs.setBoolPref("nglayout.debug.paint_flashing", false);
} }
}, },
changeVolume: function shell_changeVolume(aDelta) {
let audioManager = Cc["@mozilla.org/telephony/audiomanager;1"].getService(Ci.nsIAudioManager);
let steps = 10;
try {
steps = Services.prefs.getIntPref("media.volume.steps");
if (steps <= 0)
steps = 1;
} catch(e) {}
let volume = audioManager.masterVolume + aDelta / steps;
if (volume > 1)
volume = 1;
if (volume < 0)
volume = 0;
audioManager.masterVolume = volume;
},
handleEvent: function shell_handleEvent(evt) { handleEvent: function shell_handleEvent(evt) {
switch (evt.type) { switch (evt.type) {
@ -217,8 +244,22 @@ var shell = {
case 'Search': case 'Search':
this.toggleDebug(); this.toggleDebug();
break; break;
case 'VolumeUp':
this.changeVolume(1);
break;
case 'VolumeDown':
this.changeVolume(-1);
break;
} }
break; break;
case 'mozfullscreenchange':
// When the screen goes fullscreen make sure to set the focus to the
// main window so noboby can prevent the ESC key to get out fullscreen
// mode
if (document.mozFullScreen)
Services.fm.focusedWindow = window;
break;
case 'load': case 'load':
this.contentBrowser.removeEventListener('load', this, true); this.contentBrowser.removeEventListener('load', this, true);
this.turnScreenOn(); this.turnScreenOn();
@ -339,3 +380,50 @@ Services.obs.addObserver(function onConsoleAPILogEvent(subject, topic, data) {
" in " + (message.functionName || "anonymous") + ": "; " in " + (message.functionName || "anonymous") + ": ";
Services.console.logStringMessage(prefix + Array.join(message.arguments, " ")); Services.console.logStringMessage(prefix + Array.join(message.arguments, " "));
}, "console-api-log-event", false); }, "console-api-log-event", false);
(function Repl() {
if (!Services.prefs.getBoolPref('b2g.remote-js.enabled')) {
return;
}
const prompt = 'JS> ';
let output;
let reader = {
onInputStreamReady : function repl_readInput(input) {
let sin = Cc['@mozilla.org/scriptableinputstream;1']
.createInstance(Ci.nsIScriptableInputStream);
sin.init(input);
try {
let val = eval(sin.read(sin.available()));
let ret = (typeof val === 'undefined') ? 'undefined\n' : val + '\n';
output.write(ret, ret.length);
// TODO: check if socket has been closed
} catch (e) {
if (e.result === Cr.NS_BASE_STREAM_CLOSED ||
(typeof e === 'object' && e.result === Cr.NS_BASE_STREAM_CLOSED)) {
return;
}
let message = (typeof e === 'object') ? e.message + '\n' : e + '\n';
output.write(message, message.length);
}
output.write(prompt, prompt.length);
input.asyncWait(reader, 0, 0, Services.tm.mainThread);
}
}
let listener = {
onSocketAccepted: function repl_acceptConnection(serverSocket, clientSocket) {
dump('Accepted connection on ' + clientSocket.host + '\n');
let input = clientSocket.openInputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0)
.QueryInterface(Ci.nsIAsyncInputStream);
output = clientSocket.openOutputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0);
output.write(prompt, prompt.length);
input.asyncWait(reader, 0, 0, Services.tm.mainThread);
}
}
let serverPort = Services.prefs.getIntPref('b2g.remote-js.port');
let serverSocket = Cc['@mozilla.org/network/server-socket;1']
.createInstance(Ci.nsIServerSocket);
serverSocket.init(serverPort, true, -1);
dump('Opened socket on ' + serverSocket.port + '\n');
serverSocket.asyncListen(listener);
})();

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

@ -177,19 +177,22 @@ const ContentPanning = {
} }
}, },
position: { position: new Point(0 , 0),
origin: new Point(0, 0),
current: new Point(0 , 0)
},
onTouchStart: function cp_onTouchStart(evt) { onTouchStart: function cp_onTouchStart(evt) {
this.dragging = true; this.dragging = true;
KineticPanning.stop();
// If there is a pan animation running (from a previous pan gesture) and
// the user touch back the screen, stop this animation immediatly and
// prevent the possible click action.
if (KineticPanning.active) {
KineticPanning.stop();
this.preventNextClick = true;
}
this.scrollCallback = this.getPannable(evt.originalTarget); this.scrollCallback = this.getPannable(evt.originalTarget);
this.position.origin.set(evt.screenX, evt.screenY); this.position.set(evt.screenX, evt.screenY);
this.position.current.set(evt.screenX, evt.screenY); KineticPanning.record(new Point(0, 0), evt.timeStamp);
KineticPanning.record(new Point(0, 0));
}, },
onTouchEnd: function cp_onTouchEnd(evt) { onTouchEnd: function cp_onTouchEnd(evt) {
@ -197,26 +200,29 @@ const ContentPanning = {
return; return;
this.dragging = false; this.dragging = false;
if (this.isPan()) { this.onTouchMove(evt);
if (evt.detail) // The event will generate a click
evt.target.addEventListener('click', this, true);
let pan = KineticPanning.isPan();
let click = evt.detail;
if (click && (pan || this.preventNextClick))
evt.target.addEventListener('click', this, true);
this.preventNextClick = false;
if (pan)
KineticPanning.start(this); KineticPanning.start(this);
}
}, },
onTouchMove: function cp_onTouchMove(evt) { onTouchMove: function cp_onTouchMove(evt) {
if (!this.dragging || !this.scrollCallback) if (!this.dragging || !this.scrollCallback)
return; return;
let current = this.position.current; let current = this.position;
let delta = new Point(evt.screenX - current.x, evt.screenY - current.y); let delta = new Point(evt.screenX - current.x, evt.screenY - current.y);
current.set(evt.screenX, evt.screenY); current.set(evt.screenX, evt.screenY);
if (this.isPan()) { KineticPanning.record(delta, evt.timeStamp);
KineticPanning.record(delta); this.scrollCallback(delta.scale(-1));
this.scrollCallback(delta.scale(-1));
}
}, },
@ -232,24 +238,11 @@ const ContentPanning = {
this.scrollCallback = null; this.scrollCallback = null;
}, },
isPan: function cp_isPan() {
let dpi = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.displayDPI;
let threshold = Services.prefs.getIntPref('ui.dragThresholdX') / 240 * dpi;
let deltaX = this.position.origin.x - this.position.current.x;
let deltaY = this.position.origin.y - this.position.current.y;
return (Math.abs(deltaX) > threshold || Math.abs(deltaY) > threshold);
},
getPannable: function cp_getPannable(node) { getPannable: function cp_getPannable(node) {
if (!(node instanceof Ci.nsIDOMHTMLElement) || node.tagName == 'HTML') if (!(node instanceof Ci.nsIDOMHTMLElement) || node.tagName == 'HTML')
return null; return null;
let content = node.ownerDocument.defaultView; let content = node.ownerDocument.defaultView;
while (!(node instanceof Ci.nsIDOMHTMLBodyElement)) { while (!(node instanceof Ci.nsIDOMHTMLBodyElement)) {
let style = content.getComputedStyle(node, null); let style = content.getComputedStyle(node, null);
@ -299,7 +292,7 @@ const kMinVelocity = 0.4;
const kMaxVelocity = 6; const kMaxVelocity = 6;
// Constants that affect the "friction" of the scroll pane. // Constants that affect the "friction" of the scroll pane.
const kExponentialC = 1400; const kExponentialC = 1000;
const kPolynomialC = 100 / 1000000; const kPolynomialC = 100 / 1000000;
// How often do we change the position of the scroll pane? // How often do we change the position of the scroll pane?
@ -307,17 +300,25 @@ const kPolynomialC = 100 / 1000000;
// Too little and panning will be choppy. In milliseconds. // Too little and panning will be choppy. In milliseconds.
const kUpdateInterval = 16; const kUpdateInterval = 16;
// The numbers of momentums to use for calculating the velocity of the pan.
// Those are taken from the end of the action
const kSamples = 5;
const KineticPanning = { const KineticPanning = {
_position: new Point(0, 0), _position: new Point(0, 0),
_velocity: new Point(0, 0), _velocity: new Point(0, 0),
_acceleration: new Point(0, 0), _acceleration: new Point(0, 0),
get active() {
return this.target !== null;
},
_target: null, _target: null,
start: function kp_start(target) { start: function kp_start(target) {
this.target = target; this.target = target;
// Calculate the initial velocity of the movement based on user input // Calculate the initial velocity of the movement based on user input
let momentums = this.momentums; let momentums = this.momentums.slice(-kSamples);
let distance = new Point(0, 0); let distance = new Point(0, 0);
momentums.forEach(function(momentum) { momentums.forEach(function(momentum) {
@ -338,6 +339,7 @@ const KineticPanning = {
let velocity = this._velocity; let velocity = this._velocity;
velocity.set(Math.abs(velocityX) < kMinVelocity ? 0 : velocityX, velocity.set(Math.abs(velocityX) < kMinVelocity ? 0 : velocityX,
Math.abs(velocityY) < kMinVelocity ? 0 : velocityY); Math.abs(velocityY) < kMinVelocity ? 0 : velocityY);
this.momentums = [];
// Set acceleration vector to opposite signs of velocity // Set acceleration vector to opposite signs of velocity
function sign(x) { function sign(x) {
@ -358,20 +360,32 @@ const KineticPanning = {
if (!this.target) if (!this.target)
return; return;
this.momentums.splice(0); this.momentums = [];
this.target.onKineticEnd(); this.target.onKineticEnd();
this.target = null; this.target = null;
}, },
momentums: [], momentums: [],
record: function kp_record(delta) { record: function kp_record(delta, timestamp) {
// If the panning direction has changed, stop the current activity. this.momentums.push({ 'time': timestamp, 'dx' : delta.x, 'dy' : delta.y });
if (this.target && ((delta.x * this._velocity.x < 0) || },
(delta.y * this._velocity.y < 0)))
this.stop();
this.momentums.push({ 'time': Date.now(), 'dx' : delta.x, 'dy' : delta.y }); isPan: function cp_isPan() {
let dpi = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.displayDPI;
let threshold = Services.prefs.getIntPref('ui.dragThresholdX') / 240 * dpi;
let deltaX = 0;
let deltaY = 0;
let start = this.momentums[0].time;
return this.momentums.slice(1).some(function(momentum) {
deltaX += momentum.dx;
deltaY += momentum.dy;
return (Math.abs(deltaX) > threshold) || (Math.abs(deltaY) > threshold);
});
}, },
_startAnimation: function kp_startAnimation() { _startAnimation: function kp_startAnimation() {

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

@ -282,6 +282,7 @@ pref("browser.urlbar.doubleClickSelectsAll", true);
pref("browser.urlbar.doubleClickSelectsAll", false); pref("browser.urlbar.doubleClickSelectsAll", false);
#endif #endif
pref("browser.urlbar.autoFill", false); pref("browser.urlbar.autoFill", false);
pref("browser.urlbar.autoFill.typed", true);
// 0: Match anywhere (e.g., middle of words) // 0: Match anywhere (e.g., middle of words)
// 1: Match on word boundaries and then try matching anywhere // 1: Match on word boundaries and then try matching anywhere
// 2: Match only on word boundaries (e.g., after / or .) // 2: Match only on word boundaries (e.g., after / or .)

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

@ -9053,7 +9053,14 @@ XPCOMUtils.defineLazyGetter(Scratchpad, "ScratchpadManager", function() {
var StyleEditor = { var StyleEditor = {
prefEnabledName: "devtools.styleeditor.enabled", prefEnabledName: "devtools.styleeditor.enabled",
openChrome: function SE_openChrome() /**
* Opens the style editor. If the UI is already open, it will be focused.
*
* @param {CSSStyleSheet} [aSelectedStyleSheet] default Stylesheet.
* @param {Number} [aLine] Line to which the caret should be moved (one-indexed).
* @param {Number} [aCol] Column to which the caret should be moved (one-indexed).
*/
openChrome: function SE_openChrome(aSelectedStyleSheet, aLine, aCol)
{ {
const CHROME_URL = "chrome://browser/content/styleeditor.xul"; const CHROME_URL = "chrome://browser/content/styleeditor.xul";
const CHROME_WINDOW_TYPE = "Tools:StyleEditor"; const CHROME_WINDOW_TYPE = "Tools:StyleEditor";
@ -9067,14 +9074,23 @@ var StyleEditor = {
while (enumerator.hasMoreElements()) { while (enumerator.hasMoreElements()) {
var win = enumerator.getNext(); var win = enumerator.getNext();
if (win.styleEditorChrome.contentWindowID == contentWindowID) { if (win.styleEditorChrome.contentWindowID == contentWindowID) {
if (aSelectedStyleSheet) {
win.styleEditorChrome.selectStyleSheet(aSelectedStyleSheet, aLine, aCol);
}
win.focus(); win.focus();
return win; return win;
} }
} }
let args = {
contentWindow: contentWindow,
selectedStyleSheet: aSelectedStyleSheet,
line: aLine,
col: aCol
};
args.wrappedJSObject = args;
let chromeWindow = Services.ww.openWindow(null, CHROME_URL, "_blank", let chromeWindow = Services.ww.openWindow(null, CHROME_URL, "_blank",
CHROME_WINDOW_FLAGS, CHROME_WINDOW_FLAGS, args);
contentWindow);
chromeWindow.focus(); chromeWindow.focus();
return chromeWindow; return chromeWindow;
} }

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

@ -90,6 +90,7 @@
lightweightthemes="true" lightweightthemes="true"
lightweightthemesfooter="browser-bottombox" lightweightthemesfooter="browser-bottombox"
windowtype="navigator:browser" windowtype="navigator:browser"
macanimationtype="document"
screenX="4" screenY="4" screenX="4" screenY="4"
browsingmode="normal" browsingmode="normal"
persist="screenX screenY width height sizemode"> persist="screenX screenY width height sizemode">

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

@ -536,7 +536,8 @@
if (!this.mBlank) { if (!this.mBlank) {
if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) { if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
this.mTab.setAttribute("busy", "true"); this.mTab.setAttribute("busy", "true");
this.mTabBrowser.setTabTitleLoading(this.mTab); if (!(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_RELOAD))
this.mTabBrowser.setTabTitleLoading(this.mTab);
} }
if (this.mTab.selected) if (this.mTab.selected)
@ -1265,6 +1266,12 @@
else { else {
t._animStartTime = Date.now(); t._animStartTime = Date.now();
t.setAttribute("fadein", "true"); t.setAttribute("fadein", "true");
// This call to adjustTabstrip is redundant but needed so that
// when opening a second tab, the first tab's close buttons
// appears immediately rather than when the transition ends.
if (tabContainer.childNodes.length == 2)
tabContainer.adjustTabstrip();
} }
}, 0, this.tabContainer); }, 0, this.tabContainer);
} }
@ -1364,7 +1371,8 @@
// pretend the user typed this so it'll be available till // pretend the user typed this so it'll be available till
// the document successfully loads // the document successfully loads
b.userTypedValue = aURI; if (!isBlankPageURL(aURI))
b.userTypedValue = aURI;
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE; let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
if (aAllowThirdPartyFixup) if (aAllowThirdPartyFixup)
@ -1556,15 +1564,26 @@
<parameter name="aCloseWindowFastpath"/> <parameter name="aCloseWindowFastpath"/>
<body> <body>
<![CDATA[ <![CDATA[
if (aTab.closing || this._windowIsClosing) if (aTab.closing ||
aTab._pendingPermitUnload ||
this._windowIsClosing)
return false; return false;
var browser = this.getBrowserForTab(aTab); var browser = this.getBrowserForTab(aTab);
if (!aTabWillBeMoved) { if (!aTabWillBeMoved) {
let ds = browser.docShell; let ds = browser.docShell;
if (ds && ds.contentViewer && !ds.contentViewer.permitUnload()) if (ds && ds.contentViewer) {
return false; // We need to block while calling permitUnload() because it
// processes the event queue and may lead to another removeTab()
// call before permitUnload() even returned.
aTab._pendingPermitUnload = true;
let permitUnload = ds.contentViewer.permitUnload();
delete aTab._pendingPermitUnload;
if (!permitUnload)
return false;
}
} }
var closeWindow = false; var closeWindow = false;
@ -3983,24 +4002,18 @@
<implementation implements="nsIDOMEventListener"> <implementation implements="nsIDOMEventListener">
<constructor><![CDATA[ <constructor><![CDATA[
window.addEventListener("findbaropen", this, false);
window.addEventListener("resize", this, false); window.addEventListener("resize", this, false);
]]></constructor> ]]></constructor>
<destructor><![CDATA[ <destructor><![CDATA[
window.removeEventListener("findbaropen", this, false);
window.removeEventListener("resize", this, false); window.removeEventListener("resize", this, false);
MousePosTracker.removeListener(this); MousePosTracker.removeListener(this);
]]></destructor> ]]></destructor>
<property name="label"> <property name="label">
<setter><![CDATA[ <setter><![CDATA[
if (!this.label) { if (!this.label)
if (window.gFindBarInitialized && !window.gFindBar.hidden) this.removeAttribute("mirror");
this.setAttribute("mirror", "true");
else
this.removeAttribute("mirror");
}
this.style.minWidth = this.getAttribute("type") == "status" && this.style.minWidth = this.getAttribute("type") == "status" &&
this.getAttribute("previoustype") == "status" this.getAttribute("previoustype") == "status"
@ -4048,10 +4061,6 @@
return; return;
switch (event.type) { switch (event.type) {
case "findbaropen":
this.setAttribute("mirror", "true");
this._calcMouseTargetRect();
break;
case "resize": case "resize":
this._calcMouseTargetRect(); this._calcMouseTargetRect();
break; break;
@ -4061,10 +4070,10 @@
<method name="_calcMouseTargetRect"> <method name="_calcMouseTargetRect">
<body><![CDATA[ <body><![CDATA[
let alignRight = (window.gFindBarInitialized && !window.gFindBar.hidden); let alignRight = false;
if (getComputedStyle(document.documentElement).direction == "rtl") if (getComputedStyle(document.documentElement).direction == "rtl")
alighRight = !alignRight; alignRight = !alignRight;
let rect = this.getBoundingClientRect(); let rect = this.getBoundingClientRect();
this._mouseTargetRect = { this._mouseTargetRect = {

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

@ -15,24 +15,26 @@ function reallyHandleRequest(request, response) {
// Allow the caller to drive how authentication is processed via the query. // Allow the caller to drive how authentication is processed via the query.
// Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar // Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar
var query = request.queryString; // The extra ? allows the user/pass/realm checks to succeed if the name is
// at the beginning of the query string.
var query = "?" + request.queryString;
var expected_user = "", expected_pass = "", realm = "mochitest"; var expected_user = "", expected_pass = "", realm = "mochitest";
var proxy_expected_user = "", proxy_expected_pass = "", proxy_realm = "mochi-proxy"; var proxy_expected_user = "", proxy_expected_pass = "", proxy_realm = "mochi-proxy";
var huge = false, plugin = false; var huge = false, plugin = false, anonymous = false;
var authHeaderCount = 1; var authHeaderCount = 1;
// user=xxx // user=xxx
match = /user=([^&]*)/.exec(query); match = /[^_]user=([^&]*)/.exec(query);
if (match) if (match)
expected_user = match[1]; expected_user = match[1];
// pass=xxx // pass=xxx
match = /pass=([^&]*)/.exec(query); match = /[^_]pass=([^&]*)/.exec(query);
if (match) if (match)
expected_pass = match[1]; expected_pass = match[1];
// realm=xxx // realm=xxx
match = /realm=([^&]*)/.exec(query); match = /[^_]realm=([^&]*)/.exec(query);
if (match) if (match)
realm = match[1]; realm = match[1];
@ -66,6 +68,10 @@ function reallyHandleRequest(request, response) {
if (match) if (match)
authHeaderCount = match[1]+0; authHeaderCount = match[1]+0;
// anonymous=1
match = /anonymous=1/.exec(query);
if (match)
anonymous = true;
// Look for an authentication header, if any, in the request. // Look for an authentication header, if any, in the request.
// //
@ -74,8 +80,9 @@ function reallyHandleRequest(request, response) {
// This test only supports Basic auth. The value sent by the client is // This test only supports Basic auth. The value sent by the client is
// "username:password", obscured with base64 encoding. // "username:password", obscured with base64 encoding.
var actual_user = "", actual_pass = "", authHeader; var actual_user = "", actual_pass = "", authHeader, authPresent = false;
if (request.hasHeader("Authorization")) { if (request.hasHeader("Authorization")) {
authPresent = true;
authHeader = request.getHeader("Authorization"); authHeader = request.getHeader("Authorization");
match = /Basic (.+)/.exec(authHeader); match = /Basic (.+)/.exec(authHeader);
if (match.length != 2) if (match.length != 2)
@ -115,16 +122,24 @@ function reallyHandleRequest(request, response) {
requestProxyAuth = false; requestProxyAuth = false;
} }
if (requestProxyAuth) { if (anonymous) {
response.setStatusLine("1.0", 407, "Proxy authentication required"); if (authPresent) {
for (i = 0; i < authHeaderCount; ++i) response.setStatusLine("1.0", 400, "Unexpected authorization header found");
response.setHeader("Proxy-Authenticate", "basic realm=\"" + proxy_realm + "\"", true); } else {
} else if (requestAuth) { response.setStatusLine("1.0", 200, "Authorization header not found");
response.setStatusLine("1.0", 401, "Authentication required"); }
for (i = 0; i < authHeaderCount; ++i)
response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", true);
} else { } else {
response.setStatusLine("1.0", 200, "OK"); if (requestProxyAuth) {
response.setStatusLine("1.0", 407, "Proxy authentication required");
for (i = 0; i < authHeaderCount; ++i)
response.setHeader("Proxy-Authenticate", "basic realm=\"" + proxy_realm + "\"", true);
} else if (requestAuth) {
response.setStatusLine("1.0", 401, "Authentication required");
for (i = 0; i < authHeaderCount; ++i)
response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", true);
} else {
response.setStatusLine("1.0", 200, "OK");
}
} }
response.setHeader("Content-Type", "application/xhtml+xml", false); response.setHeader("Content-Type", "application/xhtml+xml", false);

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

@ -28,14 +28,18 @@ function test() {
executeSoon(function () { executeSoon(function () {
let consoleListener = { let consoleListener = {
observe: function (m) { observe: function (m) {
info("m: " + m + "\n");
info("m.message: " + m.message + "\n");
if (m.message.indexOf("NS_ERROR_DOM_BAD_URI") > -1) { if (m.message.indexOf("NS_ERROR_DOM_BAD_URI") > -1) {
Services.console.unregisterListener(consoleListener);
ok(true, "drop was blocked"); ok(true, "drop was blocked");
executeSoon(finish); executeSoon(finish);
} }
} }
} }
Services.console.registerListener(consoleListener); Services.console.registerListener(consoleListener);
registerCleanupFunction(function () {
Services.console.unregisterListener(consoleListener);
});
// The drop handler throws an exception when dragging URIs that inherit // The drop handler throws an exception when dragging URIs that inherit
// principal, e.g. javascript: // principal, e.g. javascript:

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

@ -1,2 +1 @@
MOZ_APP_DISPLAYNAME=Firefox MOZ_APP_DISPLAYNAME=Firefox
MOZ_UA_BUILDID=20100101

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

@ -72,6 +72,7 @@ const Cr = Components.results;
const Cu = Components.utils; const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/TelemetryStopwatch.jsm");
const STATE_RUNNING_STR = "running"; const STATE_RUNNING_STR = "running";
const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 megabytes const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 megabytes
@ -127,23 +128,30 @@ SessionStartup.prototype = {
return; return;
// parse the session state into a JS object // parse the session state into a JS object
// remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
if (iniString.charAt(0) == '(')
iniString = iniString.slice(1, -1);
let corruptFile = false;
try { try {
// remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0) this._initialState = JSON.parse(iniString);
if (iniString.charAt(0) == '(') }
iniString = iniString.slice(1, -1); catch (ex) {
debug("The session file contained un-parse-able JSON: " + ex);
// Try to eval.
// evalInSandbox will throw if iniString is not parse-able.
try { try {
this._initialState = JSON.parse(iniString);
}
catch (exJSON) {
var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'}); var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'});
this._initialState = Cu.evalInSandbox("(" + iniString + ")", s); this._initialState = Cu.evalInSandbox("(" + iniString + ")", s);
} catch(ex) {
debug("The session file contained un-eval-able JSON: " + ex);
corruptFile = true;
} }
// If this is a normal restore then throw away any previous session
if (!doResumeSessionOnce)
delete this._initialState.lastSessionState;
} }
catch (ex) { debug("The session file is invalid: " + ex); } Services.telemetry.getHistogramById("FX_SESSION_RESTORE_CORRUPT_FILE").add(corruptFile);
// If this is a normal restore then throw away any previous session
if (!doResumeSessionOnce)
delete this._initialState.lastSessionState;
let resumeFromCrash = prefBranch.getBoolPref("sessionstore.resume_from_crash"); let resumeFromCrash = prefBranch.getBoolPref("sessionstore.resume_from_crash");
let lastSessionCrashed = let lastSessionCrashed =
@ -154,8 +162,7 @@ SessionStartup.prototype = {
// Report shutdown success via telemetry. Shortcoming here are // Report shutdown success via telemetry. Shortcoming here are
// being-killed-by-OS-shutdown-logic, shutdown freezing after // being-killed-by-OS-shutdown-logic, shutdown freezing after
// session restore was written, etc. // session restore was written, etc.
let Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry); Services.telemetry.getHistogramById("SHUTDOWN_OK").add(!lastSessionCrashed);
Telemetry.getHistogramById("SHUTDOWN_OK").add(!lastSessionCrashed);
// set the startup type // set the startup type
if (lastSessionCrashed && resumeFromCrash) if (lastSessionCrashed && resumeFromCrash)
@ -296,9 +303,11 @@ SessionStartup.prototype = {
* @returns a session state string * @returns a session state string
*/ */
_readStateFile: function sss_readStateFile(aFile) { _readStateFile: function sss_readStateFile(aFile) {
TelemetryStopwatch.start("FX_SESSION_RESTORE_READ_FILE_MS");
var stateString = Cc["@mozilla.org/supports-string;1"]. var stateString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString); createInstance(Ci.nsISupportsString);
stateString.data = this._readFile(aFile) || ""; stateString.data = this._readFile(aFile) || "";
TelemetryStopwatch.finish("FX_SESSION_RESTORE_READ_FILE_MS");
Services.obs.notifyObservers(stateString, "sessionstore-state-read", ""); Services.obs.notifyObservers(stateString, "sessionstore-state-read", "");

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

@ -131,6 +131,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/debug.js"); Cu.import("resource://gre/modules/debug.js");
Cu.import("resource:///modules/TelemetryTimestamps.jsm"); Cu.import("resource:///modules/TelemetryTimestamps.jsm");
Cu.import("resource:///modules/TelemetryStopwatch.jsm");
XPCOMUtils.defineLazyGetter(this, "NetUtil", function() { XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm");
@ -3653,6 +3654,8 @@ SessionStoreService.prototype = {
// if we crash. // if we crash.
let pinnedOnly = this._loadState == STATE_RUNNING && !this._resume_from_crash; let pinnedOnly = this._loadState == STATE_RUNNING && !this._resume_from_crash;
TelemetryStopwatch.start("FX_SESSION_RESTORE_COLLECT_DATA_MS");
var oState = this._getCurrentState(aUpdateAll, pinnedOnly); var oState = this._getCurrentState(aUpdateAll, pinnedOnly);
if (!oState) if (!oState)
return; return;
@ -3691,6 +3694,8 @@ SessionStoreService.prototype = {
if (this._lastSessionState) if (this._lastSessionState)
oState.lastSessionState = this._lastSessionState; oState.lastSessionState = this._lastSessionState;
TelemetryStopwatch.finish("FX_SESSION_RESTORE_COLLECT_DATA_MS");
this._saveStateObject(oState); this._saveStateObject(oState);
}, },
@ -3698,9 +3703,11 @@ SessionStoreService.prototype = {
* write a state object to disk * write a state object to disk
*/ */
_saveStateObject: function sss_saveStateObject(aStateObj) { _saveStateObject: function sss_saveStateObject(aStateObj) {
TelemetryStopwatch.start("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
var stateString = Cc["@mozilla.org/supports-string;1"]. var stateString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString); createInstance(Ci.nsISupportsString);
stateString.data = this._toJSONString(aStateObj); stateString.data = this._toJSONString(aStateObj);
TelemetryStopwatch.finish("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
Services.obs.notifyObservers(stateString, "sessionstore-state-write", ""); Services.obs.notifyObservers(stateString, "sessionstore-state-write", "");
@ -3809,7 +3816,7 @@ SessionStoreService.prototype = {
argString.data = ""; argString.data = "";
// Build feature string // Build feature string
let features = "chrome,dialog=no,all"; let features = "chrome,dialog=no,macsuppressanimation,all";
let winState = aState.windows[0]; let winState = aState.windows[0];
WINDOW_ATTRIBUTES.forEach(function(aFeature) { WINDOW_ATTRIBUTES.forEach(function(aFeature) {
// Use !isNaN as an easy way to ignore sizemode and check for numbers // Use !isNaN as an easy way to ignore sizemode and check for numbers
@ -4427,6 +4434,7 @@ SessionStoreService.prototype = {
* String data * String data
*/ */
_writeFile: function sss_writeFile(aFile, aData) { _writeFile: function sss_writeFile(aFile, aData) {
TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_MS");
// Initialize the file output stream. // Initialize the file output stream.
var ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]. var ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream); createInstance(Ci.nsIFileOutputStream);
@ -4442,6 +4450,7 @@ SessionStoreService.prototype = {
var self = this; var self = this;
NetUtil.asyncCopy(istream, ostream, function(rc) { NetUtil.asyncCopy(istream, ostream, function(rc) {
if (Components.isSuccessCode(rc)) { if (Components.isSuccessCode(rc)) {
TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_MS");
Services.obs.notifyObservers(null, Services.obs.notifyObservers(null,
"sessionstore-state-write-complete", "sessionstore-state-write-complete",
""); "");

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

@ -0,0 +1,24 @@
. $topsrcdir/build/macosx/universal/mozconfig
# Universal builds override the default of browser (bug 575283 comment 29)
ac_add_options --enable-application=browser
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --enable-codesighs
ac_add_options --disable-install-strip
# Nightlies only since this has a cost in performance
ac_add_options --enable-js-diagnostics
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
mk_add_options MOZ_MAKE_FLAGS="-j12"
ac_add_options --with-macbundlename-prefix=Firefox
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
ac_add_options --enable-warnings-as-errors
ac_add_options --with-ccache

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

@ -0,0 +1,20 @@
. $topsrcdir/build/macosx/universal/mozconfig
# Universal builds override the default of browser (bug 575283 comment 29)
ac_add_options --enable-application=browser
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --enable-official-branding
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
ac_add_options --enable-warnings-as-errors
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j4"
ac_add_options --with-ccache

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

@ -0,0 +1,26 @@
# Just like nightlies, but without tests, not on an update channel, and with
# shark and dtrace enabled
. $topsrcdir/build/macosx/universal/mozconfig
# Universal builds override the default of browser (bug 575283 comment 29)
ac_add_options --enable-application=browser
ac_add_options --disable-tests
ac_add_options --disable-install-strip
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j12"
# shark specific options
ac_add_options --enable-shark
ac_add_options --enable-dtrace
# Need this to prevent name conflicts with the normal nightly build packages
export MOZ_PKG_SPECIAL="shark"
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
ac_add_options --enable-warnings-as-errors
ac_add_options --with-ccache

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

@ -0,0 +1,12 @@
. $topsrcdir/build/macosx/mozconfig.leopard
ac_add_options --enable-debug
ac_add_options --enable-trace-malloc
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j12"
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1
ac_add_options --with-macbundlename-prefix=Firefox
ac_add_options --with-ccache

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

@ -0,0 +1,17 @@
. $topsrcdir/build/macosx/common
ac_add_options --enable-debug
ac_add_options --enable-trace-malloc
ac_add_options --enable-accessibility
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j12"
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1
ac_add_options --with-macbundlename-prefix=Firefox
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
ac_add_options --enable-warnings-as-errors
ac_add_options --with-ccache

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

@ -0,0 +1,5 @@
ac_add_options --with-l10n-base=../../l10n-central
ac_add_options --enable-official-branding
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-ccache

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

@ -72,6 +72,7 @@ _BROWSER_TEST_FILES = \
browser_dbg_pause-resume.js \ browser_dbg_pause-resume.js \
browser_dbg_update-editor-mode.js \ browser_dbg_update-editor-mode.js \
browser_dbg_select-line.js \ browser_dbg_select-line.js \
browser_dbg_clean-exit.js \
head.js \ head.js \
$(NULL) $(NULL)

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

@ -0,0 +1,42 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test that closing a tab with the debugger in a paused state exits cleanly.
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
const DEBUGGER_TAB_URL = "http://example.com/browser/browser/devtools/" +
"debugger/test/" +
"browser_dbg_debuggerstatement.html";
function test() {
debug_tab_pane(DEBUGGER_TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testCleanExit();
});
}
function testCleanExit() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
is(gDebugger.StackFrames.activeThread.paused, true,
"Should be paused after the debugger statement.");
gPane._client.addOneTimeListener("tabDetached", function () {
finish();
});
removeTab(gTab);
}}, 0);
});
gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
}

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

@ -43,37 +43,41 @@ function testSelectLine() {
ok(gDebugger.editor.getText().search(/debugger/) != -1, ok(gDebugger.editor.getText().search(/debugger/) != -1,
"The correct script was loaded initially."); "The correct script was loaded initially.");
// getCaretPosition is 0-based. // Yield control back to the event loop so that the debugger has a
is(gDebugger.editor.getCaretPosition().line, 5, // chance to highlight the proper line.
"The correct line is selected."); executeSoon(function(){
// getCaretPosition is 0-based.
is(gDebugger.editor.getCaretPosition().line, 5,
"The correct line is selected.");
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
function onChange() { function onChange() {
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED, gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
onChange); onChange);
ok(gDebugger.editor.getText().search(/debugger/) == -1, ok(gDebugger.editor.getText().search(/debugger/) == -1,
"The second script is no longer displayed."); "The second script is no longer displayed.");
ok(gDebugger.editor.getText().search(/firstCall/) != -1, ok(gDebugger.editor.getText().search(/firstCall/) != -1,
"The first script is displayed."); "The first script is displayed.");
// Yield control back to the event loop so that the debugger has a // Yield control back to the event loop so that the debugger has a
// chance to highlight the proper line. // chance to highlight the proper line.
executeSoon(function(){ executeSoon(function(){
// getCaretPosition is 0-based. // getCaretPosition is 0-based.
is(gDebugger.editor.getCaretPosition().line, 4, is(gDebugger.editor.getCaretPosition().line, 4,
"The correct line is selected."); "The correct line is selected.");
gDebugger.StackFrames.activeThread.resume(function() { gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab); removeTab(gTab);
finish(); finish();
});
}); });
}); });
});
// Click the oldest stack frame. // Click the oldest stack frame.
let element = gDebugger.document.getElementById("stackframe-3"); let element = gDebugger.document.getElementById("stackframe-3");
EventUtils.synthesizeMouseAtCenter(element, {}, gDebugger); EventUtils.synthesizeMouseAtCenter(element, {}, gDebugger);
});
}}, 0); }}, 0);
}); });

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

@ -763,6 +763,9 @@ InspectorUI.prototype = {
this.boundRuleViewChanged = this.ruleViewChanged.bind(this); this.boundRuleViewChanged = this.ruleViewChanged.bind(this);
this.ruleView.element.addEventListener("CssRuleViewChanged", this.ruleView.element.addEventListener("CssRuleViewChanged",
this.boundRuleViewChanged); this.boundRuleViewChanged);
this.cssRuleViewBoundCSSLinkClicked = this.ruleViewCSSLinkClicked.bind(this);
this.ruleView.element.addEventListener("CssRuleViewCSSLinkClicked",
this.cssRuleViewBoundCSSLinkClicked);
doc.documentElement.appendChild(this.ruleView.element); doc.documentElement.appendChild(this.ruleView.element);
this.ruleView.highlight(this.selection); this.ruleView.highlight(this.selection);
@ -800,6 +803,30 @@ InspectorUI.prototype = {
this.nodeChanged(this.ruleViewObject); this.nodeChanged(this.ruleViewObject);
}, },
/**
* When a css link is clicked this method is called in order to either:
* 1. Open the link in view source (for element style attributes)
* 2. Open the link in the style editor
*
* @param aEvent The event containing the style rule to act on
*/
ruleViewCSSLinkClicked: function(aEvent)
{
if (!this.chromeWin) {
return;
}
let rule = aEvent.detail.rule;
let styleSheet = rule.sheet;
if (styleSheet) {
this.chromeWin.StyleEditor.openChrome(styleSheet, rule.ruleLine);
} else {
let href = rule.elementStyle.element.ownerDocument.location.href;
this.chromeWin.openUILinkIn("view-source:" + href, "window");
}
},
/** /**
* Destroy the rule view. * Destroy the rule view.
*/ */
@ -811,6 +838,8 @@ InspectorUI.prototype = {
if (this.ruleView) { if (this.ruleView) {
this.ruleView.element.removeEventListener("CssRuleViewChanged", this.ruleView.element.removeEventListener("CssRuleViewChanged",
this.boundRuleViewChanged); this.boundRuleViewChanged);
this.ruleView.element.removeEventListener("CssRuleViewCSSLinkClicked",
this.cssRuleViewBoundCSSLinkClicked);
delete boundRuleViewChanged; delete boundRuleViewChanged;
this.ruleView.clear(); this.ruleView.clear();
delete this.ruleView; delete this.ruleView;

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

@ -51,6 +51,7 @@
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&window.title;" title="&window.title;"
windowtype="devtools:scratchpad" windowtype="devtools:scratchpad"
macanimationtype="document"
screenX="4" screenY="4" screenX="4" screenY="4"
width="640" height="480" width="640" height="480"
persist="screenX screenY width height sizemode"> persist="screenX screenY width height sizemode">

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

@ -78,6 +78,9 @@ const ORION_EVENTS = {
Selection: "Selection", Selection: "Selection",
Focus: "Focus", Focus: "Focus",
Blur: "Blur", Blur: "Blur",
MouseOver: "MouseOver",
MouseOut: "MouseOut",
MouseMove: "MouseMove",
}; };
/** /**

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

@ -161,6 +161,30 @@ SourceEditor.EVENTS = {
* The blur event is fired when the editor goes out of focus. * The blur event is fired when the editor goes out of focus.
*/ */
BLUR: "Blur", BLUR: "Blur",
/**
* The MouseMove event is sent when the user moves the mouse over a line
* annotation. The event object properties:
* - event - the DOM mousemove event object.
* - x and y - the mouse coordinates relative to the document being edited.
*/
MOUSE_MOVE: "MouseMove",
/**
* The MouseOver event is sent when the mouse pointer enters a line
* annotation. The event object properties:
* - event - the DOM mouseover event object.
* - x and y - the mouse coordinates relative to the document being edited.
*/
MOUSE_OVER: "MouseOver",
/**
* This MouseOut event is sent when the mouse pointer exits a line
* annotation. The event object properties:
* - event - the DOM mouseout event object.
* - x and y - the mouse coordinates relative to the document being edited.
*/
MOUSE_OUT: "MouseOut",
}; };
/** /**

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

@ -55,6 +55,7 @@ _BROWSER_TEST_FILES = \
browser_bug687160_line_api.js \ browser_bug687160_line_api.js \
browser_bug650345_find.js \ browser_bug650345_find.js \
browser_bug703692_focus_blur.js \ browser_bug703692_focus_blur.js \
browser_bug725388_mouse_events.js \
head.js \ head.js \
libs:: $(_BROWSER_TEST_FILES) libs:: $(_BROWSER_TEST_FILES)

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

@ -0,0 +1,97 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let tempScope = {};
Cu.import("resource:///modules/source-editor.jsm", tempScope);
let SourceEditor = tempScope.SourceEditor;
let testWin;
let editor;
function test()
{
waitForExplicitFinish();
const windowUrl = "data:text/xml,<?xml version='1.0'?>" +
"<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
" title='Test for bug 725388' width='600' height='500'><hbox flex='1'/></window>";
const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
testWin.addEventListener("load", function onWindowLoad() {
testWin.removeEventListener("load", onWindowLoad, false);
waitForFocus(initEditor, testWin);
}, false);
}
function initEditor()
{
let hbox = testWin.document.querySelector("hbox");
editor = new SourceEditor();
editor.init(hbox, {}, editorLoaded);
}
function editorLoaded()
{
let text = "BrowserBug - 725388";
editor.setText(text);
let target = editor.editorElement;
let targetWin = target.ownerDocument.defaultView;
let mMoveHandler = function(aEvent) {
editor.removeEventListener(SourceEditor.EVENTS.MOUSE_MOVE, mMoveHandler);
is(aEvent.event.type, "mousemove", "MouseMove event fired.");
editor.addEventListener(SourceEditor.EVENTS.MOUSE_OVER, mOverHandler);
waitForFocus(function() {
EventUtils.synthesizeMouse(target, 10, 10, {type: "mouseover"},
targetWin);
});
};
let mOverHandler = function(aEvent) {
editor.removeEventListener(SourceEditor.EVENTS.MOUSE_OVER, mOverHandler);
is(aEvent.event.type, "mouseover", "MouseOver event fired.");
editor.addEventListener(SourceEditor.EVENTS.MOUSE_OUT, mOutHandler);
waitForFocus(function() {
EventUtils.synthesizeMouse(target, -10, -10, {type: "mouseout"},
targetWin);
}, targetWin);
};
let mOutHandler = function(aEvent) {
editor.removeEventListener(SourceEditor.EVENTS.MOUSE_OUT, mOutHandler);
is(aEvent.event.type, "mouseout", "MouseOut event fired.");
executeSoon(testEnd);
};
editor.addEventListener(SourceEditor.EVENTS.MOUSE_MOVE, mMoveHandler);
editor.focus();
waitForFocus(function() {
EventUtils.synthesizeMouse(target, 1, 1, {type: "mousemove"},
targetWin);
}, targetWin);
}
function testEnd()
{
if (editor) {
editor.destroy();
}
if (testWin) {
testWin.close();
}
testWin = editor = null;
waitForFocus(finish, window);
}

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

@ -146,7 +146,7 @@ StyleEditor.prototype = {
*/ */
get styleSheet() get styleSheet()
{ {
assert(this._styleSheet, "StyleSheet must be loaded first.") assert(this._styleSheet, "StyleSheet must be loaded first.");
return this._styleSheet; return this._styleSheet;
}, },
@ -921,9 +921,11 @@ StyleEditor.prototype = {
aArgs.unshift(this); aArgs.unshift(this);
} }
// copy the list of listeners to allow adding/removing listeners in handlers
let listeners = this._actionListeners.concat();
// trigger all listeners that have this action handler // trigger all listeners that have this action handler
for (let i = 0; i < this._actionListeners.length; ++i) { for (let i = 0; i < listeners.length; ++i) {
let listener = this._actionListeners[i]; let listener = listeners[i];
let actionHandler = listener["on" + aName]; let actionHandler = listener["on" + aName];
if (actionHandler) { if (actionHandler) {
actionHandler.apply(listener, aArgs); actionHandler.apply(listener, aArgs);

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

@ -270,9 +270,11 @@ StyleEditorChrome.prototype = {
aArgs.unshift(this); aArgs.unshift(this);
} }
// trigger all listeners that have this named handler // copy the list of listeners to allow adding/removing listeners in handlers
for (let i = 0; i < this._listeners.length; ++i) { let listeners = this._listeners.concat();
let listener = this._listeners[i]; // trigger all listeners that have this named handler.
for (let i = 0; i < listeners.length; i++) {
let listener = listeners[i];
let handler = listener["on" + aName]; let handler = listener["on" + aName];
if (handler) { if (handler) {
handler.apply(listener, aArgs); handler.apply(listener, aArgs);
@ -329,10 +331,10 @@ StyleEditorChrome.prototype = {
{ {
this._resetChrome(); this._resetChrome();
this._document.title = _("chromeWindowTitle",
this.contentDocument.title || this.contentDocument.location.href);
let document = this.contentDocument; let document = this.contentDocument;
this._document.title = _("chromeWindowTitle",
document.title || document.location.href);
for (let i = 0; i < document.styleSheets.length; ++i) { for (let i = 0; i < document.styleSheets.length; ++i) {
let styleSheet = document.styleSheets[i]; let styleSheet = document.styleSheets[i];
@ -352,6 +354,79 @@ StyleEditorChrome.prototype = {
}, this); }, this);
}, },
/**
* selects a stylesheet and optionally moves the cursor to a selected line
*
* @param {CSSStyleSheet} [aSheet]
* Stylesheet that should be selected. If a stylesheet is not passed
* and the editor is not initialized we focus the first stylesheet. If
* a stylesheet is not passed and the editor is initialized we ignore
* the call.
* @param {Number} [aLine]
* Line to which the caret should be moved (one-indexed).
* @param {Number} [aCol]
* Column to which the caret should be moved (one-indexed).
*/
selectStyleSheet: function SEC_selectSheet(aSheet, aLine, aCol)
{
let select = function DEC_select(aEditor) {
let summary = aSheet ? this.getSummaryElementForEditor(aEditor)
: this._view.getSummaryElementByOrdinal(0);
let setCaret = false;
if (aLine || aCol) {
aLine = aLine || 1;
aCol = aCol || 1;
setCaret = true;
}
if (!aEditor.sourceEditor) {
// If a line or column was specified we move the caret appropriately.
if (setCaret) {
aEditor.addActionListener({
onAttach: function SEC_selectSheet_onAttach()
{
aEditor.removeActionListener(this);
aEditor.sourceEditor.setCaretPosition(aLine - 1, aCol - 1);
}
});
}
this._view.activeSummary = summary;
} else {
this._view.activeSummary = summary;
// If a line or column was specified we move the caret appropriately.
if (setCaret) {
aEditor.sourceEditor.setCaretPosition(aLine - 1, aCol - 1);
}
}
}.bind(this);
if (!this.editors.length) {
// We are in the main initialization phase so we wait for the editor
// containing the target stylesheet to be added and select the target
// stylesheet, optionally moving the cursor to a selected line.
this.addChromeListener({
onEditorAdded: function SEC_selectSheet_onEditorAdded(aChrome, aEditor) {
if ((!aSheet && aEditor.styleSheetIndex == 0) ||
aEditor.styleSheet == aSheet) {
aChrome.removeChromeListener(this);
select(aEditor);
}
}
});
} else if (aSheet) {
// We are already initialized and a stylesheet has been specified. Here
// we iterate through the editors and select the one containing the target
// stylesheet, optionally moving the cursor to a selected line.
for each (let editor in this.editors) {
if (editor.styleSheet == aSheet) {
select(editor);
break;
}
}
}
},
/** /**
* Disable all UI, effectively making editors read-only. * Disable all UI, effectively making editors read-only.
* This is automatically called when no content window is attached. * This is automatically called when no content window is attached.
@ -455,9 +530,8 @@ StyleEditorChrome.prototype = {
} }
}, false); }, false);
// autofocus the first or new stylesheet // autofocus new stylesheets
if (editor.styleSheetIndex == 0 || if (editor.hasFlag(StyleEditorFlags.NEW)) {
editor.hasFlag(StyleEditorFlags.NEW)) {
this._view.activeSummary = aSummary; this._view.activeSummary = aSummary;
} }

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

@ -132,8 +132,10 @@
<xul:script type="application/javascript"><![CDATA[ <xul:script type="application/javascript"><![CDATA[
Components.utils.import("resource:///modules/devtools/StyleEditorChrome.jsm"); Components.utils.import("resource:///modules/devtools/StyleEditorChrome.jsm");
let chromeRoot = document.getElementById("style-editor-chrome"); let chromeRoot = document.getElementById("style-editor-chrome");
let contentWindow = window.arguments[0]; let args = window.arguments[0].wrappedJSObject;
let contentWindow = args.contentWindow;
let chrome = new StyleEditorChrome(chromeRoot, contentWindow); let chrome = new StyleEditorChrome(chromeRoot, contentWindow);
chrome.selectStyleSheet(args.selectedStyleSheet, args.line, args.col);
window.styleEditorChrome = chrome; window.styleEditorChrome = chrome;
]]></xul:script> ]]></xul:script>
</xul:window> </xul:window>

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

@ -51,6 +51,7 @@ _BROWSER_TEST_FILES = \
browser_styleeditor_init.js \ browser_styleeditor_init.js \
browser_styleeditor_loading.js \ browser_styleeditor_loading.js \
browser_styleeditor_new.js \ browser_styleeditor_new.js \
browser_styleeditor_passedinsheet.js \
browser_styleeditor_pretty.js \ browser_styleeditor_pretty.js \
browser_styleeditor_readonly.js \ browser_styleeditor_readonly.js \
browser_styleeditor_reopen.js \ browser_styleeditor_reopen.js \

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

@ -0,0 +1,61 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TESTCASE_URI = TEST_BASE + "simple.html";
const LINE = 6;
const COL = 2;
let editor = null;
let sheet = null;
function test()
{
waitForExplicitFinish();
gBrowser.selectedBrowser.addEventListener("load", function () {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
run();
}, true);
content.location = TESTCASE_URI;
}
function run()
{
sheet = content.document.styleSheets[1];
launchStyleEditorChrome(function attachListeners(aChrome) {
aChrome.addChromeListener({
onEditorAdded: checkSourceEditor
});
}, sheet, LINE, COL);
}
function checkSourceEditor(aChrome, aEditor)
{
if (!aEditor.sourceEditor) {
aEditor.addActionListener({
onAttach: function (aEditor) {
aEditor.removeActionListener(this);
validate(aEditor);
}
});
} else {
validate(aEditor);
}
}
function validate(aEditor)
{
info("validating style editor");
let sourceEditor = aEditor.sourceEditor;
let caretPosition = sourceEditor.getCaretPosition();
is(caretPosition.line, LINE - 1, "caret row is correct"); // index based
is(caretPosition.col, COL - 1, "caret column is correct");
is(aEditor.styleSheet, sheet, "loaded stylesheet matches document stylesheet");
finishUp();
}
function finishUp()
{
editor = sheet = null;
finish();
}

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

@ -19,9 +19,9 @@ function cleanup()
} }
} }
function launchStyleEditorChrome(aCallback) function launchStyleEditorChrome(aCallback, aSheet, aLine, aCol)
{ {
gChromeWindow = StyleEditor.openChrome(); gChromeWindow = StyleEditor.openChrome(aSheet, aLine, aCol);
if (gChromeWindow.document.readyState != "complete") { if (gChromeWindow.document.readyState != "complete") {
gChromeWindow.addEventListener("load", function onChromeLoad() { gChromeWindow.addEventListener("load", function onChromeLoad() {
gChromeWindow.removeEventListener("load", onChromeLoad, true); gChromeWindow.removeEventListener("load", onChromeLoad, true);
@ -34,12 +34,12 @@ function launchStyleEditorChrome(aCallback)
} }
} }
function addTabAndLaunchStyleEditorChromeWhenLoaded(aCallback) function addTabAndLaunchStyleEditorChromeWhenLoaded(aCallback, aSheet, aLine, aCol)
{ {
gBrowser.selectedTab = gBrowser.addTab(); gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onLoad() { gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
launchStyleEditorChrome(aCallback); launchStyleEditorChrome(aCallback, aSheet, aLine, aCol);
}, true); }, true);
} }

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

@ -273,6 +273,7 @@ CssHtmlTree.prototype = {
this._matchedProperties = null; this._matchedProperties = null;
if (this.htmlComplete) { if (this.htmlComplete) {
this.refreshSourceFilter();
this.refreshPanel(); this.refreshPanel();
} else { } else {
if (this._refreshProcess) { if (this._refreshProcess) {
@ -281,6 +282,9 @@ CssHtmlTree.prototype = {
CssHtmlTree.processTemplate(this.templateRoot, this.root, this); CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
// Refresh source filter ... this must be done after templateRoot has been
// processed.
this.refreshSourceFilter();
this.numVisibleProperties = 0; this.numVisibleProperties = 0;
let fragment = this.doc.createDocumentFragment(); let fragment = this.doc.createDocumentFragment();
this._refreshProcess = new UpdateProcess(this.win, CssHtmlTree.propertyNames, { this._refreshProcess = new UpdateProcess(this.win, CssHtmlTree.propertyNames, {
@ -362,21 +366,28 @@ CssHtmlTree.prototype = {
}, },
/** /**
* The change event handler for the onlyUserStyles checkbox. When * The change event handler for the onlyUserStyles checkbox.
* onlyUserStyles.checked is true we do not display properties that have no
* matched selectors, and we do not display UA styles. If .checked is false we
* do display even properties with no matched selectors, and we include the UA
* styles.
* *
* @param {Event} aEvent the DOM Event object. * @param {Event} aEvent the DOM Event object.
*/ */
onlyUserStylesChanged: function CssHtmltree_onlyUserStylesChanged(aEvent) onlyUserStylesChanged: function CssHtmltree_onlyUserStylesChanged(aEvent)
{
this.refreshSourceFilter();
this.refreshPanel();
},
/**
* When onlyUserStyles.checked is true we only display properties that have
* matched selectors and have been included by the document or one of the
* document's stylesheets. If .checked is false we display all properties
* including those that come from UA stylesheets.
*/
refreshSourceFilter: function CssHtmlTree_setSourceFilter()
{ {
this._matchedProperties = null; this._matchedProperties = null;
this.cssLogic.sourceFilter = this.showOnlyUserStyles ? this.cssLogic.sourceFilter = this.showOnlyUserStyles ?
CssLogic.FILTER.ALL : CssLogic.FILTER.ALL :
CssLogic.FILTER.UA; CssLogic.FILTER.UA;
this.refreshPanel();
}, },
/** /**
@ -974,4 +985,24 @@ SelectorView.prototype = {
return result; return result;
}, },
/**
* When a css link is clicked this method is called in order to either:
* 1. Open the link in view source (for element style attributes).
* 2. Open the link in the style editor.
*
* @param aEvent The click event
*/
openStyleEditor: function(aEvent)
{
if (this.selectorInfo.selector._cssRule._cssSheet) {
let styleSheet = this.selectorInfo.selector._cssRule._cssSheet.domSheet;
let line = this.selectorInfo.ruleLine;
this.tree.win.StyleEditor.openChrome(styleSheet, line);
} else {
let href = this.selectorInfo.sourceElement.ownerDocument.location.href;
this.tree.win.openUILinkIn("view-source:" + href, "window");
}
},
}; };

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

@ -232,7 +232,7 @@ CssLogic.prototype = {
// Update the CssSheet objects. // Update the CssSheet objects.
this.forEachSheet(function(aSheet) { this.forEachSheet(function(aSheet) {
aSheet._sheetAllowed = -1; aSheet._sheetAllowed = -1;
if (!aSheet.systemSheet && aSheet.sheetAllowed) { if (aSheet.contentSheet && aSheet.sheetAllowed) {
ruleCount += aSheet.ruleCount; ruleCount += aSheet.ruleCount;
} }
}, this); }, this);
@ -345,7 +345,7 @@ CssLogic.prototype = {
let sheets = []; let sheets = [];
this.forEachSheet(function (aSheet) { this.forEachSheet(function (aSheet) {
if (!aSheet.systemSheet) { if (aSheet.contentSheet) {
sheets.push(aSheet); sheets.push(aSheet);
} }
}, this); }, this);
@ -395,7 +395,7 @@ CssLogic.prototype = {
} }
sheet = new CssSheet(this, aDomSheet, aIndex); sheet = new CssSheet(this, aDomSheet, aIndex);
if (sheet.sheetAllowed && !sheet.systemSheet) { if (sheet.sheetAllowed && sheet.contentSheet) {
this._ruleCount += sheet.ruleCount; this._ruleCount += sheet.ruleCount;
} }
@ -569,7 +569,7 @@ CssLogic.prototype = {
this.forEachSheet(function (aSheet) { this.forEachSheet(function (aSheet) {
// We do not show unmatched selectors from system stylesheets // We do not show unmatched selectors from system stylesheets
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) { if (!aSheet.contentSheet || aSheet.disabled || !aSheet.mediaMatches) {
return; return;
} }
@ -664,7 +664,7 @@ CssLogic.prototype = {
sheet._passId = this._passId; sheet._passId = this._passId;
} }
if (filter !== CssLogic.FILTER.UA && sheet.systemSheet) { if (filter === CssLogic.FILTER.ALL && !sheet.contentSheet) {
continue; continue;
} }
@ -710,7 +710,7 @@ CssLogic.prototype = {
let result = {}; let result = {};
this.forSomeSheets(function (aSheet) { this.forSomeSheets(function (aSheet) {
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) { if (!aSheet.contentSheet || aSheet.disabled || !aSheet.mediaMatches) {
return false; return false;
} }
@ -865,29 +865,23 @@ XPCOMUtils.defineLazyGetter(CssLogic, "_strings", function() Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties")); .createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
/** /**
* Is the given property sheet a system (user agent) stylesheet? * Is the given property sheet a content stylesheet?
* *
* @param {CSSStyleSheet} aSheet a stylesheet * @param {CSSStyleSheet} aSheet a stylesheet
* @return {boolean} true if the given stylesheet is a system stylesheet or * @return {boolean} true if the given stylesheet is a content stylesheet,
* false otherwise. * false otherwise.
*/ */
CssLogic.isSystemStyleSheet = function CssLogic_isSystemStyleSheet(aSheet) CssLogic.isContentStylesheet = function CssLogic_isContentStylesheet(aSheet)
{ {
if (!aSheet) { // All sheets with owner nodes have been included by content.
if (aSheet.ownerNode) {
return true; return true;
} }
let url = aSheet.href; // If the sheet has a CSSImportRule we need to check the parent stylesheet.
if (aSheet.ownerRule instanceof Ci.nsIDOMCSSImportRule) {
if (!url) return false; return CssLogic.isContentStylesheet(aSheet.parentStyleSheet);
if (url.length === 0) return true; }
// Check for http[s]
if (url[0] === 'h') return false;
if (url.substr(0, 9) === "resource:") return true;
if (url.substr(0, 7) === "chrome:") return true;
if (url === "XPCSafeJSObjectWrapper.cpp") return true;
if (url.substr(0, 6) === "about:") return true;
return false; return false;
}; };
@ -942,7 +936,7 @@ function CssSheet(aCssLogic, aDomSheet, aIndex)
{ {
this._cssLogic = aCssLogic; this._cssLogic = aCssLogic;
this.domSheet = aDomSheet; this.domSheet = aDomSheet;
this.index = this.systemSheet ? -100 * aIndex : aIndex; this.index = this.contentSheet ? aIndex : -100 * aIndex;
// Cache of the sheets href. Cached by the getter. // Cache of the sheets href. Cached by the getter.
this._href = null; this._href = null;
@ -960,21 +954,21 @@ function CssSheet(aCssLogic, aDomSheet, aIndex)
CssSheet.prototype = { CssSheet.prototype = {
_passId: null, _passId: null,
_systemSheet: null, _contentSheet: null,
_mediaMatches: null, _mediaMatches: null,
/** /**
* Tells if the stylesheet is provided by the browser or not. * Tells if the stylesheet is provided by the browser or not.
* *
* @return {boolean} true if this is a browser-provided stylesheet, or false * @return {boolean} false if this is a browser-provided stylesheet, or true
* otherwise. * otherwise.
*/ */
get systemSheet() get contentSheet()
{ {
if (this._systemSheet === null) { if (this._contentSheet === null) {
this._systemSheet = CssLogic.isSystemStyleSheet(this.domSheet); this._contentSheet = CssLogic.isContentStylesheet(this.domSheet);
} }
return this._systemSheet; return this._contentSheet;
}, },
/** /**
@ -1048,7 +1042,7 @@ CssSheet.prototype = {
this._sheetAllowed = true; this._sheetAllowed = true;
let filter = this._cssLogic.sourceFilter; let filter = this._cssLogic.sourceFilter;
if (filter === CssLogic.FILTER.ALL && this.systemSheet) { if (filter === CssLogic.FILTER.ALL && !this.contentSheet) {
this._sheetAllowed = false; this._sheetAllowed = false;
} }
if (filter !== CssLogic.FILTER.ALL && filter !== CssLogic.FILTER.UA) { if (filter !== CssLogic.FILTER.ALL && filter !== CssLogic.FILTER.UA) {
@ -1202,13 +1196,13 @@ function CssRule(aCssSheet, aDomRule, aElement)
this.line = this._cssSheet._cssLogic.domUtils.getRuleLine(this._domRule); this.line = this._cssSheet._cssLogic.domUtils.getRuleLine(this._domRule);
this.source = this._cssSheet.shortSource + ":" + this.line; this.source = this._cssSheet.shortSource + ":" + this.line;
this.href = this._cssSheet.href; this.href = this._cssSheet.href;
this.systemRule = this._cssSheet.systemSheet; this.contentRule = this._cssSheet.contentSheet;
} else if (aElement) { } else if (aElement) {
this._selectors = [ new CssSelector(this, "@element.style") ]; this._selectors = [ new CssSelector(this, "@element.style") ];
this.line = -1; this.line = -1;
this.source = CssLogic.l10n("rule.sourceElement"); this.source = CssLogic.l10n("rule.sourceElement");
this.href = "#"; this.href = "#";
this.systemRule = false; this.contentRule = true;
this.sourceElement = aElement; this.sourceElement = aElement;
} }
} }
@ -1396,12 +1390,12 @@ CssSelector.prototype = {
/** /**
* Check if the selector comes from a browser-provided stylesheet. * Check if the selector comes from a browser-provided stylesheet.
* *
* @return {boolean} true if the selector comes from a browser-provided * @return {boolean} true if the selector comes from a content-provided
* stylesheet, or false otherwise. * stylesheet, or false otherwise.
*/ */
get systemRule() get contentRule()
{ {
return this._cssRule.systemRule; return this._cssRule.contentRule;
}, },
/** /**
@ -1794,12 +1788,12 @@ function CssSelectorInfo(aSelector, aProperty, aValue, aStatus)
4 important 4 important
5 inline important 5 inline important
*/ */
let scorePrefix = this.systemRule ? 0 : 2; let scorePrefix = this.contentRule ? 2 : 0;
if (this.elementStyle) { if (this.elementStyle) {
scorePrefix++; scorePrefix++;
} }
if (this.important) { if (this.important) {
scorePrefix += this.systemRule ? 1 : 2; scorePrefix += this.contentRule ? 2 : 1;
} }
this.specificityScore = "" + scorePrefix + this.specificity.ids + this.specificityScore = "" + scorePrefix + this.specificity.ids +
@ -1902,9 +1896,9 @@ CssSelectorInfo.prototype = {
* @return {boolean} true if the selector comes from a browser-provided * @return {boolean} true if the selector comes from a browser-provided
* stylesheet, or false otherwise. * stylesheet, or false otherwise.
*/ */
get systemRule() get contentRule()
{ {
return this.selector.systemRule; return this.selector.contentRule;
}, },
/** /**
@ -1916,8 +1910,8 @@ CssSelectorInfo.prototype = {
*/ */
compareTo: function CssSelectorInfo_compareTo(aThat) compareTo: function CssSelectorInfo_compareTo(aThat)
{ {
if (this.systemRule && !aThat.systemRule) return 1; if (!this.contentRule && aThat.contentRule) return 1;
if (!this.systemRule && aThat.systemRule) return -1; if (this.contentRule && !aThat.contentRule) return -1;
if (this.elementStyle && !aThat.elementStyle) { if (this.elementStyle && !aThat.elementStyle) {
if (!this.important && aThat.important) return 1; if (!this.important && aThat.important) return 1;

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

@ -38,7 +38,7 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
"use strict" "use strict";
const Cc = Components.classes; const Cc = Components.classes;
const Ci = Components.interfaces; const Ci = Components.interfaces;
@ -181,8 +181,8 @@ ElementStyle.prototype = {
let domRule = domRules.GetElementAt(i); let domRule = domRules.GetElementAt(i);
// XXX: Optionally provide access to system sheets. // XXX: Optionally provide access to system sheets.
let systemSheet = CssLogic.isSystemStyleSheet(domRule.parentStyleSheet); let contentSheet = CssLogic.isContentStylesheet(domRule.parentStyleSheet);
if (systemSheet) { if (!contentSheet) {
continue; continue;
} }
@ -324,7 +324,7 @@ ElementStyle.prototype = {
aProp.overridden = overridden; aProp.overridden = overridden;
return dirty; return dirty;
} }
} };
/** /**
* A single style rule or declaration. * A single style rule or declaration.
@ -358,11 +358,9 @@ Rule.prototype = {
if (this._title) { if (this._title) {
return this._title; return this._title;
} }
let sheet = this.domRule ? this.domRule.parentStyleSheet : null; this._title = CssLogic.shortSource(this.sheet);
this._title = CssLogic.shortSource(sheet);
if (this.domRule) { if (this.domRule) {
let line = this.elementStyle.domUtils.getRuleLine(this.domRule); this._title += ":" + this.ruleLine;
this._title += ":" + line;
} }
if (this.inherited) { if (this.inherited) {
@ -378,6 +376,26 @@ Rule.prototype = {
return this._title; return this._title;
}, },
/**
* The rule's stylesheet.
*/
get sheet()
{
return this.domRule ? this.domRule.parentStyleSheet : null;
},
/**
* The rule's line within a stylesheet
*/
get ruleLine()
{
if (!this.sheet) {
// No stylesheet, no ruleLine
return null;
}
return this.elementStyle.domUtils.getRuleLine(this.domRule);
},
/** /**
* Create a new TextProperty to include in the rule. * Create a new TextProperty to include in the rule.
* *
@ -530,7 +548,7 @@ Rule.prototype = {
this.textProps.push(textProp); this.textProps.push(textProp);
} }
}, },
} };
/** /**
* A single property in a rule's cssText. * A single property in a rule's cssText.
@ -618,7 +636,7 @@ TextProperty.prototype = {
{ {
this.rule.removeProperty(this); this.rule.removeProperty(this);
} }
} };
/** /**
@ -643,7 +661,7 @@ TextProperty.prototype = {
* apply to a given element. After construction, the 'element' * apply to a given element. After construction, the 'element'
* property will be available with the user interface. * property will be available with the user interface.
* *
* @param Document aDocument * @param Document aDoc
* The document that will contain the rule view. * The document that will contain the rule view.
* @param object aStore * @param object aStore
* The CSS rule view can use this object to store metadata * The CSS rule view can use this object to store metadata
@ -655,7 +673,6 @@ function CssRuleView(aDoc, aStore)
{ {
this.doc = aDoc; this.doc = aDoc;
this.store = aStore; this.store = aStore;
this.element = this.doc.createElementNS(XUL_NS, "vbox"); this.element = this.doc.createElementNS(XUL_NS, "vbox");
this.element.setAttribute("tabindex", "0"); this.element.setAttribute("tabindex", "0");
this.element.classList.add("ruleview"); this.element.classList.add("ruleview");
@ -768,6 +785,14 @@ RuleEditor.prototype = {
class: "ruleview-rule-source", class: "ruleview-rule-source",
textContent: this.rule.title textContent: this.rule.title
}); });
source.addEventListener("click", function() {
let rule = this.rule;
let evt = this.doc.createEvent("CustomEvent");
evt.initCustomEvent("CssRuleViewCSSLinkClicked", true, false, {
rule: rule,
});
this.element.dispatchEvent(evt);
}.bind(this));
let code = createChild(this.element, "div", { let code = createChild(this.element, "div", {
class: "ruleview-code" class: "ruleview-code"
@ -1094,8 +1119,6 @@ TextPropertyEditor.prototype = {
_parseValue: function TextPropertyEditor_parseValue(aValue) _parseValue: function TextPropertyEditor_parseValue(aValue)
{ {
let pieces = aValue.split("!", 2); let pieces = aValue.split("!", 2);
let value = pieces[0];
let priority = pieces.length > 1 ? pieces[1] : "";
return { return {
value: pieces[0].trim(), value: pieces[0].trim(),
priority: (pieces.length > 1 ? pieces[1].trim() : "") priority: (pieces.length > 1 ? pieces[1].trim() : "")

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

@ -114,7 +114,7 @@ To visually debug the templates without running firefox, alter the display:none
${selector.humanReadableText(__element)} ${selector.humanReadableText(__element)}
</td> </td>
<td class="rule-link"> <td class="rule-link">
<a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link" <a target="_blank" onclick="${selector.openStyleEditor}" class="link"
title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a> title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
</td> </td>
</tr> </tr>

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

@ -59,11 +59,19 @@ _BROWSER_TEST_FILES = \
browser_ruleview_manipulation.js \ browser_ruleview_manipulation.js \
browser_ruleview_override.js \ browser_ruleview_override.js \
browser_ruleview_ui.js \ browser_ruleview_ui.js \
browser_bug705707_is_content_stylesheet.js \
head.js \ head.js \
$(NULL) $(NULL)
_BROWSER_TEST_PAGES = \ _BROWSER_TEST_PAGES = \
browser_bug683672.html \ browser_bug683672.html \
browser_bug705707_is_content_stylesheet.html \
browser_bug705707_is_content_stylesheet_imported.css \
browser_bug705707_is_content_stylesheet_imported2.css \
browser_bug705707_is_content_stylesheet_linked.css \
browser_bug705707_is_content_stylesheet_script.css \
browser_bug705707_is_content_stylesheet.xul \
browser_bug705707_is_content_stylesheet_xul.css \
$(NULL) $(NULL)
libs:: $(_BROWSER_TEST_FILES) libs:: $(_BROWSER_TEST_FILES)

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

@ -0,0 +1,33 @@
<html>
<head>
<title>test</title>
<link href="./browser_bug705707_is_content_stylesheet_linked.css" rel="stylesheet" type="text/css">
<script>
// Load script.css
function loadCSS() {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = "./browser_bug705707_is_content_stylesheet_script.css";
document.getElementsByTagName('head')[0].appendChild(link);
}
</script>
<style>
table {
border: 1px solid #000;
}
</style>
</head>
<body onload="loadCSS();">
<table id="target">
<tr>
<td>
<h3>Simple test</h3>
</td>
</tr>
</table>
</body>
</html>

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

@ -0,0 +1,100 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the correct stylesheets origins are identified in HTML & XUL
// stylesheets
let doc;
const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/" +
"test/browser_bug705707_is_content_stylesheet.html";
const TEST_URI2 = "http://example.com/browser/browser/devtools/styleinspector/" +
"test/browser_bug705707_is_content_stylesheet.xul";
const XUL_URI = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(TEST_URI2, null, null);
let tempScope = {};
Cu.import("resource:///modules/devtools/CssLogic.jsm", tempScope);
let CssLogic = tempScope.CssLogic;
function test()
{
waitForExplicitFinish();
addTab(TEST_URI);
browser.addEventListener("load", htmlLoaded, true);
}
function htmlLoaded()
{
browser.removeEventListener("load", htmlLoaded, true);
doc = content.document;
testFromHTML()
}
function testFromHTML()
{
let target = doc.querySelector("#target");
executeSoon(function() {
checkSheets(target);
gBrowser.removeCurrentTab();
openXUL();
});
}
function openXUL()
{
Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager)
.add(XUL_URI, 'allowXULXBL', Ci.nsIPermissionManager.ALLOW_ACTION);
addTab(TEST_URI2);
browser.addEventListener("load", xulLoaded, true);
}
function xulLoaded()
{
browser.removeEventListener("load", xulLoaded, true);
doc = content.document;
testFromXUL()
}
function testFromXUL()
{
let target = doc.querySelector("#target");
executeSoon(function() {
checkSheets(target);
finishUp();
});
}
function checkSheets(aTarget)
{
let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
.getService(Ci.inIDOMUtils);
let domRules = domUtils.getCSSStyleRules(aTarget);
for (let i = 0, n = domRules.Count(); i < n; i++) {
let domRule = domRules.GetElementAt(i);
let sheet = domRule.parentStyleSheet;
let isContentSheet = CssLogic.isContentStylesheet(sheet);
if (!sheet.href ||
/browser_bug705707_is_content_stylesheet_/.test(sheet.href)) {
ok(isContentSheet, sheet.href + " identified as content stylesheet");
} else {
ok(!isContentSheet, sheet.href + " identified as non-content stylesheet");
}
}
}
function finishUp()
{
info("finishing up");
Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager)
.add(XUL_URI, 'allowXULXBL', Ci.nsIPermissionManager.DENY_ACTION);
doc = null;
gBrowser.removeCurrentTab();
finish();
}

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

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/xul.css" type="text/css"?>
<?xml-stylesheet href="./browser_bug705707_is_content_stylesheet_xul.css"
type="text/css"?>
<!DOCTYPE window>
<window id="testwindow" xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<label id="target" value="Simple XUL document" />
</window>

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

@ -0,0 +1,5 @@
@import url("./browser_bug705707_is_content_stylesheet_imported2.css");
#target {
text-decoration: underline;
}

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

@ -0,0 +1,3 @@
#target {
text-decoration: underline;
}

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

@ -0,0 +1,3 @@
table {
border-collapse: collapse;
}

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

@ -0,0 +1,5 @@
@import url("./browser_bug705707_is_content_stylesheet_imported.css");
table {
opacity: 1;
}

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

@ -0,0 +1,3 @@
#target {
font-size: 200px;
}

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

@ -126,6 +126,40 @@ gcli.addCommand({
} }
}); });
/**
* 'edit' command
*/
gcli.addCommand({
name: "edit",
description: gcli.lookup("editDesc"),
manual: gcli.lookup("editManual"),
params: [
{
name: 'resource',
type: {
name: 'resource',
include: 'text/css'
},
description: gcli.lookup("editResourceDesc")
},
{
name: "line",
defaultValue: 1,
type: {
name: "number",
min: 1,
step: 10
},
description: gcli.lookup("editLineToJumpToDesc")
}
],
exec: function(args, context) {
let hud = HUDService.getHudReferenceById(context.environment.hudId);
let StyleEditor = hud.gcliterm.document.defaultView.StyleEditor;
StyleEditor.openChrome(args.resource.element, args.line);
}
});
let breakpoints = []; let breakpoints = [];
/** /**

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

@ -129,3 +129,23 @@ breakdelRemoved=Breakpoint removed
# 'console close' command. This string is designed to be shown in a menu # 'console close' command. This string is designed to be shown in a menu
# alongside the command name, which is why it should be as short as possible. # alongside the command name, which is why it should be as short as possible.
consolecloseDesc=Close the console consolecloseDesc=Close the console
# LOCALIZATION NOTE (editDesc) A very short description of the 'edit'
# command. See editManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
editDesc=Tweak a page resource
# LOCALIZATION NOTE (editManual) A fuller description of the 'edit' command,
# displayed when the user asks for help on what it does.
editManual=Edit one of the resources that is part of this page (or maybe any generic web resource?)
# LOCALIZATION NOTE (editResourceDesc) A very short string to describe the
# 'resource' parameter to the 'edit' command, which is displayed in a dialog
# when the user is using this command.
editResourceDesc=URL to edit
# LOCALIZATION NOTE (editLineToJumpToDesc) A very short string to describe the
# 'line' parameter to the 'edit' command, which is displayed in a dialog
# when the user is using this command.
editLineToJumpToDesc=Line to jump to

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

@ -88,6 +88,12 @@ browser/themes/Makefile
$MOZ_BRANDING_DIRECTORY/Makefile $MOZ_BRANDING_DIRECTORY/Makefile
$MOZ_BRANDING_DIRECTORY/content/Makefile $MOZ_BRANDING_DIRECTORY/content/Makefile
$MOZ_BRANDING_DIRECTORY/locales/Makefile $MOZ_BRANDING_DIRECTORY/locales/Makefile
toolkit/locales/Makefile
extensions/spellcheck/locales/Makefile
intl/locales/Makefile
netwerk/locales/Makefile
dom/locales/Makefile
security/manager/locales/Makefile
" "
if [ "$MOZ_SAFE_BROWSING" ]; then if [ "$MOZ_SAFE_BROWSING" ]; then

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

@ -68,6 +68,9 @@
.helplink:visited { .helplink:visited {
text-decoration: none; text-decoration: none;
} }
.link:hover {
text-decoration: underline;
}
.helplink { .helplink {
display: block; display: block;
@ -135,6 +138,7 @@
.rule-link { .rule-link {
text-align: end; text-align: end;
-moz-padding-start: 10px; -moz-padding-start: 10px;
cursor: pointer;
} }
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */ /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
@ -200,7 +204,13 @@
.ruleview-rule-source { .ruleview-rule-source {
background-color: -moz-dialog; background-color: -moz-dialog;
color: #0091ff;
padding: 2px 5px; padding: 2px 5px;
cursor: pointer;
}
.ruleview-rule-source:hover {
text-decoration: underline;
} }
.ruleview-code { .ruleview-code {

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

@ -68,6 +68,9 @@
.helplink:visited { .helplink:visited {
text-decoration: none; text-decoration: none;
} }
.link:hover {
text-decoration: underline;
}
.helplink { .helplink {
display: block; display: block;
@ -137,6 +140,7 @@
.rule-link { .rule-link {
text-align: end; text-align: end;
-moz-padding-start: 10px; -moz-padding-start: 10px;
cursor: pointer;
} }
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */ /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
@ -202,7 +206,13 @@
.ruleview-rule-source { .ruleview-rule-source {
background-color: -moz-dialog; background-color: -moz-dialog;
color: #0091ff;
padding: 2px 5px; padding: 2px 5px;
cursor: pointer;
}
.ruleview-rule-source:hover {
text-decoration: underline;
} }
.ruleview-code { .ruleview-code {

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

@ -67,6 +67,9 @@
.helplink:visited { .helplink:visited {
text-decoration: none; text-decoration: none;
} }
.link:hover {
text-decoration: underline;
}
.helplink { .helplink {
display: block; display: block;
@ -135,6 +138,7 @@
.rule-link { .rule-link {
text-align: end; text-align: end;
-moz-padding-start: 10px; -moz-padding-start: 10px;
cursor: pointer;
} }
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */ /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
@ -200,7 +204,13 @@
.ruleview-rule-source { .ruleview-rule-source {
background-color: -moz-dialog; background-color: -moz-dialog;
color: #0091ff;
padding: 2px 5px; padding: 2px 5px;
cursor: pointer;
}
.ruleview-rule-source:hover {
text-decoration: underline;
} }
.ruleview-code { .ruleview-code {

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

@ -84,7 +84,7 @@ DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DAPP_BUILDID=$(APP_BUILDID)
DEFINES += -DMOZ_APP_VERSION="$(MOZ_APP_VERSION)" DEFINES += -DMOZ_APP_VERSION="$(MOZ_APP_VERSION)"
APP_INI_DEPS += $(DEPTH)/config/autoconf.mk APP_INI_DEPS += $(DEPTH)/config/autoconf.mk
MOZ_SOURCE_STAMP ?= $(firstword $(shell hg -R $(topsrcdir)/$(MOZ_BUILD_APP)/.. parent --template="{node|short}\n" 2>/dev/null)) MOZ_SOURCE_STAMP := $(firstword $(shell cd $(topsrcdir)/$(MOZ_BUILD_APP)/.. && hg parent --template="{node|short}\n" 2>/dev/null))
ifdef MOZ_SOURCE_STAMP ifdef MOZ_SOURCE_STAMP
DEFINES += -DMOZ_SOURCE_STAMP="$(MOZ_SOURCE_STAMP)" DEFINES += -DMOZ_SOURCE_STAMP="$(MOZ_SOURCE_STAMP)"
endif endif

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

@ -0,0 +1,13 @@
dnl Add compiler specific options
AC_DEFUN([MOZ_COMPILER_OPTS],
[
if test "$CLANG_CXX"; then
## We disable return-type-c-linkage because jsval is defined as a C++ type but is
## returned by C functions. This is possible because we use knowledge about the ABI
## to typedef it to a C type with the same layout when the headers are included
## from C.
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-return-type-c-linkage"
fi
])

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

@ -41,43 +41,55 @@ package @ANDROID_PACKAGE_NAME@;
import java.util.List; import java.util.List;
public interface Actions { public interface Actions {
public enum SpecialKey {
DOWN, UP, LEFT, RIGHT, ENTER, MENU, BACK
}
public interface EventExpecter { /** Special keys supported by sendSpecialKey() */
/** Blocks until the event has been received. Subsequent calls will return immediately. */ public enum SpecialKey {
public void blockForEvent(); DOWN, UP, LEFT, RIGHT, ENTER, MENU, BACK
/** Polls to see if the event has been received. Once this returns true, subsequent calls will also return true. */ }
public boolean eventReceived();
}
public interface RepeatedEventExpecter extends EventExpecter { public interface EventExpecter {
/** Blocks until at least one event has been received, and no events have been received in the last <code>millis</code> milliseconds. */ /** Blocks until the event has been received. Subsequent calls will return immediately. */
public void blockUntilClear(long millis); public void blockForEvent();
}
/** /** Polls to see if the event has been received. Once this returns true, subsequent calls will also return true. */
* Listens for a gecko event to be sent from the Gecko instance. public boolean eventReceived();
* The returned object can be used to test if the event has been }
* received. Note that only one event is listened for.
*
* @param geckoEvent The geckoEvent JSONObject's type
*/
EventExpecter expectGeckoEvent(String geckoEvent);
/** public interface RepeatedEventExpecter extends EventExpecter {
* Listens for a paint event. Note that calling expectPaint() will /** Blocks until at least one event has been received, and no events have been received in the last <code>millis</code> milliseconds. */
* invalidate the event expecters returned from any previous calls public void blockUntilClear(long millis);
* to expectPaint(); calling any methods on those invalidated objects }
* will result in undefined behaviour.
*/
RepeatedEventExpecter expectPaint();
// Send the string kewsToSend to the application /**
void sendKeys(String keysToSend); * Listens for a gecko event to be sent from the Gecko instance.
//Send any of the above keys to the element * The returned object can be used to test if the event has been
void sendSpecialKey(SpecialKey button); * received. Note that only one event is listened for.
*
* @param geckoEvent The geckoEvent JSONObject's type
*/
EventExpecter expectGeckoEvent(String geckoEvent);
void drag(int startingX, int endingX, int startingY, int endingY); /**
* Listens for a paint event. Note that calling expectPaint() will
* invalidate the event expecters returned from any previous calls
* to expectPaint(); calling any methods on those invalidated objects
* will result in undefined behaviour.
*/
RepeatedEventExpecter expectPaint();
/**
* Send a string to the application
*
* @param keysToSend The string to send
*/
void sendKeys(String keysToSend);
/**
* Send a special keycode to the element
*
* @param key The special key to send
*/
void sendSpecialKey(SpecialKey key);
void drag(int startingX, int endingX, int startingY, int endingY);
} }

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

@ -40,19 +40,19 @@
package @ANDROID_PACKAGE_NAME@; package @ANDROID_PACKAGE_NAME@;
public interface Assert { public interface Assert {
void dumpLog(String message); void dumpLog(String message);
void setLogFile(String filename); void setLogFile(String filename);
void setTestName(String testName); void setTestName(String testName);
void finalize(); void finalize();
void ok(boolean condition, String name, String diag); void ok(boolean condition, String name, String diag);
void is(Object a, Object b, String name); void is(Object a, Object b, String name);
void isnot(Object a, Object b, String name); void isnot(Object a, Object b, String name);
void todo(boolean condition, String name, String diag); void todo(boolean condition, String name, String diag);
void todo_is(Object a, Object b, String name); void todo_is(Object a, Object b, String name);
void todo_isnot(Object a, Object b, String name); void todo_isnot(Object a, Object b, String name);
void info(String name, String message); void info(String name, String message);
// robocop-specific asserts // robocop-specific asserts
void ispixel(int actual, int r, int g, int b, String name); void ispixel(int actual, int r, int g, int b, String name);
} }

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

@ -43,39 +43,39 @@ import java.util.List;
import android.app.Activity; import android.app.Activity;
public interface Driver { public interface Driver {
/** /**
* Find the first Element using the given method. * Find the first Element using the given method.
* *
* @param activity The activity the element belongs to * @param activity The activity the element belongs to
* @param name The name of the element * @param name The name of the element
* @return The first matching element on the current context * @return The first matching element on the current context
* @throws RoboCopException If no matching elements are found * @throws RoboCopException If no matching elements are found
*/ */
Element findElement(Activity activity, String name); Element findElement(Activity activity, String name);
/** /**
* Sets up scroll handling so that data is received from the extension. * Sets up scroll handling so that data is received from the extension.
*/ */
void setupScrollHandling(); void setupScrollHandling();
int getPageHeight(); int getPageHeight();
int getScrollHeight(); int getScrollHeight();
int getHeight(); int getHeight();
int getGeckoTop(); int getGeckoTop();
int getGeckoLeft(); int getGeckoLeft();
int getGeckoWidth(); int getGeckoWidth();
int getGeckoHeight(); int getGeckoHeight();
void startFrameRecording(); void startFrameRecording();
int stopFrameRecording(); int stopFrameRecording();
void startCheckerboardRecording(); void startCheckerboardRecording();
float stopCheckerboardRecording(); float stopCheckerboardRecording();
/** /**
* Get a copy of the painted content region. * Get a copy of the painted content region.
* @return A 2-D array of pixels (indexed by y, then x). The pixels * @return A 2-D array of pixels (indexed by y, then x). The pixels
* are in ARGB-8888 format. * are in ARGB-8888 format.
*/ */
int[][] getPaintedSurface(); int[][] getPaintedSurface();
} }

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

@ -39,13 +39,21 @@
package @ANDROID_PACKAGE_NAME@; package @ANDROID_PACKAGE_NAME@;
/**
* Element provides access to a specific UI view (android.view.View).
* See also Driver.findElement().
*/
public interface Element { public interface Element {
//Click on the element
void click(); /** Click on the element */
//Returns true if the element is currently displayed void click();
boolean isDisplayed();
//Returns the text currently displayed on the element. /** Returns true if the element is currently displayed */
String getText(); boolean isDisplayed();
//Returns view ID.
Integer getId(); /** Returns the text currently displayed on the element */
String getText();
/** Returns the view ID */
Integer getId();
} }

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

@ -38,202 +38,194 @@
package @ANDROID_PACKAGE_NAME@; package @ANDROID_PACKAGE_NAME@;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import android.os.SystemClock;
import java.util.Date;
public class FennecMochitestAssert implements Assert { public class FennecMochitestAssert implements Assert {
// Objects for reflexive access of fennec classes. private LinkedList<testInfo> mTestList = new LinkedList<testInfo>();
private LinkedList<testInfo> testList = new LinkedList<testInfo>(); // Internal state variables to make logging match up with existing mochitests
private int mLineNumber = 0;
private int mPassed = 0;
private int mFailed = 0;
private int mTodo = 0;
// Used to write the first line of the test file
private boolean mLogStarted = false;
// Internal state variables to make logging match up with existing mochitests // Used to write the test-start/test-end log lines
private int lineNumber = 0; private String mLogTestName = "";
private int passed = 0;
private int failed = 0;
private int todo = 0;
// Used to write the first line of the test file
private boolean logStarted = false;
// Used to write the test-start/test-end log lines // Measure the time it takes to run test case
private String logTestName = ""; private long mStartTime = 0;
// Measure the time it takes to run test case public FennecMochitestAssert() {
private long startTime = 0;
public FennecMochitestAssert() {
}
// Write information to a logfile and logcat
public void dumpLog(String message)
{
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
}
// Set the filename used for dumpLog.
public void setLogFile(String filename)
{
FennecNativeDriver.setLogFile(filename);
String message;
if (!logStarted) {
dumpLog(Integer.toString(lineNumber++) + " INFO SimpleTest START");
logStarted = true;
} }
if (logTestName != "") { /** Write information to a logfile and logcat */
long diff = (new Date().getTime()) - startTime; public void dumpLog(String message) {
message = Integer.toString(lineNumber++) + " INFO TEST-END | " + logTestName; FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
message += " | finished in " + diff + "ms";
dumpLog(message);
logTestName = "";
}
}
public void setTestName(String testName)
{
String[] nameParts = testName.split("\\.");
logTestName = nameParts[nameParts.length - 1];
startTime = new Date().getTime();
dumpLog(Integer.toString(lineNumber++) + " INFO TEST-START | " + logTestName);
}
class testInfo {
public boolean result;
public String name;
public String diag;
public boolean todo;
public testInfo(boolean r, String n, String d, boolean t) {
result = r;
name = n;
diag = d;
todo = t;
} }
} /** Set the filename used for dumpLog. */
public void setLogFile(String filename) {
FennecNativeDriver.setLogFile(filename);
private void _logMochitestResult(testInfo test, String passString, String failString) String message;
{ if (!mLogStarted) {
boolean isError = true; dumpLog(Integer.toString(mLineNumber++) + " INFO SimpleTest START");
String resultString = failString; mLogStarted = true;
if (test.result || test.todo) { }
isError = false;
}
if (test.result)
{
resultString = passString;
}
String diag = test.name;
if (test.diag != null) diag += " - " + test.diag;
String message = Integer.toString(lineNumber++) + " INFO " + resultString + " | " + logTestName + " | " + diag; if (mLogTestName != "") {
dumpLog(message); long diff = SystemClock.uptimeMillis() - mStartTime;
message = Integer.toString(mLineNumber++) + " INFO TEST-END | " + mLogTestName;
if (test.todo) { message += " | finished in " + diff + "ms";
todo++; dumpLog(message);
} else if (isError) { mLogTestName = "";
failed++; }
} else {
passed++;
}
if (isError) {
junit.framework.Assert.fail(message);
}
}
public void finalize()
{
// It appears that we call finalize during cleanup, this might be an invalid assertion.
String message;
if (logTestName != "") {
long diff = (new Date().getTime()) - startTime;
message = Integer.toString(lineNumber++) + " INFO TEST-END | " + logTestName;
message += " | finished in " + diff + "ms";
dumpLog(message);
logTestName = "";
} }
message = Integer.toString(lineNumber++) + " INFO TEST-START | Shutdown"; public void setTestName(String testName) {
dumpLog(message); String[] nameParts = testName.split("\\.");
message = Integer.toString(lineNumber++) + " INFO Passed: " + Integer.toString(passed); mLogTestName = nameParts[nameParts.length - 1];
dumpLog(message); mStartTime = SystemClock.uptimeMillis();
message = Integer.toString(lineNumber++) + " INFO Failed: " + Integer.toString(failed);
dumpLog(message);
message = Integer.toString(lineNumber++) + " INFO Todo: " + Integer.toString(todo);
dumpLog(message);
message = Integer.toString(lineNumber++) + " INFO SimpleTest FINISHED";
dumpLog(message);
}
public void ok(boolean condition, String name, String diag) { dumpLog(Integer.toString(mLineNumber++) + " INFO TEST-START | " + mLogTestName);
testInfo test = new testInfo(condition, name, diag, false);
_logMochitestResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
testList.add(test);
}
public void is(Object a, Object b, String name) {
boolean pass = a.equals(b);
String diag = "got " + a.toString() + ", expected " + b.toString();
if(pass) {
diag = a.toString() + " should equal " + b.toString();
} }
ok(pass, name, diag);
} class testInfo {
public boolean mResult;
public void isnot(Object a, Object b, String name) { public String mName;
boolean pass = !a.equals(b); public String mDiag;
String diag = "didn't expect " + a.toString() + ", but got it"; public boolean mTodo;
if(pass) { public testInfo(boolean r, String n, String d, boolean t) {
diag = a.toString() + " should not equal " + b.toString(); mResult = r;
mName = n;
mDiag = d;
mTodo = t;
}
} }
ok(pass, name, diag);
}
public void ispixel(int actual, int r, int g, int b, String name) { private void _logMochitestResult(testInfo test, String passString, String failString) {
// When we read GL pixels the GPU has already processed them and they boolean isError = true;
// are usually off by a little bit. For example a CSS-color pixel of color #64FFF5 String resultString = failString;
// was turned into #63FFF7 when it came out of glReadPixels. So in order to compare if (test.mResult || test.mTodo) {
// against the expected value, we use a little fuzz factor. For the alpha we just isError = false;
// make sure it is always 0xFF. }
int aAlpha = ((actual >> 24) & 0xFF); if (test.mResult)
int aR = ((actual >> 16) & 0xFF); {
int aG = ((actual >> 8) & 0xFF); resultString = passString;
int aB = (actual & 0xFF); }
boolean pass = (aAlpha == 0xFF) /* alpha */ String diag = test.mName;
&& (Math.abs(aR - r) < 8) /* red */ if (test.mDiag != null) diag += " - " + test.mDiag;
&& (Math.abs(aG - g) < 8) /* green */
&& (Math.abs(aB - b) < 8); /* blue */
ok(pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (pass ? " " : " not") + " close enough to expected rgb(" + r + "," + g + "," + b + ")");
}
public void todo(boolean condition, String name, String diag) { String message = Integer.toString(mLineNumber++) + " INFO " + resultString + " | " + mLogTestName + " | " + diag;
testInfo test = new testInfo(condition, name, diag, true); dumpLog(message);
_logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
testList.add(test);
}
public void todo_is(Object a, Object b, String name) { if (test.mTodo) {
boolean pass = a.equals(b); mTodo++;
String diag = "got " + a.toString() + ", expected " + b.toString(); } else if (isError) {
if(pass) { mFailed++;
diag = a.toString() + " should equal " + b.toString(); } else {
mPassed++;
}
if (isError) {
junit.framework.Assert.fail(message);
}
} }
todo(pass, name, diag);
}
public void todo_isnot(Object a, Object b, String name) {
boolean pass = !a.equals(b);
String diag = "didn't expect " + a.toString() + ", but got it";
if(pass) {
diag = a.toString() + " should not equal " + b.toString();
}
todo(pass, name, diag);
}
public void info(String name, String message) { public void finalize() {
testInfo test = new testInfo(true, name, message, false); // It appears that we call finalize during cleanup, this might be an invalid assertion.
_logMochitestResult(test, "TEST-INFO", "INFO FAILED?"); String message;
}
if (mLogTestName != "") {
long diff = SystemClock.uptimeMillis() - mStartTime;
message = Integer.toString(mLineNumber++) + " INFO TEST-END | " + mLogTestName;
message += " | finished in " + diff + "ms";
dumpLog(message);
mLogTestName = "";
}
message = Integer.toString(mLineNumber++) + " INFO TEST-START | Shutdown";
dumpLog(message);
message = Integer.toString(mLineNumber++) + " INFO Passed: " + Integer.toString(mPassed);
dumpLog(message);
message = Integer.toString(mLineNumber++) + " INFO Failed: " + Integer.toString(mFailed);
dumpLog(message);
message = Integer.toString(mLineNumber++) + " INFO Todo: " + Integer.toString(mTodo);
dumpLog(message);
message = Integer.toString(mLineNumber++) + " INFO SimpleTest FINISHED";
dumpLog(message);
}
public void ok(boolean condition, String name, String diag) {
testInfo test = new testInfo(condition, name, diag, false);
_logMochitestResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
mTestList.add(test);
}
public void is(Object a, Object b, String name) {
boolean pass = a.equals(b);
String diag = "got " + a.toString() + ", expected " + b.toString();
if (pass) {
diag = a.toString() + " should equal " + b.toString();
}
ok(pass, name, diag);
}
public void isnot(Object a, Object b, String name) {
boolean pass = !a.equals(b);
String diag = "didn't expect " + a.toString() + ", but got it";
if (pass) {
diag = a.toString() + " should not equal " + b.toString();
}
ok(pass, name, diag);
}
public void ispixel(int actual, int r, int g, int b, String name) {
// When we read GL pixels the GPU has already processed them and they
// are usually off by a little bit. For example a CSS-color pixel of color #64FFF5
// was turned into #63FFF7 when it came out of glReadPixels. So in order to compare
// against the expected value, we use a little fuzz factor. For the alpha we just
// make sure it is always 0xFF.
int aAlpha = ((actual >> 24) & 0xFF);
int aR = ((actual >> 16) & 0xFF);
int aG = ((actual >> 8) & 0xFF);
int aB = (actual & 0xFF);
boolean pass = (aAlpha == 0xFF) /* alpha */
&& (Math.abs(aR - r) < 8) /* red */
&& (Math.abs(aG - g) < 8) /* green */
&& (Math.abs(aB - b) < 8); /* blue */
ok(pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (pass ? " " : " not") + " close enough to expected rgb(" + r + "," + g + "," + b + ")");
}
public void todo(boolean condition, String name, String diag) {
testInfo test = new testInfo(condition, name, diag, true);
_logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
mTestList.add(test);
}
public void todo_is(Object a, Object b, String name) {
boolean pass = a.equals(b);
String diag = "got " + a.toString() + ", expected " + b.toString();
if (pass) {
diag = a.toString() + " should equal " + b.toString();
}
todo(pass, name, diag);
}
public void todo_isnot(Object a, Object b, String name) {
boolean pass = !a.equals(b);
String diag = "didn't expect " + a.toString() + ", but got it";
if (pass) {
diag = a.toString() + " should not equal " + b.toString();
}
todo(pass, name, diag);
}
public void info(String name, String message) {
testInfo test = new testInfo(true, name, message, false);
_logMochitestResult(test, "TEST-INFO", "INFO FAILED?");
}
} }

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

@ -59,295 +59,294 @@ import org.json.*;
import com.jayway.android.robotium.solo.Solo; import com.jayway.android.robotium.solo.Solo;
public class FennecNativeActions implements Actions { public class FennecNativeActions implements Actions {
private Solo solo; private Solo mSolo;
private Instrumentation instr; private Instrumentation mInstr;
private Activity geckoApp; private Activity mGeckoApp;
// Objects for reflexive access of fennec classes. // Objects for reflexive access of fennec classes.
private ClassLoader classLoader; private ClassLoader mClassLoader;
private Class gel; private Class mGel;
private Class ge; private Class mGe;
private Class gas; private Class mGas;
private Class drawListener; private Class mDrawListener;
private Method registerGEL; private Method mRegisterGEL;
private Method unregisterGEL; private Method mUnregisterGEL;
private Method sendGE; private Method mSendGE;
private Method getLayerClient; private Method mGetLayerClient;
private Method setDrawListener; private Method mSetDrawListener;
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation){ public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation) {
this.solo = robocop; mSolo = robocop;
this.instr = instrumentation; mInstr = instrumentation;
this.geckoApp = activity; mGeckoApp = activity;
// Set up reflexive access of java classes and methods. // Set up reflexive access of java classes and methods.
try {
classLoader = activity.getClassLoader();
gel = classLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
ge = classLoader.loadClass("org.mozilla.gecko.GeckoEvent");
gas = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
Class [] parameters = new Class[2];
parameters[0] = String.class;
parameters[1] = gel;
registerGEL = gas.getMethod("registerGeckoEventListener", parameters);
unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
parameters = new Class[1];
parameters[0] = ge;
sendGE = gas.getMethod("sendEventToGecko", parameters);
getLayerClient = activity.getClass().getMethod("getSoftwareLayerClient");
Class gslc = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient");
drawListener = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient$DrawListener");
setDrawListener = gslc.getDeclaredMethod("setDrawListener", drawListener);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
class wakeInvocationHandler implements InvocationHandler {
private final GeckoEventExpecter mEventExpecter;
public wakeInvocationHandler(GeckoEventExpecter expecter) {
mEventExpecter = expecter;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String methodName = method.getName();
//Depending on the method, return a completely different type.
if(methodName.equals("toString")) {
return "wakeInvocationHandler";
}
if(methodName.equals("equals")) {
return this == args[0];
}
if(methodName.equals("clone")) {
return this;
}
if(methodName.equals("hashCode")) {
return 314;
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
"Waking up on "+methodName);
mEventExpecter.notifyOfEvent();
return null;
}
}
class GeckoEventExpecter implements EventExpecter {
private final String mGeckoEvent;
private final Object[] mRegistrationParams;
private boolean mEventReceived;
GeckoEventExpecter(String geckoEvent, Object[] registrationParams) {
mGeckoEvent = geckoEvent;
mRegistrationParams = registrationParams;
}
public synchronized void blockForEvent() {
while (! mEventReceived) {
try { try {
this.wait(); mClassLoader = activity.getClassLoader();
} catch (InterruptedException ie) { mGel = mClassLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
ie.printStackTrace(); mGe = mClassLoader.loadClass("org.mozilla.gecko.GeckoEvent");
break; mGas = mClassLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
Class [] parameters = new Class[2];
parameters[0] = String.class;
parameters[1] = mGel;
mRegisterGEL = mGas.getMethod("registerGeckoEventListener", parameters);
mUnregisterGEL = mGas.getMethod("unregisterGeckoEventListener", parameters);
parameters = new Class[1];
parameters[0] = mGe;
mSendGE = mGas.getMethod("sendEventToGecko", parameters);
mGetLayerClient = activity.getClass().getMethod("getSoftwareLayerClient");
Class gslc = mClassLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient");
mDrawListener = mClassLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient$DrawListener");
mSetDrawListener = gslc.getDeclaredMethod("setDrawListener", mDrawListener);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
class wakeInvocationHandler implements InvocationHandler {
private final GeckoEventExpecter mEventExpecter;
public wakeInvocationHandler(GeckoEventExpecter expecter) {
mEventExpecter = expecter;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String methodName = method.getName();
//Depending on the method, return a completely different type.
if(methodName.equals("toString")) {
return "wakeInvocationHandler";
}
if(methodName.equals("equals")) {
return this == args[0];
}
if(methodName.equals("clone")) {
return this;
}
if(methodName.equals("hashCode")) {
return 314;
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
"Waking up on "+methodName);
mEventExpecter.notifyOfEvent();
return null;
} }
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
"unblocked on expecter for " + mGeckoEvent);
} }
public synchronized boolean eventReceived() { class GeckoEventExpecter implements EventExpecter {
return mEventReceived; private final String mGeckoEvent;
} private final Object[] mRegistrationParams;
private boolean mEventReceived;
void notifyOfEvent() { GeckoEventExpecter(String geckoEvent, Object[] registrationParams) {
try { mGeckoEvent = geckoEvent;
unregisterGEL.invoke(null, mRegistrationParams); mRegistrationParams = registrationParams;
} catch (IllegalAccessException e) { }
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
"received event " + mGeckoEvent);
synchronized (this) {
mEventReceived = true;
this.notifyAll();
}
}
}
public EventExpecter expectGeckoEvent(String geckoEvent) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
"waiting for "+geckoEvent);
try {
Class [] interfaces = new Class[1];
interfaces[0] = gel;
Object[] finalParams = new Object[2];
finalParams[0] = geckoEvent;
GeckoEventExpecter expecter = new GeckoEventExpecter(geckoEvent, finalParams);
wakeInvocationHandler wIH = new wakeInvocationHandler(expecter);
Object proxy = Proxy.newProxyInstance(classLoader, interfaces, wIH);
finalParams[1] = proxy;
registerGEL.invoke(null, finalParams);
return expecter;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
class DrawListenerProxy implements InvocationHandler { public synchronized void blockForEvent() {
private final PaintExpecter mPaintExpecter; while (! mEventReceived) {
try {
this.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
}
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
"unblocked on expecter for " + mGeckoEvent);
}
DrawListenerProxy(PaintExpecter paintExpecter) { public synchronized boolean eventReceived() {
mPaintExpecter = paintExpecter; return mEventReceived;
}
void notifyOfEvent() {
try {
mUnregisterGEL.invoke(null, mRegistrationParams);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
"received event " + mGeckoEvent);
synchronized (this) {
mEventReceived = true;
this.notifyAll();
}
}
} }
public Object invoke(Object proxy, Method method, Object[] args) { public EventExpecter expectGeckoEvent(String geckoEvent) {
String methodName = method.getName();
if ("drawFinished".equals(methodName)) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG, FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
"Received drawFinished notification"); "waiting for "+geckoEvent);
mPaintExpecter.notifyOfEvent();
} else if ("toString".equals(methodName)) {
return "DrawListenerProxy";
} else if ("equals".equals(methodName)) {
return false;
} else if ("hashCode".equals(methodName)) {
return 0;
}
return null;
}
}
class PaintExpecter implements RepeatedEventExpecter {
private Object mLayerClient;
private boolean mPaintDone;
PaintExpecter() throws IllegalAccessException, InvocationTargetException {
mLayerClient = getLayerClient.invoke(geckoApp);
setDrawListener.invoke(mLayerClient, Proxy.newProxyInstance(classLoader, new Class[] { drawListener }, new DrawListenerProxy(this)));
}
void notifyOfEvent() {
synchronized (this) {
mPaintDone = true;
this.notifyAll();
}
}
public synchronized void blockForEvent() {
while (! mPaintDone) {
try { try {
this.wait(); Class [] interfaces = new Class[1];
} catch (InterruptedException ie) { interfaces[0] = mGel;
ie.printStackTrace(); Object[] finalParams = new Object[2];
break; finalParams[0] = geckoEvent;
GeckoEventExpecter expecter = new GeckoEventExpecter(geckoEvent, finalParams);
wakeInvocationHandler wIH = new wakeInvocationHandler(expecter);
Object proxy = Proxy.newProxyInstance(mClassLoader, interfaces, wIH);
finalParams[1] = proxy;
mRegisterGEL.invoke(null, finalParams);
return expecter;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} }
} return null;
try {
setDrawListener.invoke(mLayerClient, (Object)null);
} catch (Exception e) {
e.printStackTrace();
}
} }
public synchronized boolean eventReceived() { class DrawListenerProxy implements InvocationHandler {
return mPaintDone; private final PaintExpecter mPaintExpecter;
DrawListenerProxy(PaintExpecter paintExpecter) {
mPaintExpecter = paintExpecter;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String methodName = method.getName();
if ("drawFinished".equals(methodName)) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_DEBUG,
"Received drawFinished notification");
mPaintExpecter.notifyOfEvent();
} else if ("toString".equals(methodName)) {
return "DrawListenerProxy";
} else if ("equals".equals(methodName)) {
return false;
} else if ("hashCode".equals(methodName)) {
return 0;
}
return null;
}
} }
public synchronized void blockUntilClear(long millis) { class PaintExpecter implements RepeatedEventExpecter {
if (millis <= 0) { private Object mLayerClient;
throw new IllegalArgumentException("millis must be > 0"); private boolean mPaintDone;
}
// wait for at least one event PaintExpecter() throws IllegalAccessException, InvocationTargetException {
while (! mPaintDone) { mLayerClient = mGetLayerClient.invoke(mGeckoApp);
mSetDrawListener.invoke(mLayerClient, Proxy.newProxyInstance(mClassLoader, new Class[] { mDrawListener }, new DrawListenerProxy(this)));
}
void notifyOfEvent() {
synchronized (this) {
mPaintDone = true;
this.notifyAll();
}
}
public synchronized void blockForEvent() {
while (!mPaintDone) {
try {
this.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
}
}
try {
mSetDrawListener.invoke(mLayerClient, (Object)null);
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized boolean eventReceived() {
return mPaintDone;
}
public synchronized void blockUntilClear(long millis) {
if (millis <= 0) {
throw new IllegalArgumentException("millis must be > 0");
}
// wait for at least one event
while (!mPaintDone) {
try {
this.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
}
}
// now wait for a period of millis where we don't get an event
long startTime = SystemClock.uptimeMillis();
while (true) {
try {
this.wait(millis);
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
}
long endTime = SystemClock.uptimeMillis();
if (endTime - startTime >= millis) {
// success
break;
}
// we got a notify() before we could wait long enough, so we need to start over
startTime = endTime;
}
try {
mSetDrawListener.invoke(mLayerClient, (Object)null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public RepeatedEventExpecter expectPaint() {
try { try {
this.wait(); return new PaintExpecter();
} catch (InterruptedException ie) { } catch (Exception e) {
ie.printStackTrace(); e.printStackTrace();
break; return null;
} }
} }
// now wait for a period of millis where we don't get an event
long startTime = SystemClock.uptimeMillis(); public void sendSpecialKey(SpecialKey button) {
while (true) { switch(button) {
try { case DOWN:
this.wait(millis); mInstr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
} catch (InterruptedException ie) { break;
ie.printStackTrace(); case UP:
break; mInstr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
break;
case LEFT:
mInstr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_LEFT);
break;
case RIGHT:
mInstr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_RIGHT);
break;
case ENTER:
mInstr.sendCharacterSync(KeyEvent.KEYCODE_ENTER);
break;
case MENU:
mInstr.sendCharacterSync(KeyEvent.KEYCODE_MENU);
break;
case BACK:
mInstr.sendCharacterSync(KeyEvent.KEYCODE_BACK);
break;
default:
break;
} }
long endTime = SystemClock.uptimeMillis();
if (endTime - startTime >= millis) {
// success
break;
}
// we got a notify() before we could wait long enough, so we need to start over
startTime = endTime;
}
try {
setDrawListener.invoke(mLayerClient, (Object)null);
} catch (Exception e) {
e.printStackTrace();
}
} }
}
public RepeatedEventExpecter expectPaint() { @Override
try { public void sendKeys(String input) {
return new PaintExpecter(); mInstr.sendStringSync(input);
} catch (Exception e) {
e.printStackTrace();
return null;
} }
}
public void sendSpecialKey(SpecialKey button) { public void drag(int startingX, int endingX, int startingY, int endingY) {
switch( button) { mSolo.drag(startingX, endingX, startingY, endingY, 10);
case DOWN:
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
break;
case UP:
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
break;
case LEFT:
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_LEFT);
break;
case RIGHT:
instr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_RIGHT);
break;
case ENTER:
instr.sendCharacterSync(KeyEvent.KEYCODE_ENTER);
break;
case MENU:
instr.sendCharacterSync(KeyEvent.KEYCODE_MENU);
break;
case BACK:
instr.sendCharacterSync(KeyEvent.KEYCODE_BACK);
break;
default:
break;
} }
}
@Override
public void sendKeys(String input) {
instr.sendStringSync(input);
}
public void drag(int startingX, int endingX, int startingY, int endingY) {
solo.drag(startingX, endingX, startingY, endingY, 10);
}
} }

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

@ -46,8 +46,6 @@ import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -68,396 +66,405 @@ import org.json.*;
import com.jayway.android.robotium.solo.Solo; import com.jayway.android.robotium.solo.Solo;
public class FennecNativeDriver implements Driver { public class FennecNativeDriver implements Driver {
// Map of IDs to element names. // Map of IDs to element names.
private HashMap locators = null; private HashMap mLocators = null;
private Activity activity; private Activity mActivity;
private Solo solo; private Solo mSolo;
private static String mLogFile = null; private static String mLogFile = null;
private static LogLevel mLogLevel = LogLevel.LOG_LEVEL_INFO; private static LogLevel mLogLevel = LogLevel.LOG_LEVEL_INFO;
// Objects for reflexive access of fennec classes. // Objects for reflexive access of fennec classes.
private ClassLoader classLoader; private ClassLoader mClassLoader;
private Class gel; private Class mGel;
private Class ge; private Class mGe;
private Class gas; private Class mGas;
private Method registerGEL; private Method mRegisterGEL;
private Method unregisterGEL; private Method mUnregisterGEL;
private Method sendGE; private Method mSendGE;
private Method _startFrameRecording; private Method _startFrameRecording;
private Method _stopFrameRecording; private Method _stopFrameRecording;
private Method _startCheckerboardRecording; private Method _startCheckerboardRecording;
private Method _stopCheckerboardRecording; private Method _stopCheckerboardRecording;
private Method _getPixels; private Method _getPixels;
public enum LogLevel { public enum LogLevel {
LOG_LEVEL_DEBUG(1), LOG_LEVEL_DEBUG(1),
LOG_LEVEL_INFO(2), LOG_LEVEL_INFO(2),
LOG_LEVEL_WARN(3), LOG_LEVEL_WARN(3),
LOG_LEVEL_ERROR(4); LOG_LEVEL_ERROR(4);
private int mValue; private int mValue;
LogLevel(int value) { LogLevel(int value) {
mValue = value; mValue = value;
}
public boolean isEnabled(LogLevel configuredLevel) {
return mValue >= configuredLevel.getValue();
}
private int getValue() {
return mValue;
}
}
public FennecNativeDriver(Activity activity, Solo robocop){
this.activity = activity;
this.solo = robocop;
// Set up table of fennec_ids.
locators = convertTextToTable(getFile("/mnt/sdcard/fennec_ids.txt"));
// Set up reflexive access of java classes and methods.
try {
classLoader = activity.getClassLoader();
gel = classLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
ge = classLoader.loadClass("org.mozilla.gecko.GeckoEvent");
gas = classLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
Class [] parameters = new Class[2];
parameters[0] = String.class;
parameters[1] = gel;
registerGEL = gas.getMethod("registerGeckoEventListener", parameters);
unregisterGEL = gas.getMethod("unregisterGeckoEventListener", parameters);
parameters = new Class[1];
parameters[0] = ge;
sendGE = gas.getMethod("sendEventToGecko", parameters);
Class gfx = classLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
_startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
_stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
_startCheckerboardRecording = gfx.getDeclaredMethod("startCheckerboardRecording");
_stopCheckerboardRecording = gfx.getDeclaredMethod("stopCheckerboardRecording");
Class layerView = classLoader.loadClass("org.mozilla.gecko.gfx.LayerView");
_getPixels = layerView.getDeclaredMethod("getPixels");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
//Information on the location of the Gecko Frame.
private boolean geckoInfo = false;
private int geckoTop = 100;
private int geckoLeft = 0;
private int geckoHeight= 700;
private int geckoWidth = 1024;
private void getGeckoInfo() {
View geckoLayout = activity.findViewById(Integer.decode((String)locators.get("gecko_layout")));
if (geckoLayout != null) {
int[] pos = new int[2];
geckoLayout.getLocationOnScreen(pos);
geckoTop = pos[1];
geckoLeft = pos[0];
geckoWidth = geckoLayout.getWidth();
geckoHeight = geckoLayout.getHeight();
geckoInfo = true;
} else {
throw new RoboCopException("Unable to find view gecko_layout");
}
}
public int getGeckoTop() {
if(!geckoInfo) {
getGeckoInfo();
}
return geckoTop;
}
public int getGeckoLeft() {
if(!geckoInfo) {
getGeckoInfo();
}
return geckoLeft;
}
public int getGeckoHeight() {
if(!geckoInfo) {
getGeckoInfo();
}
return geckoHeight;
}
public int getGeckoWidth() {
if(!geckoInfo) {
getGeckoInfo();
}
return geckoWidth;
}
public Element findElement(Activity activity, String name) {
if (name == null)
throw new IllegalArgumentException("Can not findElements when passed a null");
if (locators.containsKey(name)){
return new FennecNativeElement(Integer.decode((String)locators.get(name)), activity, solo);
}
throw new RoboCopException("Element does not exist in the list");
}
public void startFrameRecording() {
try {
Object [] params = null;
_startFrameRecording.invoke(null, params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public int stopFrameRecording() {
Class [] parameters = new Class[1];
parameters[0] = null;
List frames;
try {
Object [] params = null;
frames = (List)_stopFrameRecording.invoke(null, params);
Object [] framearray = frames.toArray();
Long last = new Long(0);
Long threshold = new Long(17);
int numDelays = 0;
for (int i=0; i < framearray.length; i++) {
Long val = (Long)framearray[i];
if ((val - last) > threshold) {
numDelays++;
} }
last = val; public boolean isEnabled(LogLevel configuredLevel) {
} return mValue >= configuredLevel.getValue();
return numDelays; }
} catch (IllegalAccessException e) { private int getValue() {
e.printStackTrace(); return mValue;
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
public void startCheckerboardRecording() {
try {
Object [] params = null;
_startCheckerboardRecording.invoke(null, params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public float stopCheckerboardRecording() {
Class [] parameters = new Class[1];
parameters[0] = null;
List checkerboard;
try {
Object [] params = null;
checkerboard = (List)_stopCheckerboardRecording.invoke(null, params);
Object [] amountarray = checkerboard.toArray();
double completeness = 0;
for (Object obj : amountarray) {
float val = (Float)obj;
completeness += (1.0 - (double)val) / (double)amountarray.length;
}
return (float)completeness;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return 0.0f;
}
private GLSurfaceView getSurfaceView() {
for (View v : solo.getCurrentViews()) {
if (v instanceof GLSurfaceView) {
return (GLSurfaceView)v;
}
}
return null;
}
public int[][] getPaintedSurface() {
GLSurfaceView view = getSurfaceView();
if (view == null) {
return null;
}
IntBuffer pixelBuffer;
try {
pixelBuffer = (IntBuffer)_getPixels.invoke(view);
} catch (Exception e) {
e.printStackTrace();
return null;
}
// now we need to (1) flip the image, because GL likes to do things up-side-down,
// and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
int w = view.getWidth();
int h = view.getHeight();
pixelBuffer.position(0);
int[][] pixels = new int[h][w];
for (int y = h - 1; y >= 0; y--) {
for (int x = 0; x < w; x++) {
int agbr = pixelBuffer.get();
pixels[y][x] = (agbr & 0xFF00FF00) | ((agbr >> 16) & 0x000000FF) | ((agbr << 16) & 0x00FF0000);
}
}
return pixels;
}
class scrollHandler implements InvocationHandler {
public scrollHandler(){};
public Object invoke(Object proxy, Method method, Object[] args) {
try{
//Disect the JSON object into the appropriate variables
JSONObject jo = ((JSONObject)args[1]);
scrollHeight = jo.getInt("y");
height = jo.getInt("cheight");
//We don't want a height of 0. That means it's a bad response.
if( height > 0) {
pageHeight = jo.getInt("height");
} }
} catch( Throwable e) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_WARN,
"WARNING: ScrollReceived, but read wrong!");
}
return null;
}
}
public int getScrollHeight() {
return scrollHeight;
}
public int getPageHeight() {
return pageHeight;
}
public int getHeight() {
return height;
}
public int height=0;
public int scrollHeight=0;
public int pageHeight=10;
public void setupScrollHandling() {
//Setup scrollHandler to catch "robocop:scroll" events.
try {
Class [] interfaces = new Class[1];
interfaces[0] = gel;
Object[] finalParams = new Object[2];
finalParams[0] = "robocop:scroll";
finalParams[1] = Proxy.newProxyInstance(classLoader, interfaces, new scrollHandler());
registerGEL.invoke(null, finalParams);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} }
} public FennecNativeDriver(Activity activity, Solo robocop) {
mActivity = activity;
mSolo = robocop;
//Takes a filename, loads the file, // Set up table of fennec_ids.
// and returns a string version of the entire file. mLocators = convertTextToTable(getFile("/mnt/sdcard/fennec_ids.txt"));
public static String getFile(String filename)
{
StringBuilder text = new StringBuilder();
BufferedReader br = null; // Set up reflexive access of java classes and methods.
try {
br = new BufferedReader(new FileReader(filename));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
}
}
return text.toString();
}
// Takes a string of "key=value" pairs split by \n and creates a hash table.
public static HashMap convertTextToTable(String data)
{
HashMap retVal = new HashMap();
String[] lines = data.split("\n");
for (int i = 0; i < lines.length; i++) {
String[] parts = lines[i].split("=");
retVal.put(parts[0].trim(), parts[1].trim());
}
return retVal;
}
// Set the filename used for logging. If the file already exists, delete it
// as a safe-guard against accidentally appending to an old log file.
public static void setLogFile(String filename) {
mLogFile = filename;
File file = new File(mLogFile);
if (file.exists()) {
file.delete();
}
}
public static void setLogLevel(LogLevel level) {
mLogLevel = level;
}
public static void log(LogLevel level, String message) {
if (mLogFile == null) {
assert(false);
}
if (level.isEnabled(mLogLevel)) {
File file = new File(mLogFile);
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(mLogFile, true));
bw.write(message);
bw.newLine();
} catch(IOException e) {
Log.e("Robocop", "exception with file writer on: " + mLogFile);
} finally {
try { try {
if (bw != null) { mClassLoader = activity.getClassLoader();
bw.flush(); mGel = mClassLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
bw.close(); mGe = mClassLoader.loadClass("org.mozilla.gecko.GeckoEvent");
} mGas = mClassLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
} catch (IOException ex) { Class [] parameters = new Class[2];
ex.printStackTrace(); parameters[0] = String.class;
} parameters[1] = mGel;
} mRegisterGEL = mGas.getMethod("registerGeckoEventListener", parameters);
mUnregisterGEL = mGas.getMethod("unregisterGeckoEventListener", parameters);
parameters = new Class[1];
parameters[0] = mGe;
mSendGE = mGas.getMethod("sendEventToGecko", parameters);
Class gfx = mClassLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
_startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
_stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
_startCheckerboardRecording = gfx.getDeclaredMethod("startCheckerboardRecording");
_stopCheckerboardRecording = gfx.getDeclaredMethod("stopCheckerboardRecording");
Class layerView = mClassLoader.loadClass("org.mozilla.gecko.gfx.LayerView");
_getPixels = layerView.getDeclaredMethod("getPixels");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
} }
if (level == LogLevel.LOG_LEVEL_INFO) { //Information on the location of the Gecko Frame.
Log.i("Robocop", message); private boolean mGeckoInfo = false;
} else if (level == LogLevel.LOG_LEVEL_DEBUG) { private int mGeckoTop = 100;
Log.d("Robocop", message); private int mGeckoLeft = 0;
} else if (level == LogLevel.LOG_LEVEL_WARN) { private int mGeckoHeight= 700;
Log.w("Robocop", message); private int mGeckoWidth = 1024;
} else if (level == LogLevel.LOG_LEVEL_ERROR) {
Log.e("Robocop", message); private void getGeckoInfo() {
View geckoLayout = mActivity.findViewById(Integer.decode((String)mLocators.get("gecko_layout")));
if (geckoLayout != null) {
int[] pos = new int[2];
geckoLayout.getLocationOnScreen(pos);
mGeckoTop = pos[1];
mGeckoLeft = pos[0];
mGeckoWidth = geckoLayout.getWidth();
mGeckoHeight = geckoLayout.getHeight();
mGeckoInfo = true;
} else {
throw new RoboCopException("Unable to find view gecko_layout");
}
}
public int getGeckoTop() {
if (!mGeckoInfo) {
getGeckoInfo();
}
return mGeckoTop;
}
public int getGeckoLeft() {
if (!mGeckoInfo) {
getGeckoInfo();
}
return mGeckoLeft;
}
public int getGeckoHeight() {
if (!mGeckoInfo) {
getGeckoInfo();
}
return mGeckoHeight;
}
public int getGeckoWidth() {
if (!mGeckoInfo) {
getGeckoInfo();
}
return mGeckoWidth;
}
public Element findElement(Activity activity, String name) {
if (name == null) {
throw new IllegalArgumentException("Can not findElements when passed a null");
}
if (mLocators.containsKey(name)) {
return new FennecNativeElement(Integer.decode((String)mLocators.get(name)), activity, mSolo);
}
throw new RoboCopException("Element does not exist in the list");
}
public void startFrameRecording() {
try {
Object [] params = null;
_startFrameRecording.invoke(null, params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public int stopFrameRecording() {
Class [] parameters = new Class[1];
parameters[0] = null;
List frames;
try {
Object [] params = null;
frames = (List)_stopFrameRecording.invoke(null, params);
Object [] framearray = frames.toArray();
Long last = new Long(0);
Long threshold = new Long(17);
int numDelays = 0;
for (int i=0; i < framearray.length; i++) {
Long val = (Long)framearray[i];
if ((val - last) > threshold) {
numDelays++;
}
last = val;
}
return numDelays;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return 0;
}
public void startCheckerboardRecording() {
try {
Object [] params = null;
_startCheckerboardRecording.invoke(null, params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public float stopCheckerboardRecording() {
Class [] parameters = new Class[1];
parameters[0] = null;
List checkerboard;
try {
Object [] params = null;
checkerboard = (List)_stopCheckerboardRecording.invoke(null, params);
Object [] amountarray = checkerboard.toArray();
double completeness = 0;
for (Object obj : amountarray) {
float val = (Float)obj;
completeness += (1.0 - (double)val) / (double)amountarray.length;
}
return (float)completeness;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return 0.0f;
}
private GLSurfaceView getSurfaceView() {
for (View v : mSolo.getCurrentViews()) {
if (v instanceof GLSurfaceView) {
return (GLSurfaceView)v;
}
}
return null;
}
public int[][] getPaintedSurface() {
GLSurfaceView view = getSurfaceView();
if (view == null) {
return null;
}
IntBuffer pixelBuffer;
try {
pixelBuffer = (IntBuffer)_getPixels.invoke(view);
} catch (Exception e) {
e.printStackTrace();
return null;
}
// now we need to (1) flip the image, because GL likes to do things up-side-down,
// and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
int w = view.getWidth();
int h = view.getHeight();
pixelBuffer.position(0);
int[][] pixels = new int[h][w];
for (int y = h - 1; y >= 0; y--) {
for (int x = 0; x < w; x++) {
int agbr = pixelBuffer.get();
pixels[y][x] = (agbr & 0xFF00FF00) | ((agbr >> 16) & 0x000000FF) | ((agbr << 16) & 0x00FF0000);
}
}
return pixels;
}
public int mHeight=0;
public int mScrollHeight=0;
public int mPageHeight=10;
class scrollHandler implements InvocationHandler {
public scrollHandler(){};
public Object invoke(Object proxy, Method method, Object[] args) {
try {
// Disect the JSON object into the appropriate variables
JSONObject jo = ((JSONObject)args[1]);
mScrollHeight = jo.getInt("y");
mHeight = jo.getInt("cheight");
// We don't want a height of 0. That means it's a bad response.
if (mHeight > 0) {
mPageHeight = jo.getInt("height");
}
} catch( Throwable e) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_WARN,
"WARNING: ScrollReceived, but read wrong!");
}
return null;
}
}
public int getScrollHeight() {
return mScrollHeight;
}
public int getPageHeight() {
return mPageHeight;
}
public int getHeight() {
return mHeight;
}
public void setupScrollHandling() {
//Setup scrollHandler to catch "robocop:scroll" events.
try {
Class [] interfaces = new Class[1];
interfaces[0] = mGel;
Object[] finalParams = new Object[2];
finalParams[0] = "robocop:scroll";
finalParams[1] = Proxy.newProxyInstance(mClassLoader, interfaces, new scrollHandler());
mRegisterGEL.invoke(null, finalParams);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* Takes a filename, loads the file, and returns a string version of the entire file.
*/
public static String getFile(String filename)
{
StringBuilder text = new StringBuilder();
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(filename));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
}
}
return text.toString();
}
/**
* Takes a string of "key=value" pairs split by \n and creates a hash table.
*/
public static HashMap convertTextToTable(String data)
{
HashMap retVal = new HashMap();
String[] lines = data.split("\n");
for (int i = 0; i < lines.length; i++) {
String[] parts = lines[i].split("=");
retVal.put(parts[0].trim(), parts[1].trim());
}
return retVal;
}
/**
* Set the filename used for logging. If the file already exists, delete it
* as a safe-guard against accidentally appending to an old log file.
*/
public static void setLogFile(String filename) {
mLogFile = filename;
File file = new File(mLogFile);
if (file.exists()) {
file.delete();
}
}
public static void setLogLevel(LogLevel level) {
mLogLevel = level;
}
public static void log(LogLevel level, String message) {
if (mLogFile == null) {
assert(false);
}
if (level.isEnabled(mLogLevel)) {
File file = new File(mLogFile);
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(mLogFile, true));
bw.write(message);
bw.newLine();
} catch(IOException e) {
Log.e("Robocop", "exception with file writer on: " + mLogFile);
} finally {
try {
if (bw != null) {
bw.flush();
bw.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
if (level == LogLevel.LOG_LEVEL_INFO) {
Log.i("Robocop", message);
} else if (level == LogLevel.LOG_LEVEL_DEBUG) {
Log.d("Robocop", message);
} else if (level == LogLevel.LOG_LEVEL_WARN) {
Log.w("Robocop", message);
} else if (level == LogLevel.LOG_LEVEL_ERROR) {
Log.e("Robocop", message);
}
} }
}
} }

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

@ -42,7 +42,6 @@ package @ANDROID_PACKAGE_NAME@;
import java.util.List; import java.util.List;
import android.app.Activity; import android.app.Activity;
import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
@ -55,110 +54,110 @@ import com.jayway.android.robotium.solo.Solo;
import java.util.concurrent.SynchronousQueue; import java.util.concurrent.SynchronousQueue;
public class FennecNativeElement implements Element { public class FennecNativeElement implements Element {
private final Activity mActivity; private final Activity mActivity;
private Integer id; private Integer mId;
private Solo robocop; private Solo mSolo;
public FennecNativeElement(Integer id, Activity activity, Solo solo){ public FennecNativeElement(Integer id, Activity activity, Solo solo) {
this.id = id; mId = id;
mActivity = activity; mActivity = activity;
robocop = solo; mSolo = solo;
}
public Integer getId() {
return id;
}
public void click() {
final SynchronousQueue syncQueue = new SynchronousQueue();
mActivity.runOnUiThread(
new Runnable() {
public void run() {
View view = (View)mActivity.findViewById(id);
if(view != null) {
if (!view.performClick()) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_WARN,
"Robocop called click on an element with no listener");
}
} else {
throw new RoboCopException("click: unable to find view "+id);
}
syncQueue.offer(new Object());
}
});
try {
syncQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
} }
}
private Object text; public Integer getId() {
return mId;
}
public String getText() { public void click() {
final SynchronousQueue syncQueue = new SynchronousQueue(); final SynchronousQueue syncQueue = new SynchronousQueue();
mActivity.runOnUiThread( mActivity.runOnUiThread(
new Runnable() { new Runnable() {
public void run() { public void run() {
View v = mActivity.findViewById(id); View view = (View)mActivity.findViewById(mId);
if(v instanceof EditText) { if(view != null) {
EditText et = (EditText)v; if (!view.performClick()) {
text = et.getEditableText(); FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_WARN,
}else if(v instanceof TextSwitcher) { "Robocop called click on an element with no listener");
TextSwitcher ts = (TextSwitcher)v; }
ts.getNextView(); } else {
text = ((TextView)ts.getCurrentView()).getText(); throw new RoboCopException("click: unable to find view "+mId);
}else if(v instanceof ViewGroup) { }
ViewGroup vg = (ViewGroup)v; syncQueue.offer(new Object());
for(int i = 0; i < vg.getChildCount(); i++) {
if(vg.getChildAt(i) instanceof TextView) {
text = ((TextView)vg.getChildAt(i)).getText();
} }
} //end of for });
} else if(v instanceof TextView) { try {
text = ((TextView)v).getText(); syncQueue.take();
} else if(v == null) { } catch (InterruptedException e) {
throw new RoboCopException("getText: unable to find view "+id); e.printStackTrace();
} else { }
throw new RoboCopException("getText: unhandled type for view "+id);
}
syncQueue.offer(new Object());
} // end of run() method definition
} // end of anonymous Runnable object instantiation
);
try {
//Wait for the UiThread code to finish running
syncQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
} }
if(text == null) {
throw new RoboCopException("getText: Text is null for view "+id);
}
return text.toString();
}
private boolean displayed; private Object mText;
public boolean isDisplayed() { public String getText() {
final SynchronousQueue syncQueue = new SynchronousQueue(); final SynchronousQueue syncQueue = new SynchronousQueue();
displayed = false; mActivity.runOnUiThread(
mActivity.runOnUiThread( new Runnable() {
new Runnable() { public void run() {
public void run() { View v = mActivity.findViewById(mId);
View view = (View)mActivity.findViewById(id); if (v instanceof EditText) {
if(view != null) { EditText et = (EditText)v;
displayed = true; mText = et.getEditableText();
} } else if (v instanceof TextSwitcher) {
syncQueue.offer(new Object()); TextSwitcher ts = (TextSwitcher)v;
} ts.getNextView();
}); mText = ((TextView)ts.getCurrentView()).getText();
try { } else if (v instanceof ViewGroup) {
syncQueue.take(); ViewGroup vg = (ViewGroup)v;
} catch (InterruptedException e) { for (int i = 0; i < vg.getChildCount(); i++) {
e.printStackTrace(); if (vg.getChildAt(i) instanceof TextView) {
mText = ((TextView)vg.getChildAt(i)).getText();
}
}
} else if (v instanceof TextView) {
mText = ((TextView)v).getText();
} else if (v == null) {
throw new RoboCopException("getText: unable to find view "+mId);
} else {
throw new RoboCopException("getText: unhandled type for view "+mId);
}
syncQueue.offer(new Object());
} // end of run() method definition
} // end of anonymous Runnable object instantiation
);
try {
// Wait for the UiThread code to finish running
syncQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (mText == null) {
throw new RoboCopException("getText: Text is null for view "+mId);
}
return mText.toString();
}
private boolean mDisplayed;
public boolean isDisplayed() {
final SynchronousQueue syncQueue = new SynchronousQueue();
mDisplayed = false;
mActivity.runOnUiThread(
new Runnable() {
public void run() {
View view = (View)mActivity.findViewById(mId);
if (view != null) {
mDisplayed = true;
}
syncQueue.offer(new Object());
}
});
try {
syncQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return mDisplayed;
} }
return displayed;
}
} }

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

@ -39,52 +39,40 @@ package @ANDROID_PACKAGE_NAME@;
public class FennecTalosAssert implements Assert { public class FennecTalosAssert implements Assert {
public FennecTalosAssert() { public FennecTalosAssert() { }
}
// Write information to a logfile and logcat /**
public void dumpLog(String message) * Write information to a logfile and logcat
{ */
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message); public void dumpLog(String message) {
} FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
}
// Set the filename used for dumpLog. /**
public void setLogFile(String filename) * Set the filename used for dumpLog.
{ */
FennecNativeDriver.setLogFile(filename); public void setLogFile(String filename) {
} FennecNativeDriver.setLogFile(filename);
}
public void setTestName(String testName) public void setTestName(String testName) { }
{
}
public void finalize() { }
public void finalize() public void ok(boolean condition, String name, String diag) { }
{
}
public void ok(boolean condition, String name, String diag) { public void is(Object a, Object b, String name) { }
}
public void isnot(Object a, Object b, String name) { }
public void is(Object a, Object b, String name) { public void ispixel(int actual, int r, int g, int b, String name) { }
}
public void isnot(Object a, Object b, String name) {
}
public void ispixel(int actual, int r, int g, int b, String name) { public void todo(boolean condition, String name, String diag) { }
}
public void todo(boolean condition, String name, String diag) { public void todo_is(Object a, Object b, String name) { }
}
public void todo_isnot(Object a, Object b, String name) { }
public void todo_is(Object a, Object b, String name) { public void info(String name, String message) { }
}
public void todo_isnot(Object a, Object b, String name) {
}
public void info(String name, String message) {
}
} }

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

@ -40,20 +40,20 @@
package @ANDROID_PACKAGE_NAME@; package @ANDROID_PACKAGE_NAME@;
public class RoboCopException extends RuntimeException { public class RoboCopException extends RuntimeException {
public RoboCopException(){ public RoboCopException() {
super(); super();
} }
public RoboCopException(String message){ public RoboCopException(String message) {
super(message); super(message);
} }
public RoboCopException(Throwable cause){ public RoboCopException(Throwable cause) {
super(cause); super(cause);
} }
public RoboCopException(String message, Throwable cause){ public RoboCopException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
} }

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

@ -1,5 +1,18 @@
#!/usr/bin/python #!/usr/bin/python
# The directories end up in the debug info, so the easy way of getting
# a reproducible build is to run it in a know absolute directory.
# We use a directory in /builds/slave because the mozilla infrastructure
# cleans it up automatically.
base_dir = "/builds/slave/moz-toolschain"
source_dir = base_dir + "/src"
build_dir = base_dir + "/build"
aux_inst_dir = build_dir + '/aux_inst'
old_make = aux_inst_dir + '/bin/make'
##############################################
import urllib import urllib
import os import os
import os.path import os.path
@ -33,17 +46,21 @@ def patch(patch, plevel, srcdir):
check_run(['patch', '-d', srcdir, '-p%s' % plevel, '-i', patch, '--fuzz=0', check_run(['patch', '-d', srcdir, '-p%s' % plevel, '-i', patch, '--fuzz=0',
'-s']) '-s'])
def build_package(package_source_dir, package_build_dir, configure_args): def build_package(package_source_dir, package_build_dir, configure_args,
make = old_make):
os.mkdir(package_build_dir) os.mkdir(package_build_dir)
run_in(package_build_dir, run_in(package_build_dir,
["%s/configure" % package_source_dir] + configure_args) ["%s/configure" % package_source_dir] + configure_args)
run_in(package_build_dir, ["make", "-j8"]) run_in(package_build_dir, [make, "-j8"])
run_in(package_build_dir, ["make", "install"]) run_in(package_build_dir, [make, "install"])
def build_tar(base_dir, tar_inst_dir): def build_aux_tools(base_dir):
make_build_dir = base_dir + '/make_build'
build_package(make_source_dir, make_build_dir,
["--prefix=%s" % aux_inst_dir], "make")
tar_build_dir = base_dir + '/tar_build' tar_build_dir = base_dir + '/tar_build'
build_package(tar_source_dir, tar_build_dir, build_package(tar_source_dir, tar_build_dir,
["--prefix=%s" % tar_inst_dir]) ["--prefix=%s" % aux_inst_dir])
def with_env(env, f): def with_env(env, f):
old_env = os.environ.copy() old_env = os.environ.copy()
@ -133,21 +150,13 @@ def build_tar_package(tar, name, base, directory):
############################################## ##############################################
# The directories end up in the debug info, so the easy way of getting
# a reproducible build is to run it in a know absolute directory.
# We use a directory in /builds/slave because the mozilla infrastructure
# cleans it up automatically.
base_dir = "/builds/slave/moz-toolschain"
source_dir = base_dir + "/src"
build_dir = base_dir + "/build"
def build_source_dir(prefix, version): def build_source_dir(prefix, version):
return source_dir + '/' + prefix + version return source_dir + '/' + prefix + version
binutils_version = "2.21.1" binutils_version = "2.21.1"
glibc_version = "2.12.2" #FIXME: should probably use 2.5.1 glibc_version = "2.5.1"
tar_version = "1.26" tar_version = "1.26"
make_version = "3.81"
gcc_version = "4.5.2" gcc_version = "4.5.2"
mpfr_version = "2.4.2" mpfr_version = "2.4.2"
gmp_version = "5.0.1" gmp_version = "5.0.1"
@ -159,6 +168,8 @@ glibc_source_uri = "http://ftp.gnu.org/gnu/glibc/glibc-%s.tar.bz2" % \
glibc_version glibc_version
tar_source_uri = "http://ftp.gnu.org/gnu/tar/tar-%s.tar.bz2" % \ tar_source_uri = "http://ftp.gnu.org/gnu/tar/tar-%s.tar.bz2" % \
tar_version tar_version
make_source_uri = "http://ftp.gnu.org/gnu/make/make-%s.tar.bz2" % \
make_version
gcc_source_uri = "http://ftp.gnu.org/gnu/gcc/gcc-%s/gcc-%s.tar.bz2" % \ gcc_source_uri = "http://ftp.gnu.org/gnu/gcc/gcc-%s/gcc-%s.tar.bz2" % \
(gcc_version, gcc_version) (gcc_version, gcc_version)
mpfr_source_uri = "http://www.mpfr.org/mpfr-%s/mpfr-%s.tar.bz2" % \ mpfr_source_uri = "http://www.mpfr.org/mpfr-%s/mpfr-%s.tar.bz2" % \
@ -170,6 +181,7 @@ mpc_source_uri = "http://www.multiprecision.org/mpc/download/mpc-%s.tar.gz" % \
binutils_source_tar = download_uri(binutils_source_uri) binutils_source_tar = download_uri(binutils_source_uri)
glibc_source_tar = download_uri(glibc_source_uri) glibc_source_tar = download_uri(glibc_source_uri)
tar_source_tar = download_uri(tar_source_uri) tar_source_tar = download_uri(tar_source_uri)
make_source_tar = download_uri(make_source_uri)
mpc_source_tar = download_uri(mpc_source_uri) mpc_source_tar = download_uri(mpc_source_uri)
mpfr_source_tar = download_uri(mpfr_source_uri) mpfr_source_tar = download_uri(mpfr_source_uri)
gmp_source_tar = download_uri(gmp_source_uri) gmp_source_tar = download_uri(gmp_source_uri)
@ -178,6 +190,7 @@ gcc_source_tar = download_uri(gcc_source_uri)
binutils_source_dir = build_source_dir('binutils-', binutils_version) binutils_source_dir = build_source_dir('binutils-', binutils_version)
glibc_source_dir = build_source_dir('glibc-', glibc_version) glibc_source_dir = build_source_dir('glibc-', glibc_version)
tar_source_dir = build_source_dir('tar-', tar_version) tar_source_dir = build_source_dir('tar-', tar_version)
make_source_dir = build_source_dir('make-', make_version)
mpc_source_dir = build_source_dir('mpc-', mpc_version) mpc_source_dir = build_source_dir('mpc-', mpc_version)
mpfr_source_dir = build_source_dir('mpfr-', mpfr_version) mpfr_source_dir = build_source_dir('mpfr-', mpfr_version)
gmp_source_dir = build_source_dir('gmp-', gmp_version) gmp_source_dir = build_source_dir('gmp-', gmp_version)
@ -191,6 +204,7 @@ if not os.path.exists(source_dir):
patch('glibc-deterministic.patch', 1, glibc_source_dir) patch('glibc-deterministic.patch', 1, glibc_source_dir)
run_in(glibc_source_dir, ["autoconf"]) run_in(glibc_source_dir, ["autoconf"])
extract(tar_source_tar, source_dir) extract(tar_source_tar, source_dir)
extract(make_source_tar, source_dir)
extract(mpc_source_tar, source_dir) extract(mpc_source_tar, source_dir)
extract(mpfr_source_tar, source_dir) extract(mpfr_source_tar, source_dir)
extract(gmp_source_tar, source_dir) extract(gmp_source_tar, source_dir)
@ -203,19 +217,18 @@ if os.path.exists(build_dir):
shutil.rmtree(build_dir) shutil.rmtree(build_dir)
os.makedirs(build_dir) os.makedirs(build_dir)
tar_inst_dir = build_dir + '/tar_inst' build_aux_tools(build_dir)
build_tar(build_dir, tar_inst_dir)
stage1_dir = build_dir + '/stage1' stage1_dir = build_dir + '/stage1'
build_one_stage({"CC": "gcc", "CXX" : "g++"}, stage1_dir, True) build_one_stage({"CC": "gcc", "CXX" : "g++"}, stage1_dir, True)
stage1_tool_inst_dir = stage1_dir + '/inst' stage1_tool_inst_dir = stage1_dir + '/inst'
stage2_dir = build_dir + '/stage2' stage2_dir = build_dir + '/stage2'
build_one_stage({"CC" : stage1_tool_inst_dir + "/bin/gcc", build_one_stage({"CC" : stage1_tool_inst_dir + "/bin/gcc -fgnu89-inline",
"CXX" : stage1_tool_inst_dir + "/bin/g++", "CXX" : stage1_tool_inst_dir + "/bin/g++",
"AR" : stage1_tool_inst_dir + "/bin/ar", "AR" : stage1_tool_inst_dir + "/bin/ar",
"RANLIB" : "true" }, "RANLIB" : "true" },
stage2_dir, False) stage2_dir, False)
build_tar_package(tar_inst_dir + "/bin/tar", build_tar_package(aux_inst_dir + "/bin/tar",
"toolchain.tar", stage2_dir, "inst") "toolchain.tar", stage2_dir, "inst")

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

@ -1,7 +1,22 @@
diff -ru a/configure.in b/configure.in diff -ru a/configure.in b/configure.in
--- a/configure.in 2011-01-17 23:34:07.000000000 -0500 --- a/configure.in 2011-01-17 23:34:07.000000000 -0500
+++ b/configure.in 2012-01-25 20:40:27.919485606 -0500 +++ b/configure.in 2012-01-25 20:40:27.919485606 -0500
@@ -2230,6 +2230,7 @@ @@ -841,14 +841,6 @@
LIBC_PROG_BINUTILS
AC_SUBST(MIG)dnl Needed by sysdeps/mach/configure.in
-# Accept binutils 2.13 or newer.
-AC_CHECK_PROG_VER(AS, $AS, --version,
- [GNU assembler.* \([0-9]*\.[0-9.]*\)],
- [2.1[3-9]*], AS=: critic_missing="$critic_missing as")
-AC_CHECK_PROG_VER(LD, $LD, --version,
- [GNU ld.* \([0-9][0-9]*\.[0-9.]*\)],
- [2.1[3-9]*], LD=: critic_missing="$critic_missing ld")
-
# We need the physical current working directory. We cannot use the
# "pwd -P" shell builtin since that's not portable. Instead we try to
# find a pwd binary. Note that assigning to the PWD environment
@@ -2175,6 +2167,7 @@
fi fi
AC_SUBST(old_glibc_headers) AC_SUBST(old_glibc_headers)
@ -12,7 +27,7 @@ diff -ru a/configure.in b/configure.in
diff -ru a/csu/Makefile b/csu/Makefile diff -ru a/csu/Makefile b/csu/Makefile
--- a/csu/Makefile 2011-01-17 23:34:07.000000000 -0500 --- a/csu/Makefile 2011-01-17 23:34:07.000000000 -0500
+++ b/csu/Makefile 2012-01-23 13:58:28.957792633 -0500 +++ b/csu/Makefile 2012-01-23 13:58:28.957792633 -0500
@@ -234,8 +234,7 @@ @@ -223,8 +223,7 @@
if [ -z "$$os" ]; then \ if [ -z "$$os" ]; then \
os=Linux; \ os=Linux; \
fi; \ fi; \
@ -22,10 +37,58 @@ diff -ru a/csu/Makefile b/csu/Makefile
*) ;; \ *) ;; \
esac; \ esac; \
files="$(all-Banner-files)"; \ files="$(all-Banner-files)"; \
diff -ru a/elf/Makefile b/elf/Makefile
--- a/elf/Makefile 2008-10-31 16:35:11.000000000 -0400
+++ b/elf/Makefile 2012-02-16 12:20:00.038593752 -0500
@@ -295,18 +295,11 @@
z-now-yes = -Wl,-z,now
$(objpfx)ld.so: $(objpfx)librtld.os $(ld-map)
- @rm -f $@.lds
- $(LINK.o) -nostdlib -nostartfiles -shared $(z-now-$(bind-now)) \
- $(LDFLAGS-rtld) -Wl,-z,defs -Wl,--verbose 2>&1 | \
- LC_ALL=C \
- sed -e '/^=========/,/^=========/!d;/^=========/d' \
- -e 's/\. = 0 + SIZEOF_HEADERS;/& _begin = . - SIZEOF_HEADERS;/' \
- > $@.lds
$(LINK.o) -nostdlib -nostartfiles -shared -o $@ \
$(LDFLAGS-rtld) -Wl,-z,defs $(z-now-$(bind-now)) \
$(filter-out $(map-file),$^) $(load-map-file) \
- -Wl,-soname=$(rtld-installed-name) -T $@.lds
- rm -f $@.lds
+ -Wl,-soname=$(rtld-installed-name) \
+ -Wl,-defsym=_begin=0
# interp.c exists just to get this string into the libraries.
CFLAGS-interp.c = -D'RUNTIME_LINKER="$(slibdir)/$(rtld-installed-name)"' \
diff -ru a/localedata/Makefile b/localedata/Makefile
--- a/localedata/Makefile 2006-04-26 01:14:03.000000000 -0400
+++ b/localedata/Makefile 2012-02-17 10:31:24.592345047 -0500
@@ -113,7 +113,7 @@
$(make-target-directory)
rm -f $(@:.gz=) $@
$(INSTALL_DATA) $< $(@:.gz=)
- gzip -9 $(@:.gz=)
+ gzip -9n $(@:.gz=)
# Install the locale source files in the appropriate directory.
$(inst_i18ndir)/locales/%: locales/% $(+force); $(do-install)
diff -ru a/Makeconfig b/Makeconfig
--- a/Makeconfig 2006-07-10 17:42:27.000000000 -0400
+++ b/Makeconfig 2012-02-17 08:28:31.859584817 -0500
@@ -674,7 +674,7 @@
$(foreach lib,$(libof-$(basename $(@F))) \
$(libof-$(<F)) $(libof-$(@F)),$(CPPFLAGS-$(lib))) \
$(CPPFLAGS-$(<F)) $(CPPFLAGS-$(@F)) $(CPPFLAGS-$(basename $(@F)))
-override CFLAGS = -std=gnu99 \
+override CFLAGS = -std=gnu99 -fgnu89-inline \
$(filter-out %frame-pointer,$(+cflags)) $(+gccwarn-c) \
$(sysdep-CFLAGS) $(CFLAGS-$(suffix $@)) $(CFLAGS-$(<F)) \
$(CFLAGS-$(@F))
diff -ru a/Makerules b/Makerules diff -ru a/Makerules b/Makerules
--- a/Makerules 2011-01-17 23:34:07.000000000 -0500 --- a/Makerules 2011-01-17 23:34:07.000000000 -0500
+++ b/Makerules 2012-01-30 08:47:56.565068903 -0500 +++ b/Makerules 2012-01-30 08:47:56.565068903 -0500
@@ -992,9 +992,9 @@ @@ -977,9 +977,9 @@
echo ' Use the shared library, but some functions are only in';\ echo ' Use the shared library, but some functions are only in';\
echo ' the static library, so try that secondarily. */';\ echo ' the static library, so try that secondarily. */';\
cat $<; \ cat $<; \

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

@ -57,7 +57,6 @@ MOZ_PROFILE_MIGRATOR = @MOZ_PROFILE_MIGRATOR@
MOZ_EXTENSION_MANAGER = @MOZ_EXTENSION_MANAGER@ MOZ_EXTENSION_MANAGER = @MOZ_EXTENSION_MANAGER@
MOZ_APP_UA_NAME = @MOZ_APP_UA_NAME@ MOZ_APP_UA_NAME = @MOZ_APP_UA_NAME@
MOZ_APP_VERSION = @MOZ_APP_VERSION@ MOZ_APP_VERSION = @MOZ_APP_VERSION@
MOZ_UA_BUILDID = @MOZ_UA_BUILDID@
MOZ_MACBUNDLE_NAME = @MOZ_MACBUNDLE_NAME@ MOZ_MACBUNDLE_NAME = @MOZ_MACBUNDLE_NAME@
MOZ_APP_STATIC_INI = @MOZ_APP_STATIC_INI@ MOZ_APP_STATIC_INI = @MOZ_APP_STATIC_INI@
@ -181,6 +180,7 @@ LIBJPEG_TURBO_AS = @LIBJPEG_TURBO_AS@
LIBJPEG_TURBO_ASFLAGS = @LIBJPEG_TURBO_ASFLAGS@ LIBJPEG_TURBO_ASFLAGS = @LIBJPEG_TURBO_ASFLAGS@
LIBJPEG_TURBO_X86_ASM = @LIBJPEG_TURBO_X86_ASM@ LIBJPEG_TURBO_X86_ASM = @LIBJPEG_TURBO_X86_ASM@
LIBJPEG_TURBO_X64_ASM = @LIBJPEG_TURBO_X64_ASM@ LIBJPEG_TURBO_X64_ASM = @LIBJPEG_TURBO_X64_ASM@
LIBJPEG_TURBO_ARM_ASM = @LIBJPEG_TURBO_ARM_ASM@
NS_PRINTING = @NS_PRINTING@ NS_PRINTING = @NS_PRINTING@
MOZ_PDF_PRINTING = @MOZ_PDF_PRINTING@ MOZ_PDF_PRINTING = @MOZ_PDF_PRINTING@
MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@ MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@

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

@ -35,7 +35,7 @@
# #
# ***** END LICENSE BLOCK ***** # ***** END LICENSE BLOCK *****
import sys, os, subprocess, struct import sys, os, subprocess, struct, re
local_file_header = [ local_file_header = [
("signature", "uint32"), ("signature", "uint32"),
@ -329,10 +329,12 @@ if len(sys.argv) != 5:
print "Usage: --optimize|--deoptimize %s JAR_LOG_DIR IN_JAR_DIR OUT_JAR_DIR" % sys.argv[0] print "Usage: --optimize|--deoptimize %s JAR_LOG_DIR IN_JAR_DIR OUT_JAR_DIR" % sys.argv[0]
exit(1) exit(1)
jar_regex = re.compile("\\.jar?$")
def optimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR): def optimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR):
ls = os.listdir(IN_JAR_DIR) ls = os.listdir(IN_JAR_DIR)
for jarfile in ls: for jarfile in ls:
if not jarfile.endswith(".jar"): if not re.search(jar_regex, jarfile):
continue continue
injarfile = os.path.join(IN_JAR_DIR, jarfile) injarfile = os.path.join(IN_JAR_DIR, jarfile)
outjarfile = os.path.join(OUT_JAR_DIR, jarfile) outjarfile = os.path.join(OUT_JAR_DIR, jarfile)
@ -347,7 +349,7 @@ def deoptimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR):
ls = os.listdir(IN_JAR_DIR) ls = os.listdir(IN_JAR_DIR)
for jarfile in ls: for jarfile in ls:
if not jarfile.endswith(".jar"): if not re.search(jar_regex, jarfile):
continue continue
injarfile = os.path.join(IN_JAR_DIR, jarfile) injarfile = os.path.join(IN_JAR_DIR, jarfile)
outjarfile = os.path.join(OUT_JAR_DIR, jarfile) outjarfile = os.path.join(OUT_JAR_DIR, jarfile)

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

@ -225,7 +225,14 @@ if test -n "$L10NBASEDIR"; then
if test "$L10NBASEDIR" = "yes" -o "$L10NBASEDIR" = "no"; then if test "$L10NBASEDIR" = "yes" -o "$L10NBASEDIR" = "no"; then
AC_MSG_ERROR([--with-l10n-base must specify a path]) AC_MSG_ERROR([--with-l10n-base must specify a path])
elif test -d "$L10NBASEDIR"; then elif test -d "$L10NBASEDIR"; then
L10NBASEDIR=`cd "$L10NBASEDIR" && pwd` case "$host_os" in
mingw*)
L10NBASEDIR=`cd "$L10NBASEDIR" && pwd -W`
;;
*)
L10NBASEDIR=`cd "$L10NBASEDIR" && pwd`
;;
esac
else else
AC_MSG_ERROR([Invalid value --with-l10n-base, $L10NBASEDIR doesn't exist]) AC_MSG_ERROR([Invalid value --with-l10n-base, $L10NBASEDIR doesn't exist])
fi fi
@ -3336,6 +3343,7 @@ AC_SUBST(WRAP_SYSTEM_INCLUDES)
AC_SUBST(VISIBILITY_FLAGS) AC_SUBST(VISIBILITY_FLAGS)
MOZ_GCC_PR49911 MOZ_GCC_PR49911
MOZ_COMPILER_OPTS
dnl Check for __force_align_arg_pointer__ for SSE2 on gcc dnl Check for __force_align_arg_pointer__ for SSE2 on gcc
dnl ======================================================== dnl ========================================================
@ -4084,6 +4092,56 @@ if test "$ac_cv_thread_keyword" = yes -a "$MOZ_LINKER" != 1; then
esac esac
fi fi
dnl Using the custom linker on ARMv6 requires 16k alignment of ELF segments.
if test -n "$MOZ_LINKER"; then
if test "$CPU_ARCH" = arm; then
dnl Determine the target ARM architecture (5 for ARMv5, v5T, v5E, etc.; 6 for ARMv6, v6K, etc.)
ARM_ARCH=`${CC-cc} ${CFLAGS} -dM -E - < /dev/null | sed -n 's/.*__ARM_ARCH_\([[0-9]]*\).*/\1/p'`
dnl When building for < ARMv7, we need to ensure 16k alignment of ELF segments
if test -n "$ARM_ARCH" && test "$ARM_ARCH" -lt 7; then
LDFLAGS="$LDFLAGS -Wl,-z,max-page-size=0x4000"
_SUBDIR_LDFLAGS="$_SUBDIR_LDFLAGS -Wl,-z,max-page-size=0x4000"
fi
fi
fi
dnl The custom linker doesn't support text relocations, but NDK >= r6b
dnl creates some (http://code.google.com/p/android/issues/detail?id=23203)
dnl We however want to avoid these text relocations, and this can be done
dnl by making gcc not link crtbegin and crtend. In the broken NDKs, crtend
dnl doesn't contain anything at all, beside placeholders for some sections,
dnl and crtbegin only contains a finalizer function that calls
dnl __cxa_finalize. The custom linker actually takes care of calling
dnl __cxa_finalize when the library doesn't call it itself, which makes it
dnl safe not to link crtbegin. Besides, previous versions of the NDK didn't
dnl link crtbegin and crtend at all.
if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a "$OS_TARGET" = "Android"; then
AC_CACHE_CHECK([whether the CRT objects have text relocations],
ac_cv_crt_has_text_relocations,
[echo 'int foo() { return 0; }' > conftest.cpp
if AC_TRY_COMMAND(${CXX-g++} -o conftest${DLL_SUFFIX} $CXXFLAGS $DSO_LDOPTS $LDFLAGS conftest.cpp $LIBS 1>&5) &&
test -s conftest${DLL_SUFFIX}; then
if readelf -d conftest${DLL_SUFFIX} | grep TEXTREL > /dev/null; then
ac_cv_crt_has_text_relocations=yes
else
ac_cv_crt_has_text_relocations=no
fi
else
AC_ERROR([couldn't compile a simple C file])
fi
rm -rf conftest*])
if test "$ac_cv_crt_has_text_relocations" = yes; then
dnl While we want libraries to skip the CRT files, we don't want
dnl executables to be treated the same way. We thus set the flag
dnl in DSO_LDOPTS and not LDFLAGS. However, to pass it to nspr,
dnl we need to use LDFLAGS because nspr doesn't inherit DSO_LDOPTS.
dnl Using LDFLAGS in nspr is safe, since we only really build
dnl libraries there.
DSO_LDOPTS="$DSO_LDOPTS -nostartfiles"
NSPR_LDFLAGS=-nostartfiles
fi
fi
dnl Check for the existence of various allocation headers/functions dnl Check for the existence of various allocation headers/functions
MALLOC_H= MALLOC_H=
@ -4605,6 +4663,7 @@ LIBJPEG_TURBO_AS=
LIBJPEG_TURBO_ASFLAGS= LIBJPEG_TURBO_ASFLAGS=
LIBJPEG_TURBO_X86_ASM= LIBJPEG_TURBO_X86_ASM=
LIBJPEG_TURBO_X64_ASM= LIBJPEG_TURBO_X64_ASM=
LIBJPEG_TURBO_ARM_ASM=
MOZ_PANGO=1 MOZ_PANGO=1
MOZ_PERMISSIONS=1 MOZ_PERMISSIONS=1
MOZ_PLACES=1 MOZ_PLACES=1
@ -6163,38 +6222,51 @@ if test -n "$MOZ_LIBJPEG_TURBO"; then
LIBJPEG_TURBO_ASFLAGS="-f win64 -rnasm -pnasm -D__x86_64__ -DPIC -DWIN64 -DMSVC" LIBJPEG_TURBO_ASFLAGS="-f win64 -rnasm -pnasm -D__x86_64__ -DPIC -DWIN64 -DMSVC"
LIBJPEG_TURBO_X64_ASM=1 LIBJPEG_TURBO_X64_ASM=1
;; ;;
*:arm*)
LIBJPEG_TURBO_ASFLAGS="-march=armv7-a -mfpu=neon"
LIBJPEG_TURBO_ARM_ASM=1
;;
esac esac
fi fi
dnl If we're on a system which supports libjpeg-turbo's asm routines and dnl If we're on an x86 or x64 system which supports libjpeg-turbo's asm routines
dnl --disable-libjpeg-turbo wasn't passed, check for yasm, and error out if it dnl and --disable-libjpeg-turbo wasn't passed, check for Yasm, and error out if
dnl doesn't exist or we have too old of a version. dnl it doesn't exist or we have too old of a version.
if test -n "$LIBJPEG_TURBO_X86_ASM" -o -n "$LIBJPEG_TURBO_X64_ASM" ; then if test -n "$LIBJPEG_TURBO_X86_ASM" -o -n "$LIBJPEG_TURBO_X64_ASM" ; then
AC_MSG_CHECKING([for YASM assembler]) AC_MSG_CHECKING([for Yasm assembler])
AC_CHECK_PROGS(LIBJPEG_TURBO_AS, yasm, "") AC_CHECK_PROGS(LIBJPEG_TURBO_AS, yasm, "")
if test -z "$LIBJPEG_TURBO_AS" ; then if test -z "$LIBJPEG_TURBO_AS" ; then
AC_MSG_ERROR([yasm is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you do not appear to have yasm installed. Either install it or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder. See https://developer.mozilla.org/en/YASM for more details.]) AC_MSG_ERROR([Yasm is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you do not appear to have Yasm installed. Either install it or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder. See https://developer.mozilla.org/en/YASM for more details.])
fi fi
dnl Check that we have the right yasm version. We require 1.0.1 or newer dnl Check that we have the right yasm version. We require 1.0.1 or newer
dnl on Linux and 1.1 or newer everywhere else. dnl on Linux and 1.1 or newer everywhere else.
if test "$OS_ARCH" = "Linux" ; then if test "$OS_ARCH" = "Linux" ; then
if test "$_YASM_MAJOR_VERSION" -lt "1" -o \( "$_YASM_MAJOR_VERSION" -eq "1" -a "$_YASM_MINOR_VERSION" -eq "0" -a "$_YASM_RELEASE" -lt "1" \) ; then if test "$_YASM_MAJOR_VERSION" -lt "1" -o \( "$_YASM_MAJOR_VERSION" -eq "1" -a "$_YASM_MINOR_VERSION" -eq "0" -a "$_YASM_RELEASE" -lt "1" \) ; then
AC_MSG_ERROR([yasm 1.0.1 or greater is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION.$_YASM_RELEASE. Upgrade to the newest version or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder. See https://developer.mozilla.org/en/YASM for more details.]) AC_MSG_ERROR([Yasm 1.0.1 or greater is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION.$_YASM_RELEASE. Upgrade to the newest version or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder. See https://developer.mozilla.org/en/YASM for more details.])
fi fi
else else
if test "$_YASM_MAJOR_VERSION" -lt "1" -o \( "$_YASM_MAJOR_VERSION" -eq "1" -a "$_YASM_MINOR_VERSION" -lt "1" \) ; then if test "$_YASM_MAJOR_VERSION" -lt "1" -o \( "$_YASM_MAJOR_VERSION" -eq "1" -a "$_YASM_MINOR_VERSION" -lt "1" \) ; then
AC_MSG_ERROR([yasm 1.1 or greater is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION. Upgrade to the newest version or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder. See https://developer.mozilla.org/en/YASM for more details.]) AC_MSG_ERROR([Yasm 1.1 or greater is required to build with libjpeg-turbo's optimized JPEG decoding routines, but you appear to have version $_YASM_MAJOR_VERSION.$_YASM_MINOR_VERSION. Upgrade to the newest version or configure with --disable-libjpeg-turbo to use the pure C JPEG decoder. See https://developer.mozilla.org/en/YASM for more details.])
fi fi
fi fi
fi fi
dnl If we're on an ARM system which supports libjpeg-turbo's asm routines and
dnl --disable-libjpeg-turbo wasn't passed, use the C compiler as the assembler.
if test -n "$LIBJPEG_TURBO_ARM_ASM" ; then
echo "Using $AS as the assembler for ARM code."
LIBJPEG_TURBO_AS=$AS
fi
if test -n "$LIBJPEG_TURBO_X86_ASM"; then if test -n "$LIBJPEG_TURBO_X86_ASM"; then
AC_DEFINE(LIBJPEG_TURBO_X86_ASM) AC_DEFINE(LIBJPEG_TURBO_X86_ASM)
elif test -n "$LIBJPEG_TURBO_X64_ASM"; then elif test -n "$LIBJPEG_TURBO_X64_ASM"; then
AC_DEFINE(LIBJPEG_TURBO_X64_ASM) AC_DEFINE(LIBJPEG_TURBO_X64_ASM)
elif test -n "$LIBJPEG_TURBO_ARM_ASM"; then
AC_DEFINE(LIBJPEG_TURBO_ARM_ASM)
elif test -n "$MOZ_LIBJPEG_TURBO"; then elif test -n "$MOZ_LIBJPEG_TURBO"; then
dnl Warn if we're not building the optimized routines, even though the user dnl Warn if we're not building the optimized routines, even though the user
dnl didn't specify --disable-libjpeg-turbo. dnl didn't specify --disable-libjpeg-turbo.
@ -8565,8 +8637,6 @@ AC_SUBST(MOZ_APP_VERSION)
AC_DEFINE_UNQUOTED(MOZ_UA_FIREFOX_VERSION, "$FIREFOX_VERSION") AC_DEFINE_UNQUOTED(MOZ_UA_FIREFOX_VERSION, "$FIREFOX_VERSION")
AC_DEFINE_UNQUOTED(FIREFOX_VERSION,$FIREFOX_VERSION) AC_DEFINE_UNQUOTED(FIREFOX_VERSION,$FIREFOX_VERSION)
AC_SUBST(FIREFOX_VERSION) AC_SUBST(FIREFOX_VERSION)
AC_DEFINE_UNQUOTED(MOZ_UA_BUILDID, "$MOZ_UA_BUILDID")
AC_SUBST(MOZ_UA_BUILDID)
# We can't use the static application.ini data when building against # We can't use the static application.ini data when building against
# a libxul SDK. # a libxul SDK.
@ -8736,6 +8806,7 @@ AC_SUBST(LIBJPEG_TURBO_AS)
AC_SUBST(LIBJPEG_TURBO_ASFLAGS) AC_SUBST(LIBJPEG_TURBO_ASFLAGS)
AC_SUBST(LIBJPEG_TURBO_X86_ASM) AC_SUBST(LIBJPEG_TURBO_X86_ASM)
AC_SUBST(LIBJPEG_TURBO_X64_ASM) AC_SUBST(LIBJPEG_TURBO_X64_ASM)
AC_SUBST(LIBJPEG_TURBO_ARM_ASM)
AC_MSG_CHECKING([for posix_fallocate]) AC_MSG_CHECKING([for posix_fallocate])
AC_TRY_LINK([#define _XOPEN_SOURCE 600 AC_TRY_LINK([#define _XOPEN_SOURCE 600
@ -9070,7 +9141,11 @@ if test -z "$MOZ_NATIVE_NSPR"; then
_SAVE_CPPFLAGS="$CPPFLAGS" _SAVE_CPPFLAGS="$CPPFLAGS"
export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS" export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS"
fi fi
_SAVE_LDFLAGS="$LDFLAGS"
export LDFLAGS="$LDFLAGS $NSPR_LDFLAGS"
AC_OUTPUT_SUBDIRS(nsprpub) AC_OUTPUT_SUBDIRS(nsprpub)
unset LDFLAGS
LDFLAGS="$_SAVE_LDFLAGS"
if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a "$ac_cv_func_dladdr" = no; then if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a "$ac_cv_func_dladdr" = no; then
unset CPPFLAGS unset CPPFLAGS
CPPFLAGS="$_SAVE_CFLAGS" CPPFLAGS="$_SAVE_CFLAGS"

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

@ -1,7 +1,7 @@
onmessage = function(event) { onmessage = function(event) {
var blob = event.data; var blob = event.data;
blob.mozSlice(1, 5); blob.slice(1, 5);
postMessage("done"); postMessage("done");
} }

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

@ -71,9 +71,9 @@ interface nsIDOMBlob : nsISupports
// blob: protocol handler // blob: protocol handler
[noscript] DOMString getInternalUrl(in nsIPrincipal principal); [noscript] DOMString getInternalUrl(in nsIPrincipal principal);
[optional_argc] nsIDOMBlob mozSlice([optional] in long long start, [optional_argc] nsIDOMBlob slice([optional] in long long start,
[optional] in long long end, [optional] in long long end,
[optional] in DOMString contentType); [optional] in DOMString contentType);
// Get internal id of stored file. Returns -1 if it is not a stored file. // Get internal id of stored file. Returns -1 if it is not a stored file.
// Intended only for testing. It can be called on any thread. // Intended only for testing. It can be called on any thread.

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

@ -136,6 +136,10 @@ public:
} }
PRInt64 SizeOf() const; PRInt64 SizeOf() const;
bool HasMappedAttrs() const
{
return MappedAttrCount();
}
private: private:
nsAttrAndChildArray(const nsAttrAndChildArray& aOther) MOZ_DELETE; nsAttrAndChildArray(const nsAttrAndChildArray& aOther) MOZ_DELETE;

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

@ -54,6 +54,8 @@
namespace css = mozilla::css; namespace css = mozilla::css;
using mozilla::SVGAttrValueWrapper;
#define MISC_STR_PTR(_cont) \ #define MISC_STR_PTR(_cont) \
reinterpret_cast<void*>((_cont)->mStringBits & NS_ATTRVALUE_POINTERVALUE_MASK) reinterpret_cast<void*>((_cont)->mStringBits & NS_ATTRVALUE_POINTERVALUE_MASK)
@ -76,6 +78,12 @@ nsAttrValue::nsAttrValue(const nsAString& aValue)
SetTo(aValue); SetTo(aValue);
} }
nsAttrValue::nsAttrValue(nsIAtom* aValue)
: mBits(0)
{
SetTo(aValue);
}
nsAttrValue::nsAttrValue(css::StyleRule* aValue, const nsAString* aSerialized) nsAttrValue::nsAttrValue(css::StyleRule* aValue, const nsAString* aSerialized)
: mBits(0) : mBits(0)
{ {
@ -260,7 +268,13 @@ nsAttrValue::SetTo(const nsAttrValue& aOther)
} }
default: default:
{ {
NS_NOTREACHED("unknown type stored in MiscContainer"); if (IsSVGType(otherCont->mType)) {
// All SVG types are just pointers to classes and will therefore have
// the same size so it doesn't really matter which one we assign
cont->mSVGAngle = otherCont->mSVGAngle;
} else {
NS_NOTREACHED("unknown type stored in MiscContainer");
}
break; break;
} }
} }
@ -290,6 +304,16 @@ nsAttrValue::SetTo(const nsAString& aValue)
} }
} }
void
nsAttrValue::SetTo(nsIAtom* aValue)
{
ResetIfSet();
if (aValue) {
NS_ADDREF(aValue);
SetPtrValueAndType(aValue, eAtomBase);
}
}
void void
nsAttrValue::SetTo(PRInt16 aInt) nsAttrValue::SetTo(PRInt16 aInt)
{ {
@ -297,6 +321,24 @@ nsAttrValue::SetTo(PRInt16 aInt)
SetIntValueAndType(aInt, eInteger, nsnull); SetIntValueAndType(aInt, eInteger, nsnull);
} }
void
nsAttrValue::SetTo(PRInt32 aInt, const nsAString* aSerialized)
{
ResetIfSet();
SetIntValueAndType(aInt, eInteger, aSerialized);
}
void
nsAttrValue::SetTo(double aValue, const nsAString* aSerialized)
{
if (EnsureEmptyMiscContainer()) {
MiscContainer* cont = GetMiscContainer();
cont->mDoubleValue = aValue;
cont->mType = eDoubleValue;
SetMiscAtomOrString(aSerialized);
}
}
void void
nsAttrValue::SetTo(css::StyleRule* aValue, const nsAString* aSerialized) nsAttrValue::SetTo(css::StyleRule* aValue, const nsAString* aSerialized)
{ {
@ -331,6 +373,115 @@ nsAttrValue::SetToSerialized(const nsAttrValue& aOther)
} }
} }
void
nsAttrValue::SetTo(const nsSVGAngle& aValue, const nsAString* aSerialized)
{
SetSVGType(eSVGAngle, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const nsSVGIntegerPair& aValue, const nsAString* aSerialized)
{
SetSVGType(eSVGIntegerPair, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const nsSVGLength2& aValue, const nsAString* aSerialized)
{
SetSVGType(eSVGLength, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const mozilla::SVGLengthList& aValue,
const nsAString* aSerialized)
{
// While an empty string will parse as a length list, there's no need to store
// it (and SetMiscAtomOrString will assert if we try)
if (aSerialized && aSerialized->IsEmpty()) {
aSerialized = nsnull;
}
SetSVGType(eSVGLengthList, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const mozilla::SVGNumberList& aValue,
const nsAString* aSerialized)
{
// While an empty string will parse as a number list, there's no need to store
// it (and SetMiscAtomOrString will assert if we try)
if (aSerialized && aSerialized->IsEmpty()) {
aSerialized = nsnull;
}
SetSVGType(eSVGNumberList, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const nsSVGNumberPair& aValue, const nsAString* aSerialized)
{
SetSVGType(eSVGNumberPair, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const mozilla::SVGPathData& aValue,
const nsAString* aSerialized)
{
// While an empty string will parse as path data, there's no need to store it
// (and SetMiscAtomOrString will assert if we try)
if (aSerialized && aSerialized->IsEmpty()) {
aSerialized = nsnull;
}
SetSVGType(eSVGPathData, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const mozilla::SVGPointList& aValue,
const nsAString* aSerialized)
{
// While an empty string will parse as a point list, there's no need to store
// it (and SetMiscAtomOrString will assert if we try)
if (aSerialized && aSerialized->IsEmpty()) {
aSerialized = nsnull;
}
SetSVGType(eSVGPointList, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const mozilla::SVGAnimatedPreserveAspectRatio& aValue,
const nsAString* aSerialized)
{
SetSVGType(eSVGPreserveAspectRatio, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const mozilla::SVGStringList& aValue,
const nsAString* aSerialized)
{
// While an empty string will parse as a string list, there's no need to store
// it (and SetMiscAtomOrString will assert if we try)
if (aSerialized && aSerialized->IsEmpty()) {
aSerialized = nsnull;
}
SetSVGType(eSVGStringList, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const mozilla::SVGTransformList& aValue,
const nsAString* aSerialized)
{
// While an empty string will parse as a transform list, there's no need to
// store it (and SetMiscAtomOrString will assert if we try)
if (aSerialized && aSerialized->IsEmpty()) {
aSerialized = nsnull;
}
SetSVGType(eSVGTransformList, &aValue, aSerialized);
}
void
nsAttrValue::SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized)
{
SetSVGType(eSVGViewBox, &aValue, aSerialized);
}
void void
nsAttrValue::SwapValueWith(nsAttrValue& aOther) nsAttrValue::SwapValueWith(nsAttrValue& aOther)
{ {
@ -428,6 +579,73 @@ nsAttrValue::ToString(nsAString& aResult) const
aResult.AppendFloat(GetDoubleValue()); aResult.AppendFloat(GetDoubleValue());
break; break;
} }
case eSVGAngle:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGAngle, aResult);
break;
}
case eSVGIntegerPair:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGIntegerPair,
aResult);
break;
}
case eSVGLength:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGLength, aResult);
break;
}
case eSVGLengthList:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGLengthList,
aResult);
break;
}
case eSVGNumberList:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGNumberList,
aResult);
break;
}
case eSVGNumberPair:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGNumberPair,
aResult);
break;
}
case eSVGPathData:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGPathData, aResult);
break;
}
case eSVGPointList:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGPointList, aResult);
break;
}
case eSVGPreserveAspectRatio:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGPreserveAspectRatio,
aResult);
break;
}
case eSVGStringList:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGStringList,
aResult);
break;
}
case eSVGTransformList:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGTransformList,
aResult);
break;
}
case eSVGViewBox:
{
SVGAttrValueWrapper::ToString(GetMiscContainer()->mSVGViewBox, aResult);
break;
}
default: default:
{ {
aResult.Truncate(); aResult.Truncate();
@ -614,6 +832,10 @@ nsAttrValue::HashValue() const
} }
default: default:
{ {
if (IsSVGType(cont->mType)) {
// All SVG types are just pointers to classes so we can treat them alike
return NS_PTR_TO_INT32(cont->mSVGAngle);
}
NS_NOTREACHED("unknown type stored in MiscContainer"); NS_NOTREACHED("unknown type stored in MiscContainer");
return 0; return 0;
} }
@ -706,6 +928,16 @@ nsAttrValue::Equals(const nsAttrValue& aOther) const
} }
default: default:
{ {
if (IsSVGType(thisCont->mType)) {
// Currently this method is never called for nsAttrValue objects that
// point to SVG data types.
// If that changes then we probably want to add methods to the
// corresponding SVG types to compare their base values.
// As a shortcut, however, we can begin by comparing the pointers.
NS_ABORT_IF_FALSE(false, "Comparing nsAttrValues that point to SVG "
"data");
return false;
}
NS_NOTREACHED("unknown type stored in MiscContainer"); NS_NOTREACHED("unknown type stored in MiscContainer");
return false; return false;
} }
@ -1351,6 +1583,22 @@ nsAttrValue::ResetMiscAtomOrString()
} }
} }
void
nsAttrValue::SetSVGType(ValueType aType, const void* aValue,
const nsAString* aSerialized) {
NS_ABORT_IF_FALSE(IsSVGType(aType), "Not an SVG type");
if (EnsureEmptyMiscContainer()) {
MiscContainer* cont = GetMiscContainer();
// All SVG types are just pointers to classes so just setting any of them
// will do. We'll lose type-safety but the signature of the calling
// function should ensure we don't get anything unexpected, and once we
// stick aValue in a union we lose type information anyway.
cont->mSVGAngle = static_cast<const nsSVGAngle*>(aValue);
cont->mType = aType;
SetMiscAtomOrString(aSerialized);
}
}
bool bool
nsAttrValue::EnsureEmptyMiscContainer() nsAttrValue::EnsureEmptyMiscContainer()
{ {

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

@ -51,6 +51,7 @@
#include "nsCaseTreatment.h" #include "nsCaseTreatment.h"
#include "nsMargin.h" #include "nsMargin.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "SVGAttrValueWrapper.h"
typedef PRUptrdiff PtrBits; typedef PRUptrdiff PtrBits;
class nsAString; class nsAString;
@ -102,6 +103,7 @@ public:
nsAttrValue(); nsAttrValue();
nsAttrValue(const nsAttrValue& aOther); nsAttrValue(const nsAttrValue& aOther);
explicit nsAttrValue(const nsAString& aValue); explicit nsAttrValue(const nsAString& aValue);
explicit nsAttrValue(nsIAtom* aValue);
nsAttrValue(mozilla::css::StyleRule* aValue, const nsAString* aSerialized); nsAttrValue(mozilla::css::StyleRule* aValue, const nsAString* aSerialized);
explicit nsAttrValue(const nsIntMargin& aValue); explicit nsAttrValue(const nsIntMargin& aValue);
~nsAttrValue(); ~nsAttrValue();
@ -123,9 +125,23 @@ public:
// Values below here won't matter, they'll be always stored in the 'misc' // Values below here won't matter, they'll be always stored in the 'misc'
// struct. // struct.
eCSSStyleRule = 0x10 eCSSStyleRule = 0x10
,eAtomArray = 0x11 ,eAtomArray = 0x11
,eDoubleValue = 0x12 ,eDoubleValue = 0x12
,eIntMarginValue = 0x13 ,eIntMarginValue = 0x13
,eSVGTypesBegin = 0x14
,eSVGAngle = eSVGTypesBegin
,eSVGIntegerPair = 0x15
,eSVGLength = 0x16
,eSVGLengthList = 0x17
,eSVGNumberList = 0x18
,eSVGNumberPair = 0x19
,eSVGPathData = 0x20
,eSVGPointList = 0x21
,eSVGPreserveAspectRatio = 0x22
,eSVGStringList = 0x23
,eSVGTransformList = 0x24
,eSVGViewBox = 0x25
,eSVGTypesEnd = 0x34
}; };
ValueType Type() const; ValueType Type() const;
@ -134,9 +150,29 @@ public:
void SetTo(const nsAttrValue& aOther); void SetTo(const nsAttrValue& aOther);
void SetTo(const nsAString& aValue); void SetTo(const nsAString& aValue);
void SetTo(nsIAtom* aValue);
void SetTo(PRInt16 aInt); void SetTo(PRInt16 aInt);
void SetTo(PRInt32 aInt, const nsAString* aSerialized);
void SetTo(double aValue, const nsAString* aSerialized);
void SetTo(mozilla::css::StyleRule* aValue, const nsAString* aSerialized); void SetTo(mozilla::css::StyleRule* aValue, const nsAString* aSerialized);
void SetTo(const nsIntMargin& aValue); void SetTo(const nsIntMargin& aValue);
void SetTo(const nsSVGAngle& aValue, const nsAString* aSerialized);
void SetTo(const nsSVGIntegerPair& aValue, const nsAString* aSerialized);
void SetTo(const nsSVGLength2& aValue, const nsAString* aSerialized);
void SetTo(const mozilla::SVGLengthList& aValue,
const nsAString* aSerialized);
void SetTo(const mozilla::SVGNumberList& aValue,
const nsAString* aSerialized);
void SetTo(const nsSVGNumberPair& aValue, const nsAString* aSerialized);
void SetTo(const mozilla::SVGPathData& aValue, const nsAString* aSerialized);
void SetTo(const mozilla::SVGPointList& aValue, const nsAString* aSerialized);
void SetTo(const mozilla::SVGAnimatedPreserveAspectRatio& aValue,
const nsAString* aSerialized);
void SetTo(const mozilla::SVGStringList& aValue,
const nsAString* aSerialized);
void SetTo(const mozilla::SVGTransformList& aValue,
const nsAString* aSerialized);
void SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized);
/** /**
* Sets this object with the string or atom representation of aValue. * Sets this object with the string or atom representation of aValue.
@ -368,10 +404,23 @@ private:
AtomArray* mAtomArray; AtomArray* mAtomArray;
double mDoubleValue; double mDoubleValue;
nsIntMargin* mIntMargin; nsIntMargin* mIntMargin;
const nsSVGAngle* mSVGAngle;
const nsSVGIntegerPair* mSVGIntegerPair;
const nsSVGLength2* mSVGLength;
const mozilla::SVGLengthList* mSVGLengthList;
const mozilla::SVGNumberList* mSVGNumberList;
const nsSVGNumberPair* mSVGNumberPair;
const mozilla::SVGPathData* mSVGPathData;
const mozilla::SVGPointList* mSVGPointList;
const mozilla::SVGAnimatedPreserveAspectRatio* mSVGPreserveAspectRatio;
const mozilla::SVGStringList* mSVGStringList;
const mozilla::SVGTransformList* mSVGTransformList;
const nsSVGViewBox* mSVGViewBox;
}; };
}; };
inline ValueBaseType BaseType() const; inline ValueBaseType BaseType() const;
inline bool IsSVGType(ValueType aType) const;
/** /**
* Get the index of an EnumTable in the sEnumTableArray. * Get the index of an EnumTable in the sEnumTableArray.
@ -388,6 +437,8 @@ private:
void SetColorValue(nscolor aColor, const nsAString& aString); void SetColorValue(nscolor aColor, const nsAString& aString);
void SetMiscAtomOrString(const nsAString* aValue); void SetMiscAtomOrString(const nsAString* aValue);
void ResetMiscAtomOrString(); void ResetMiscAtomOrString();
void SetSVGType(ValueType aType, const void* aValue,
const nsAString* aSerialized);
inline void ResetIfSet(); inline void ResetIfSet();
inline void* GetPtr() const; inline void* GetPtr() const;
@ -502,6 +553,12 @@ nsAttrValue::BaseType() const
return static_cast<ValueBaseType>(mBits & NS_ATTRVALUE_BASETYPE_MASK); return static_cast<ValueBaseType>(mBits & NS_ATTRVALUE_BASETYPE_MASK);
} }
inline bool
nsAttrValue::IsSVGType(ValueType aType) const
{
return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd;
}
inline void inline void
nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType) nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType)
{ {

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

@ -48,6 +48,7 @@
#include "nsCopySupport.h" #include "nsCopySupport.h"
#include "nsIDOMUIEvent.h" #include "nsIDOMUIEvent.h"
#include "nsISelection.h" #include "nsISelection.h"
#include "nsISelectionController.h"
#include "nsIDOMNode.h" #include "nsIDOMNode.h"
#include "nsIDOMNodeList.h" #include "nsIDOMNodeList.h"
#include "nsIDOMEvent.h" #include "nsIDOMEvent.h"
@ -70,6 +71,7 @@
#include "nsIDocShell.h" #include "nsIDocShell.h"
#include "nsIContent.h" #include "nsIContent.h"
#include "nsIImageLoadingContent.h" #include "nsIImageLoadingContent.h"
#include "nsITextControlElement.h"
#include "nsUnicharUtils.h" #include "nsUnicharUtils.h"
#include "nsIURL.h" #include "nsIURL.h"
#include "nsIDocument.h" #include "nsIDocument.h"
@ -84,37 +86,6 @@
#include "imgIRequest.h" #include "imgIRequest.h"
#include "nsDOMDataTransfer.h" #include "nsDOMDataTransfer.h"
// private clipboard data flavors for html copy, used by editor when pasting
#define kHTMLContext "text/_moz_htmlcontext"
#define kHTMLInfo "text/_moz_htmlinfo"
// if aNode is null, use the selection from the window
static nsresult
GetTransferableForNodeOrSelection(nsIDOMWindow* aWindow,
nsIContent* aNode,
nsITransferable** aTransferable)
{
NS_ENSURE_ARG_POINTER(aWindow);
nsCOMPtr<nsIDOMDocument> domDoc;
aWindow->GetDocument(getter_AddRefs(domDoc));
NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
nsresult rv;
if (aNode) {
rv = nsCopySupport::GetTransferableForNode(aNode, doc, aTransferable);
} else {
nsCOMPtr<nsISelection> selection;
aWindow->GetSelection(getter_AddRefs(selection));
rv = nsCopySupport::GetTransferableForSelection(selection, doc,
aTransferable);
}
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
class NS_STACK_CLASS DragDataProducer class NS_STACK_CLASS DragDataProducer
{ {
public: public:
@ -124,7 +95,7 @@ public:
bool aIsAltKeyPressed); bool aIsAltKeyPressed);
nsresult Produce(nsDOMDataTransfer* aDataTransfer, nsresult Produce(nsDOMDataTransfer* aDataTransfer,
bool* aCanDrag, bool* aCanDrag,
bool* aDragSelection, nsISelection** aSelection,
nsIContent** aDragNode); nsIContent** aDragNode);
private: private:
@ -172,7 +143,7 @@ nsContentAreaDragDrop::GetDragData(nsIDOMWindow* aWindow,
bool aIsAltKeyPressed, bool aIsAltKeyPressed,
nsDOMDataTransfer* aDataTransfer, nsDOMDataTransfer* aDataTransfer,
bool* aCanDrag, bool* aCanDrag,
bool* aDragSelection, nsISelection** aSelection,
nsIContent** aDragNode) nsIContent** aDragNode)
{ {
NS_ENSURE_TRUE(aSelectionTargetNode, NS_ERROR_INVALID_ARG); NS_ENSURE_TRUE(aSelectionTargetNode, NS_ERROR_INVALID_ARG);
@ -181,7 +152,7 @@ nsContentAreaDragDrop::GetDragData(nsIDOMWindow* aWindow,
DragDataProducer DragDataProducer
provider(aWindow, aTarget, aSelectionTargetNode, aIsAltKeyPressed); provider(aWindow, aTarget, aSelectionTargetNode, aIsAltKeyPressed);
return provider.Produce(aDataTransfer, aCanDrag, aDragSelection, aDragNode); return provider.Produce(aDataTransfer, aCanDrag, aSelection, aDragNode);
} }
@ -412,10 +383,10 @@ DragDataProducer::GetNodeString(nsIContent* inNode,
nsresult nsresult
DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer, DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
bool* aCanDrag, bool* aCanDrag,
bool* aDragSelection, nsISelection** aSelection,
nsIContent** aDragNode) nsIContent** aDragNode)
{ {
NS_PRECONDITION(aCanDrag && aDragSelection && aDataTransfer && aDragNode, NS_PRECONDITION(aCanDrag && aSelection && aDataTransfer && aDragNode,
"null pointer passed to Produce"); "null pointer passed to Produce");
NS_ASSERTION(mWindow, "window not set"); NS_ASSERTION(mWindow, "window not set");
NS_ASSERTION(mSelectionTargetNode, "selection target node should have been set"); NS_ASSERTION(mSelectionTargetNode, "selection target node should have been set");
@ -424,33 +395,72 @@ DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
nsresult rv; nsresult rv;
nsIContent* dragNode = nsnull; nsIContent* dragNode = nsnull;
*aSelection = nsnull;
// find the selection to see what we could be dragging and if // Find the selection to see what we could be dragging and if what we're
// what we're dragging is in what is selected. // dragging is in what is selected. If this is an editable textbox, use
// the textbox's selection, otherwise use the window's selection.
nsCOMPtr<nsISelection> selection; nsCOMPtr<nsISelection> selection;
mWindow->GetSelection(getter_AddRefs(selection)); nsIContent* editingElement = mSelectionTargetNode->IsEditable() ?
if (!selection) { mSelectionTargetNode->GetEditingHost() : nsnull;
return NS_OK; nsCOMPtr<nsITextControlElement> textControl(do_QueryInterface(editingElement));
} if (textControl) {
nsISelectionController* selcon = textControl->GetSelectionController();
// check if the node is inside a form control. If so, dragging will be if (selcon) {
// handled in editor code (nsPlaintextDataTransfer::DoDrag). Don't set selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
// aCanDrag to false however, as we still want to allow the drag. if (!selection)
nsCOMPtr<nsIContent> findFormNode = mSelectionTargetNode; return NS_OK;
nsIContent* findFormParent = findFormNode->GetParent(); }
while (findFormParent) { }
nsCOMPtr<nsIFormControl> form(do_QueryInterface(findFormParent)); else {
if (form && !form->AllowDraggableChildren()) { mWindow->GetSelection(getter_AddRefs(selection));
return NS_OK; if (!selection)
return NS_OK;
// Check if the node is inside a form control. Don't set aCanDrag to false
//however, as we still want to allow the drag.
nsCOMPtr<nsIContent> findFormNode = mSelectionTargetNode;
nsIContent* findFormParent = findFormNode->GetParent();
while (findFormParent) {
nsCOMPtr<nsIFormControl> form(do_QueryInterface(findFormParent));
if (form && !form->AllowDraggableChildren()) {
return NS_OK;
}
findFormParent = findFormParent->GetParent();
} }
findFormParent = findFormParent->GetParent();
} }
// if set, serialize the content under this node // if set, serialize the content under this node
nsCOMPtr<nsIContent> nodeToSerialize; nsCOMPtr<nsIContent> nodeToSerialize;
*aDragSelection = false;
{ bool isChromeShell = false;
nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(mWindow);
nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(webnav);
if (dsti) {
PRInt32 type = -1;
if (NS_SUCCEEDED(dsti->GetItemType(&type)) &&
type == nsIDocShellTreeItem::typeChrome) {
isChromeShell = true;
}
}
// In chrome shells, only allow dragging inside editable areas.
if (isChromeShell && !editingElement)
return NS_OK;
if (isChromeShell && textControl) {
// Only use the selection if it isn't collapsed.
bool isCollapsed = false;
selection->GetIsCollapsed(&isCollapsed);
if (!isCollapsed)
selection.swap(*aSelection);
}
else {
// In content shells, a number of checks are made below to determine
// whether an image or a link is being dragged. If so, add additional
// data to the data transfer. This is also done for chrome shells, but
// only when in a non-textbox editor.
bool haveSelectedContent = false; bool haveSelectedContent = false;
// possible parent link node // possible parent link node
@ -490,7 +500,7 @@ DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
return NS_OK; return NS_OK;
} }
*aDragSelection = true; selection.swap(*aSelection);
} else if (selectedImageOrLinkNode) { } else if (selectedImageOrLinkNode) {
// an image is selected // an image is selected
image = do_QueryInterface(selectedImageOrLinkNode); image = do_QueryInterface(selectedImageOrLinkNode);
@ -660,20 +670,28 @@ DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
} }
} }
if (nodeToSerialize || *aDragSelection) { if (nodeToSerialize || *aSelection) {
// if we have selected text, use it in preference to the node
if (*aDragSelection) {
nodeToSerialize = nsnull;
}
mHtmlString.Truncate(); mHtmlString.Truncate();
mContextString.Truncate(); mContextString.Truncate();
mInfoString.Truncate(); mInfoString.Truncate();
mTitleString.Truncate(); mTitleString.Truncate();
nsCOMPtr<nsIDOMDocument> domDoc;
mWindow->GetDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
// if we have selected text, use it in preference to the node
nsCOMPtr<nsITransferable> transferable; nsCOMPtr<nsITransferable> transferable;
rv = ::GetTransferableForNodeOrSelection(mWindow, nodeToSerialize, if (*aSelection) {
getter_AddRefs(transferable)); rv = nsCopySupport::GetTransferableForSelection(*aSelection, doc,
NS_ENSURE_SUCCESS(rv, rv); getter_AddRefs(transferable));
}
else {
rv = nsCopySupport::GetTransferableForNode(nodeToSerialize, doc,
getter_AddRefs(transferable));
}
nsCOMPtr<nsISupportsString> data; nsCOMPtr<nsISupportsString> data;
PRUint32 dataSize; PRUint32 dataSize;
rv = transferable->GetTransferData(kHTMLMime, getter_AddRefs(data), &dataSize); rv = transferable->GetTransferData(kHTMLMime, getter_AddRefs(data), &dataSize);
@ -747,15 +765,17 @@ DragDataProducer::AddStringsToDataTransfer(nsIContent* aDragNode,
AddString(aDataTransfer, NS_LITERAL_STRING("text/uri-list"), mUrlString, principal); AddString(aDataTransfer, NS_LITERAL_STRING("text/uri-list"), mUrlString, principal);
} }
// add a special flavor, even if we don't have html context data // add a special flavor for the html context data
AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), mContextString, principal); if (!mContextString.IsEmpty())
AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), mContextString, principal);
// add a special flavor if we have html info data // add a special flavor if we have html info data
if (!mInfoString.IsEmpty()) if (!mInfoString.IsEmpty())
AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), mInfoString, principal); AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), mInfoString, principal);
// add the full html // add the full html
AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLMime), mHtmlString, principal); if (!mHtmlString.IsEmpty())
AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLMime), mHtmlString, principal);
// add the plain text. we use the url for text/plain data if an anchor is // add the plain text. we use the url for text/plain data if an anchor is
// being dragged, rather than the title text of the link or the alt text for // being dragged, rather than the title text of the link or the alt text for

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

@ -78,8 +78,8 @@ public:
* aDataTransfer - the dataTransfer for the drag event. * aDataTransfer - the dataTransfer for the drag event.
* aCanDrag - [out] set to true if the drag may proceed, false to stop the * aCanDrag - [out] set to true if the drag may proceed, false to stop the
* drag entirely * drag entirely
* aDragSelection - [out] set to true to indicate that a selection is being * aSelection - [out] set to the selection being dragged, or null if no
* dragged, rather than a specific node * selection is being dragged.
* aDragNode - [out] the link, image or area being dragged, or null if the * aDragNode - [out] the link, image or area being dragged, or null if the
* drag occurred on another element. * drag occurred on another element.
*/ */
@ -89,7 +89,7 @@ public:
bool aIsAltKeyPressed, bool aIsAltKeyPressed,
nsDOMDataTransfer* aDataTransfer, nsDOMDataTransfer* aDataTransfer,
bool* aCanDrag, bool* aCanDrag,
bool* aDragSelection, nsISelection** aSelection,
nsIContent** aDragNode); nsIContent** aDragNode);
}; };

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

@ -91,10 +91,6 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID); static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID);
static NS_DEFINE_CID(kHTMLConverterCID, NS_HTMLFORMATCONVERTER_CID); static NS_DEFINE_CID(kHTMLConverterCID, NS_HTMLFORMATCONVERTER_CID);
// private clipboard data flavors for html copy, used by editor when pasting
#define kHTMLContext "text/_moz_htmlcontext"
#define kHTMLInfo "text/_moz_htmlinfo"
// copy string data onto the transferable // copy string data onto the transferable
static nsresult AppendString(nsITransferable *aTransferable, static nsresult AppendString(nsITransferable *aTransferable,
const nsAString& aString, const nsAString& aString,

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

@ -122,9 +122,9 @@ nsDOMMultipartFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
PRUint64 upperBound = NS_MIN<PRUint64>(l - skipStart, length); PRUint64 upperBound = NS_MIN<PRUint64>(l - skipStart, length);
nsCOMPtr<nsIDOMBlob> firstBlob; nsCOMPtr<nsIDOMBlob> firstBlob;
rv = blob->MozSlice(skipStart, skipStart + upperBound, rv = blob->Slice(skipStart, skipStart + upperBound,
aContentType, 3, aContentType, 3,
getter_AddRefs(firstBlob)); getter_AddRefs(firstBlob));
NS_ENSURE_SUCCESS(rv, nsnull); NS_ENSURE_SUCCESS(rv, nsnull);
// Avoid wrapping a single blob inside an nsDOMMultipartFile // Avoid wrapping a single blob inside an nsDOMMultipartFile
@ -150,8 +150,8 @@ nsDOMMultipartFile::CreateSlice(PRUint64 aStart, PRUint64 aLength,
if (length < l) { if (length < l) {
nsCOMPtr<nsIDOMBlob> lastBlob; nsCOMPtr<nsIDOMBlob> lastBlob;
rv = blob->MozSlice(0, length, aContentType, 3, rv = blob->Slice(0, length, aContentType, 3,
getter_AddRefs(lastBlob)); getter_AddRefs(lastBlob));
NS_ENSURE_SUCCESS(rv, nsnull); NS_ENSURE_SUCCESS(rv, nsnull);
blobs.AppendElement(lastBlob); blobs.AppendElement(lastBlob);

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

@ -238,9 +238,9 @@ ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsDOMFileBase::MozSlice(PRInt64 aStart, PRInt64 aEnd, nsDOMFileBase::Slice(PRInt64 aStart, PRInt64 aEnd,
const nsAString& aContentType, PRUint8 optional_argc, const nsAString& aContentType, PRUint8 optional_argc,
nsIDOMBlob **aBlob) nsIDOMBlob **aBlob)
{ {
*aBlob = nsnull; *aBlob = nsnull;

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

@ -89,6 +89,7 @@ nsEventSource::nsEventSource() :
mErrorLoadOnRedirect(false), mErrorLoadOnRedirect(false),
mGoingToDispatchAllMessages(false), mGoingToDispatchAllMessages(false),
mWithCredentials(false), mWithCredentials(false),
mWaitingForOnStopRequest(false),
mLastConvertionResult(NS_OK), mLastConvertionResult(NS_OK),
mReadyState(nsIEventSource::CONNECTING), mReadyState(nsIEventSource::CONNECTING),
mScriptLine(0), mScriptLine(0),
@ -108,13 +109,19 @@ nsEventSource::~nsEventSource()
NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventSource) NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventSource)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsEventSource) NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsEventSource)
if (tmp->IsBlack()) { bool isBlack = tmp->IsBlack();
if (isBlack || tmp->mWaitingForOnStopRequest) {
if (tmp->mListenerManager) { if (tmp->mListenerManager) {
tmp->mListenerManager->UnmarkGrayJSListeners(); tmp->mListenerManager->UnmarkGrayJSListeners();
NS_UNMARK_LISTENER_WRAPPER(Open) NS_UNMARK_LISTENER_WRAPPER(Open)
NS_UNMARK_LISTENER_WRAPPER(Message) NS_UNMARK_LISTENER_WRAPPER(Message)
NS_UNMARK_LISTENER_WRAPPER(Error) NS_UNMARK_LISTENER_WRAPPER(Error)
} }
if (!isBlack) {
xpc_UnmarkGrayObject(tmp->PreservingWrapper() ?
tmp->GetWrapperPreserveColor() :
tmp->GetExpandoObjectPreserveColor());
}
return true; return true;
} }
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
@ -599,6 +606,8 @@ nsEventSource::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext, nsISupports *aContext,
nsresult aStatusCode) nsresult aStatusCode)
{ {
mWaitingForOnStopRequest = false;
if (mReadyState == nsIEventSource::CLOSED) { if (mReadyState == nsIEventSource::CLOSED) {
return NS_ERROR_ABORT; return NS_ERROR_ABORT;
} }
@ -949,7 +958,11 @@ nsEventSource::InitChannelAndRequestEventSource()
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Start reading from the channel // Start reading from the channel
return mHttpChannel->AsyncOpen(listener, nsnull); rv = mHttpChannel->AsyncOpen(listener, nsnull);
if (NS_SUCCEEDED(rv)) {
mWaitingForOnStopRequest = true;
}
return rv;
} }
void void

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

@ -216,6 +216,7 @@ protected:
bool mErrorLoadOnRedirect; bool mErrorLoadOnRedirect;
bool mGoingToDispatchAllMessages; bool mGoingToDispatchAllMessages;
bool mWithCredentials; bool mWithCredentials;
bool mWaitingForOnStopRequest;
// used while reading the input streams // used while reading the input streams
nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder; nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;

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

@ -1700,9 +1700,29 @@ nsINode::SetExplicitBaseURI(nsIURI* aURI)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
static JSObject*
GetJSObjectChild(nsWrapperCache* aCache)
{
if (aCache->PreservingWrapper()) {
return aCache->GetWrapperPreserveColor();
}
return aCache->GetExpandoObjectPreserveColor();
}
static bool
NeedsScriptTraverse(nsWrapperCache* aCache)
{
JSObject* o = GetJSObjectChild(aCache);
return o && xpc_IsGrayGCThing(o);
}
//----------------------------------------------------------------------
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList)
// If nsChildContentList is changed so that any additional fields are
// traversed by the cycle collector, then CAN_SKIP must be updated.
NS_IMPL_CYCLE_COLLECTION_CLASS(nsChildContentList) NS_IMPL_CYCLE_COLLECTION_CLASS(nsChildContentList)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsChildContentList) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsChildContentList)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@ -1714,6 +1734,20 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsChildContentList)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRACE_END
// nsChildContentList only ever has a single child, its wrapper, so if
// the wrapper is black, the list can't be part of a garbage cycle.
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsChildContentList)
return !NeedsScriptTraverse(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsChildContentList)
return !NeedsScriptTraverse(tmp);
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
// CanSkipThis returns false to avoid problems with incomplete unlinking.
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsChildContentList)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
NS_INTERFACE_TABLE_HEAD(nsChildContentList) NS_INTERFACE_TABLE_HEAD(nsChildContentList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsChildContentList) NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsChildContentList)
@ -4405,22 +4439,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericElement)
nsINode::Trace(tmp, aCallback, aClosure); nsINode::Trace(tmp, aCallback, aClosure);
NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRACE_END
static JSObject*
GetJSObjectChild(nsINode* aNode)
{
if (aNode->PreservingWrapper()) {
return aNode->GetWrapperPreserveColor();
}
return aNode->GetExpandoObjectPreserveColor();
}
static bool
NeedsScriptTraverse(nsINode* aNode)
{
JSObject* o = GetJSObjectChild(aNode);
return o && xpc_IsGrayGCThing(o);
}
void void
nsGenericElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild, nsGenericElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
void* aData) void* aData)

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

@ -102,7 +102,7 @@ public:
} }
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsChildContentList) NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsChildContentList)
// nsWrapperCache // nsWrapperCache
virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope, virtual JSObject* WrapObject(JSContext *cx, XPCWrappedNativeScope *scope,

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

@ -439,7 +439,8 @@ nsWebSocket::~nsWebSocket()
NS_IMPL_CYCLE_COLLECTION_CLASS(nsWebSocket) NS_IMPL_CYCLE_COLLECTION_CLASS(nsWebSocket)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsWebSocket) NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsWebSocket)
if (tmp->IsBlack()) { bool isBlack = tmp->IsBlack();
if (isBlack|| tmp->mKeepingAlive) {
if (tmp->mListenerManager) { if (tmp->mListenerManager) {
tmp->mListenerManager->UnmarkGrayJSListeners(); tmp->mListenerManager->UnmarkGrayJSListeners();
NS_UNMARK_LISTENER_WRAPPER(Open) NS_UNMARK_LISTENER_WRAPPER(Open)
@ -447,6 +448,11 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsWebSocket)
NS_UNMARK_LISTENER_WRAPPER(Message) NS_UNMARK_LISTENER_WRAPPER(Message)
NS_UNMARK_LISTENER_WRAPPER(Close) NS_UNMARK_LISTENER_WRAPPER(Close)
} }
if (!isBlack) {
xpc_UnmarkGrayObject(tmp->PreservingWrapper() ?
tmp->GetWrapperPreserveColor() :
tmp->GetExpandoObjectPreserveColor());
}
return true; return true;
} }
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END

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

@ -445,8 +445,8 @@ nsXMLHttpRequest::nsXMLHttpRequest()
mProgressSinceLastProgressEvent(false), mProgressSinceLastProgressEvent(false),
mUploadProgress(0), mUploadProgressMax(0), mUploadProgress(0), mUploadProgressMax(0),
mRequestSentTime(0), mTimeoutMilliseconds(0), mRequestSentTime(0), mTimeoutMilliseconds(0),
mErrorLoad(false), mProgressTimerIsActive(false), mErrorLoad(false), mWaitingForOnStopRequest(false),
mProgressEventWasDelayed(false), mProgressTimerIsActive(false), mProgressEventWasDelayed(false),
mIsHtml(false), mIsHtml(false),
mWarnAboutMultipartHtml(false), mWarnAboutMultipartHtml(false),
mWarnAboutSyncHtml(false), mWarnAboutSyncHtml(false),
@ -602,7 +602,8 @@ nsXMLHttpRequest::SetRequestObserver(nsIRequestObserver* aObserver)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest) NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest) NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
if (tmp->IsBlack()) { bool isBlack = tmp->IsBlack();
if (isBlack || tmp->mWaitingForOnStopRequest) {
if (tmp->mListenerManager) { if (tmp->mListenerManager) {
tmp->mListenerManager->UnmarkGrayJSListeners(); tmp->mListenerManager->UnmarkGrayJSListeners();
NS_UNMARK_LISTENER_WRAPPER(Load) NS_UNMARK_LISTENER_WRAPPER(Load)
@ -614,6 +615,11 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
NS_UNMARK_LISTENER_WRAPPER(UploadProgress) NS_UNMARK_LISTENER_WRAPPER(UploadProgress)
NS_UNMARK_LISTENER_WRAPPER(Readystatechange) NS_UNMARK_LISTENER_WRAPPER(Readystatechange)
} }
if (!isBlack) {
xpc_UnmarkGrayObject(tmp->PreservingWrapper() ?
tmp->GetWrapperPreserveColor() :
tmp->GetExpandoObjectPreserveColor());
}
return true; return true;
} }
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
@ -2140,6 +2146,8 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult
return NS_OK; return NS_OK;
} }
mWaitingForOnStopRequest = false;
nsresult rv = NS_OK; nsresult rv = NS_OK;
// If we're loading a multipart stream of XML documents, we'll get // If we're loading a multipart stream of XML documents, we'll get
@ -2774,6 +2782,9 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
return rv; return rv;
} }
// Either AsyncOpen was called, or CORS will open the channel later.
mWaitingForOnStopRequest = true;
// If we're synchronous, spin an event loop here and wait // If we're synchronous, spin an event loop here and wait
if (!(mState & XML_HTTP_REQUEST_ASYNC)) { if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
mState |= XML_HTTP_REQUEST_SYNCLOOPING; mState |= XML_HTTP_REQUEST_SYNCLOOPING;

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

@ -365,7 +365,7 @@ protected:
void HandleTimeoutCallback(); void HandleTimeoutCallback();
bool mErrorLoad; bool mErrorLoad;
bool mWaitingForOnStopRequest;
bool mProgressTimerIsActive; bool mProgressTimerIsActive;
bool mProgressEventWasDelayed; bool mProgressEventWasDelayed;
bool mIsHtml; bool mIsHtml;

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

@ -201,24 +201,24 @@ function testSlice(file, size, type, contents, fileType) {
ok(file instanceof File, fileType + " file is a File"); ok(file instanceof File, fileType + " file is a File");
ok(file instanceof Blob, fileType + " file is also a Blob"); ok(file instanceof Blob, fileType + " file is also a Blob");
var slice = file.mozSlice(0, size); var slice = file.slice(0, size);
ok(slice instanceof Blob, fileType + " fullsize slice is a Blob"); ok(slice instanceof Blob, fileType + " fullsize slice is a Blob");
ok(!(slice instanceof File), fileType + " fullsize slice is not a File"); ok(!(slice instanceof File), fileType + " fullsize slice is not a File");
slice = file.mozSlice(0, 1234); slice = file.slice(0, 1234);
ok(slice instanceof Blob, fileType + " sized slice is a Blob"); ok(slice instanceof Blob, fileType + " sized slice is a Blob");
ok(!(slice instanceof File), fileType + " sized slice is not a File"); ok(!(slice instanceof File), fileType + " sized slice is not a File");
slice = file.mozSlice(0, size, "foo/bar"); slice = file.slice(0, size, "foo/bar");
is(slice.type, "foo/bar", fileType + " fullsize slice foo/bar type"); is(slice.type, "foo/bar", fileType + " fullsize slice foo/bar type");
slice = file.mozSlice(0, 5432, "foo/bar"); slice = file.slice(0, 5432, "foo/bar");
is(slice.type, "foo/bar", fileType + " sized slice foo/bar type"); is(slice.type, "foo/bar", fileType + " sized slice foo/bar type");
is(slice.mozSlice(0, 10).type, "", fileType + " slice-slice type"); is(slice.slice(0, 10).type, "", fileType + " slice-slice type");
is(slice.mozSlice(0, 10).size, 10, fileType + " slice-slice size"); is(slice.slice(0, 10).size, 10, fileType + " slice-slice size");
is(slice.mozSlice(0, 10, "hello/world").type, "hello/world", fileType + " slice-slice hello/world type"); is(slice.slice(0, 10, "hello/world").type, "hello/world", fileType + " slice-slice hello/world type");
is(slice.mozSlice(0, 10, "hello/world").size, 10, fileType + " slice-slice hello/world size"); is(slice.slice(0, 10, "hello/world").size, 10, fileType + " slice-slice hello/world size");
// Start, end, expected size // Start, end, expected size
var indexes = [[0, size, size], var indexes = [[0, size, size],
@ -247,17 +247,17 @@ function testSlice(file, size, type, contents, fileType) {
var sliceContents; var sliceContents;
var testName; var testName;
if (indexes[i][0] == undefined) { if (indexes[i][0] == undefined) {
slice = file.mozSlice(); slice = file.slice();
sliceContents = contents.slice(); sliceContents = contents.slice();
testName = fileType + " slice()"; testName = fileType + " slice()";
} }
else if (indexes[i][1] == undefined) { else if (indexes[i][1] == undefined) {
slice = file.mozSlice(indexes[i][0]); slice = file.slice(indexes[i][0]);
sliceContents = contents.slice(indexes[i][0]); sliceContents = contents.slice(indexes[i][0]);
testName = fileType + " slice(" + indexes[i][0] + ")"; testName = fileType + " slice(" + indexes[i][0] + ")";
} }
else { else {
slice = file.mozSlice(indexes[i][0], indexes[i][1]); slice = file.slice(indexes[i][0], indexes[i][1]);
sliceContents = contents.slice(indexes[i][0], indexes[i][1]); sliceContents = contents.slice(indexes[i][0], indexes[i][1]);
testName = fileType + " slice(" + indexes[i][0] + ", " + indexes[i][1] + ")"; testName = fileType + " slice(" + indexes[i][0] + ", " + indexes[i][1] + ")";
} }
@ -268,11 +268,11 @@ function testSlice(file, size, type, contents, fileType) {
} }
// Slice of slice // Slice of slice
var slice = file.mozSlice(0, 40000); var slice = file.slice(0, 40000);
testFile(slice.mozSlice(5000, 42000), contents.slice(5000, 40000), "file slice slice"); testFile(slice.slice(5000, 42000), contents.slice(5000, 40000), "file slice slice");
// ...of slice of slice // ...of slice of slice
slice = slice.mozSlice(5000, 42000).mozSlice(400, 700); slice = slice.slice(5000, 42000).slice(400, 700);
SpecialPowers.gc(); SpecialPowers.gc();
testFile(slice, contents.slice(5400, 5700), "file slice slice slice"); testFile(slice, contents.slice(5400, 5700), "file slice slice slice");
} }

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

@ -151,7 +151,7 @@ function doTest(data) {
ok(blob instanceof Blob, "Test " + testCounter + " blob is a Blob"); ok(blob instanceof Blob, "Test " + testCounter + " blob is a Blob");
ok(!(blob instanceof File), "Test " + testCounter + " blob is not a File"); ok(!(blob instanceof File), "Test " + testCounter + " blob is not a File");
let slice = blob.mozSlice(test.start, test.start + test.length); let slice = blob.slice(test.start, test.start + test.length);
ok(slice, "Test " + testCounter + " got slice"); ok(slice, "Test " + testCounter + " got slice");
ok(slice instanceof Blob, "Test " + testCounter + " slice is a Blob"); ok(slice instanceof Blob, "Test " + testCounter + " slice is a Blob");
ok(!(slice instanceof File), "Test " + testCounter + " slice is not a File"); ok(!(slice instanceof File), "Test " + testCounter + " slice is not a File");

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

@ -49,7 +49,7 @@ function attr_modified(ev) {
e_prev = e_new; e_prev = e_new;
if (!recursive) { if (!recursive) {
recursive = true; recursive = true;
e_new = "width: 0pt;"; e_new = "width: 0px;";
testDiv.style.width = "0"; testDiv.style.width = "0";
} else { } else {
recursive = false; recursive = false;

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

@ -104,7 +104,7 @@ function imageLoadHandler(event) {
var imgfile = createFileWithData(testBinaryData + fileData + testBinaryData); var imgfile = createFileWithData(testBinaryData + fileData + testBinaryData);
is(imgfile.size, size + testBinaryData.length * 2, "correct file size (middle)"); is(imgfile.size, size + testBinaryData.length * 2, "correct file size (middle)");
var img = new Image; var img = new Image;
img.src = URL.createObjectURL(imgfile.mozSlice(testBinaryData.length, testBinaryData.length + size)); img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size));
img.onload = imageLoadHandler; img.onload = imageLoadHandler;
expectedTestCount++; expectedTestCount++;
@ -112,7 +112,7 @@ expectedTestCount++;
var imgfile = createFileWithData(fileData + testBinaryData); var imgfile = createFileWithData(fileData + testBinaryData);
is(imgfile.size, size + testBinaryData.length, "correct file size (start)"); is(imgfile.size, size + testBinaryData.length, "correct file size (start)");
var img = new Image; var img = new Image;
img.src = URL.createObjectURL(imgfile.mozSlice(0, size)); img.src = URL.createObjectURL(imgfile.slice(0, size));
img.onload = imageLoadHandler; img.onload = imageLoadHandler;
expectedTestCount++; expectedTestCount++;
@ -120,7 +120,7 @@ expectedTestCount++;
var imgfile = createFileWithData(testBinaryData + fileData); var imgfile = createFileWithData(testBinaryData + fileData);
is(imgfile.size, size + testBinaryData.length, "correct file size (end)"); is(imgfile.size, size + testBinaryData.length, "correct file size (end)");
var img = new Image; var img = new Image;
img.src = URL.createObjectURL(imgfile.mozSlice(testBinaryData.length, testBinaryData.length + size)); img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size));
img.onload = imageLoadHandler; img.onload = imageLoadHandler;
expectedTestCount++; expectedTestCount++;
@ -128,7 +128,7 @@ expectedTestCount++;
var imgfile = createFileWithData(testBinaryData + fileData); var imgfile = createFileWithData(testBinaryData + fileData);
is(imgfile.size, size + testBinaryData.length, "correct file size (past end)"); is(imgfile.size, size + testBinaryData.length, "correct file size (past end)");
var img = new Image; var img = new Image;
img.src = URL.createObjectURL(imgfile.mozSlice(testBinaryData.length, testBinaryData.length + size + 1000)); img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size + 1000));
img.onload = imageLoadHandler; img.onload = imageLoadHandler;
expectedTestCount++; expectedTestCount++;

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

@ -1024,7 +1024,7 @@ struct WebGLVertexAttribData {
} }
}; };
class WebGLBuffer class WebGLBuffer MOZ_FINAL
: public nsIWebGLBuffer : public nsIWebGLBuffer
, public WebGLRefCountedObject<WebGLBuffer> , public WebGLRefCountedObject<WebGLBuffer>
, public WebGLContextBoundObject , public WebGLContextBoundObject
@ -1158,7 +1158,7 @@ protected:
void* mData; // in the case of an Element Array Buffer, we keep a copy. void* mData; // in the case of an Element Array Buffer, we keep a copy.
}; };
class WebGLTexture class WebGLTexture MOZ_FINAL
: public nsIWebGLTexture : public nsIWebGLTexture
, public WebGLRefCountedObject<WebGLTexture> , public WebGLRefCountedObject<WebGLTexture>
, public WebGLContextBoundObject , public WebGLContextBoundObject
@ -1608,7 +1608,7 @@ public:
} }
}; };
class WebGLShader class WebGLShader MOZ_FINAL
: public nsIWebGLShader : public nsIWebGLShader
, public WebGLRefCountedObject<WebGLShader> , public WebGLRefCountedObject<WebGLShader>
, public WebGLContextBoundObject , public WebGLContextBoundObject
@ -1673,7 +1673,7 @@ protected:
WebGLMonotonicHandle mMonotonicHandle; WebGLMonotonicHandle mMonotonicHandle;
}; };
class WebGLProgram class WebGLProgram MOZ_FINAL
: public nsIWebGLProgram : public nsIWebGLProgram
, public WebGLRefCountedObject<WebGLProgram> , public WebGLRefCountedObject<WebGLProgram>
, public WebGLContextBoundObject , public WebGLContextBoundObject
@ -1795,7 +1795,7 @@ protected:
WebGLMonotonicHandle mMonotonicHandle; WebGLMonotonicHandle mMonotonicHandle;
}; };
class WebGLRenderbuffer class WebGLRenderbuffer MOZ_FINAL
: public nsIWebGLRenderbuffer : public nsIWebGLRenderbuffer
, public WebGLRefCountedObject<WebGLRenderbuffer> , public WebGLRefCountedObject<WebGLRenderbuffer>
, public WebGLRectangleObject , public WebGLRectangleObject
@ -2001,7 +2001,7 @@ public:
} }
}; };
class WebGLFramebuffer class WebGLFramebuffer MOZ_FINAL
: public nsIWebGLFramebuffer : public nsIWebGLFramebuffer
, public WebGLRefCountedObject<WebGLFramebuffer> , public WebGLRefCountedObject<WebGLFramebuffer>
, public WebGLContextBoundObject , public WebGLContextBoundObject
@ -2296,7 +2296,7 @@ public:
WebGLMonotonicHandle mMonotonicHandle; WebGLMonotonicHandle mMonotonicHandle;
}; };
class WebGLUniformLocation class WebGLUniformLocation MOZ_FINAL
: public nsIWebGLUniformLocation : public nsIWebGLUniformLocation
, public WebGLContextBoundObject , public WebGLContextBoundObject
, public WebGLRefCountedObject<WebGLUniformLocation> , public WebGLRefCountedObject<WebGLUniformLocation>
@ -2337,7 +2337,7 @@ protected:
friend class WebGLProgram; friend class WebGLProgram;
}; };
class WebGLActiveInfo class WebGLActiveInfo MOZ_FINAL
: public nsIWebGLActiveInfo : public nsIWebGLActiveInfo
{ {
public: public:
@ -2356,7 +2356,7 @@ protected:
nsString mName; nsString mName;
}; };
class WebGLShaderPrecisionFormat class WebGLShaderPrecisionFormat MOZ_FINAL
: public nsIWebGLShaderPrecisionFormat : public nsIWebGLShaderPrecisionFormat
{ {
public: public:
@ -2388,6 +2388,7 @@ public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSIWEBGLEXTENSION NS_DECL_NSIWEBGLEXTENSION
virtual ~WebGLExtension() {}
}; };
inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const { inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {

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

@ -4377,7 +4377,7 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
// ESSL backend // ESSL backend
compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(), compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
SH_WEBGL_SPEC, SH_WEBGL_SPEC,
#ifdef MOZ_WIDGET_ANDROID #ifdef ANDROID
SH_GLSL_OUTPUT, SH_GLSL_OUTPUT,
#else #else
gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT, gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT,

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

@ -180,7 +180,7 @@ CopyContext(gfxContext* dest, gfxContext* src)
**/ **/
#define NS_CANVASGRADIENT_PRIVATE_IID \ #define NS_CANVASGRADIENT_PRIVATE_IID \
{ 0x491d39d8, 0x4058, 0x42bd, { 0xac, 0x76, 0x70, 0xd5, 0x62, 0x7f, 0x02, 0x10 } } { 0x491d39d8, 0x4058, 0x42bd, { 0xac, 0x76, 0x70, 0xd5, 0x62, 0x7f, 0x02, 0x10 } }
class nsCanvasGradient : public nsIDOMCanvasGradient class nsCanvasGradient MOZ_FINAL : public nsIDOMCanvasGradient
{ {
public: public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID)
@ -238,7 +238,7 @@ NS_INTERFACE_MAP_END
**/ **/
#define NS_CANVASPATTERN_PRIVATE_IID \ #define NS_CANVASPATTERN_PRIVATE_IID \
{ 0xb85c6c8a, 0x0624, 0x4530, { 0xb8, 0xee, 0xff, 0xdf, 0x42, 0xe8, 0x21, 0x6d } } { 0xb85c6c8a, 0x0624, 0x4530, { 0xb8, 0xee, 0xff, 0xdf, 0x42, 0xe8, 0x21, 0x6d } }
class nsCanvasPattern : public nsIDOMCanvasPattern class nsCanvasPattern MOZ_FINAL : public nsIDOMCanvasPattern
{ {
public: public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERN_PRIVATE_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERN_PRIVATE_IID)

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

@ -7,3 +7,5 @@ conformance/more/conformance/quickCheckAPI-S_V.html
conformance/glsl/misc/attrib-location-length-limits.html conformance/glsl/misc/attrib-location-length-limits.html
conformance/glsl/misc/uniform-location-length-limits.html conformance/glsl/misc/uniform-location-length-limits.html
conformance/programs/program-test.html conformance/programs/program-test.html
conformance/textures/texture-mips.html
conformance/textures/texture-npot.html

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

@ -180,8 +180,7 @@ nsDOMEvent::InitPresContextData(nsPresContext* aPresContext)
// Get the explicit original target (if it's anonymous make it null) // Get the explicit original target (if it's anonymous make it null)
{ {
nsCOMPtr<nsIContent> content = GetTargetFromFrame(); nsCOMPtr<nsIContent> content = GetTargetFromFrame();
mTmpRealOriginalTarget = do_QueryInterface(content); mExplicitOriginalTarget = do_QueryInterface(content);
mExplicitOriginalTarget = mTmpRealOriginalTarget;
if (content && content->IsInAnonymousSubtree()) { if (content && content->IsInAnonymousSubtree()) {
mExplicitOriginalTarget = nsnull; mExplicitOriginalTarget = nsnull;
} }
@ -237,10 +236,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMEvent)
} }
} }
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPresContext); NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPresContext);
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTmpRealOriginalTarget) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mExplicitOriginalTarget);
// Always set mExplicitOriginalTarget to null, when
// mTmpRealOriginalTarget doesn't point to any object!
tmp->mExplicitOriginalTarget = nsnull;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMEvent) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMEvent)
@ -275,7 +271,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMEvent)
} }
} }
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mPresContext.get(), nsPresContext) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mPresContext.get(), nsPresContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTmpRealOriginalTarget) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mExplicitOriginalTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
// nsIDOMEventInterface // nsIDOMEventInterface
@ -355,18 +351,6 @@ nsDOMEvent::GetExplicitOriginalTarget(nsIDOMEventTarget** aRealEventTarget)
return GetTarget(aRealEventTarget); return GetTarget(aRealEventTarget);
} }
NS_IMETHODIMP
nsDOMEvent::GetTmpRealOriginalTarget(nsIDOMEventTarget** aRealEventTarget)
{
if (mTmpRealOriginalTarget) {
*aRealEventTarget = mTmpRealOriginalTarget;
NS_ADDREF(*aRealEventTarget);
return NS_OK;
}
return GetOriginalTarget(aRealEventTarget);
}
NS_IMETHODIMP NS_IMETHODIMP
nsDOMEvent::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget) nsDOMEvent::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget)
{ {

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