зеркало из https://github.com/mozilla/pjs.git
Merge m-c to s-c.
This commit is contained in:
Коммит
8381eca623
|
@ -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>
|
|
@ -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)
|
||||
|
|
95
configure.in
95
configure.in
|
@ -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)
|
||||
{
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче