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
*/
// Check for styled background color across the row
// Alternating background color is a common way
nsCOMPtr<nsIDOMNodeList> nodeList;
nsCOMPtr<nsIDOMElement> tableElt(do_QueryInterface(mContent));
tableElt->GetElementsByTagName(NS_LITERAL_STRING("tr"), getter_AddRefs(nodeList));
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
PRUint32 length;
nodeList->GetLength(&length);
nsAutoString color, lastRowColor;
for (PRUint32 rowCount = 0; rowCount < length; rowCount ++) {
nsCOMPtr<nsIDOMNode> rowNode;
nodeList->Item(rowCount, getter_AddRefs(rowNode));
nsCOMPtr<nsIContent> rowContent(do_QueryInterface(rowNode));
nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl =
nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), rowContent);
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");
// Check for styled background color across rows (alternating background
// color is a common feature for data tables).
PRUint32 childCount = GetChildCount();
nsAutoString rowColor, prevRowColor;
for (PRUint32 childIdx = 0; childIdx < childCount; childIdx++) {
nsAccessible* child = GetChildAt(childIdx);
if (child->Role() == roles::ROW) {
nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl =
nsCoreUtils::GetComputedStyleDeclaration(EmptyString(),
child->GetContent());
if (styleDecl) {
prevRowColor = rowColor;
styleDecl->GetPropertyValue(NS_LITERAL_STRING("background-color"),
rowColor);
if (childIdx > 0 && !prevRowColor.Equals(rowColor)) {
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);
*aCaretOffset = -1;
if (IsDefunct())
return NS_ERROR_FAILURE;
// Not focused focusable accessible except document accessible doesn't have
// a caret.
if (!IsDoc() && !FocusMgr()->IsFocused(this) &&

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

@ -48,6 +48,7 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
test_ariadialog.html \
test_colorpicker.xul \
test_cssoverflow.html \
test_contextmenu.xul \
test_doc.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/gcc-pr49911.m4)dnl
builtin(include, build/autoconf/frameptr.m4)dnl
builtin(include, build/autoconf/compiler-opts.m4)dnl
MOZ_PROG_CHECKMSYS()

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

@ -426,7 +426,13 @@ pref("media.realtime_decoder.enabled", true);
// by bug 710563.
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
pref("power.screen.timeout", 60);
pref("full-screen-api.enabled", true);
pref("media.volume.steps", 10);

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

@ -8,6 +8,7 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const CC = Components.Constructor;
const Cr = Components.results;
const LocalFile = CC('@mozilla.org/file/local;1',
'nsILocalFile',
@ -25,11 +26,18 @@ XPCOMUtils.defineLazyGetter(Services, 'ss', function() {
return Cc['@mozilla.org/content/style-sheet-service;1']
.getService(Ci.nsIStyleSheetService);
});
XPCOMUtils.defineLazyGetter(Services, 'idle', function() {
return Cc['@mozilla.org/widget/idleservice;1']
.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
// (that is much more restricted) the following code kick-off
// 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('MozApplicationManifest', this);
window.addEventListener("AppCommand", this);
window.addEventListener('mozfullscreenchange', this);
this.contentBrowser.addEventListener('load', this, true);
try {
@ -186,6 +195,24 @@ var shell = {
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) {
switch (evt.type) {
@ -217,8 +244,22 @@ var shell = {
case 'Search':
this.toggleDebug();
break;
case 'VolumeUp':
this.changeVolume(1);
break;
case 'VolumeDown':
this.changeVolume(-1);
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':
this.contentBrowser.removeEventListener('load', this, true);
this.turnScreenOn();
@ -339,3 +380,50 @@ Services.obs.addObserver(function onConsoleAPILogEvent(subject, topic, data) {
" in " + (message.functionName || "anonymous") + ": ";
Services.console.logStringMessage(prefix + Array.join(message.arguments, " "));
}, "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: {
origin: new Point(0, 0),
current: new Point(0 , 0)
},
position: new Point(0 , 0),
onTouchStart: function cp_onTouchStart(evt) {
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.position.origin.set(evt.screenX, evt.screenY);
this.position.current.set(evt.screenX, evt.screenY);
KineticPanning.record(new Point(0, 0));
this.position.set(evt.screenX, evt.screenY);
KineticPanning.record(new Point(0, 0), evt.timeStamp);
},
onTouchEnd: function cp_onTouchEnd(evt) {
@ -197,26 +200,29 @@ const ContentPanning = {
return;
this.dragging = false;
if (this.isPan()) {
if (evt.detail) // The event will generate a click
evt.target.addEventListener('click', this, true);
this.onTouchMove(evt);
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);
}
},
onTouchMove: function cp_onTouchMove(evt) {
if (!this.dragging || !this.scrollCallback)
return;
let current = this.position.current;
let current = this.position;
let delta = new Point(evt.screenX - current.x, evt.screenY - current.y);
current.set(evt.screenX, evt.screenY);
if (this.isPan()) {
KineticPanning.record(delta);
this.scrollCallback(delta.scale(-1));
}
KineticPanning.record(delta, evt.timeStamp);
this.scrollCallback(delta.scale(-1));
},
@ -232,24 +238,11 @@ const ContentPanning = {
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) {
if (!(node instanceof Ci.nsIDOMHTMLElement) || node.tagName == 'HTML')
return null;
let content = node.ownerDocument.defaultView;
while (!(node instanceof Ci.nsIDOMHTMLBodyElement)) {
let style = content.getComputedStyle(node, null);
@ -299,7 +292,7 @@ const kMinVelocity = 0.4;
const kMaxVelocity = 6;
// Constants that affect the "friction" of the scroll pane.
const kExponentialC = 1400;
const kExponentialC = 1000;
const kPolynomialC = 100 / 1000000;
// 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.
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 = {
_position: new Point(0, 0),
_velocity: new Point(0, 0),
_acceleration: new Point(0, 0),
get active() {
return this.target !== null;
},
_target: null,
start: function kp_start(target) {
this.target = target;
// 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);
momentums.forEach(function(momentum) {
@ -338,6 +339,7 @@ const KineticPanning = {
let velocity = this._velocity;
velocity.set(Math.abs(velocityX) < kMinVelocity ? 0 : velocityX,
Math.abs(velocityY) < kMinVelocity ? 0 : velocityY);
this.momentums = [];
// Set acceleration vector to opposite signs of velocity
function sign(x) {
@ -358,20 +360,32 @@ const KineticPanning = {
if (!this.target)
return;
this.momentums.splice(0);
this.momentums = [];
this.target.onKineticEnd();
this.target = null;
},
momentums: [],
record: function kp_record(delta) {
// If the panning direction has changed, stop the current activity.
if (this.target && ((delta.x * this._velocity.x < 0) ||
(delta.y * this._velocity.y < 0)))
this.stop();
record: function kp_record(delta, timestamp) {
this.momentums.push({ 'time': timestamp, 'dx' : delta.x, 'dy' : delta.y });
},
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() {

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

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

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

@ -9053,7 +9053,14 @@ XPCOMUtils.defineLazyGetter(Scratchpad, "ScratchpadManager", function() {
var StyleEditor = {
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_WINDOW_TYPE = "Tools:StyleEditor";
@ -9067,14 +9074,23 @@ var StyleEditor = {
while (enumerator.hasMoreElements()) {
var win = enumerator.getNext();
if (win.styleEditorChrome.contentWindowID == contentWindowID) {
if (aSelectedStyleSheet) {
win.styleEditorChrome.selectStyleSheet(aSelectedStyleSheet, aLine, aCol);
}
win.focus();
return win;
}
}
let args = {
contentWindow: contentWindow,
selectedStyleSheet: aSelectedStyleSheet,
line: aLine,
col: aCol
};
args.wrappedJSObject = args;
let chromeWindow = Services.ww.openWindow(null, CHROME_URL, "_blank",
CHROME_WINDOW_FLAGS,
contentWindow);
CHROME_WINDOW_FLAGS, args);
chromeWindow.focus();
return chromeWindow;
}

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

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

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

@ -536,7 +536,8 @@
if (!this.mBlank) {
if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
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)
@ -1265,6 +1266,12 @@
else {
t._animStartTime = Date.now();
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);
}
@ -1364,7 +1371,8 @@
// pretend the user typed this so it'll be available till
// the document successfully loads
b.userTypedValue = aURI;
if (!isBlankPageURL(aURI))
b.userTypedValue = aURI;
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
if (aAllowThirdPartyFixup)
@ -1556,15 +1564,26 @@
<parameter name="aCloseWindowFastpath"/>
<body>
<![CDATA[
if (aTab.closing || this._windowIsClosing)
if (aTab.closing ||
aTab._pendingPermitUnload ||
this._windowIsClosing)
return false;
var browser = this.getBrowserForTab(aTab);
if (!aTabWillBeMoved) {
let ds = browser.docShell;
if (ds && ds.contentViewer && !ds.contentViewer.permitUnload())
return false;
if (ds && ds.contentViewer) {
// 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;
@ -3983,24 +4002,18 @@
<implementation implements="nsIDOMEventListener">
<constructor><![CDATA[
window.addEventListener("findbaropen", this, false);
window.addEventListener("resize", this, false);
]]></constructor>
<destructor><![CDATA[
window.removeEventListener("findbaropen", this, false);
window.removeEventListener("resize", this, false);
MousePosTracker.removeListener(this);
]]></destructor>
<property name="label">
<setter><![CDATA[
if (!this.label) {
if (window.gFindBarInitialized && !window.gFindBar.hidden)
this.setAttribute("mirror", "true");
else
this.removeAttribute("mirror");
}
if (!this.label)
this.removeAttribute("mirror");
this.style.minWidth = this.getAttribute("type") == "status" &&
this.getAttribute("previoustype") == "status"
@ -4048,10 +4061,6 @@
return;
switch (event.type) {
case "findbaropen":
this.setAttribute("mirror", "true");
this._calcMouseTargetRect();
break;
case "resize":
this._calcMouseTargetRect();
break;
@ -4061,10 +4070,10 @@
<method name="_calcMouseTargetRect">
<body><![CDATA[
let alignRight = (window.gFindBarInitialized && !window.gFindBar.hidden);
let alignRight = false;
if (getComputedStyle(document.documentElement).direction == "rtl")
alighRight = !alignRight;
alignRight = !alignRight;
let rect = this.getBoundingClientRect();
this._mouseTargetRect = {

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

@ -15,24 +15,26 @@ function reallyHandleRequest(request, response) {
// Allow the caller to drive how authentication is processed via the query.
// 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 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;
// user=xxx
match = /user=([^&]*)/.exec(query);
match = /[^_]user=([^&]*)/.exec(query);
if (match)
expected_user = match[1];
// pass=xxx
match = /pass=([^&]*)/.exec(query);
match = /[^_]pass=([^&]*)/.exec(query);
if (match)
expected_pass = match[1];
// realm=xxx
match = /realm=([^&]*)/.exec(query);
match = /[^_]realm=([^&]*)/.exec(query);
if (match)
realm = match[1];
@ -66,6 +68,10 @@ function reallyHandleRequest(request, response) {
if (match)
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.
//
@ -74,8 +80,9 @@ function reallyHandleRequest(request, response) {
// This test only supports Basic auth. The value sent by the client is
// "username:password", obscured with base64 encoding.
var actual_user = "", actual_pass = "", authHeader;
var actual_user = "", actual_pass = "", authHeader, authPresent = false;
if (request.hasHeader("Authorization")) {
authPresent = true;
authHeader = request.getHeader("Authorization");
match = /Basic (.+)/.exec(authHeader);
if (match.length != 2)
@ -115,16 +122,24 @@ function reallyHandleRequest(request, response) {
requestProxyAuth = false;
}
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);
if (anonymous) {
if (authPresent) {
response.setStatusLine("1.0", 400, "Unexpected authorization header found");
} else {
response.setStatusLine("1.0", 200, "Authorization header not found");
}
} 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);

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

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

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

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

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

@ -72,6 +72,7 @@ const Cr = Components.results;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/TelemetryStopwatch.jsm");
const STATE_RUNNING_STR = "running";
const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100 megabytes
@ -127,23 +128,30 @@ SessionStartup.prototype = {
return;
// 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 {
// remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
if (iniString.charAt(0) == '(')
iniString = iniString.slice(1, -1);
this._initialState = JSON.parse(iniString);
}
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 {
this._initialState = JSON.parse(iniString);
}
catch (exJSON) {
var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'});
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 lastSessionCrashed =
@ -154,8 +162,7 @@ SessionStartup.prototype = {
// Report shutdown success via telemetry. Shortcoming here are
// being-killed-by-OS-shutdown-logic, shutdown freezing after
// session restore was written, etc.
let Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
Telemetry.getHistogramById("SHUTDOWN_OK").add(!lastSessionCrashed);
Services.telemetry.getHistogramById("SHUTDOWN_OK").add(!lastSessionCrashed);
// set the startup type
if (lastSessionCrashed && resumeFromCrash)
@ -296,9 +303,11 @@ SessionStartup.prototype = {
* @returns a session state string
*/
_readStateFile: function sss_readStateFile(aFile) {
TelemetryStopwatch.start("FX_SESSION_RESTORE_READ_FILE_MS");
var stateString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
stateString.data = this._readFile(aFile) || "";
TelemetryStopwatch.finish("FX_SESSION_RESTORE_READ_FILE_MS");
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:///modules/TelemetryTimestamps.jsm");
Cu.import("resource:///modules/TelemetryStopwatch.jsm");
XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
Cu.import("resource://gre/modules/NetUtil.jsm");
@ -3653,6 +3654,8 @@ SessionStoreService.prototype = {
// if we 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);
if (!oState)
return;
@ -3691,6 +3694,8 @@ SessionStoreService.prototype = {
if (this._lastSessionState)
oState.lastSessionState = this._lastSessionState;
TelemetryStopwatch.finish("FX_SESSION_RESTORE_COLLECT_DATA_MS");
this._saveStateObject(oState);
},
@ -3698,9 +3703,11 @@ SessionStoreService.prototype = {
* write a state object to disk
*/
_saveStateObject: function sss_saveStateObject(aStateObj) {
TelemetryStopwatch.start("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
var stateString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
stateString.data = this._toJSONString(aStateObj);
TelemetryStopwatch.finish("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
Services.obs.notifyObservers(stateString, "sessionstore-state-write", "");
@ -3809,7 +3816,7 @@ SessionStoreService.prototype = {
argString.data = "";
// Build feature string
let features = "chrome,dialog=no,all";
let features = "chrome,dialog=no,macsuppressanimation,all";
let winState = aState.windows[0];
WINDOW_ATTRIBUTES.forEach(function(aFeature) {
// Use !isNaN as an easy way to ignore sizemode and check for numbers
@ -4427,6 +4434,7 @@ SessionStoreService.prototype = {
* String data
*/
_writeFile: function sss_writeFile(aFile, aData) {
TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_MS");
// Initialize the file output stream.
var ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
@ -4442,6 +4450,7 @@ SessionStoreService.prototype = {
var self = this;
NetUtil.asyncCopy(istream, ostream, function(rc) {
if (Components.isSuccessCode(rc)) {
TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_MS");
Services.obs.notifyObservers(null,
"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_update-editor-mode.js \
browser_dbg_select-line.js \
browser_dbg_clean-exit.js \
head.js \
$(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,
"The correct script was loaded initially.");
// getCaretPosition is 0-based.
is(gDebugger.editor.getCaretPosition().line, 5,
"The correct line is selected.");
// Yield control back to the event loop so that the debugger has a
// chance to highlight the proper line.
executeSoon(function(){
// getCaretPosition is 0-based.
is(gDebugger.editor.getCaretPosition().line, 5,
"The correct line is selected.");
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
function onChange() {
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
onChange);
ok(gDebugger.editor.getText().search(/debugger/) == -1,
"The second script is no longer displayed.");
gDebugger.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
function onChange() {
gDebugger.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
onChange);
ok(gDebugger.editor.getText().search(/debugger/) == -1,
"The second script is no longer displayed.");
ok(gDebugger.editor.getText().search(/firstCall/) != -1,
"The first script is displayed.");
ok(gDebugger.editor.getText().search(/firstCall/) != -1,
"The first script is displayed.");
// Yield control back to the event loop so that the debugger has a
// chance to highlight the proper line.
executeSoon(function(){
// getCaretPosition is 0-based.
is(gDebugger.editor.getCaretPosition().line, 4,
"The correct line is selected.");
// Yield control back to the event loop so that the debugger has a
// chance to highlight the proper line.
executeSoon(function(){
// getCaretPosition is 0-based.
is(gDebugger.editor.getCaretPosition().line, 4,
"The correct line is selected.");
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
gDebugger.StackFrames.activeThread.resume(function() {
removeTab(gTab);
finish();
});
});
});
});
// Click the oldest stack frame.
let element = gDebugger.document.getElementById("stackframe-3");
EventUtils.synthesizeMouseAtCenter(element, {}, gDebugger);
// Click the oldest stack frame.
let element = gDebugger.document.getElementById("stackframe-3");
EventUtils.synthesizeMouseAtCenter(element, {}, gDebugger);
});
}}, 0);
});

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

@ -763,6 +763,9 @@ InspectorUI.prototype = {
this.boundRuleViewChanged = this.ruleViewChanged.bind(this);
this.ruleView.element.addEventListener("CssRuleViewChanged",
this.boundRuleViewChanged);
this.cssRuleViewBoundCSSLinkClicked = this.ruleViewCSSLinkClicked.bind(this);
this.ruleView.element.addEventListener("CssRuleViewCSSLinkClicked",
this.cssRuleViewBoundCSSLinkClicked);
doc.documentElement.appendChild(this.ruleView.element);
this.ruleView.highlight(this.selection);
@ -800,6 +803,30 @@ InspectorUI.prototype = {
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.
*/
@ -811,6 +838,8 @@ InspectorUI.prototype = {
if (this.ruleView) {
this.ruleView.element.removeEventListener("CssRuleViewChanged",
this.boundRuleViewChanged);
this.ruleView.element.removeEventListener("CssRuleViewCSSLinkClicked",
this.cssRuleViewBoundCSSLinkClicked);
delete boundRuleViewChanged;
this.ruleView.clear();
delete this.ruleView;

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

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

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

@ -78,6 +78,9 @@ const ORION_EVENTS = {
Selection: "Selection",
Focus: "Focus",
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.
*/
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_bug650345_find.js \
browser_bug703692_focus_blur.js \
browser_bug725388_mouse_events.js \
head.js \
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()
{
assert(this._styleSheet, "StyleSheet must be loaded first.")
assert(this._styleSheet, "StyleSheet must be loaded first.");
return this._styleSheet;
},
@ -921,9 +921,11 @@ StyleEditor.prototype = {
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
for (let i = 0; i < this._actionListeners.length; ++i) {
let listener = this._actionListeners[i];
for (let i = 0; i < listeners.length; ++i) {
let listener = listeners[i];
let actionHandler = listener["on" + aName];
if (actionHandler) {
actionHandler.apply(listener, aArgs);

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

@ -270,9 +270,11 @@ StyleEditorChrome.prototype = {
aArgs.unshift(this);
}
// trigger all listeners that have this named handler
for (let i = 0; i < this._listeners.length; ++i) {
let listener = this._listeners[i];
// copy the list of listeners to allow adding/removing listeners in handlers
let listeners = this._listeners.concat();
// 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];
if (handler) {
handler.apply(listener, aArgs);
@ -329,10 +331,10 @@ StyleEditorChrome.prototype = {
{
this._resetChrome();
this._document.title = _("chromeWindowTitle",
this.contentDocument.title || this.contentDocument.location.href);
let document = this.contentDocument;
this._document.title = _("chromeWindowTitle",
document.title || document.location.href);
for (let i = 0; i < document.styleSheets.length; ++i) {
let styleSheet = document.styleSheets[i];
@ -352,6 +354,79 @@ StyleEditorChrome.prototype = {
}, 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.
* This is automatically called when no content window is attached.
@ -455,9 +530,8 @@ StyleEditorChrome.prototype = {
}
}, false);
// autofocus the first or new stylesheet
if (editor.styleSheetIndex == 0 ||
editor.hasFlag(StyleEditorFlags.NEW)) {
// autofocus new stylesheets
if (editor.hasFlag(StyleEditorFlags.NEW)) {
this._view.activeSummary = aSummary;
}

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

@ -132,8 +132,10 @@
<xul:script type="application/javascript"><![CDATA[
Components.utils.import("resource:///modules/devtools/StyleEditorChrome.jsm");
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);
chrome.selectStyleSheet(args.selectedStyleSheet, args.line, args.col);
window.styleEditorChrome = chrome;
]]></xul:script>
</xul:window>

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

@ -51,6 +51,7 @@ _BROWSER_TEST_FILES = \
browser_styleeditor_init.js \
browser_styleeditor_loading.js \
browser_styleeditor_new.js \
browser_styleeditor_passedinsheet.js \
browser_styleeditor_pretty.js \
browser_styleeditor_readonly.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") {
gChromeWindow.addEventListener("load", function onChromeLoad() {
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.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
launchStyleEditorChrome(aCallback);
launchStyleEditorChrome(aCallback, aSheet, aLine, aCol);
}, true);
}

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

@ -273,6 +273,7 @@ CssHtmlTree.prototype = {
this._matchedProperties = null;
if (this.htmlComplete) {
this.refreshSourceFilter();
this.refreshPanel();
} else {
if (this._refreshProcess) {
@ -281,6 +282,9 @@ CssHtmlTree.prototype = {
CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
// Refresh source filter ... this must be done after templateRoot has been
// processed.
this.refreshSourceFilter();
this.numVisibleProperties = 0;
let fragment = this.doc.createDocumentFragment();
this._refreshProcess = new UpdateProcess(this.win, CssHtmlTree.propertyNames, {
@ -362,21 +366,28 @@ CssHtmlTree.prototype = {
},
/**
* The change event handler for the onlyUserStyles checkbox. When
* 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.
* The change event handler for the onlyUserStyles checkbox.
*
* @param {Event} aEvent the DOM Event object.
*/
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.cssLogic.sourceFilter = this.showOnlyUserStyles ?
CssLogic.FILTER.ALL :
CssLogic.FILTER.UA;
this.refreshPanel();
},
/**
@ -974,4 +985,24 @@ SelectorView.prototype = {
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.
this.forEachSheet(function(aSheet) {
aSheet._sheetAllowed = -1;
if (!aSheet.systemSheet && aSheet.sheetAllowed) {
if (aSheet.contentSheet && aSheet.sheetAllowed) {
ruleCount += aSheet.ruleCount;
}
}, this);
@ -345,7 +345,7 @@ CssLogic.prototype = {
let sheets = [];
this.forEachSheet(function (aSheet) {
if (!aSheet.systemSheet) {
if (aSheet.contentSheet) {
sheets.push(aSheet);
}
}, this);
@ -395,7 +395,7 @@ CssLogic.prototype = {
}
sheet = new CssSheet(this, aDomSheet, aIndex);
if (sheet.sheetAllowed && !sheet.systemSheet) {
if (sheet.sheetAllowed && sheet.contentSheet) {
this._ruleCount += sheet.ruleCount;
}
@ -569,7 +569,7 @@ CssLogic.prototype = {
this.forEachSheet(function (aSheet) {
// We do not show unmatched selectors from system stylesheets
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
if (!aSheet.contentSheet || aSheet.disabled || !aSheet.mediaMatches) {
return;
}
@ -664,7 +664,7 @@ CssLogic.prototype = {
sheet._passId = this._passId;
}
if (filter !== CssLogic.FILTER.UA && sheet.systemSheet) {
if (filter === CssLogic.FILTER.ALL && !sheet.contentSheet) {
continue;
}
@ -710,7 +710,7 @@ CssLogic.prototype = {
let result = {};
this.forSomeSheets(function (aSheet) {
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
if (!aSheet.contentSheet || aSheet.disabled || !aSheet.mediaMatches) {
return false;
}
@ -865,29 +865,23 @@ XPCOMUtils.defineLazyGetter(CssLogic, "_strings", function() Services.strings
.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
* @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.
*/
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;
}
let url = aSheet.href;
if (!url) return false;
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;
// If the sheet has a CSSImportRule we need to check the parent stylesheet.
if (aSheet.ownerRule instanceof Ci.nsIDOMCSSImportRule) {
return CssLogic.isContentStylesheet(aSheet.parentStyleSheet);
}
return false;
};
@ -942,7 +936,7 @@ function CssSheet(aCssLogic, aDomSheet, aIndex)
{
this._cssLogic = aCssLogic;
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.
this._href = null;
@ -960,21 +954,21 @@ function CssSheet(aCssLogic, aDomSheet, aIndex)
CssSheet.prototype = {
_passId: null,
_systemSheet: null,
_contentSheet: null,
_mediaMatches: null,
/**
* 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.
*/
get systemSheet()
get contentSheet()
{
if (this._systemSheet === null) {
this._systemSheet = CssLogic.isSystemStyleSheet(this.domSheet);
if (this._contentSheet === null) {
this._contentSheet = CssLogic.isContentStylesheet(this.domSheet);
}
return this._systemSheet;
return this._contentSheet;
},
/**
@ -1048,7 +1042,7 @@ CssSheet.prototype = {
this._sheetAllowed = true;
let filter = this._cssLogic.sourceFilter;
if (filter === CssLogic.FILTER.ALL && this.systemSheet) {
if (filter === CssLogic.FILTER.ALL && !this.contentSheet) {
this._sheetAllowed = false;
}
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.source = this._cssSheet.shortSource + ":" + this.line;
this.href = this._cssSheet.href;
this.systemRule = this._cssSheet.systemSheet;
this.contentRule = this._cssSheet.contentSheet;
} else if (aElement) {
this._selectors = [ new CssSelector(this, "@element.style") ];
this.line = -1;
this.source = CssLogic.l10n("rule.sourceElement");
this.href = "#";
this.systemRule = false;
this.contentRule = true;
this.sourceElement = aElement;
}
}
@ -1396,12 +1390,12 @@ CssSelector.prototype = {
/**
* 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.
*/
get systemRule()
get contentRule()
{
return this._cssRule.systemRule;
return this._cssRule.contentRule;
},
/**
@ -1794,12 +1788,12 @@ function CssSelectorInfo(aSelector, aProperty, aValue, aStatus)
4 important
5 inline important
*/
let scorePrefix = this.systemRule ? 0 : 2;
let scorePrefix = this.contentRule ? 2 : 0;
if (this.elementStyle) {
scorePrefix++;
}
if (this.important) {
scorePrefix += this.systemRule ? 1 : 2;
scorePrefix += this.contentRule ? 2 : 1;
}
this.specificityScore = "" + scorePrefix + this.specificity.ids +
@ -1902,9 +1896,9 @@ CssSelectorInfo.prototype = {
* @return {boolean} true if the selector comes from a browser-provided
* 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)
{
if (this.systemRule && !aThat.systemRule) return 1;
if (!this.systemRule && aThat.systemRule) return -1;
if (!this.contentRule && aThat.contentRule) return 1;
if (this.contentRule && !aThat.contentRule) return -1;
if (this.elementStyle && !aThat.elementStyle) {
if (!this.important && aThat.important) return 1;

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

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

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

@ -59,11 +59,19 @@ _BROWSER_TEST_FILES = \
browser_ruleview_manipulation.js \
browser_ruleview_override.js \
browser_ruleview_ui.js \
browser_bug705707_is_content_stylesheet.js \
head.js \
$(NULL)
_BROWSER_TEST_PAGES = \
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)
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 = [];
/**

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

@ -129,3 +129,23 @@ breakdelRemoved=Breakpoint removed
# '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.
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/content/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

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

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

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

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

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

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

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

@ -84,7 +84,7 @@ DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DAPP_BUILDID=$(APP_BUILDID)
DEFINES += -DMOZ_APP_VERSION="$(MOZ_APP_VERSION)"
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
DEFINES += -DMOZ_SOURCE_STAMP="$(MOZ_SOURCE_STAMP)"
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;
public interface Actions {
public enum SpecialKey {
DOWN, UP, LEFT, RIGHT, ENTER, MENU, BACK
}
public interface EventExpecter {
/** Blocks until the event has been received. Subsequent calls will return immediately. */
public void blockForEvent();
/** Polls to see if the event has been received. Once this returns true, subsequent calls will also return true. */
public boolean eventReceived();
}
/** Special keys supported by sendSpecialKey() */
public enum SpecialKey {
DOWN, UP, LEFT, RIGHT, ENTER, MENU, BACK
}
public interface RepeatedEventExpecter extends EventExpecter {
/** Blocks until at least one event has been received, and no events have been received in the last <code>millis</code> milliseconds. */
public void blockUntilClear(long millis);
}
public interface EventExpecter {
/** Blocks until the event has been received. Subsequent calls will return immediately. */
public void blockForEvent();
/**
* Listens for a gecko event to be sent from the Gecko instance.
* 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);
/** Polls to see if the event has been received. Once this returns true, subsequent calls will also return true. */
public boolean eventReceived();
}
/**
* 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();
public interface RepeatedEventExpecter extends EventExpecter {
/** Blocks until at least one event has been received, and no events have been received in the last <code>millis</code> milliseconds. */
public void blockUntilClear(long millis);
}
// Send the string kewsToSend to the application
void sendKeys(String keysToSend);
//Send any of the above keys to the element
void sendSpecialKey(SpecialKey button);
/**
* Listens for a gecko event to be sent from the Gecko instance.
* 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);
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@;
public interface Assert {
void dumpLog(String message);
void setLogFile(String filename);
void setTestName(String testName);
void dumpLog(String message);
void setLogFile(String filename);
void setTestName(String testName);
void finalize();
void ok(boolean condition, String name, String diag);
void is(Object a, Object b, String name);
void isnot(Object a, Object b, String name);
void todo(boolean condition, String name, String diag);
void todo_is(Object a, Object b, String name);
void todo_isnot(Object a, Object b, String name);
void info(String name, String message);
void finalize();
void ok(boolean condition, String name, String diag);
void is(Object a, Object b, String name);
void isnot(Object a, Object b, String name);
void todo(boolean condition, String name, String diag);
void todo_is(Object a, Object b, String name);
void todo_isnot(Object a, Object b, String name);
void info(String name, String message);
// robocop-specific asserts
void ispixel(int actual, int r, int g, int b, String name);
// robocop-specific asserts
void ispixel(int actual, int r, int g, int b, String name);
}

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

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

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

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

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

@ -38,202 +38,194 @@
package @ANDROID_PACKAGE_NAME@;
import java.util.LinkedList;
import java.util.List;
import java.util.Date;
import android.os.SystemClock;
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
private int lineNumber = 0;
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
private String mLogTestName = "";
// Used to write the test-start/test-end log lines
private String logTestName = "";
// Measure the time it takes to run test case
private long mStartTime = 0;
// Measure the time it takes to run test case
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;
public FennecMochitestAssert() {
}
if (logTestName != "") {
long diff = (new Date().getTime()) - startTime;
message = Integer.toString(lineNumber++) + " INFO TEST-END | " + logTestName;
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;
/** 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);
private void _logMochitestResult(testInfo test, String passString, String failString)
{
boolean isError = true;
String resultString = failString;
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;
if (!mLogStarted) {
dumpLog(Integer.toString(mLineNumber++) + " INFO SimpleTest START");
mLogStarted = true;
}
String message = Integer.toString(lineNumber++) + " INFO " + resultString + " | " + logTestName + " | " + diag;
dumpLog(message);
if (test.todo) {
todo++;
} else if (isError) {
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 = "";
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(lineNumber++) + " INFO TEST-START | Shutdown";
dumpLog(message);
message = Integer.toString(lineNumber++) + " INFO Passed: " + Integer.toString(passed);
dumpLog(message);
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 setTestName(String testName) {
String[] nameParts = testName.split("\\.");
mLogTestName = nameParts[nameParts.length - 1];
mStartTime = SystemClock.uptimeMillis();
public void ok(boolean condition, String name, String diag) {
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();
dumpLog(Integer.toString(mLineNumber++) + " INFO TEST-START | " + mLogTestName);
}
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();
class testInfo {
public boolean mResult;
public String mName;
public String mDiag;
public boolean mTodo;
public testInfo(boolean r, String n, String d, boolean t) {
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) {
// 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 + ")");
}
private void _logMochitestResult(testInfo test, String passString, String failString) {
boolean isError = true;
String resultString = failString;
if (test.mResult || test.mTodo) {
isError = false;
}
if (test.mResult)
{
resultString = passString;
}
String diag = test.mName;
if (test.mDiag != null) diag += " - " + test.mDiag;
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");
testList.add(test);
}
String message = Integer.toString(mLineNumber++) + " INFO " + resultString + " | " + mLogTestName + " | " + diag;
dumpLog(message);
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();
if (test.mTodo) {
mTodo++;
} else if (isError) {
mFailed++;
} 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) {
testInfo test = new testInfo(true, name, message, false);
_logMochitestResult(test, "TEST-INFO", "INFO FAILED?");
}
public void finalize() {
// It appears that we call finalize during cleanup, this might be an invalid assertion.
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;
public class FennecNativeActions implements Actions {
private Solo solo;
private Instrumentation instr;
private Activity geckoApp;
private Solo mSolo;
private Instrumentation mInstr;
private Activity mGeckoApp;
// Objects for reflexive access of fennec classes.
private ClassLoader classLoader;
private Class gel;
private Class ge;
private Class gas;
private Class drawListener;
private Method registerGEL;
private Method unregisterGEL;
private Method sendGE;
private Method getLayerClient;
private Method setDrawListener;
// Objects for reflexive access of fennec classes.
private ClassLoader mClassLoader;
private Class mGel;
private Class mGe;
private Class mGas;
private Class mDrawListener;
private Method mRegisterGEL;
private Method mUnregisterGEL;
private Method mSendGE;
private Method mGetLayerClient;
private Method mSetDrawListener;
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation){
this.solo = robocop;
this.instr = instrumentation;
this.geckoApp = activity;
// 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) {
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation) {
mSolo = robocop;
mInstr = instrumentation;
mGeckoApp = activity;
// Set up reflexive access of java classes and methods.
try {
this.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
mClassLoader = activity.getClassLoader();
mGel = mClassLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
mGe = mClassLoader.loadClass("org.mozilla.gecko.GeckoEvent");
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() {
return mEventReceived;
}
class GeckoEventExpecter implements EventExpecter {
private final String mGeckoEvent;
private final Object[] mRegistrationParams;
private boolean mEventReceived;
void notifyOfEvent() {
try {
unregisterGEL.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 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;
}
GeckoEventExpecter(String geckoEvent, Object[] registrationParams) {
mGeckoEvent = geckoEvent;
mRegistrationParams = registrationParams;
}
class DrawListenerProxy implements InvocationHandler {
private final PaintExpecter mPaintExpecter;
public synchronized void blockForEvent() {
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) {
mPaintExpecter = paintExpecter;
public synchronized boolean eventReceived() {
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) {
String methodName = method.getName();
if ("drawFinished".equals(methodName)) {
public EventExpecter expectGeckoEvent(String geckoEvent) {
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;
}
}
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) {
"waiting for "+geckoEvent);
try {
this.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
Class [] interfaces = new Class[1];
interfaces[0] = mGel;
Object[] finalParams = new Object[2];
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();
}
}
try {
setDrawListener.invoke(mLayerClient, (Object)null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public synchronized boolean eventReceived() {
return mPaintDone;
class DrawListenerProxy implements InvocationHandler {
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) {
if (millis <= 0) {
throw new IllegalArgumentException("millis must be > 0");
}
// wait for at least one event
while (! mPaintDone) {
class PaintExpecter implements RepeatedEventExpecter {
private Object mLayerClient;
private boolean mPaintDone;
PaintExpecter() throws IllegalAccessException, InvocationTargetException {
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 {
this.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
return new PaintExpecter();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 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;
}
public void sendSpecialKey(SpecialKey button) {
switch(button) {
case DOWN:
mInstr.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
break;
case UP:
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() {
try {
return new PaintExpecter();
} catch (Exception e) {
e.printStackTrace();
return null;
@Override
public void sendKeys(String input) {
mInstr.sendStringSync(input);
}
}
public void sendSpecialKey(SpecialKey button) {
switch( button) {
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;
public void drag(int startingX, int endingX, int startingY, int endingY) {
mSolo.drag(startingX, endingX, startingY, endingY, 10);
}
}
@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.IOException;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.List;
@ -68,396 +66,405 @@ import org.json.*;
import com.jayway.android.robotium.solo.Solo;
public class FennecNativeDriver implements Driver {
// Map of IDs to element names.
private HashMap locators = null;
private Activity activity;
private Solo solo;
// Map of IDs to element names.
private HashMap mLocators = null;
private Activity mActivity;
private Solo mSolo;
private static String mLogFile = null;
private static LogLevel mLogLevel = LogLevel.LOG_LEVEL_INFO;
private static String mLogFile = null;
private static LogLevel mLogLevel = LogLevel.LOG_LEVEL_INFO;
// Objects for reflexive access of fennec classes.
private ClassLoader classLoader;
private Class gel;
private Class ge;
private Class gas;
private Method registerGEL;
private Method unregisterGEL;
private Method sendGE;
private Method _startFrameRecording;
private Method _stopFrameRecording;
private Method _startCheckerboardRecording;
private Method _stopCheckerboardRecording;
private Method _getPixels;
// Objects for reflexive access of fennec classes.
private ClassLoader mClassLoader;
private Class mGel;
private Class mGe;
private Class mGas;
private Method mRegisterGEL;
private Method mUnregisterGEL;
private Method mSendGE;
private Method _startFrameRecording;
private Method _stopFrameRecording;
private Method _startCheckerboardRecording;
private Method _stopCheckerboardRecording;
private Method _getPixels;
public enum LogLevel {
LOG_LEVEL_DEBUG(1),
LOG_LEVEL_INFO(2),
LOG_LEVEL_WARN(3),
LOG_LEVEL_ERROR(4);
public enum LogLevel {
LOG_LEVEL_DEBUG(1),
LOG_LEVEL_INFO(2),
LOG_LEVEL_WARN(3),
LOG_LEVEL_ERROR(4);
private int mValue;
LogLevel(int 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++;
private int mValue;
LogLevel(int value) {
mValue = value;
}
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 : 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");
public boolean isEnabled(LogLevel configuredLevel) {
return mValue >= configuredLevel.getValue();
}
private int getValue() {
return mValue;
}
} 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,
// and returns a string version of the entire file.
public static String getFile(String filename)
{
StringBuilder text = new StringBuilder();
// Set up table of fennec_ids.
mLocators = convertTextToTable(getFile("/mnt/sdcard/fennec_ids.txt"));
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 {
// Set up reflexive access of java classes and methods.
try {
if (bw != null) {
bw.flush();
bw.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
mClassLoader = activity.getClassLoader();
mGel = mClassLoader.loadClass("org.mozilla.gecko.GeckoEventListener");
mGe = mClassLoader.loadClass("org.mozilla.gecko.GeckoEvent");
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);
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) {
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);
//Information on the location of the Gecko Frame.
private boolean mGeckoInfo = false;
private int mGeckoTop = 100;
private int mGeckoLeft = 0;
private int mGeckoHeight= 700;
private int mGeckoWidth = 1024;
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 android.app.Activity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@ -55,110 +54,110 @@ import com.jayway.android.robotium.solo.Solo;
import java.util.concurrent.SynchronousQueue;
public class FennecNativeElement implements Element {
private final Activity mActivity;
private Integer id;
private Solo robocop;
private final Activity mActivity;
private Integer mId;
private Solo mSolo;
public FennecNativeElement(Integer id, Activity activity, Solo solo){
this.id = id;
mActivity = activity;
robocop = 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();
public FennecNativeElement(Integer id, Activity activity, Solo solo) {
mId = id;
mActivity = activity;
mSolo = solo;
}
}
private Object text;
public Integer getId() {
return mId;
}
public String getText() {
final SynchronousQueue syncQueue = new SynchronousQueue();
mActivity.runOnUiThread(
new Runnable() {
public void run() {
View v = mActivity.findViewById(id);
if(v instanceof EditText) {
EditText et = (EditText)v;
text = et.getEditableText();
}else if(v instanceof TextSwitcher) {
TextSwitcher ts = (TextSwitcher)v;
ts.getNextView();
text = ((TextView)ts.getCurrentView()).getText();
}else if(v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup)v;
for(int i = 0; i < vg.getChildCount(); i++) {
if(vg.getChildAt(i) instanceof TextView) {
text = ((TextView)vg.getChildAt(i)).getText();
public void click() {
final SynchronousQueue syncQueue = new SynchronousQueue();
mActivity.runOnUiThread(
new Runnable() {
public void run() {
View view = (View)mActivity.findViewById(mId);
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 "+mId);
}
syncQueue.offer(new Object());
}
} //end of for
} else if(v instanceof TextView) {
text = ((TextView)v).getText();
} else if(v == null) {
throw new RoboCopException("getText: unable to find view "+id);
} 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();
});
try {
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() {
final SynchronousQueue syncQueue = new SynchronousQueue();
displayed = false;
mActivity.runOnUiThread(
new Runnable() {
public void run() {
View view = (View)mActivity.findViewById(id);
if(view != null) {
displayed = true;
}
syncQueue.offer(new Object());
}
});
try {
syncQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
public String getText() {
final SynchronousQueue syncQueue = new SynchronousQueue();
mActivity.runOnUiThread(
new Runnable() {
public void run() {
View v = mActivity.findViewById(mId);
if (v instanceof EditText) {
EditText et = (EditText)v;
mText = et.getEditableText();
} else if (v instanceof TextSwitcher) {
TextSwitcher ts = (TextSwitcher)v;
ts.getNextView();
mText = ((TextView)ts.getCurrentView()).getText();
} else if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup)v;
for (int i = 0; i < vg.getChildCount(); i++) {
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 FennecTalosAssert() {
}
public FennecTalosAssert() { }
// Write information to a logfile and logcat
public void dumpLog(String message)
{
FennecNativeDriver.log(FennecNativeDriver.LogLevel.LOG_LEVEL_INFO, message);
}
/**
* 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);
}
/**
* Set the filename used for dumpLog.
*/
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 isnot(Object a, Object b, String name) {
}
public void ispixel(int actual, int r, int g, int 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 todo_isnot(Object a, Object b, String name) {
}
public void info(String name, String message) {
}
public void info(String name, String message) { }
}

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

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

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

@ -1,5 +1,18 @@
#!/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 os
import os.path
@ -33,17 +46,21 @@ def patch(patch, plevel, srcdir):
check_run(['patch', '-d', srcdir, '-p%s' % plevel, '-i', patch, '--fuzz=0',
'-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)
run_in(package_build_dir,
["%s/configure" % package_source_dir] + configure_args)
run_in(package_build_dir, ["make", "-j8"])
run_in(package_build_dir, ["make", "install"])
run_in(package_build_dir, [make, "-j8"])
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'
build_package(tar_source_dir, tar_build_dir,
["--prefix=%s" % tar_inst_dir])
["--prefix=%s" % aux_inst_dir])
def with_env(env, f):
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):
return source_dir + '/' + prefix + version
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"
make_version = "3.81"
gcc_version = "4.5.2"
mpfr_version = "2.4.2"
gmp_version = "5.0.1"
@ -159,6 +168,8 @@ glibc_source_uri = "http://ftp.gnu.org/gnu/glibc/glibc-%s.tar.bz2" % \
glibc_version
tar_source_uri = "http://ftp.gnu.org/gnu/tar/tar-%s.tar.bz2" % \
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_version, gcc_version)
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)
glibc_source_tar = download_uri(glibc_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)
mpfr_source_tar = download_uri(mpfr_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)
glibc_source_dir = build_source_dir('glibc-', glibc_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)
mpfr_source_dir = build_source_dir('mpfr-', mpfr_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)
run_in(glibc_source_dir, ["autoconf"])
extract(tar_source_tar, source_dir)
extract(make_source_tar, source_dir)
extract(mpc_source_tar, source_dir)
extract(mpfr_source_tar, source_dir)
extract(gmp_source_tar, source_dir)
@ -203,19 +217,18 @@ if os.path.exists(build_dir):
shutil.rmtree(build_dir)
os.makedirs(build_dir)
tar_inst_dir = build_dir + '/tar_inst'
build_tar(build_dir, tar_inst_dir)
build_aux_tools(build_dir)
stage1_dir = build_dir + '/stage1'
build_one_stage({"CC": "gcc", "CXX" : "g++"}, stage1_dir, True)
stage1_tool_inst_dir = stage1_dir + '/inst'
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++",
"AR" : stage1_tool_inst_dir + "/bin/ar",
"RANLIB" : "true" },
stage2_dir, False)
build_tar_package(tar_inst_dir + "/bin/tar",
build_tar_package(aux_inst_dir + "/bin/tar",
"toolchain.tar", stage2_dir, "inst")

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

@ -1,7 +1,22 @@
diff -ru a/configure.in b/configure.in
--- a/configure.in 2011-01-17 23:34:07.000000000 -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
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
--- a/csu/Makefile 2011-01-17 23:34:07.000000000 -0500
+++ b/csu/Makefile 2012-01-23 13:58:28.957792633 -0500
@@ -234,8 +234,7 @@
@@ -223,8 +223,7 @@
if [ -z "$$os" ]; then \
os=Linux; \
fi; \
@ -22,10 +37,58 @@ diff -ru a/csu/Makefile b/csu/Makefile
*) ;; \
esac; \
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
--- a/Makerules 2011-01-17 23:34:07.000000000 -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 ' the static library, so try that secondarily. */';\
cat $<; \

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

@ -57,7 +57,6 @@ MOZ_PROFILE_MIGRATOR = @MOZ_PROFILE_MIGRATOR@
MOZ_EXTENSION_MANAGER = @MOZ_EXTENSION_MANAGER@
MOZ_APP_UA_NAME = @MOZ_APP_UA_NAME@
MOZ_APP_VERSION = @MOZ_APP_VERSION@
MOZ_UA_BUILDID = @MOZ_UA_BUILDID@
MOZ_MACBUNDLE_NAME = @MOZ_MACBUNDLE_NAME@
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_X86_ASM = @LIBJPEG_TURBO_X86_ASM@
LIBJPEG_TURBO_X64_ASM = @LIBJPEG_TURBO_X64_ASM@
LIBJPEG_TURBO_ARM_ASM = @LIBJPEG_TURBO_ARM_ASM@
NS_PRINTING = @NS_PRINTING@
MOZ_PDF_PRINTING = @MOZ_PDF_PRINTING@
MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@

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

@ -35,7 +35,7 @@
#
# ***** END LICENSE BLOCK *****
import sys, os, subprocess, struct
import sys, os, subprocess, struct, re
local_file_header = [
("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]
exit(1)
jar_regex = re.compile("\\.jar?$")
def optimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR):
ls = os.listdir(IN_JAR_DIR)
for jarfile in ls:
if not jarfile.endswith(".jar"):
if not re.search(jar_regex, jarfile):
continue
injarfile = os.path.join(IN_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)
for jarfile in ls:
if not jarfile.endswith(".jar"):
if not re.search(jar_regex, jarfile):
continue
injarfile = os.path.join(IN_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
AC_MSG_ERROR([--with-l10n-base must specify a path])
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
AC_MSG_ERROR([Invalid value --with-l10n-base, $L10NBASEDIR doesn't exist])
fi
@ -3336,6 +3343,7 @@ AC_SUBST(WRAP_SYSTEM_INCLUDES)
AC_SUBST(VISIBILITY_FLAGS)
MOZ_GCC_PR49911
MOZ_COMPILER_OPTS
dnl Check for __force_align_arg_pointer__ for SSE2 on gcc
dnl ========================================================
@ -4084,6 +4092,56 @@ if test "$ac_cv_thread_keyword" = yes -a "$MOZ_LINKER" != 1; then
esac
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
MALLOC_H=
@ -4605,6 +4663,7 @@ LIBJPEG_TURBO_AS=
LIBJPEG_TURBO_ASFLAGS=
LIBJPEG_TURBO_X86_ASM=
LIBJPEG_TURBO_X64_ASM=
LIBJPEG_TURBO_ARM_ASM=
MOZ_PANGO=1
MOZ_PERMISSIONS=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_X64_ASM=1
;;
*:arm*)
LIBJPEG_TURBO_ASFLAGS="-march=armv7-a -mfpu=neon"
LIBJPEG_TURBO_ARM_ASM=1
;;
esac
fi
dnl If we're on a system which supports libjpeg-turbo's asm routines and
dnl --disable-libjpeg-turbo wasn't passed, check for yasm, and error out if it
dnl doesn't exist or we have too old of a version.
dnl If we're on an x86 or x64 system which supports libjpeg-turbo's asm routines
dnl and --disable-libjpeg-turbo wasn't passed, check for Yasm, and error out if
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
AC_MSG_CHECKING([for YASM assembler])
AC_MSG_CHECKING([for Yasm assembler])
AC_CHECK_PROGS(LIBJPEG_TURBO_AS, yasm, "")
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
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.
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
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
else
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
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
AC_DEFINE(LIBJPEG_TURBO_X86_ASM)
elif test -n "$LIBJPEG_TURBO_X64_ASM"; then
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
dnl Warn if we're not building the optimized routines, even though the user
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(FIREFOX_VERSION,$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
# a libxul SDK.
@ -8736,6 +8806,7 @@ AC_SUBST(LIBJPEG_TURBO_AS)
AC_SUBST(LIBJPEG_TURBO_ASFLAGS)
AC_SUBST(LIBJPEG_TURBO_X86_ASM)
AC_SUBST(LIBJPEG_TURBO_X64_ASM)
AC_SUBST(LIBJPEG_TURBO_ARM_ASM)
AC_MSG_CHECKING([for posix_fallocate])
AC_TRY_LINK([#define _XOPEN_SOURCE 600
@ -9070,7 +9141,11 @@ if test -z "$MOZ_NATIVE_NSPR"; then
_SAVE_CPPFLAGS="$CPPFLAGS"
export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS"
fi
_SAVE_LDFLAGS="$LDFLAGS"
export LDFLAGS="$LDFLAGS $NSPR_LDFLAGS"
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
unset CPPFLAGS
CPPFLAGS="$_SAVE_CFLAGS"

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

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

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

@ -71,9 +71,9 @@ interface nsIDOMBlob : nsISupports
// blob: protocol handler
[noscript] DOMString getInternalUrl(in nsIPrincipal principal);
[optional_argc] nsIDOMBlob mozSlice([optional] in long long start,
[optional] in long long end,
[optional] in DOMString contentType);
[optional_argc] nsIDOMBlob slice([optional] in long long start,
[optional] in long long end,
[optional] in DOMString contentType);
// 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.

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

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

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

@ -54,6 +54,8 @@
namespace css = mozilla::css;
using mozilla::SVGAttrValueWrapper;
#define MISC_STR_PTR(_cont) \
reinterpret_cast<void*>((_cont)->mStringBits & NS_ATTRVALUE_POINTERVALUE_MASK)
@ -76,6 +78,12 @@ nsAttrValue::nsAttrValue(const nsAString& aValue)
SetTo(aValue);
}
nsAttrValue::nsAttrValue(nsIAtom* aValue)
: mBits(0)
{
SetTo(aValue);
}
nsAttrValue::nsAttrValue(css::StyleRule* aValue, const nsAString* aSerialized)
: mBits(0)
{
@ -260,7 +268,13 @@ nsAttrValue::SetTo(const nsAttrValue& aOther)
}
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;
}
}
@ -290,6 +304,16 @@ nsAttrValue::SetTo(const nsAString& aValue)
}
}
void
nsAttrValue::SetTo(nsIAtom* aValue)
{
ResetIfSet();
if (aValue) {
NS_ADDREF(aValue);
SetPtrValueAndType(aValue, eAtomBase);
}
}
void
nsAttrValue::SetTo(PRInt16 aInt)
{
@ -297,6 +321,24 @@ nsAttrValue::SetTo(PRInt16 aInt)
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
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
nsAttrValue::SwapValueWith(nsAttrValue& aOther)
{
@ -428,6 +579,73 @@ nsAttrValue::ToString(nsAString& aResult) const
aResult.AppendFloat(GetDoubleValue());
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:
{
aResult.Truncate();
@ -614,6 +832,10 @@ nsAttrValue::HashValue() const
}
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");
return 0;
}
@ -706,6 +928,16 @@ nsAttrValue::Equals(const nsAttrValue& aOther) const
}
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");
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
nsAttrValue::EnsureEmptyMiscContainer()
{

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

@ -51,6 +51,7 @@
#include "nsCaseTreatment.h"
#include "nsMargin.h"
#include "nsCOMPtr.h"
#include "SVGAttrValueWrapper.h"
typedef PRUptrdiff PtrBits;
class nsAString;
@ -102,6 +103,7 @@ public:
nsAttrValue();
nsAttrValue(const nsAttrValue& aOther);
explicit nsAttrValue(const nsAString& aValue);
explicit nsAttrValue(nsIAtom* aValue);
nsAttrValue(mozilla::css::StyleRule* aValue, const nsAString* aSerialized);
explicit nsAttrValue(const nsIntMargin& aValue);
~nsAttrValue();
@ -123,9 +125,23 @@ public:
// Values below here won't matter, they'll be always stored in the 'misc'
// struct.
eCSSStyleRule = 0x10
,eAtomArray = 0x11
,eAtomArray = 0x11
,eDoubleValue = 0x12
,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;
@ -134,9 +150,29 @@ public:
void SetTo(const nsAttrValue& aOther);
void SetTo(const nsAString& aValue);
void SetTo(nsIAtom* aValue);
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(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.
@ -368,10 +404,23 @@ private:
AtomArray* mAtomArray;
double mDoubleValue;
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 bool IsSVGType(ValueType aType) const;
/**
* Get the index of an EnumTable in the sEnumTableArray.
@ -388,6 +437,8 @@ private:
void SetColorValue(nscolor aColor, const nsAString& aString);
void SetMiscAtomOrString(const nsAString* aValue);
void ResetMiscAtomOrString();
void SetSVGType(ValueType aType, const void* aValue,
const nsAString* aSerialized);
inline void ResetIfSet();
inline void* GetPtr() const;
@ -502,6 +553,12 @@ nsAttrValue::BaseType() const
return static_cast<ValueBaseType>(mBits & NS_ATTRVALUE_BASETYPE_MASK);
}
inline bool
nsAttrValue::IsSVGType(ValueType aType) const
{
return aType >= eSVGTypesBegin && aType <= eSVGTypesEnd;
}
inline void
nsAttrValue::SetPtrValueAndType(void* aValue, ValueBaseType aType)
{

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

@ -48,6 +48,7 @@
#include "nsCopySupport.h"
#include "nsIDOMUIEvent.h"
#include "nsISelection.h"
#include "nsISelectionController.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMEvent.h"
@ -70,6 +71,7 @@
#include "nsIDocShell.h"
#include "nsIContent.h"
#include "nsIImageLoadingContent.h"
#include "nsITextControlElement.h"
#include "nsUnicharUtils.h"
#include "nsIURL.h"
#include "nsIDocument.h"
@ -84,37 +86,6 @@
#include "imgIRequest.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
{
public:
@ -124,7 +95,7 @@ public:
bool aIsAltKeyPressed);
nsresult Produce(nsDOMDataTransfer* aDataTransfer,
bool* aCanDrag,
bool* aDragSelection,
nsISelection** aSelection,
nsIContent** aDragNode);
private:
@ -172,7 +143,7 @@ nsContentAreaDragDrop::GetDragData(nsIDOMWindow* aWindow,
bool aIsAltKeyPressed,
nsDOMDataTransfer* aDataTransfer,
bool* aCanDrag,
bool* aDragSelection,
nsISelection** aSelection,
nsIContent** aDragNode)
{
NS_ENSURE_TRUE(aSelectionTargetNode, NS_ERROR_INVALID_ARG);
@ -181,7 +152,7 @@ nsContentAreaDragDrop::GetDragData(nsIDOMWindow* aWindow,
DragDataProducer
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
DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
bool* aCanDrag,
bool* aDragSelection,
nsISelection** aSelection,
nsIContent** aDragNode)
{
NS_PRECONDITION(aCanDrag && aDragSelection && aDataTransfer && aDragNode,
NS_PRECONDITION(aCanDrag && aSelection && aDataTransfer && aDragNode,
"null pointer passed to Produce");
NS_ASSERTION(mWindow, "window not set");
NS_ASSERTION(mSelectionTargetNode, "selection target node should have been set");
@ -424,33 +395,72 @@ DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
nsresult rv;
nsIContent* dragNode = nsnull;
*aSelection = nsnull;
// find the selection to see what we could be dragging and if
// what we're dragging is in what is selected.
// Find the selection to see what we could be dragging and if what we're
// 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;
mWindow->GetSelection(getter_AddRefs(selection));
if (!selection) {
return NS_OK;
}
// check if the node is inside a form control. If so, dragging will be
// handled in editor code (nsPlaintextDataTransfer::DoDrag). 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;
nsIContent* editingElement = mSelectionTargetNode->IsEditable() ?
mSelectionTargetNode->GetEditingHost() : nsnull;
nsCOMPtr<nsITextControlElement> textControl(do_QueryInterface(editingElement));
if (textControl) {
nsISelectionController* selcon = textControl->GetSelectionController();
if (selcon) {
selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
if (!selection)
return NS_OK;
}
}
else {
mWindow->GetSelection(getter_AddRefs(selection));
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
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;
// possible parent link node
@ -490,7 +500,7 @@ DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
return NS_OK;
}
*aDragSelection = true;
selection.swap(*aSelection);
} else if (selectedImageOrLinkNode) {
// an image is selected
image = do_QueryInterface(selectedImageOrLinkNode);
@ -660,20 +670,28 @@ DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
}
}
if (nodeToSerialize || *aDragSelection) {
// if we have selected text, use it in preference to the node
if (*aDragSelection) {
nodeToSerialize = nsnull;
}
if (nodeToSerialize || *aSelection) {
mHtmlString.Truncate();
mContextString.Truncate();
mInfoString.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;
rv = ::GetTransferableForNodeOrSelection(mWindow, nodeToSerialize,
getter_AddRefs(transferable));
NS_ENSURE_SUCCESS(rv, rv);
if (*aSelection) {
rv = nsCopySupport::GetTransferableForSelection(*aSelection, doc,
getter_AddRefs(transferable));
}
else {
rv = nsCopySupport::GetTransferableForNode(nodeToSerialize, doc,
getter_AddRefs(transferable));
}
nsCOMPtr<nsISupportsString> data;
PRUint32 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);
}
// add a special flavor, even if we don't have html context data
AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), mContextString, principal);
// add a special flavor for the html context data
if (!mContextString.IsEmpty())
AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLContext), mContextString, principal);
// add a special flavor if we have html info data
if (!mInfoString.IsEmpty())
AddString(aDataTransfer, NS_LITERAL_STRING(kHTMLInfo), mInfoString, principal);
// 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
// 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.
* aCanDrag - [out] set to true if the drag may proceed, false to stop the
* drag entirely
* aDragSelection - [out] set to true to indicate that a selection is being
* dragged, rather than a specific node
* aSelection - [out] set to the selection being dragged, or null if no
* selection is being dragged.
* aDragNode - [out] the link, image or area being dragged, or null if the
* drag occurred on another element.
*/
@ -89,7 +89,7 @@ public:
bool aIsAltKeyPressed,
nsDOMDataTransfer* aDataTransfer,
bool* aCanDrag,
bool* aDragSelection,
nsISelection** aSelection,
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(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
static nsresult AppendString(nsITransferable *aTransferable,
const nsAString& aString,

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

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

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

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

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

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

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

@ -216,6 +216,7 @@ protected:
bool mErrorLoadOnRedirect;
bool mGoingToDispatchAllMessages;
bool mWithCredentials;
bool mWaitingForOnStopRequest;
// used while reading the input streams
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_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_UNLINK_BEGIN(nsChildContentList)
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_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_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsChildContentList)
@ -4405,22 +4439,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGenericElement)
nsINode::Trace(tmp, aCallback, aClosure);
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
nsGenericElement::MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
void* aData)

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

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

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

@ -439,7 +439,8 @@ nsWebSocket::~nsWebSocket()
NS_IMPL_CYCLE_COLLECTION_CLASS(nsWebSocket)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsWebSocket)
if (tmp->IsBlack()) {
bool isBlack = tmp->IsBlack();
if (isBlack|| tmp->mKeepingAlive) {
if (tmp->mListenerManager) {
tmp->mListenerManager->UnmarkGrayJSListeners();
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(Close)
}
if (!isBlack) {
xpc_UnmarkGrayObject(tmp->PreservingWrapper() ?
tmp->GetWrapperPreserveColor() :
tmp->GetExpandoObjectPreserveColor());
}
return true;
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END

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

@ -445,8 +445,8 @@ nsXMLHttpRequest::nsXMLHttpRequest()
mProgressSinceLastProgressEvent(false),
mUploadProgress(0), mUploadProgressMax(0),
mRequestSentTime(0), mTimeoutMilliseconds(0),
mErrorLoad(false), mProgressTimerIsActive(false),
mProgressEventWasDelayed(false),
mErrorLoad(false), mWaitingForOnStopRequest(false),
mProgressTimerIsActive(false), mProgressEventWasDelayed(false),
mIsHtml(false),
mWarnAboutMultipartHtml(false),
mWarnAboutSyncHtml(false),
@ -602,7 +602,8 @@ nsXMLHttpRequest::SetRequestObserver(nsIRequestObserver* aObserver)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequest)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsXMLHttpRequest)
if (tmp->IsBlack()) {
bool isBlack = tmp->IsBlack();
if (isBlack || tmp->mWaitingForOnStopRequest) {
if (tmp->mListenerManager) {
tmp->mListenerManager->UnmarkGrayJSListeners();
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(Readystatechange)
}
if (!isBlack) {
xpc_UnmarkGrayObject(tmp->PreservingWrapper() ?
tmp->GetWrapperPreserveColor() :
tmp->GetExpandoObjectPreserveColor());
}
return true;
}
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
@ -2140,6 +2146,8 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult
return NS_OK;
}
mWaitingForOnStopRequest = false;
nsresult rv = NS_OK;
// If we're loading a multipart stream of XML documents, we'll get
@ -2774,6 +2782,9 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
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 (!(mState & XML_HTTP_REQUEST_ASYNC)) {
mState |= XML_HTTP_REQUEST_SYNCLOOPING;

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

@ -365,7 +365,7 @@ protected:
void HandleTimeoutCallback();
bool mErrorLoad;
bool mWaitingForOnStopRequest;
bool mProgressTimerIsActive;
bool mProgressEventWasDelayed;
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 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 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 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");
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.mozSlice(0, 10).type, "", fileType + " slice-slice type");
is(slice.mozSlice(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.mozSlice(0, 10, "hello/world").size, 10, fileType + " slice-slice hello/world size");
is(slice.slice(0, 10).type, "", fileType + " slice-slice type");
is(slice.slice(0, 10).size, 10, fileType + " slice-slice size");
is(slice.slice(0, 10, "hello/world").type, "hello/world", fileType + " slice-slice hello/world type");
is(slice.slice(0, 10, "hello/world").size, 10, fileType + " slice-slice hello/world size");
// Start, end, expected size
var indexes = [[0, size, size],
@ -247,17 +247,17 @@ function testSlice(file, size, type, contents, fileType) {
var sliceContents;
var testName;
if (indexes[i][0] == undefined) {
slice = file.mozSlice();
slice = file.slice();
sliceContents = contents.slice();
testName = fileType + " slice()";
}
else if (indexes[i][1] == undefined) {
slice = file.mozSlice(indexes[i][0]);
slice = file.slice(indexes[i][0]);
sliceContents = contents.slice(indexes[i][0]);
testName = fileType + " slice(" + indexes[i][0] + ")";
}
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]);
testName = fileType + " slice(" + indexes[i][0] + ", " + indexes[i][1] + ")";
}
@ -268,11 +268,11 @@ function testSlice(file, size, type, contents, fileType) {
}
// Slice of slice
var slice = file.mozSlice(0, 40000);
testFile(slice.mozSlice(5000, 42000), contents.slice(5000, 40000), "file slice slice");
var slice = file.slice(0, 40000);
testFile(slice.slice(5000, 42000), contents.slice(5000, 40000), "file slice slice");
// ...of slice of slice
slice = slice.mozSlice(5000, 42000).mozSlice(400, 700);
slice = slice.slice(5000, 42000).slice(400, 700);
SpecialPowers.gc();
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 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 instanceof Blob, "Test " + testCounter + " slice is a Blob");
ok(!(slice instanceof File), "Test " + testCounter + " slice is not a File");

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

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

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

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

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

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

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

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

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

@ -180,7 +180,7 @@ CopyContext(gfxContext* dest, gfxContext* src)
**/
#define NS_CANVASGRADIENT_PRIVATE_IID \
{ 0x491d39d8, 0x4058, 0x42bd, { 0xac, 0x76, 0x70, 0xd5, 0x62, 0x7f, 0x02, 0x10 } }
class nsCanvasGradient : public nsIDOMCanvasGradient
class nsCanvasGradient MOZ_FINAL : public nsIDOMCanvasGradient
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENT_PRIVATE_IID)
@ -238,7 +238,7 @@ NS_INTERFACE_MAP_END
**/
#define NS_CANVASPATTERN_PRIVATE_IID \
{ 0xb85c6c8a, 0x0624, 0x4530, { 0xb8, 0xee, 0xff, 0xdf, 0x42, 0xe8, 0x21, 0x6d } }
class nsCanvasPattern : public nsIDOMCanvasPattern
class nsCanvasPattern MOZ_FINAL : public nsIDOMCanvasPattern
{
public:
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/uniform-location-length-limits.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)
{
nsCOMPtr<nsIContent> content = GetTargetFromFrame();
mTmpRealOriginalTarget = do_QueryInterface(content);
mExplicitOriginalTarget = mTmpRealOriginalTarget;
mExplicitOriginalTarget = do_QueryInterface(content);
if (content && content->IsInAnonymousSubtree()) {
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(mTmpRealOriginalTarget)
// Always set mExplicitOriginalTarget to null, when
// mTmpRealOriginalTarget doesn't point to any object!
tmp->mExplicitOriginalTarget = nsnull;
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mExplicitOriginalTarget);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
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_NSCOMPTR(mTmpRealOriginalTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mExplicitOriginalTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
// nsIDOMEventInterface
@ -355,18 +351,6 @@ nsDOMEvent::GetExplicitOriginalTarget(nsIDOMEventTarget** 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
nsDOMEvent::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget)
{

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