зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team
This commit is contained in:
Коммит
528ae6bcd0
|
@ -18,11 +18,10 @@ MOCHITEST_A11Y_FILES = \
|
|||
test_doc.html \
|
||||
test_gettext.html \
|
||||
test_hypertext.html \
|
||||
test_lineboundary.html \
|
||||
test_label.xul \
|
||||
test_multiline.html \
|
||||
test_passwords.html \
|
||||
test_selection.html \
|
||||
test_singleline.html \
|
||||
test_wordboundary.html \
|
||||
test_words.html \
|
||||
$(NULL)
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Line boundary getText* functions tests</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="../text.js"></script>
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
|
||||
var IDs = [ "input", "div", "editable", "textarea" ];
|
||||
|
||||
testTextBeforeOffset(IDs, BOUNDARY_LINE_START,
|
||||
[ [ 0, 15, "", 0, 0 ] ]);
|
||||
testTextBeforeOffset(IDs, BOUNDARY_LINE_END,
|
||||
[ [ 0, 15, "", 0, 0 ] ]);
|
||||
|
||||
testTextAtOffset(IDs, BOUNDARY_LINE_START,
|
||||
[ [ 0, 15, "hello my friend", 0, 15 ] ]);
|
||||
testTextAtOffset(IDs, BOUNDARY_LINE_END,
|
||||
[ [ 0, 15, "hello my friend", 0, 15 ] ]);
|
||||
|
||||
testTextAfterOffset(IDs, BOUNDARY_LINE_START,
|
||||
[ [ 0, 15, "", 15, 15 ] ]);
|
||||
testTextAfterOffset(IDs, BOUNDARY_LINE_END,
|
||||
[ [ 0, 15, "", 15, 15 ] ]);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// __o__n__e__w__o__r__d__\n
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// __\n
|
||||
// 8
|
||||
// __t__w__o__ __w__o__r__d__s__\n
|
||||
// 9 10 11 12 13 14 15 16 17 18
|
||||
|
||||
IDs = [ "ml_div", "ml_divbr", "ml_editable", "ml_editablebr", "ml_textarea"];
|
||||
|
||||
testTextBeforeOffset(IDs, BOUNDARY_LINE_START,
|
||||
[ [ 0, 7, "", 0, 0 ],
|
||||
[ 8, 8, "oneword\n", 0, 8 ],
|
||||
[ 9, 18, "\n", 8, 9 ],
|
||||
[ 19, 19, "two words\n", 9, 19 ]]);
|
||||
testTextBeforeOffset(IDs, BOUNDARY_LINE_END,
|
||||
[ [ 0, 7, "", 0, 0 ],
|
||||
[ 8, 8, "oneword", 0, 7 ],
|
||||
[ 9, 18, "\n", 7, 8 ],
|
||||
[ 19, 19, "\ntwo words", 8, 18 ]]);
|
||||
|
||||
testTextAtOffset(IDs, BOUNDARY_LINE_START,
|
||||
[ [ 0, 7, "oneword\n", 0, 8 ],
|
||||
[ 8, 8, "\n", 8, 9 ],
|
||||
[ 9, 18, "two words\n", 9, 19 ],
|
||||
[ 19, 19, "", 19, 19 ]]);
|
||||
testTextAtOffset(IDs, BOUNDARY_LINE_END,
|
||||
[ [ 0, 7, "oneword", 0, 7 ],
|
||||
[ 8, 8, "\n", 7, 8 ],
|
||||
[ 9, 18, "\ntwo words", 8, 18 ],
|
||||
[ 19, 19, "\n", 18, 19 ]]);
|
||||
|
||||
testTextAfterOffset(IDs, BOUNDARY_LINE_START,
|
||||
[ [ 0, 7, "\n", 8, 9 ],
|
||||
[ 8, 8, "two words\n", 9, 19 ],
|
||||
[ 9, 19, "", 19, 19 ]]);
|
||||
testTextAfterOffset(IDs, BOUNDARY_LINE_END,
|
||||
[ [ 0, 7, "\n", 7, 8 ],
|
||||
[ 8, 8, "\ntwo words", 8, 18 ],
|
||||
[ 9, 18, "\n", 18, 19 ],
|
||||
[ 19, 19, "", 19, 19 ]]);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
title="getTextAtOffset for word boundaries: beginning of a new life"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=853340">
|
||||
Bug 853340
|
||||
</a>
|
||||
<a target="_blank"
|
||||
title="getTextBeforeOffset for word boundaries: evolving"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=855732">
|
||||
Bug 855732
|
||||
</a>
|
||||
<a target="_blank"
|
||||
title=" getTextAfterOffset for line boundary on new rails"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=882292">
|
||||
Bug 882292
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<input id="input" value="hello my friend"/>
|
||||
<div id="div">hello my friend</div>
|
||||
<div id="editable" contenteditable="true">hello my friend</div>
|
||||
<textarea id="textarea">hello my friend</textarea>
|
||||
|
||||
<pre>
|
||||
<div id="ml_div">oneword
|
||||
|
||||
two words
|
||||
</div>
|
||||
<div id="ml_divbr">oneword<br/><br/>two words<br/></div>
|
||||
<div id="ml_editable" contenteditable="true">oneword
|
||||
|
||||
two words
|
||||
</div>
|
||||
<div id="ml_editablebr" contenteditable="true">oneword<br/><br/>two words<br/></div>
|
||||
<textarea id="ml_textarea" cols="300">oneword
|
||||
|
||||
two words
|
||||
</textarea>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,137 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>nsIAccessibleText getText related function in multiline text</title>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<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="../text.js"></script>
|
||||
<script type="application/javascript">
|
||||
|
||||
function doTest()
|
||||
{
|
||||
// __o__n__e__w__o__r__d__\n
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// __\n
|
||||
// 8
|
||||
// __t__w__o__ __w__o__r__d__s__\n
|
||||
// 9 10 11 12 13 14 15 16 17 18
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// getText
|
||||
|
||||
var IDs = ["div", "divbr", "editable", "editablebr", "textarea"];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// getTextAfterOffset
|
||||
|
||||
// BOUNDARY_LINE_START
|
||||
testTextAfterOffset(0, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
|
||||
testTextAfterOffset(7, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
|
||||
testTextAfterOffset(8, BOUNDARY_LINE_START, "two words\n", 9, 19, IDs);
|
||||
testTextAfterOffset(9, BOUNDARY_LINE_START, "", 19, 19, IDs);
|
||||
testTextAfterOffset(19, BOUNDARY_LINE_START, "", 19, 19, IDs);
|
||||
|
||||
// BOUNDARY_LINE_END
|
||||
testTextAfterOffset(0, BOUNDARY_LINE_END, "\n", 7, 8, IDs);
|
||||
testTextAfterOffset(7, BOUNDARY_LINE_END, "\n", 7, 8, IDs);
|
||||
testTextAfterOffset(8, BOUNDARY_LINE_END, "\ntwo words", 8, 18, IDs);
|
||||
testTextAfterOffset(9, BOUNDARY_LINE_END, "\n", 18, 19, IDs);
|
||||
testTextAfterOffset(18, BOUNDARY_LINE_END, "\n", 18, 19, IDs);
|
||||
testTextAfterOffset(19, BOUNDARY_LINE_END, "", 19, 19, IDs);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// getTextBeforeOffset
|
||||
|
||||
// BOUNDARY_LINE_START
|
||||
testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0, IDs);
|
||||
testTextBeforeOffset(8, BOUNDARY_LINE_START, "oneword\n", 0, 8, IDs);
|
||||
testTextBeforeOffset(9, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
|
||||
testTextBeforeOffset(18, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
|
||||
testTextBeforeOffset(19, BOUNDARY_LINE_START, "two words\n", 9, 19, IDs);
|
||||
|
||||
// BOUNDARY_LINE_END
|
||||
testTextBeforeOffset(0, BOUNDARY_LINE_END, "", 0, 0, IDs);
|
||||
testTextBeforeOffset(7, BOUNDARY_LINE_END, "", 0, 0, IDs);
|
||||
testTextBeforeOffset(8, BOUNDARY_LINE_END, "oneword", 0, 7, IDs);
|
||||
testTextBeforeOffset(9, BOUNDARY_LINE_END, "\n", 7, 8, IDs);
|
||||
testTextBeforeOffset(18, BOUNDARY_LINE_END, "\n", 7, 8, IDs);
|
||||
testTextBeforeOffset(19, BOUNDARY_LINE_END, "\ntwo words", 8, 18, IDs);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// getTextAtOffset
|
||||
|
||||
// BOUNDARY_LINE_START
|
||||
testTextAtOffset(0, BOUNDARY_LINE_START, "oneword\n", 0, 8, IDs);
|
||||
testTextAtOffset(7, BOUNDARY_LINE_START, "oneword\n", 0, 8, IDs);
|
||||
testTextAtOffset(8, BOUNDARY_LINE_START, "\n", 8, 9, IDs);
|
||||
testTextAtOffset(9, BOUNDARY_LINE_START, "two words\n", 9, 19, IDs);
|
||||
testTextAtOffset(13, BOUNDARY_LINE_START, "two words\n", 9, 19, IDs);
|
||||
testTextAtOffset(18, BOUNDARY_LINE_START, "two words\n", 9, 19, IDs);
|
||||
testTextAtOffset(19, BOUNDARY_LINE_START, "", 19, 19, IDs);
|
||||
|
||||
// BOUNDARY_LINE_END
|
||||
testTextAtOffset(0, BOUNDARY_LINE_END, "oneword", 0, 7, IDs);
|
||||
testTextAtOffset(7, BOUNDARY_LINE_END, "oneword", 0, 7, IDs);
|
||||
testTextAtOffset(8, BOUNDARY_LINE_END, "\n", 7, 8, IDs);
|
||||
testTextAtOffset(9, BOUNDARY_LINE_END, "\ntwo words", 8, 18, IDs);
|
||||
testTextAtOffset(17, BOUNDARY_LINE_END, "\ntwo words", 8, 18, IDs);
|
||||
testTextAtOffset(18, BOUNDARY_LINE_END, "\ntwo words", 8, 18, IDs);
|
||||
testTextAtOffset(19, BOUNDARY_LINE_END, "\n", 18, 19, IDs);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
title="nsIAccessibleText getText related functions test in multiline text"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=612331">
|
||||
Bug 612331
|
||||
</a>
|
||||
<a target="_blank"
|
||||
title="getTextAtOffset for word boundaries: beginning of a new life"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=853340">
|
||||
Bug 853340
|
||||
</a>
|
||||
<a target="_blank"
|
||||
title="getTextBeforeOffset for word boundaries: evolving"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=855732">
|
||||
Bug 855732
|
||||
</a>
|
||||
<a target="_blank"
|
||||
title=" getTextAfterOffset for line boundary on new rails"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=882292">
|
||||
Bug 882292
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
|
||||
<div id="div">oneword
|
||||
|
||||
two words
|
||||
</div>
|
||||
<div id="divbr">oneword<br/><br/>two words<br/></div>
|
||||
<div id="editable" contenteditable="true">oneword
|
||||
|
||||
two words
|
||||
</div>
|
||||
<div id="editablebr" contenteditable="true">oneword<br/><br/>two words<br/></div>
|
||||
<textarea id="textarea" cols="300">oneword
|
||||
|
||||
two words
|
||||
</textarea>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,112 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>nsIAccessibleText getText related function tests for html:input,html:div and html:textarea</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="../text.js"></script>
|
||||
<script type="application/javascript">
|
||||
function doTest()
|
||||
{
|
||||
// __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// getTextAfterOffset
|
||||
|
||||
var IDs = [ "input", "div", "editable", "textarea" ];
|
||||
var regularIDs = [ "input", "div", "editable" ];
|
||||
|
||||
// BOUNDARY_LINE_START
|
||||
testTextAfterOffset(0, BOUNDARY_LINE_START, "", 15, 15, IDs);
|
||||
testTextAfterOffset(1, BOUNDARY_LINE_START, "", 15, 15, IDs);
|
||||
testTextAfterOffset(14, BOUNDARY_LINE_START, "", 15, 15, IDs);
|
||||
testTextAfterOffset(15, BOUNDARY_LINE_START, "", 15, 15, IDs);
|
||||
|
||||
// BOUNDARY_LINE_END
|
||||
testTextAfterOffset(0, BOUNDARY_LINE_END, "", 15, 15, IDs);
|
||||
testTextAfterOffset(1, BOUNDARY_LINE_END, "", 15, 15, IDs);
|
||||
testTextAfterOffset(14, BOUNDARY_LINE_END, "", 15, 15, IDs);
|
||||
testTextAfterOffset(15, BOUNDARY_LINE_END, "", 15, 15, IDs);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// getTextBeforeOffset
|
||||
|
||||
var IDs = [ "input", "div", "editable", "textarea" ];
|
||||
|
||||
// BOUNDARY_LINE_START
|
||||
testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0, IDs);
|
||||
testTextBeforeOffset(1, BOUNDARY_LINE_START, "", 0, 0, IDs);
|
||||
testTextBeforeOffset(14, BOUNDARY_LINE_START, "", 0, 0, IDs);
|
||||
testTextBeforeOffset(15, BOUNDARY_LINE_START, "", 0, 0, IDs);
|
||||
|
||||
// BOUNDARY_LINE_END
|
||||
testTextBeforeOffset(0, BOUNDARY_LINE_END, "", 0, 0, IDs);
|
||||
testTextBeforeOffset(1, BOUNDARY_LINE_END, "", 0, 0, IDs);
|
||||
testTextBeforeOffset(14, BOUNDARY_LINE_END, "", 0, 0, IDs);
|
||||
testTextBeforeOffset(15, BOUNDARY_LINE_END, "", 0, 0, IDs);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// getTextAtOffset
|
||||
|
||||
IDs = [ "input", "div", "editable", "textarea" ];
|
||||
regularIDs = [ "input", "div", "editable" ];
|
||||
|
||||
// BOUNDARY_LINE_START
|
||||
testTextAtOffset(0, BOUNDARY_LINE_START, "hello my friend", 0, 15, IDs);
|
||||
testTextAtOffset(1, BOUNDARY_LINE_START, "hello my friend", 0, 15, IDs);
|
||||
testTextAtOffset(14, BOUNDARY_LINE_START, "hello my friend", 0, 15, IDs);
|
||||
testTextAtOffset(15, BOUNDARY_LINE_START, "hello my friend", 0, 15, IDs);
|
||||
|
||||
// BOUNDARY_LINE_END
|
||||
testTextAtOffset(0, BOUNDARY_LINE_END, "hello my friend", 0, 15, IDs);
|
||||
testTextAtOffset(1, BOUNDARY_LINE_END, "hello my friend", 0, 15, IDs);
|
||||
testTextAtOffset(14, BOUNDARY_LINE_END, "hello my friend", 0, 15, IDs);
|
||||
testTextAtOffset(15, BOUNDARY_LINE_END, "hello my friend", 0, 15, IDs);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
title="nsIAccessibleText getText related function tests for html:input,html:div and html:textarea"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=452769">
|
||||
Bug 452769
|
||||
</a>
|
||||
<a target="_blank"
|
||||
title="getTextAtOffset for word boundaries: beginning of a new life"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=853340">
|
||||
Bug 853340
|
||||
</a>
|
||||
<a target="_blank"
|
||||
title="getTextBeforeOffset for word boundaries: evolving"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=855732">
|
||||
Bug 855732
|
||||
</a>
|
||||
<a target="_blank"
|
||||
title=" getTextAfterOffset for line boundary on new rails"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=882292">
|
||||
Bug 882292
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<input id="input" value="hello my friend"/>
|
||||
<div id="div">hello my friend</div>
|
||||
<div id="editable" contenteditable="true">hello my friend</div>
|
||||
<textarea id="textarea">hello my friend</textarea>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -220,8 +220,6 @@ function startup(data, reasonCode) {
|
|||
// options used by system module.
|
||||
// File to write 'OK' or 'FAIL' (exit code emulation).
|
||||
resultFile: options.resultFile,
|
||||
// File to write stdout.
|
||||
logFile: options.logFile,
|
||||
// Arguments passed as --static-args
|
||||
staticArgs: options.staticArgs,
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>19.0</em:minVersion>
|
||||
<em:maxVersion>22.0a1</em:maxVersion>
|
||||
<em:minVersion>21.0</em:minVersion>
|
||||
<em:maxVersion>25.0a1</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
|
|
|
@ -640,15 +640,14 @@ and this usually involves using HTTPS for the links.
|
|||
So if we run the following command:
|
||||
|
||||
<pre>
|
||||
cfx xpi --update-link https://example.com/addon/latest
|
||||
--update-url https://example.com/addon/update_rdf
|
||||
cfx xpi --update-link https://example.com/addon/latest/pluginName.xpi --update-url https://example.com/addon/update_rdf/pluginName.update.rdf
|
||||
</pre>
|
||||
|
||||
`cfx` will create two files:
|
||||
|
||||
* an XPI file which embeds
|
||||
`https://example.com/addon/update_rdf` as the value of `updateURL`
|
||||
* an RDF file which embeds `https://example.com/addon/latest` as the value of
|
||||
`https://example.com/addon/update_rdf/pluginName.update.rdf` as the value of `updateURL`
|
||||
* an RDF file which embeds `https://example.com/addon/latest/pluginName.xpi` as the value of
|
||||
`updateLink`.
|
||||
|
||||
### Supported Options ###
|
||||
|
|
|
@ -13,6 +13,13 @@ Note that the `self` module is completely different from the global `self`
|
|||
object accessible to content scripts, which is used by a content script to
|
||||
[communicate with the add-on code](dev-guide/guides/content-scripts/using-port.html).
|
||||
|
||||
<api name="uri">
|
||||
@property {string}
|
||||
This property represents an add-on associated unique URI string.
|
||||
This URI can be used for APIs which require a valid URI string, such as the
|
||||
[passwords](modules/sdk/passwords.html) module.
|
||||
</api>
|
||||
|
||||
<api name="id">
|
||||
@property {string}
|
||||
This property is a printable string that is unique for each add-on. It comes
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
The `test/utils` module provides additional helper methods to be used in
|
||||
the CommonJS Unit Testing test suite.
|
||||
|
||||
## Before and After
|
||||
|
||||
Helper functions `before()` and `after()` are available for running a function
|
||||
before or after each test in a suite. They're useful when you need to
|
||||
guarantee a particular state before running a test, and to clean up
|
||||
after your test.
|
||||
|
||||
let { before, after } = require('sdk/test/utils');
|
||||
let { search } = require('sdk/places/bookmarks');
|
||||
|
||||
exports.testCountBookmarks = function (assert, done) {
|
||||
search().on('end', function (results) {
|
||||
assert.equal(results, 0, 'should be no bookmarks');
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
before(exports, function (name, assert) {
|
||||
removeAllBookmarks();
|
||||
});
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
||||
Both `before` and `after` may be asynchronous. To make them asynchronous,
|
||||
pass a third argument `done`, which is a function to call when you have
|
||||
finished:
|
||||
|
||||
let { before, after } = require('sdk/test/utils');
|
||||
let { search } = require('sdk/places/bookmarks');
|
||||
|
||||
exports.testCountBookmarks = function (assert, done) {
|
||||
search().on('end', function (results) {
|
||||
assert.equal(results, 0, 'should be no bookmarks');
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
before(exports, function (name, assert, done) {
|
||||
removeAllBookmarksAsync(function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
||||
<api name="before">
|
||||
@function
|
||||
Runs `beforeFn` before each test in the file. May be asynchronous
|
||||
if `beforeFn` accepts a third argument, which is a callback.
|
||||
|
||||
@param exports {Object}
|
||||
A test file's `exports` object
|
||||
@param beforeFn {Function}
|
||||
The function to be called before each test. It has two arguments,
|
||||
or three if it is asynchronous:
|
||||
|
||||
* the first argument is the test's name as a `String`.
|
||||
* the second argument is the `assert` object for the test.
|
||||
* the third, optional, argument is a callback. If the callback is
|
||||
defined, then the `beforeFn` is considered asynchronous, and the
|
||||
callback must be invoked before the test runs.
|
||||
|
||||
</api>
|
||||
|
||||
<api name="after">
|
||||
@function
|
||||
Runs `afterFn` after each test in the file. May be asynchronous
|
||||
if `afterFn` accepts a third argument, which is a callback.
|
||||
|
||||
@param exports {Object}
|
||||
A test file's `exports` object
|
||||
@param afterFn {Function}
|
||||
The function to be called after each test. It has two arguments,
|
||||
or three if it is asynchronous:
|
||||
|
||||
* the first argument is the test's name as a `String`.
|
||||
* the second argument is the `assert` object for the test.
|
||||
* the third, optional, argument is a callback. If the callback is
|
||||
defined, then the `afterFn` is considered asynchronous, and the
|
||||
callback must be invoked before the next test runs.
|
||||
|
||||
</api>
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
The `util/array` module provides simple helper functions for working with
|
||||
The `util/array` module provides simple helper functions for working with
|
||||
arrays.
|
||||
|
||||
<api name="has">
|
||||
|
@ -29,7 +29,7 @@ A simplified version of `array.indexOf(element) >= 0`.
|
|||
|
||||
<api name="hasAny">
|
||||
@function
|
||||
Returns `true` if the given [`Array`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array) contains any of the elements in the
|
||||
Returns `true` if the given [`Array`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array) contains any of the elements in the
|
||||
`elements` array, or `false` otherwise.
|
||||
|
||||
let { hasAny } = require('sdk/util/array');
|
||||
|
@ -84,7 +84,7 @@ does not alter the array and returns `false`.
|
|||
let a = ['alice', 'bob', 'carol'];
|
||||
|
||||
remove(a, 'dave'); // false
|
||||
remove(a, 'bob'); // true
|
||||
remove(a, 'bob'); // true
|
||||
remove(a, 'bob'); // false
|
||||
|
||||
console.log(a); // ['alice', 'carol']
|
||||
|
@ -154,3 +154,24 @@ Iterates over an [iterator](https://developer.mozilla.org/en-US/docs/JavaScript/
|
|||
The iterator's results in an array.
|
||||
</api>
|
||||
|
||||
<api name="find">
|
||||
@function
|
||||
Iterates over given `array` and applies given `predicate` function until
|
||||
`predicate(element)` is `true`. If such element is found it's retured back
|
||||
otherwise third optional `fallback` argument is returned back. If fallback
|
||||
is not provided returns `undefined`.
|
||||
|
||||
let { find } = require('sdk/util/array');
|
||||
let isOdd = (x) => x % 2;
|
||||
find([2, 4, 5, 7, 8, 9], isOdd); // => 5
|
||||
find([2, 4, 6, 8], isOdd); // => undefiend
|
||||
find([2, 4, 6, 8], isOdd, null); // => null
|
||||
|
||||
fromIterator(i) // ['otoro', 'unagi', 'keon']
|
||||
|
||||
@param iterator {iterator}
|
||||
The [`Iterator`](https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Iterators_and_Generators#Iterators) object over which to iterate and place results into an array.
|
||||
|
||||
@returns {array}
|
||||
The iterator's results in an array.
|
||||
</api>
|
||||
|
|
|
@ -8,34 +8,32 @@ module.metadata = {
|
|||
"stability": "unstable"
|
||||
};
|
||||
|
||||
const { Cc, Ci } = require("chrome");
|
||||
const { Cc, Ci, Cu, Cr } = require("chrome");
|
||||
const self = require("../self");
|
||||
const traceback = require("./traceback")
|
||||
const prefs = require("../preferences/service");
|
||||
const { merge } = require("../util/object");
|
||||
const { partial } = require("../lang/functional");
|
||||
const { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm");
|
||||
|
||||
const LEVELS = {
|
||||
"all": Number.MIN_VALUE,
|
||||
"debug": 20000,
|
||||
"info": 30000,
|
||||
"warn": 40000,
|
||||
"error": 50000,
|
||||
"off": Number.MAX_VALUE,
|
||||
};
|
||||
const DEFAULT_LOG_LEVEL = "error";
|
||||
const ADDON_LOG_LEVEL_PREF = "extensions." + self.id + ".sdk.console.logLevel";
|
||||
const SDK_LOG_LEVEL_PREF = "extensions.sdk.console.logLevel";
|
||||
|
||||
let logLevel;
|
||||
|
||||
let logLevel = DEFAULT_LOG_LEVEL;
|
||||
function setLogLevel() {
|
||||
logLevel = prefs.get(ADDON_LOG_LEVEL_PREF, prefs.get(SDK_LOG_LEVEL_PREF,
|
||||
DEFAULT_LOG_LEVEL));
|
||||
logLevel = prefs.get(ADDON_LOG_LEVEL_PREF,
|
||||
prefs.get(SDK_LOG_LEVEL_PREF,
|
||||
DEFAULT_LOG_LEVEL));
|
||||
}
|
||||
setLogLevel();
|
||||
|
||||
let logLevelObserver = {
|
||||
QueryInterface: function(iid) {
|
||||
if (!iid.equals(Ci.nsIObserver) &&
|
||||
!iid.equals(Ci.nsISupportsWeakReference) &&
|
||||
!iid.equals(Ci.nsISupports))
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
},
|
||||
observe: function(subject, topic, data) {
|
||||
setLogLevel();
|
||||
}
|
||||
|
@ -43,79 +41,23 @@ let logLevelObserver = {
|
|||
let branch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService).
|
||||
getBranch(null);
|
||||
branch.addObserver(ADDON_LOG_LEVEL_PREF, logLevelObserver, false);
|
||||
branch.addObserver(SDK_LOG_LEVEL_PREF, logLevelObserver, false);
|
||||
|
||||
function stringify(arg) {
|
||||
try {
|
||||
return String(arg);
|
||||
}
|
||||
catch(ex) {
|
||||
return "<toString() error>";
|
||||
}
|
||||
}
|
||||
|
||||
function stringifyArgs(args) {
|
||||
return Array.map(args, stringify).join(" ");
|
||||
}
|
||||
|
||||
function message(print, level) {
|
||||
if (LEVELS[level] < LEVELS[logLevel])
|
||||
return;
|
||||
|
||||
let args = Array.slice(arguments, 2);
|
||||
|
||||
print(level + ": " + self.name + ": " + stringifyArgs(args) + "\n", level);
|
||||
}
|
||||
|
||||
function errorMessage(print, e) {
|
||||
// Some platform exception doesn't have name nor message but
|
||||
// can be stringified to a meaningfull message
|
||||
var fullString = ("An exception occurred.\n" +
|
||||
(e.name ? e.name + ": " : "") +
|
||||
(e.message ? e.message : e.toString()) + "\n" +
|
||||
(e.fileName ? traceback.sourceURI(e.fileName) + " " +
|
||||
e.lineNumber + "\n"
|
||||
: "") +
|
||||
traceback.format(e));
|
||||
|
||||
message(print, "error", fullString);
|
||||
}
|
||||
|
||||
function traceMessage(print) {
|
||||
var stack = traceback.get();
|
||||
stack.splice(-1, 1);
|
||||
|
||||
message(print, "info", traceback.format(stack));
|
||||
}
|
||||
branch.addObserver(ADDON_LOG_LEVEL_PREF, logLevelObserver, true);
|
||||
branch.addObserver(SDK_LOG_LEVEL_PREF, logLevelObserver, true);
|
||||
|
||||
function PlainTextConsole(print) {
|
||||
if (!print)
|
||||
print = dump;
|
||||
|
||||
if (print === dump) {
|
||||
// If we're just using dump(), auto-enable preferences so
|
||||
// that the developer actually sees the console output.
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"]
|
||||
.getService(Ci.nsIPrefBranch);
|
||||
prefs.setBoolPref("browser.dom.window.dump.enabled", true);
|
||||
}
|
||||
let consoleOptions = {
|
||||
prefix: self.name + ": ",
|
||||
maxLogLevel: logLevel,
|
||||
dump: print
|
||||
};
|
||||
let console = new ConsoleAPI(consoleOptions);
|
||||
|
||||
merge(this, {
|
||||
log: partial(message, print, "info"),
|
||||
info: partial(message, print, "info"),
|
||||
warn: partial(message, print, "warn"),
|
||||
error: partial(message, print, "error"),
|
||||
debug: partial(message, print, "debug"),
|
||||
exception: partial(errorMessage, print),
|
||||
trace: partial(traceMessage, print),
|
||||
|
||||
dir: function dir() {},
|
||||
group: function group() {},
|
||||
groupCollapsed: function groupCollapsed() {},
|
||||
groupEnd: function groupEnd() {},
|
||||
time: function time() {},
|
||||
timeEnd: function timeEnd() {}
|
||||
// As we freeze the console object, we can't modify this property afterward
|
||||
Object.defineProperty(console, "maxLogLevel", {
|
||||
get: function() {
|
||||
return logLevel;
|
||||
}
|
||||
});
|
||||
|
||||
// We defined the `__exposedProps__` in our console chrome object.
|
||||
|
@ -126,11 +68,12 @@ function PlainTextConsole(print) {
|
|||
// Meanwhile we're investigating with the platform team if `__exposedProps__`
|
||||
// are needed, or are just a left-over.
|
||||
|
||||
this.__exposedProps__ = Object.keys(this).reduce(function(exposed, prop) {
|
||||
console.__exposedProps__ = Object.keys(ConsoleAPI.prototype).reduce(function(exposed, prop) {
|
||||
exposed[prop] = "r";
|
||||
return exposed;
|
||||
}, {});
|
||||
|
||||
Object.freeze(this);
|
||||
Object.freeze(console);
|
||||
return console;
|
||||
};
|
||||
exports.PlainTextConsole = PlainTextConsole;
|
||||
|
|
|
@ -9,7 +9,8 @@ module.metadata = {
|
|||
"stability": "deprecated"
|
||||
};
|
||||
|
||||
const memory = require('./memory');
|
||||
const { Cu } = require("chrome");
|
||||
const memory = require("./memory");
|
||||
var timer = require("../timers");
|
||||
var cfxArgs = require("@test/options");
|
||||
|
||||
|
@ -443,7 +444,7 @@ TestRunner.prototype = {
|
|||
},
|
||||
|
||||
startMany: function startMany(options) {
|
||||
function runNextTest(self) {
|
||||
let runNextTest = (self) => Cu.schedulePreciseGC(_ => {
|
||||
var test = options.tests.shift();
|
||||
if (options.stopOnError && self.test && self.test.failed) {
|
||||
self.console.error("aborted: test failed and --stop-on-error was specified");
|
||||
|
@ -453,7 +454,8 @@ TestRunner.prototype = {
|
|||
} else {
|
||||
options.onDone(self);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
runNextTest(this);
|
||||
},
|
||||
|
||||
|
|
|
@ -9,74 +9,252 @@ module.metadata = {
|
|||
};
|
||||
|
||||
|
||||
const { Cc, Ci, CC } = require("chrome");
|
||||
const { Class } = require("../core/heritage");
|
||||
const { Cu } = require("chrome");
|
||||
const { TextEncoder, TextDecoder } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
|
||||
|
||||
const Transcoder = CC("@mozilla.org/intl/scriptableunicodeconverter",
|
||||
"nsIScriptableUnicodeConverter");
|
||||
exports.TextEncoder = TextEncoder;
|
||||
exports.TextDecoder = TextDecoder;
|
||||
|
||||
var Buffer = Class({
|
||||
initialize: function initialize(subject, encoding) {
|
||||
subject = subject ? subject.valueOf() : 0;
|
||||
let length = typeof subject === "number" ? subject : 0;
|
||||
this.encoding = encoding || "utf-8";
|
||||
this.valueOf(Array.isArray(subject) ? subject : new Array(length));
|
||||
|
||||
if (typeof subject === "string") this.write(subject);
|
||||
function Buffer(subject, encoding) {
|
||||
var type = typeof(subject);
|
||||
switch (type) {
|
||||
case "number":
|
||||
// Create typed array of the given size if number.
|
||||
return Uint8Array(subject > 0 ? Math.floor(subject) : 0);
|
||||
case "string":
|
||||
// If string encode it and use buffer for the returned Uint8Array
|
||||
// to create a local patched version that acts like node buffer.
|
||||
encoding = encoding || "utf8";
|
||||
return Uint8Array(TextEncoder(encoding).encode(subject).buffer);
|
||||
case "object":
|
||||
// If array or alike just make a copy with a local patched prototype.
|
||||
return Uint8Array(subject);
|
||||
default:
|
||||
throw new TypeError("must start with number, buffer, array or string");
|
||||
}
|
||||
}
|
||||
exports.Buffer = Buffer;
|
||||
|
||||
// Tests if `value` is a Buffer.
|
||||
Buffer.isBuffer = value => value instanceof Buffer
|
||||
|
||||
// Returns true if the encoding is a valid encoding argument & false otherwise
|
||||
Buffer.isEncoding = encoding => !!ENCODINGS[String(encoding).toLowerCase()]
|
||||
|
||||
// Gives the actual byte length of a string. encoding defaults to 'utf8'.
|
||||
// This is not the same as String.prototype.length since that returns the
|
||||
// number of characters in a string.
|
||||
Buffer.byteLength = (value, encoding = "utf8") =>
|
||||
TextEncoder(encoding).encode(value).byteLength
|
||||
|
||||
// Direct copy of the nodejs's buffer implementation:
|
||||
// https://github.com/joyent/node/blob/b255f4c10a80343f9ce1cee56d0288361429e214/lib/buffer.js#L146-L177
|
||||
Buffer.concat = function(list, length) {
|
||||
if (!Array.isArray(list))
|
||||
throw new TypeError('Usage: Buffer.concat(list[, length])');
|
||||
|
||||
if (typeof length === 'undefined') {
|
||||
length = 0;
|
||||
for (var i = 0; i < list.length; i++)
|
||||
length += list[i].length;
|
||||
} else {
|
||||
length = ~~length;
|
||||
}
|
||||
|
||||
if (length < 0)
|
||||
length = 0;
|
||||
|
||||
if (list.length === 0)
|
||||
return new Buffer(0);
|
||||
else if (list.length === 1)
|
||||
return list[0];
|
||||
|
||||
if (length < 0)
|
||||
throw new RangeError('length is not a positive number');
|
||||
|
||||
var buffer = new Buffer(length);
|
||||
var pos = 0;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var buf = list[i];
|
||||
buf.copy(buffer, pos);
|
||||
pos += buf.length;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
};
|
||||
|
||||
// Node buffer is very much like Uint8Array although it has bunch of methods
|
||||
// that typically can be used in combination with `DataView` while preserving
|
||||
// access by index. Since in SDK echo module has it's own set of bult-ins it
|
||||
// ok to patch ours to make it nodejs Buffer compatible.
|
||||
Buffer.prototype = Uint8Array.prototype;
|
||||
Object.defineProperties(Buffer.prototype, {
|
||||
view: {
|
||||
get: function() this._view || (this._view = DataView(this.buffer))
|
||||
},
|
||||
get length() {
|
||||
return this.valueOf().length;
|
||||
toString: {
|
||||
value: function(encoding, start, end) {
|
||||
encoding = !!encoding ? (encoding + '').toLowerCase() : "utf8";
|
||||
start = Math.max(0, ~~start);
|
||||
end = Math.min(this.length, end === void(0) ? this.length : ~~end);
|
||||
return TextDecoder(encoding).decode(this.subarray(start, end));
|
||||
}
|
||||
},
|
||||
get: function get(index) {
|
||||
return this.valueOf()[index];
|
||||
toJSON: {
|
||||
value: function() ({ type: "Buffer", data: Array.slice(this, 0) })
|
||||
},
|
||||
set: function set(index, value) {
|
||||
return this.valueOf()[index] = value;
|
||||
get: {
|
||||
value: function(offset) this[offset]
|
||||
},
|
||||
valueOf: function valueOf(value) {
|
||||
Object.defineProperty(this, "valueOf", {
|
||||
value: Array.prototype.valueOf.bind(value),
|
||||
configurable: false,
|
||||
writable: false,
|
||||
enumerable: false
|
||||
});
|
||||
set: {
|
||||
value: function(offset, value) this[offset] = value
|
||||
},
|
||||
toString: function toString(encoding, start, end) {
|
||||
let bytes = this.valueOf().slice(start || 0, end || this.length);
|
||||
let transcoder = Transcoder();
|
||||
transcoder.charset = String(encoding || this.encoding).toUpperCase();
|
||||
return transcoder.convertFromByteArray(bytes, this.length);
|
||||
copy: {
|
||||
value: function(target, offset, start, end)
|
||||
Uint8Array.set(target, this.subarray(start, end), offset)
|
||||
},
|
||||
toJSON: function toJSON() {
|
||||
return this.toString()
|
||||
slice: {
|
||||
value: Buffer.prototype.subarray
|
||||
},
|
||||
write: function write(string, offset, encoding) {
|
||||
offset = Math.max(offset || 0, 0);
|
||||
let value = this.valueOf();
|
||||
let transcoder = Transcoder();
|
||||
transcoder.charset = String(encoding || this.encoding).toUpperCase();
|
||||
let bytes = transcoder.convertToByteArray(string, {});
|
||||
value.splice.apply(value, [
|
||||
offset,
|
||||
Math.min(value.length - offset, bytes.length, bytes)
|
||||
].concat(bytes));
|
||||
return bytes;
|
||||
write: {
|
||||
value: function(string, offset, length, encoding = "utf8") {
|
||||
if (typeof(offset) === "string")
|
||||
([offset, length, encoding]) = [0, null, offset];
|
||||
else if (typeof(length) === "string")
|
||||
([length, encoding]) = [null, length];
|
||||
|
||||
offset = ~~offset;
|
||||
length = length || this.length - offset;
|
||||
let buffer = TextEncoder(encoding).encode(string);
|
||||
let result = Math.min(buffer.length, length);
|
||||
if (buffer.length !== length)
|
||||
buffer = buffer.subarray(0, length);
|
||||
Uint8Array.set(this, buffer, offset);
|
||||
return result;
|
||||
}
|
||||
},
|
||||
slice: function slice(start, end) {
|
||||
return new Buffer(this.valueOf().slice(start, end));
|
||||
},
|
||||
copy: function copy(target, offset, start, end) {
|
||||
offset = Math.max(offset || 0, 0);
|
||||
target = target.valueOf();
|
||||
let bytes = this.valueOf();
|
||||
bytes.slice(Math.max(start || 0, 0), end);
|
||||
target.splice.apply(target, [
|
||||
offset,
|
||||
Math.min(target.length - offset, bytes.length),
|
||||
].concat(bytes));
|
||||
fill: {
|
||||
value: function fill(value, start, end) {
|
||||
value = value || 0;
|
||||
start = start || 0;
|
||||
end = end || this.length;
|
||||
|
||||
if (typeof(value) === "string")
|
||||
value = value.charCodeAt(0);
|
||||
if (typeof(value) !== "number" || isNaN(value))
|
||||
throw TypeError("value is not a number");
|
||||
if (end < start)
|
||||
throw new RangeError("end < start");
|
||||
|
||||
// Fill 0 bytes; we're done
|
||||
if (end === start)
|
||||
return 0;
|
||||
if (this.length == 0)
|
||||
return 0;
|
||||
|
||||
if (start < 0 || start >= this.length)
|
||||
throw RangeError("start out of bounds");
|
||||
|
||||
if (end < 0 || end > this.length)
|
||||
throw RangeError("end out of bounds");
|
||||
|
||||
let index = start;
|
||||
while (index < end) this[index++] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
Buffer.isBuffer = function isBuffer(buffer) {
|
||||
return buffer instanceof Buffer
|
||||
};
|
||||
exports.Buffer = Buffer;
|
||||
|
||||
// Define nodejs Buffer's getter and setter functions that just proxy
|
||||
// to internal DataView's equivalent methods.
|
||||
[["readUInt16LE", "getUint16", true],
|
||||
["readUInt16BE", "getUint16", false],
|
||||
["readInt16LE", "getInt16", true],
|
||||
["readInt16BE", "getInt16", false],
|
||||
["readUInt32LE", "getInt32", true],
|
||||
["readUInt32BE", "getInt32", false],
|
||||
["readInt32LE", "getInt32", true],
|
||||
["readInt32BE", "getInt32", false],
|
||||
["readFloatLE", "getFloat32", true],
|
||||
["readFloatBE", "getFloat32", false],
|
||||
["readDoubleLE", "getFloat64", true],
|
||||
["readDoubleBE", "getFloat64", false],
|
||||
["readUInt8", "getUint8"],
|
||||
["readInt8", "getInt8"]].forEach(([alias, name, littleEndian]) => {
|
||||
Object.defineProperty(Buffer.prototype, alias, {
|
||||
value: function(offset) this.view[name](offset, littleEndian)
|
||||
});
|
||||
});
|
||||
|
||||
[["writeUInt16LE", "setUint16", true],
|
||||
["writeUInt16BE", "setUint16", false],
|
||||
["writeInt16LE", "setInt16", true],
|
||||
["writeInt16BE", "setInt16", false],
|
||||
["writeUInt32LE", "setUint32", true],
|
||||
["writeUInt32BE", "setUint32", false],
|
||||
["writeInt32LE", "setInt32", true],
|
||||
["writeInt32BE", "setInt32", false],
|
||||
["writeFloatLE", "setFloat32", true],
|
||||
["writeFloatBE", "setFloat32", false],
|
||||
["writeDoubleLE", "setFloat64", true],
|
||||
["writeDoubleBE", "setFloat64", false],
|
||||
["writeUInt8", "setUint8"],
|
||||
["writeInt8", "setInt8"]].forEach(([alias, name, littleEndian]) => {
|
||||
Object.defineProperty(Buffer.prototype, alias, {
|
||||
value: function(value, offset) this.view[name](offset, value, littleEndian)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// List of supported encodings taken from:
|
||||
// http://mxr.mozilla.org/mozilla-central/source/dom/encoding/labelsencodings.properties
|
||||
const ENCODINGS = { "unicode-1-1-utf-8": 1, "utf-8": 1, "utf8": 1,
|
||||
"866": 1, "cp866": 1, "csibm866": 1, "ibm866": 1, "csisolatin2": 1,
|
||||
"iso-8859-2": 1, "iso-ir-101": 1, "iso8859-2": 1, "iso88592": 1,
|
||||
"iso_8859-2": 1, "iso_8859-2:1987": 1, "l2": 1, "latin2": 1, "csisolatin3": 1,
|
||||
"iso-8859-3": 1, "iso-ir-109": 1, "iso8859-3": 1, "iso88593": 1,
|
||||
"iso_8859-3": 1, "iso_8859-3:1988": 1, "l3": 1, "latin3": 1, "csisolatin4": 1,
|
||||
"iso-8859-4": 1, "iso-ir-110": 1, "iso8859-4": 1, "iso88594": 1,
|
||||
"iso_8859-4": 1, "iso_8859-4:1988": 1, "l4": 1, "latin4": 1,
|
||||
"csisolatincyrillic": 1, "cyrillic": 1, "iso-8859-5": 1, "iso-ir-144": 1,
|
||||
"iso8859-5": 1, "iso88595": 1, "iso_8859-5": 1, "iso_8859-5:1988": 1,
|
||||
"arabic": 1, "asmo-708": 1, "csiso88596e": 1, "csiso88596i": 1,
|
||||
"csisolatinarabic": 1, "ecma-114": 1, "iso-8859-6": 1, "iso-8859-6-e": 1,
|
||||
"iso-8859-6-i": 1, "iso-ir-127": 1, "iso8859-6": 1, "iso88596": 1,
|
||||
"iso_8859-6": 1, "iso_8859-6:1987": 1, "csisolatingreek": 1, "ecma-118": 1,
|
||||
"elot_928": 1, "greek": 1, "greek8": 1, "iso-8859-7": 1, "iso-ir-126": 1,
|
||||
"iso8859-7": 1, "iso88597": 1, "iso_8859-7": 1, "iso_8859-7:1987": 1,
|
||||
"sun_eu_greek": 1, "csiso88598e": 1, "csisolatinhebrew": 1, "hebrew": 1,
|
||||
"iso-8859-8": 1, "iso-8859-8-e": 1, "iso-ir-138": 1, "iso8859-8": 1,
|
||||
"iso88598": 1, "iso_8859-8": 1, "iso_8859-8:1988": 1, "visual": 1,
|
||||
"csiso88598i": 1, "iso-8859-8-i": 1, "logical": 1, "csisolatin6": 1,
|
||||
"iso-8859-10": 1, "iso-ir-157": 1, "iso8859-10": 1, "iso885910": 1,
|
||||
"l6": 1, "latin6": 1, "iso-8859-13": 1, "iso8859-13": 1, "iso885913": 1,
|
||||
"iso-8859-14": 1, "iso8859-14": 1, "iso885914": 1, "csisolatin9": 1,
|
||||
"iso-8859-15": 1, "iso8859-15": 1, "iso885915": 1, "iso_8859-15": 1,
|
||||
"l9": 1, "iso-8859-16": 1, "cskoi8r": 1, "koi": 1, "koi8": 1, "koi8-r": 1,
|
||||
"koi8_r": 1, "koi8-u": 1, "csmacintosh": 1, "mac": 1, "macintosh": 1,
|
||||
"x-mac-roman": 1, "dos-874": 1, "iso-8859-11": 1, "iso8859-11": 1,
|
||||
"iso885911": 1, "tis-620": 1, "windows-874": 1, "cp1250": 1,
|
||||
"windows-1250": 1, "x-cp1250": 1, "cp1251": 1, "windows-1251": 1,
|
||||
"x-cp1251": 1, "ansi_x3.4-1968": 1, "ascii": 1, "cp1252": 1, "cp819": 1,
|
||||
"csisolatin1": 1, "ibm819": 1, "iso-8859-1": 1, "iso-ir-100": 1,
|
||||
"iso8859-1": 1, "iso88591": 1, "iso_8859-1": 1, "iso_8859-1:1987": 1,
|
||||
"l1": 1, "latin1": 1, "us-ascii": 1, "windows-1252": 1, "x-cp1252": 1,
|
||||
"cp1253": 1, "windows-1253": 1, "x-cp1253": 1, "cp1254": 1, "csisolatin5": 1,
|
||||
"iso-8859-9": 1, "iso-ir-148": 1, "iso8859-9": 1, "iso88599": 1,
|
||||
"iso_8859-9": 1, "iso_8859-9:1989": 1, "l5": 1, "latin5": 1,
|
||||
"windows-1254": 1, "x-cp1254": 1, "cp1255": 1, "windows-1255": 1,
|
||||
"x-cp1255": 1, "cp1256": 1, "windows-1256": 1, "x-cp1256": 1, "cp1257": 1,
|
||||
"windows-1257": 1, "x-cp1257": 1, "cp1258": 1, "windows-1258": 1,
|
||||
"x-cp1258": 1, "x-mac-cyrillic": 1, "x-mac-ukrainian": 1, "chinese": 1,
|
||||
"csgb2312": 1, "csiso58gb231280": 1, "gb2312": 1, "gb_2312": 1,
|
||||
"gb_2312-80": 1, "gbk": 1, "iso-ir-58": 1, "x-gbk": 1, "gb18030": 1,
|
||||
"hz-gb-2312": 1, "big5": 1, "big5-hkscs": 1, "cn-big5": 1, "csbig5": 1,
|
||||
"x-x-big5": 1, "cseucpkdfmtjapanese": 1, "euc-jp": 1, "x-euc-jp": 1,
|
||||
"csiso2022jp": 1, "iso-2022-jp": 1, "csshiftjis": 1, "ms_kanji": 1,
|
||||
"shift-jis": 1, "shift_jis": 1, "sjis": 1, "windows-31j": 1, "x-sjis": 1,
|
||||
"cseuckr": 1, "csksc56011987": 1, "euc-kr": 1, "iso-ir-149": 1, "korean": 1,
|
||||
"ks_c_5601-1987": 1, "ks_c_5601-1989": 1, "ksc5601": 1, "ksc_5601": 1,
|
||||
"windows-949": 1, "csiso2022kr": 1, "iso-2022-kr": 1, "utf-16": 1,
|
||||
"utf-16le": 1, "utf-16be": 1, "x-user-defined": 1 };
|
||||
|
|
|
@ -12,10 +12,12 @@ const { Cc, Ci, CC } = require("chrome");
|
|||
|
||||
const { setTimeout } = require("../timers");
|
||||
const { Stream, InputStream, OutputStream } = require("./stream");
|
||||
const { emit, on } = require("../event/core");
|
||||
const { Buffer } = require("./buffer");
|
||||
const { ns } = require("../core/namespace");
|
||||
const { Class } = require("../core/heritage");
|
||||
|
||||
|
||||
const nsILocalFile = CC("@mozilla.org/file/local;1", "nsILocalFile",
|
||||
"initWithPath");
|
||||
const FileOutputStream = CC("@mozilla.org/network/file-output-stream;1",
|
||||
|
@ -33,6 +35,8 @@ const { createOutputTransport, createInputTransport } =
|
|||
Cc["@mozilla.org/network/stream-transport-service;1"].
|
||||
getService(Ci.nsIStreamTransportService);
|
||||
|
||||
const { OPEN_UNBUFFERED } = Ci.nsITransport;
|
||||
|
||||
|
||||
const { REOPEN_ON_REWIND, DEFER_OPEN } = Ci.nsIFileInputStream;
|
||||
const { DIRECTORY_TYPE, NORMAL_FILE_TYPE } = Ci.nsIFile;
|
||||
|
@ -157,14 +161,16 @@ const ReadStream = Class({
|
|||
// Open an input stream on a transport. We don"t pass flags to guarantee
|
||||
// non-blocking stream semantics. Also we use defaults for segment size &
|
||||
// count.
|
||||
let asyncInputStream = transport.openInputStream(null, 0, 0);
|
||||
let binaryInputStream = BinaryInputStream(asyncInputStream);
|
||||
nsIBinaryInputStream(fd, binaryInputStream);
|
||||
let pump = StreamPump(asyncInputStream, position, length, 0, 0, false);
|
||||
|
||||
InputStream.prototype.initialize.call(this, {
|
||||
input: binaryInputStream, pump: pump
|
||||
asyncInputStream: transport.openInputStream(null, 0, 0)
|
||||
});
|
||||
|
||||
// Close file descriptor on end and destroy the stream.
|
||||
on(this, "end", _ => {
|
||||
this.destroy();
|
||||
emit(this, "close");
|
||||
});
|
||||
|
||||
this.read();
|
||||
},
|
||||
destroy: function() {
|
||||
|
@ -211,21 +217,20 @@ const WriteStream = Class({
|
|||
// Open an output stream on a transport. We don"t pass flags to guarantee
|
||||
// non-blocking stream semantics. Also we use defaults for segment size &
|
||||
// count.
|
||||
let asyncOutputStream = transport.openOutputStream(null, 0, 0);
|
||||
// Finally we create a non-blocking binary output stream. This will allows
|
||||
// us to write buffers as byte arrays without any further transcoding.
|
||||
let binaryOutputStream = BinaryOutputStream(asyncOutputStream);
|
||||
nsIBinaryOutputStream(fd, binaryOutputStream);
|
||||
|
||||
// Storing output stream so that it can beaccessed later.
|
||||
OutputStream.prototype.initialize.call(this, {
|
||||
output: binaryOutputStream,
|
||||
asyncOutputStream: asyncOutputStream
|
||||
asyncOutputStream: transport.openOutputStream(OPEN_UNBUFFERED, 0, 0),
|
||||
output: output
|
||||
});
|
||||
|
||||
// For write streams "finish" basically means close.
|
||||
on(this, "finish", _ => {
|
||||
this.destroy();
|
||||
emit(this, "close");
|
||||
});
|
||||
},
|
||||
destroy: function() {
|
||||
closeSync(this.fd);
|
||||
OutputStream.prototype.destroy.call(this);
|
||||
closeSync(this.fd);
|
||||
}
|
||||
});
|
||||
exports.WriteStream = WriteStream;
|
||||
|
@ -365,7 +370,7 @@ function ftruncate(fd, length, callback) {
|
|||
}
|
||||
exports.ftruncate = ftruncate;
|
||||
|
||||
function ftruncateSync(fd, length) {
|
||||
function ftruncateSync(fd, length = 0) {
|
||||
writeSync(fd, new Buffer(length), 0, length, 0);
|
||||
}
|
||||
exports.ftruncateSync = ftruncateSync;
|
||||
|
@ -634,6 +639,8 @@ function openSync(path, flags, mode) {
|
|||
let [ fd, flags, mode, file ] =
|
||||
[ { path: path }, Flags(flags), Mode(mode), nsILocalFile(path) ];
|
||||
|
||||
nsIFile(fd, file);
|
||||
|
||||
// If trying to open file for just read that does not exists
|
||||
// need to throw exception as node does.
|
||||
if (!file.exists() && !isWritable(flags))
|
||||
|
@ -675,7 +682,9 @@ function writeSync(fd, buffer, offset, length, position) {
|
|||
}
|
||||
let writeStream = new WriteStream(fd, { position: position,
|
||||
length: length });
|
||||
let output = nsIBinaryOutputStream(fd);
|
||||
|
||||
let output = BinaryOutputStream(nsIFileOutputStream(fd));
|
||||
nsIBinaryOutputStream(fd, output);
|
||||
// We write content as a byte array as this will avoid any transcoding
|
||||
// if content was a buffer.
|
||||
output.writeByteArray(buffer.valueOf(), buffer.length);
|
||||
|
@ -736,10 +745,14 @@ function readSync(fd, buffer, offset, length, position) {
|
|||
// without blocking the main thread.
|
||||
let binaryInputStream = BinaryInputStream(input);
|
||||
let count = length === ALL ? binaryInputStream.available() : length;
|
||||
var bytes = binaryInputStream.readByteArray(count);
|
||||
buffer.copy.call(bytes, buffer, offset);
|
||||
if (offset === 0) binaryInputStream.readArrayBuffer(count, buffer.buffer);
|
||||
else {
|
||||
let chunk = new Buffer(count);
|
||||
binaryInputStream.readArrayBuffer(count, chunk.buffer);
|
||||
chunk.copy(buffer, offset);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
return buffer.slice(offset, offset + count);
|
||||
};
|
||||
exports.readSync = readSync;
|
||||
|
||||
|
@ -759,9 +772,9 @@ exports.readSync = readSync;
|
|||
function read(fd, buffer, offset, length, position, callback) {
|
||||
let bytesRead = 0;
|
||||
let readStream = new ReadStream(fd, { position: position, length: length });
|
||||
readStream.on("data", function onData(chunck) {
|
||||
chunck.copy(buffer, offset + bytesRead);
|
||||
bytesRead += chunck.length;
|
||||
readStream.on("data", function onData(data) {
|
||||
data.copy(buffer, offset + bytesRead);
|
||||
bytesRead += data.length;
|
||||
});
|
||||
readStream.on("end", function onEnd() {
|
||||
callback(null, bytesRead, buffer);
|
||||
|
@ -781,19 +794,26 @@ function readFile(path, encoding, callback) {
|
|||
encoding = null
|
||||
}
|
||||
|
||||
let buffer = new Buffer();
|
||||
let buffer = null;
|
||||
try {
|
||||
let readStream = new ReadStream(path);
|
||||
readStream.on("data", function(chunck) {
|
||||
chunck.copy(buffer, buffer.length);
|
||||
readStream.on("data", function(data) {
|
||||
if (!buffer) buffer = data;
|
||||
else {
|
||||
let bufferred = buffer
|
||||
buffer = new Buffer(buffer.length + data.length);
|
||||
bufferred.copy(buffer, 0);
|
||||
data.copy(buffer, bufferred.length);
|
||||
}
|
||||
});
|
||||
readStream.on("error", function onError(error) {
|
||||
callback(error);
|
||||
readStream.destroy();
|
||||
});
|
||||
readStream.on("end", function onEnd() {
|
||||
callback(null, buffer);
|
||||
// Note: Need to destroy before invoking a callback
|
||||
// so that file descriptor is released.
|
||||
readStream.destroy();
|
||||
callback(null, buffer);
|
||||
});
|
||||
} catch (error) {
|
||||
setTimeout(callback, 0, error);
|
||||
|
@ -807,8 +827,9 @@ exports.readFile = readFile;
|
|||
* Otherwise it returns a buffer.
|
||||
*/
|
||||
function readFileSync(path, encoding) {
|
||||
let buffer = new Buffer();
|
||||
let fd = openSync(path, "r");
|
||||
let size = fstatSync(fd).size;
|
||||
let buffer = new Buffer(size);
|
||||
try {
|
||||
readSync(fd, buffer, 0, ALL, 0);
|
||||
}
|
||||
|
@ -833,13 +854,16 @@ function writeFile(path, content, encoding, callback) {
|
|||
content = new Buffer(content, encoding);
|
||||
|
||||
let writeStream = new WriteStream(path);
|
||||
writeStream.on("error", function onError(error) {
|
||||
let error = null;
|
||||
|
||||
writeStream.end(content, function() {
|
||||
writeStream.destroy();
|
||||
callback(error);
|
||||
writeStream.destroy();
|
||||
});
|
||||
writeStream.write(content, function onDrain() {
|
||||
|
||||
writeStream.on("error", function onError(reason) {
|
||||
error = reason;
|
||||
writeStream.destroy();
|
||||
callback(null);
|
||||
});
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
|
|
|
@ -8,99 +8,45 @@ module.metadata = {
|
|||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const { CC, Cc, Ci, Cu, Cr, components } = require("chrome");
|
||||
const { EventTarget } = require("../event/target");
|
||||
const { emit } = require("../event/core");
|
||||
const { Buffer } = require("./buffer");
|
||||
const { Class } = require("../core/heritage");
|
||||
const { setTimeout } = require("../timers");
|
||||
const { ns } = require("../core/namespace");
|
||||
|
||||
function isFunction(value) typeof value === "function"
|
||||
|
||||
const MultiplexInputStream = CC("@mozilla.org/io/multiplex-input-stream;1",
|
||||
"nsIMultiplexInputStream");
|
||||
const AsyncStreamCopier = CC("@mozilla.org/network/async-stream-copier;1",
|
||||
"nsIAsyncStreamCopier", "init");
|
||||
const StringInputStream = CC("@mozilla.org/io/string-input-stream;1",
|
||||
"nsIStringInputStream");
|
||||
const ArrayBufferInputStream = CC("@mozilla.org/io/arraybuffer-input-stream;1",
|
||||
"nsIArrayBufferInputStream");
|
||||
|
||||
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream", "setInputStream");
|
||||
const InputStreamPump = CC("@mozilla.org/network/input-stream-pump;1",
|
||||
"nsIInputStreamPump", "init");
|
||||
|
||||
const threadManager = Cc["@mozilla.org/thread-manager;1"].
|
||||
getService(Ci.nsIThreadManager);
|
||||
|
||||
const eventTarget = Cc["@mozilla.org/network/socket-transport-service;1"].
|
||||
getService(Ci.nsIEventTarget);
|
||||
|
||||
let isFunction = value => typeof(value) === "function"
|
||||
|
||||
function accessor() {
|
||||
let map = new WeakMap();
|
||||
return function(fd, value) {
|
||||
if (value === null) map.delete(fd);
|
||||
if (value !== undefined) map.set(fd, value);
|
||||
return map.get(fd);
|
||||
return function(target, value) {
|
||||
if (value)
|
||||
map.set(target, value);
|
||||
return map.get(target);
|
||||
}
|
||||
}
|
||||
|
||||
let nsIInputStreamPump = accessor();
|
||||
let nsIAsyncOutputStream = accessor();
|
||||
let nsIInputStream = accessor();
|
||||
let nsIOutputStream = accessor();
|
||||
|
||||
|
||||
/**
|
||||
* Utility function / hack that we use to figure if output stream is closed.
|
||||
*/
|
||||
function isClosed(stream) {
|
||||
// We assume that stream is not closed.
|
||||
let isClosed = false;
|
||||
stream.asyncWait({
|
||||
// If `onClose` callback is called before outer function returns
|
||||
// (synchronously) `isClosed` will be set to `true` identifying
|
||||
// that stream is closed.
|
||||
onOutputStreamReady: function onClose() isClosed = true
|
||||
|
||||
// `WAIT_CLOSURE_ONLY` flag overrides the default behavior, causing the
|
||||
// `onOutputStreamReady` notification to be suppressed until the stream
|
||||
// becomes closed.
|
||||
}, stream.WAIT_CLOSURE_ONLY, 0, null);
|
||||
return isClosed;
|
||||
}
|
||||
/**
|
||||
* Utility function takes output `stream`, `onDrain`, `onClose` callbacks and
|
||||
* calls one of this callbacks depending on stream state. It is guaranteed
|
||||
* that only one called will be called and it will be called asynchronously.
|
||||
* @param {nsIAsyncOutputStream} stream
|
||||
* @param {Function} onDrain
|
||||
* callback that is called when stream becomes writable.
|
||||
* @param {Function} onClose
|
||||
* callback that is called when stream becomes closed.
|
||||
*/
|
||||
function onStateChange(stream, target) {
|
||||
let isAsync = false;
|
||||
stream.asyncWait({
|
||||
onOutputStreamReady: function onOutputStreamReady() {
|
||||
// If `isAsync` was not yet set to `true` by the last line we know that
|
||||
// `onOutputStreamReady` was called synchronously. In such case we just
|
||||
// defer execution until next turn of event loop.
|
||||
if (!isAsync)
|
||||
return setTimeout(onOutputStreamReady, 0);
|
||||
|
||||
// As it"s not clear what is a state of the stream (TODO: Is there really
|
||||
// no better way ?) we employ hack (see details in `isClosed`) to verify
|
||||
// if stream is closed.
|
||||
emit(target, isClosed(stream) ? "close" : "drain");
|
||||
}
|
||||
}, 0, 0, null);
|
||||
isAsync = true;
|
||||
}
|
||||
|
||||
function pump(stream) {
|
||||
let input = nsIInputStream(stream);
|
||||
nsIInputStreamPump(stream).asyncRead({
|
||||
onStartRequest: function onStartRequest() {
|
||||
emit(stream, "start");
|
||||
},
|
||||
onDataAvailable: function onDataAvailable(req, c, is, offset, count) {
|
||||
try {
|
||||
let bytes = input.readByteArray(count);
|
||||
emit(stream, "data", new Buffer(bytes, stream.encoding));
|
||||
} catch (error) {
|
||||
emit(stream, "error", error);
|
||||
stream.readable = false;
|
||||
}
|
||||
},
|
||||
onStopRequest: function onStopRequest() {
|
||||
stream.readable = false;
|
||||
emit(stream, "end");
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
const Stream = Class({
|
||||
extends: EventTarget,
|
||||
initialize: function() {
|
||||
|
@ -120,7 +66,8 @@ const Stream = Class({
|
|||
}
|
||||
}
|
||||
function onDrain() {
|
||||
if (source.readable) source.resume();
|
||||
if (source.readable)
|
||||
source.resume();
|
||||
}
|
||||
function onEnd() {
|
||||
target.end();
|
||||
|
@ -176,18 +123,69 @@ const Stream = Class({
|
|||
});
|
||||
exports.Stream = Stream;
|
||||
|
||||
|
||||
let nsIStreamListener = accessor();
|
||||
let nsIInputStreamPump = accessor();
|
||||
let nsIAsyncInputStream = accessor();
|
||||
let nsIBinaryInputStream = accessor();
|
||||
|
||||
const StreamListener = Class({
|
||||
initialize: function(stream) {
|
||||
this.stream = stream;
|
||||
},
|
||||
|
||||
// Next three methods are part of `nsIStreamListener` interface and are
|
||||
// invoked by `nsIInputStreamPump.asyncRead`.
|
||||
onDataAvailable: function(request, context, input, offset, count) {
|
||||
let stream = this.stream;
|
||||
let buffer = new ArrayBuffer(count);
|
||||
nsIBinaryInputStream(stream).readArrayBuffer(count, buffer);
|
||||
emit(stream, "data", new Buffer(buffer, stream.encoding));
|
||||
},
|
||||
|
||||
// Next two methods implement `nsIRequestObserver` interface and are invoked
|
||||
// by `nsIInputStreamPump.asyncRead`.
|
||||
onStartRequest: function() {},
|
||||
// Called to signify the end of an asynchronous request. We only care to
|
||||
// discover errors.
|
||||
onStopRequest: function(request, context, status) {
|
||||
let stream = this.stream;
|
||||
stream.readable = false;
|
||||
if (!components.isSuccessCode(status))
|
||||
emit(stream, "error", status);
|
||||
else
|
||||
emit(stream, "end");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const InputStream = Class({
|
||||
extends: Stream,
|
||||
readable: false,
|
||||
paused: false,
|
||||
initialize: function initialize(options) {
|
||||
let { input, pump } = options;
|
||||
let { asyncInputStream } = options;
|
||||
|
||||
this.readable = true;
|
||||
this.paused = false;
|
||||
nsIInputStream(this, input);
|
||||
nsIInputStreamPump(this, pump);
|
||||
|
||||
let binaryInputStream = new BinaryInputStream(asyncInputStream);
|
||||
let inputStreamPump = new InputStreamPump(asyncInputStream,
|
||||
-1, -1, 0, 0, false);
|
||||
let streamListener = new StreamListener(this);
|
||||
|
||||
nsIAsyncInputStream(this, asyncInputStream);
|
||||
nsIInputStreamPump(this, inputStreamPump);
|
||||
nsIBinaryInputStream(this, binaryInputStream);
|
||||
nsIStreamListener(this, streamListener);
|
||||
|
||||
this.asyncInputStream = asyncInputStream;
|
||||
this.inputStreamPump = inputStreamPump;
|
||||
this.binaryInputStream = binaryInputStream;
|
||||
},
|
||||
get status() nsIInputStreamPump(this).status,
|
||||
read: function() pump(this),
|
||||
read: function() {
|
||||
nsIInputStreamPump(this).asyncRead(nsIStreamListener(this), null);
|
||||
},
|
||||
pause: function pause() {
|
||||
this.paused = true;
|
||||
nsIInputStreamPump(this).suspend();
|
||||
|
@ -198,67 +196,176 @@ const InputStream = Class({
|
|||
nsIInputStreamPump(this).resume();
|
||||
emit(this, "resume");
|
||||
},
|
||||
destroy: function destroy() {
|
||||
close: function close() {
|
||||
this.readable = false;
|
||||
try {
|
||||
emit(this, "close", null);
|
||||
nsIInputStreamPump(this).cancel(null);
|
||||
nsIInputStreamPump(this, null);
|
||||
nsIInputStreamPump(this).cancel(Cr.NS_OK);
|
||||
nsIBinaryInputStream(this).close();
|
||||
nsIAsyncInputStream(this).close();
|
||||
},
|
||||
destroy: function destroy() {
|
||||
this.close();
|
||||
|
||||
nsIInputStream(this).close();
|
||||
nsIInputStream(this, null);
|
||||
} catch (error) {
|
||||
emit(this, "error", error);
|
||||
}
|
||||
nsIInputStreamPump(this);
|
||||
nsIAsyncInputStream(this);
|
||||
nsIBinaryInputStream(this);
|
||||
nsIStreamListener(this);
|
||||
}
|
||||
});
|
||||
exports.InputStream = InputStream;
|
||||
|
||||
|
||||
|
||||
let nsIRequestObserver = accessor();
|
||||
let nsIAsyncOutputStream = accessor();
|
||||
let nsIAsyncStreamCopier = accessor();
|
||||
let nsIMultiplexInputStream = accessor();
|
||||
|
||||
const RequestObserver = Class({
|
||||
initialize: function(stream) {
|
||||
this.stream = stream;
|
||||
},
|
||||
// Method is part of `nsIRequestObserver` interface that is
|
||||
// invoked by `nsIAsyncStreamCopier.asyncCopy`.
|
||||
onStartRequest: function() {},
|
||||
// Method is part of `nsIRequestObserver` interface that is
|
||||
// invoked by `nsIAsyncStreamCopier.asyncCopy`.
|
||||
onStopRequest: function(request, context, status) {
|
||||
let stream = this.stream;
|
||||
stream.drained = true;
|
||||
|
||||
// Remove copied chunk.
|
||||
let multiplexInputStream = nsIMultiplexInputStream(stream);
|
||||
multiplexInputStream.removeStream(0);
|
||||
|
||||
// If there was an error report.
|
||||
if (!components.isSuccessCode(status))
|
||||
emit(stream, "error", status);
|
||||
|
||||
// If there more chunks in queue then flush them.
|
||||
else if (multiplexInputStream.count)
|
||||
stream.flush();
|
||||
|
||||
// If stream is still writable notify that queue has drained.
|
||||
else if (stream.writable)
|
||||
emit(stream, "drain");
|
||||
|
||||
// If stream is no longer writable close it.
|
||||
else {
|
||||
nsIAsyncStreamCopier(stream).cancel(Cr.NS_OK);
|
||||
nsIMultiplexInputStream(stream).close();
|
||||
nsIAsyncOutputStream(stream).close();
|
||||
nsIAsyncOutputStream(stream).flush();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const OutputStreamCallback = Class({
|
||||
initialize: function(stream) {
|
||||
this.stream = stream;
|
||||
},
|
||||
// Method is part of `nsIOutputStreamCallback` interface that
|
||||
// is invoked by `nsIAsyncOutputStream.asyncWait`. It is registered
|
||||
// with `WAIT_CLOSURE_ONLY` flag that overrides the default behavior,
|
||||
// causing the `onOutputStreamReady` notification to be suppressed until
|
||||
// the stream becomes closed.
|
||||
onOutputStreamReady: function(nsIAsyncOutputStream) {
|
||||
emit(this.stream, "finish");
|
||||
}
|
||||
});
|
||||
|
||||
const OutputStream = Class({
|
||||
extends: Stream,
|
||||
writable: false,
|
||||
drained: true,
|
||||
get bufferSize() {
|
||||
let multiplexInputStream = nsIMultiplexInputStream(this);
|
||||
return multiplexInputStream && multiplexInputStream.available();
|
||||
},
|
||||
initialize: function initialize(options) {
|
||||
let { output, asyncOutputStream } = options;
|
||||
|
||||
let { asyncOutputStream, output } = options;
|
||||
this.writable = true;
|
||||
nsIOutputStream(this, output);
|
||||
|
||||
// Ensure that `nsIAsyncOutputStream` was provided.
|
||||
asyncOutputStream.QueryInterface(Ci.nsIAsyncOutputStream);
|
||||
|
||||
// Create a `nsIMultiplexInputStream` and `nsIAsyncStreamCopier`. Former
|
||||
// is used to queue written data chunks that `asyncStreamCopier` will
|
||||
// asynchronously drain into `asyncOutputStream`.
|
||||
let multiplexInputStream = MultiplexInputStream();
|
||||
let asyncStreamCopier = AsyncStreamCopier(multiplexInputStream,
|
||||
output || asyncOutputStream,
|
||||
eventTarget,
|
||||
// nsIMultiplexInputStream
|
||||
// implemnts .readSegments()
|
||||
true,
|
||||
// nsIOutputStream may or
|
||||
// may not implemnet
|
||||
// .writeSegments().
|
||||
false,
|
||||
// Use default buffer size.
|
||||
null,
|
||||
// Should not close an input.
|
||||
false,
|
||||
// Should not close an output.
|
||||
false);
|
||||
|
||||
// Create `requestObserver` implementing `nsIRequestObserver` interface
|
||||
// in the constructor that's gonna be reused across several flushes.
|
||||
let requestObserver = RequestObserver(this);
|
||||
|
||||
|
||||
// Create observer that implements `nsIOutputStreamCallback` and register
|
||||
// using `WAIT_CLOSURE_ONLY` flag. That way it will be notfied once
|
||||
// `nsIAsyncOutputStream` is closed.
|
||||
asyncOutputStream.asyncWait(OutputStreamCallback(this),
|
||||
asyncOutputStream.WAIT_CLOSURE_ONLY,
|
||||
0,
|
||||
threadManager.currentThread);
|
||||
|
||||
nsIRequestObserver(this, requestObserver);
|
||||
nsIAsyncOutputStream(this, asyncOutputStream);
|
||||
nsIMultiplexInputStream(this, multiplexInputStream);
|
||||
nsIAsyncStreamCopier(this, asyncStreamCopier);
|
||||
|
||||
this.asyncOutputStream = asyncOutputStream;
|
||||
this.multiplexInputStream = multiplexInputStream;
|
||||
this.asyncStreamCopier = asyncStreamCopier;
|
||||
},
|
||||
write: function write(content, encoding, callback) {
|
||||
let output = nsIOutputStream(this);
|
||||
let asyncOutputStream = nsIAsyncOutputStream(this);
|
||||
|
||||
if (isFunction(encoding)) {
|
||||
callback = encoding;
|
||||
encoding = callback;
|
||||
}
|
||||
|
||||
// Flag indicating whether or not content has been flushed to the kernel
|
||||
// buffer.
|
||||
let isWritten = false;
|
||||
// If stream is not writable we throw an error.
|
||||
if (!this.writable)
|
||||
throw Error("stream not writable");
|
||||
if (!this.writable) throw Error("stream is not writable");
|
||||
|
||||
try {
|
||||
// If content is not a buffer then we create one out of it.
|
||||
if (!Buffer.isBuffer(content))
|
||||
content = new Buffer(content, encoding);
|
||||
let chunk = null;
|
||||
|
||||
// We write content as a byte array as this will avoid any transcoding
|
||||
// if content was a buffer.
|
||||
output.writeByteArray(content.valueOf(), content.length);
|
||||
output.flush();
|
||||
|
||||
if (callback) this.once("drain", callback);
|
||||
onStateChange(asyncOutputStream, this);
|
||||
return true;
|
||||
} catch (error) {
|
||||
// If errors occur we emit appropriate event.
|
||||
emit(this, "error", error);
|
||||
// If content is not a buffer then we create one out of it.
|
||||
if (Buffer.isBuffer(content)) {
|
||||
chunk = new ArrayBufferInputStream();
|
||||
chunk.setData(content.buffer, 0, content.length);
|
||||
}
|
||||
else {
|
||||
chunk = new StringInputStream();
|
||||
chunk.setData(content, content.length);
|
||||
}
|
||||
|
||||
if (callback)
|
||||
this.once("drain", callback);
|
||||
|
||||
// Queue up chunk to be copied to output sync.
|
||||
nsIMultiplexInputStream(this).appendStream(chunk);
|
||||
this.flush();
|
||||
|
||||
return this.drained;
|
||||
},
|
||||
flush: function flush() {
|
||||
nsIOutputStream(this).flush();
|
||||
flush: function() {
|
||||
if (this.drained) {
|
||||
this.drained = false;
|
||||
nsIAsyncStreamCopier(this).asyncCopy(nsIRequestObserver(this), null);
|
||||
}
|
||||
},
|
||||
end: function end(content, encoding, callback) {
|
||||
if (isFunction(content)) {
|
||||
|
@ -270,53 +377,59 @@ const OutputStream = Class({
|
|||
encoding = callback
|
||||
}
|
||||
|
||||
// Setting a listener to "close" event if passed.
|
||||
// Setting a listener to "finish" event if passed.
|
||||
if (isFunction(callback))
|
||||
this.once("close", callback);
|
||||
this.once("finish", callback);
|
||||
|
||||
|
||||
// If content is passed then we defer closing until we finish with writing.
|
||||
if (content)
|
||||
this.write(content, encoding, end.bind(this));
|
||||
// If we don"t write anything, then we close an outputStream.
|
||||
else
|
||||
nsIOutputStream(this).close();
|
||||
this.write(content, encoding);
|
||||
this.writable = false;
|
||||
|
||||
// Close `asyncOutputStream` only if output has drained. If it's
|
||||
// not drained than `asyncStreamCopier` is busy writing, so let
|
||||
// it finish. Note that since `this.writable` is false copier will
|
||||
// close `asyncOutputStream` once output drains.
|
||||
if (this.drained)
|
||||
nsIAsyncOutputStream(this).close();
|
||||
},
|
||||
destroy: function destroy(callback) {
|
||||
try {
|
||||
this.end(callback);
|
||||
nsIOutputStream(this, null);
|
||||
nsIAsyncOutputStream(this, null);
|
||||
} catch (error) {
|
||||
emit(this, "error", error);
|
||||
}
|
||||
destroy: function destroy() {
|
||||
nsIAsyncOutputStream(this).close();
|
||||
nsIAsyncOutputStream(this);
|
||||
nsIMultiplexInputStream(this);
|
||||
nsIAsyncStreamCopier(this);
|
||||
nsIRequestObserver(this);
|
||||
}
|
||||
});
|
||||
exports.OutputStream = OutputStream;
|
||||
|
||||
const DuplexStream = Class({
|
||||
extends: Stream,
|
||||
implements: [InputStream, OutputStream],
|
||||
allowHalfOpen: true,
|
||||
initialize: function initialize(options) {
|
||||
let { input, output, pump } = options;
|
||||
options = options || {};
|
||||
let { readable, writable, allowHalfOpen } = options;
|
||||
|
||||
this.writable = true;
|
||||
this.readable = true;
|
||||
this.encoding = null;
|
||||
InputStream.prototype.initialize.call(this, options);
|
||||
OutputStream.prototype.initialize.call(this, options);
|
||||
|
||||
nsIInputStream(this, input);
|
||||
nsIOutputStream(this, output);
|
||||
nsIInputStreamPump(this, pump);
|
||||
if (readable === false)
|
||||
this.readable = false;
|
||||
|
||||
if (writable === false)
|
||||
this.writable = false;
|
||||
|
||||
if (allowHalfOpen === false)
|
||||
this.allowHalfOpen = false;
|
||||
|
||||
// If in a half open state and it's disabled enforce end.
|
||||
this.once("end", () => {
|
||||
if (!this.allowHalfOpen && (!this.readable || !this.writable))
|
||||
this.end();
|
||||
});
|
||||
},
|
||||
read: InputStream.prototype.read,
|
||||
pause: InputStream.prototype.pause,
|
||||
resume: InputStream.prototype.resume,
|
||||
|
||||
write: OutputStream.prototype.write,
|
||||
flush: OutputStream.prototype.flush,
|
||||
end: OutputStream.prototype.end,
|
||||
|
||||
destroy: function destroy(error) {
|
||||
if (error)
|
||||
emit(this, "error", error);
|
||||
InputStream.prototype.destroy.call(this);
|
||||
OutputStream.prototype.destroy.call(this);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ module.metadata = {
|
|||
"stability": "unstable"
|
||||
};
|
||||
|
||||
const { setTimeout } = require("../timers");
|
||||
const { setImmediate, setTimeout } = require("../timers");
|
||||
const { deprecateFunction } = require("../util/deprecate");
|
||||
|
||||
/**
|
||||
|
@ -30,13 +30,12 @@ exports.method = method;
|
|||
/**
|
||||
* Takes a function and returns a wrapped one instead, calling which will call
|
||||
* original function in the next turn of event loop. This is basically utility
|
||||
* to do `setTimeout(function() { ... }, 0)`, with a difference that returned
|
||||
* to do `setImmediate(function() { ... })`, with a difference that returned
|
||||
* function is reused, instead of creating a new one each time. This also allows
|
||||
* to use this functions as event listeners.
|
||||
*/
|
||||
function defer(f) {
|
||||
return function deferred()
|
||||
setTimeout(invoke, 0, f, arguments, this);
|
||||
return function deferred() setImmediate(invoke, f, arguments, this);
|
||||
}
|
||||
exports.defer = defer;
|
||||
// Exporting `remit` alias as `defer` may conflict with promises.
|
||||
|
|
|
@ -68,19 +68,11 @@ exports.exit = function exit(code) {
|
|||
appStartup.quit(code ? E_ATTEMPT : E_FORCE);
|
||||
};
|
||||
|
||||
exports.stdout = new function() {
|
||||
let write = dump
|
||||
if ('logFile' in options && options.logFile) {
|
||||
let mode = PR_WRONLY | PR_CREATE_FILE | PR_APPEND;
|
||||
let stream = openFile(options.logFile, mode);
|
||||
write = function write(data) {
|
||||
let text = String(data);
|
||||
stream.write(text, text.length);
|
||||
stream.flush();
|
||||
}
|
||||
}
|
||||
return Object.freeze({ write: write });
|
||||
};
|
||||
// Adapter for nodejs's stdout & stderr:
|
||||
// http://nodejs.org/api/process.html#process_process_stdout
|
||||
let stdout = Object.freeze({ write: dump, end: dump });
|
||||
exports.stdout = stdout;
|
||||
exports.stderr = stdout;
|
||||
|
||||
/**
|
||||
* Returns a path of the system's or application's special directory / file
|
||||
|
@ -134,7 +126,7 @@ exports.build = appInfo.appBuildID;
|
|||
exports.id = appInfo.ID;
|
||||
|
||||
/**
|
||||
* The name of the application.
|
||||
* The name of the application.
|
||||
*/
|
||||
exports.name = appInfo.name;
|
||||
|
||||
|
|
|
@ -22,20 +22,7 @@ let consoleService = Cc['@mozilla.org/consoleservice;1'].getService().
|
|||
// For more details see: bug-673383
|
||||
exports.dump = stdout.write;
|
||||
|
||||
// Bug 718230: We need to send console messages to stdout and JS Console
|
||||
function forsakenConsoleDump(msg, level) {
|
||||
stdout.write(msg);
|
||||
|
||||
if (level === 'error') {
|
||||
let error = ScriptError();
|
||||
msg = msg.replace(/^error: /, '');
|
||||
error.init(msg, null, null, 0, 0, 0, 'Add-on SDK');
|
||||
consoleService.logMessage(error);
|
||||
}
|
||||
else
|
||||
consoleService.logStringMessage(msg);
|
||||
};
|
||||
exports.console = new PlainTextConsole(forsakenConsoleDump);
|
||||
exports.console = new PlainTextConsole();
|
||||
|
||||
// Provide CommonJS `define` to allow authoring modules in a format that can be
|
||||
// loaded both into jetpack and into browser via AMD loaders.
|
||||
|
|
|
@ -26,10 +26,9 @@ Object.defineProperties(tabs, {
|
|||
newTabWindow(options);
|
||||
return undefined;
|
||||
}
|
||||
// Open in active window if new window was not required.
|
||||
|
||||
let activeWindow = windows.activeWindow;
|
||||
let privateState = !!options.isPrivate;
|
||||
let privateState = (supportPrivateTabs && (options.isPrivate || isPrivate(activeWindow))) || false;
|
||||
|
||||
// if the active window is in the state that we need then use it
|
||||
if (activeWindow && (!supportPrivateTabs || privateState === isPrivate(activeWindow))) {
|
||||
|
|
|
@ -8,7 +8,7 @@ module.metadata = {
|
|||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const { Cc,Ci } = require("chrome");
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { Loader } = require('./loader');
|
||||
const { serializeStack, parseStack } = require("toolkit/loader");
|
||||
const { setTimeout } = require('../timers');
|
||||
|
@ -147,9 +147,11 @@ function reportMemoryUsage() {
|
|||
|
||||
var mgr = Cc["@mozilla.org/memory-reporter-manager;1"]
|
||||
.getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
var reporters = mgr.enumerateReporters();
|
||||
if (reporters.hasMoreElements())
|
||||
print("\n");
|
||||
|
||||
while (reporters.hasMoreElements()) {
|
||||
var reporter = reporters.getNext();
|
||||
reporter.QueryInterface(Ci.nsIMemoryReporter);
|
||||
|
@ -167,26 +169,24 @@ var gWeakrefInfo;
|
|||
|
||||
function checkMemory() {
|
||||
memory.gc();
|
||||
setTimeout(function () {
|
||||
memory.gc();
|
||||
setTimeout(function () {
|
||||
let leaks = getPotentialLeaks();
|
||||
let compartmentURLs = Object.keys(leaks.compartments).filter(function(url) {
|
||||
return !(url in startLeaks.compartments);
|
||||
});
|
||||
Cu.schedulePreciseGC(function () {
|
||||
let leaks = getPotentialLeaks();
|
||||
|
||||
let windowURLs = Object.keys(leaks.windows).filter(function(url) {
|
||||
return !(url in startLeaks.windows);
|
||||
});
|
||||
|
||||
for (let url of compartmentURLs)
|
||||
console.warn("LEAKED", leaks.compartments[url]);
|
||||
|
||||
for (let url of windowURLs)
|
||||
console.warn("LEAKED", leaks.windows[url]);
|
||||
|
||||
showResults();
|
||||
let compartmentURLs = Object.keys(leaks.compartments).filter(function(url) {
|
||||
return !(url in startLeaks.compartments);
|
||||
});
|
||||
|
||||
let windowURLs = Object.keys(leaks.windows).filter(function(url) {
|
||||
return !(url in startLeaks.windows);
|
||||
});
|
||||
|
||||
for (let url of compartmentURLs)
|
||||
console.warn("LEAKED", leaks.compartments[url]);
|
||||
|
||||
for (let url of windowURLs)
|
||||
console.warn("LEAKED", leaks.windows[url]);
|
||||
|
||||
showResults();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -298,6 +298,7 @@ function getPotentialLeaks() {
|
|||
let pos = spec.indexOf("!/");
|
||||
WHITELIST_BASE_URLS.push(spec.substring(0, pos + 2));
|
||||
|
||||
let zoneRegExp = new RegExp("^explicit/js-non-window/zones/zone[^/]+/compartment\\((.+)\\)");
|
||||
let compartmentRegexp = new RegExp("^explicit/js-non-window/compartments/non-window-global/compartment\\((.+)\\)/");
|
||||
let compartmentDetails = new RegExp("^([^,]+)(?:, (.+?))?(?: \\(from: (.*)\\))?$");
|
||||
let windowRegexp = new RegExp("^explicit/window-objects/top\\((.*)\\)/active");
|
||||
|
@ -318,8 +319,9 @@ function getPotentialLeaks() {
|
|||
let compartments = {};
|
||||
let windows = {};
|
||||
function logReporter(process, path, kind, units, amount, description) {
|
||||
let matches = compartmentRegexp.exec(path);
|
||||
if (matches) {
|
||||
let matches;
|
||||
|
||||
if ((matches = compartmentRegexp.exec(path)) || (matches = zoneRegExp.exec(path))) {
|
||||
if (matches[1] in compartments)
|
||||
return;
|
||||
|
||||
|
@ -576,7 +578,7 @@ var runTests = exports.runTests = function runTests(options) {
|
|||
if (options.parseable)
|
||||
testConsole = new TestRunnerTinderboxConsole(options);
|
||||
else
|
||||
testConsole = new TestRunnerConsole(new PlainTextConsole(print), options);
|
||||
testConsole = new TestRunnerConsole(new PlainTextConsole(), options);
|
||||
|
||||
loader = Loader(module, {
|
||||
console: testConsole,
|
||||
|
|
|
@ -7,22 +7,31 @@ module.metadata = {
|
|||
"stability": "stable"
|
||||
};
|
||||
|
||||
const { CC, Ci } = require('chrome');
|
||||
const { when: unload } = require('./system/unload');
|
||||
const { CC, Cc, Ci } = require("chrome");
|
||||
const { when: unload } = require("./system/unload");
|
||||
|
||||
const { TYPE_ONE_SHOT, TYPE_REPEATING_SLACK } = Ci.nsITimer;
|
||||
const Timer = CC('@mozilla.org/timer;1', 'nsITimer');
|
||||
const Timer = CC("@mozilla.org/timer;1", "nsITimer");
|
||||
const timers = Object.create(null);
|
||||
const threadManager = Cc["@mozilla.org/thread-manager;1"].
|
||||
getService(Ci.nsIThreadManager);
|
||||
const prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService).
|
||||
QueryInterface(Ci.nsIPrefBranch);
|
||||
|
||||
let MIN_DELAY = 4;
|
||||
// Try to get min timeout delay used by browser.
|
||||
try { MIN_DELAY = prefBranch.getIntPref("dom.min_timeout_value"); } finally {}
|
||||
|
||||
|
||||
// Last timer id.
|
||||
let lastID = 0;
|
||||
|
||||
// Sets typer either by timeout or by interval
|
||||
// depending on a given type.
|
||||
function setTimer(type, callback, delay) {
|
||||
function setTimer(type, callback, delay, ...args) {
|
||||
let id = ++ lastID;
|
||||
let timer = timers[id] = Timer();
|
||||
let args = Array.slice(arguments, 3);
|
||||
timer.initWithCallback({
|
||||
notify: function notify() {
|
||||
try {
|
||||
|
@ -34,20 +43,63 @@ function setTimer(type, callback, delay) {
|
|||
console.exception(error);
|
||||
}
|
||||
}
|
||||
}, delay || 0, type);
|
||||
}, Math.max(delay || MIN_DELAY), type);
|
||||
return id;
|
||||
}
|
||||
|
||||
function unsetTimer(id) {
|
||||
let timer = timers[id];
|
||||
delete timers[id];
|
||||
if (timer)
|
||||
timer.cancel();
|
||||
if (timer) timer.cancel();
|
||||
}
|
||||
|
||||
let immediates = new Map();
|
||||
|
||||
let dispatcher = _ => {
|
||||
// Allow scheduling of a new dispatch loop.
|
||||
dispatcher.scheduled = false;
|
||||
// Take a snapshot of timer `id`'s that have being present before
|
||||
// starting a dispatch loop, in order to ignore timers registered
|
||||
// in side effect to dispatch while also skipping immediates that
|
||||
// were removed in side effect.
|
||||
let ids = [id for ([id] of immediates)];
|
||||
for (let id of ids) {
|
||||
let immediate = immediates.get(id);
|
||||
if (immediate) {
|
||||
immediates.delete(id);
|
||||
try { immediate(); }
|
||||
catch (error) { console.exception(error); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setImmediate(callback, ...params) {
|
||||
let id = ++ lastID;
|
||||
// register new immediate timer with curried params.
|
||||
immediates.set(id, _ => callback.apply(callback, params));
|
||||
// if dispatch loop is not scheduled schedule one. Own scheduler
|
||||
if (!dispatcher.scheduled) {
|
||||
dispatcher.scheduled = true;
|
||||
threadManager.currentThread.dispatch(dispatcher,
|
||||
Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
function clearImmediate(id) {
|
||||
immediates.delete(id);
|
||||
}
|
||||
|
||||
// Bind timers so that toString-ing them looks same as on native timers.
|
||||
exports.setImmediate = setImmediate.bind(null);
|
||||
exports.clearImmediate = clearImmediate.bind(null);
|
||||
exports.setTimeout = setTimer.bind(null, TYPE_ONE_SHOT);
|
||||
exports.setInterval = setTimer.bind(null, TYPE_REPEATING_SLACK);
|
||||
exports.clearTimeout = unsetTimer.bind(null);
|
||||
exports.clearInterval = unsetTimer.bind(null);
|
||||
|
||||
unload(function() { Object.keys(timers).forEach(unsetTimer) });
|
||||
// all timers are cleared out on unload.
|
||||
unload(function() {
|
||||
immediates.clear();
|
||||
Object.keys(timers).forEach(unsetTimer)
|
||||
});
|
||||
|
|
|
@ -101,7 +101,7 @@ function fromIterator(iterator) {
|
|||
}
|
||||
exports.fromIterator = fromIterator;
|
||||
|
||||
function find(array, predicate) {
|
||||
function find(array, predicate, fallback) {
|
||||
var index = 0;
|
||||
var count = array.length;
|
||||
while (index < count) {
|
||||
|
@ -109,5 +109,6 @@ function find(array, predicate) {
|
|||
if (predicate(value)) return value;
|
||||
else index = index + 1;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
exports.find = find;
|
||||
|
|
|
@ -18,6 +18,8 @@ const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
|
|||
getService(Ci.nsIAppShellService);
|
||||
const WM = Cc['@mozilla.org/appshell/window-mediator;1'].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
const io = Cc['@mozilla.org/network/io-service;1'].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
const BROWSER = 'navigator:browser',
|
||||
URI_BROWSER = 'chrome://browser/content/browser.xul',
|
||||
|
@ -184,18 +186,21 @@ function serializeFeatures(options) {
|
|||
* Map of key, values like: `{ width: 10, height: 15, chrome: true, private: true }`.
|
||||
*/
|
||||
function open(uri, options) {
|
||||
options = options || {};
|
||||
uri = uri || URI_BROWSER;
|
||||
options = options || {}
|
||||
|
||||
if (['chrome', 'resource', 'data'].indexOf(io.newURI(uri, null, null).scheme) < 0)
|
||||
throw new Error('only chrome, resource and data uris are allowed');
|
||||
|
||||
let newWindow = windowWatcher.
|
||||
openWindow(options.parent || null,
|
||||
uri || URI_BROWSER,
|
||||
uri,
|
||||
options.name || null,
|
||||
serializeFeatures(options.features || {}),
|
||||
options.args || null);
|
||||
|
||||
return newWindow;
|
||||
}
|
||||
|
||||
|
||||
exports.open = open;
|
||||
|
||||
function onFocus(window) {
|
||||
|
|
|
@ -52,6 +52,9 @@ def parse_options(options, jetpack_id):
|
|||
doc.appendChild(root)
|
||||
|
||||
for pref in options:
|
||||
if ("hidden" in pref and pref["hidden"] == True):
|
||||
continue;
|
||||
|
||||
setting = doc.createElement("setting")
|
||||
setting.setAttribute("pref-name", pref["name"])
|
||||
setting.setAttribute("data-jetpack-id", jetpack_id)
|
||||
|
|
|
@ -30,7 +30,7 @@ PARSEABLE_TEST_NAME = re.compile(r'TEST-START \| ([^\n]+)\n')
|
|||
# The purpose of this timeout is to recover from infinite loops. It should be
|
||||
# longer than the amount of time any test run takes, including those on slow
|
||||
# machines running slow (debug) versions of Firefox.
|
||||
RUN_TIMEOUT = 45 * 60 # 45 minutes
|
||||
RUN_TIMEOUT = 1.5 * 60 * 60 # 1.5 Hour
|
||||
|
||||
# Maximum time we'll wait for tests to emit output, in seconds.
|
||||
# The purpose of this timeout is to recover from hangs. It should be longer
|
||||
|
@ -496,9 +496,6 @@ def run_app(harness_root_dir, manifest_rdf, harness_options,
|
|||
logfile = os.path.abspath(os.path.expanduser(logfile))
|
||||
maybe_remove_logfile()
|
||||
|
||||
if app_type != "fennec-on-device":
|
||||
harness_options['logFile'] = logfile
|
||||
|
||||
env = {}
|
||||
env.update(os.environ)
|
||||
env['MOZ_NO_REMOTE'] = '1'
|
||||
|
|
|
@ -330,13 +330,9 @@ GetExitCodeProcess = GetExitCodeProcessProto(
|
|||
GetExitCodeProcess.errcheck = ErrCheckBool
|
||||
|
||||
def CanCreateJobObject():
|
||||
currentProc = GetCurrentProcess()
|
||||
if IsProcessInJob(currentProc):
|
||||
jobinfo = QueryInformationJobObject(HANDLE(0), 'JobObjectExtendedLimitInformation')
|
||||
limitflags = jobinfo['BasicLimitInformation']['LimitFlags']
|
||||
return bool(limitflags & JOB_OBJECT_LIMIT_BREAKAWAY_OK) or bool(limitflags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
|
||||
else:
|
||||
return True
|
||||
# Running firefox in a job (from cfx) hangs on sites using flash plugin
|
||||
# so job creation is turned off for now. (see Bug 768651).
|
||||
return False
|
||||
|
||||
### testing functions
|
||||
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const xulApp = require("sdk/system/xul-app");
|
||||
const { PageMod } = require("sdk/page-mod");
|
||||
const tabs = require("sdk/tabs");
|
||||
const { startServerAsync } = require("sdk/test/httpd");
|
||||
|
||||
const serverPort = 8099;
|
||||
|
||||
exports.testCrossDomainIframe = function(assert, done) {
|
||||
let serverPort = 8099;
|
||||
let server = require("sdk/test/httpd").startServerAsync(serverPort);
|
||||
let server = startServerAsync(serverPort);
|
||||
server.registerPathHandler("/iframe", function handle(request, response) {
|
||||
response.write("<html><body>foo</body></html>");
|
||||
});
|
||||
|
@ -31,19 +32,23 @@ exports.testCrossDomainIframe = function(assert, done) {
|
|||
w.on("message", function (body) {
|
||||
assert.equal(body, "foo", "received iframe html content");
|
||||
pageMod.destroy();
|
||||
w.tab.close();
|
||||
server.stop(done);
|
||||
w.tab.close(function() {
|
||||
server.stop(done);
|
||||
});
|
||||
});
|
||||
|
||||
w.postMessage("http://localhost:8099/iframe");
|
||||
}
|
||||
});
|
||||
|
||||
tabs.open("about:credits");
|
||||
tabs.open({
|
||||
url: "about:home",
|
||||
inBackground: true
|
||||
});
|
||||
};
|
||||
|
||||
exports.testCrossDomainXHR = function(assert, done) {
|
||||
let serverPort = 8099;
|
||||
let server = require("sdk/test/httpd").startServerAsync(serverPort);
|
||||
let server = startServerAsync(serverPort);
|
||||
server.registerPathHandler("/xhr", function handle(request, response) {
|
||||
response.write("foo");
|
||||
});
|
||||
|
@ -65,22 +70,19 @@ exports.testCrossDomainXHR = function(assert, done) {
|
|||
w.on("message", function (body) {
|
||||
assert.equal(body, "foo", "received XHR content");
|
||||
pageMod.destroy();
|
||||
w.tab.close();
|
||||
server.stop(done);
|
||||
w.tab.close(function() {
|
||||
server.stop(done);
|
||||
});
|
||||
});
|
||||
|
||||
w.postMessage("http://localhost:8099/xhr");
|
||||
}
|
||||
});
|
||||
|
||||
tabs.open("about:credits");
|
||||
tabs.open({
|
||||
url: "about:home",
|
||||
inBackground: true
|
||||
});
|
||||
};
|
||||
|
||||
if (!xulApp.versionInRange(xulApp.platformVersion, "17.0a2", "*")) {
|
||||
module.exports = {
|
||||
"test Unsupported Application": function Unsupported (assert) {
|
||||
assert.pass("This firefox version doesn't support cross-domain-content permission.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
require("sdk/test/runner").runTestsFromModule(module);
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
'use strict';
|
||||
|
||||
const { setTimeout } = require('sdk/timers');
|
||||
|
||||
let mainStarted = false;
|
||||
|
||||
exports.main = function main(options, callbacks) {
|
||||
mainStarted = true;
|
||||
|
||||
let tests = {};
|
||||
|
||||
tests.testMainArguments = function(assert) {
|
||||
assert.ok(!!options, 'options argument provided to main');
|
||||
assert.ok('loadReason' in options, 'loadReason is in options provided by main');
|
||||
assert.equal(typeof callbacks.print, 'function', 'callbacks.print is a function');
|
||||
assert.equal(typeof callbacks.quit, 'function', 'callbacks.quit is a function');
|
||||
assert.equal(options.loadReason, 'install', 'options.loadReason is install');
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule({exports: tests});
|
||||
}
|
||||
|
||||
// this causes a fail if main does not start
|
||||
setTimeout(function() {
|
||||
if (mainStarted)
|
||||
return;
|
||||
|
||||
// main didn't start, fail..
|
||||
require("sdk/test/runner").runTestsFromModule({exports: {
|
||||
testFail: function(assert) assert.fail('Main did not start..')
|
||||
}});
|
||||
}, 500);
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"id": "test-main"
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
'use strict';
|
||||
|
||||
const { merge } = require('sdk/util/object');
|
||||
const app = require("sdk/system/xul-app");
|
||||
const app = require('sdk/system/xul-app');
|
||||
const { isGlobalPBSupported } = require('sdk/private-browsing/utils');
|
||||
|
||||
merge(module.exports,
|
||||
|
@ -18,7 +18,7 @@ merge(module.exports,
|
|||
|
||||
// Doesn't make sense to test window-utils and windows on fennec,
|
||||
// as there is only one window which is never private
|
||||
if (!app.is("Fennec"))
|
||||
if (!app.is('Fennec'))
|
||||
merge(module.exports, require('./test-windows'));
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
||||
|
|
|
@ -5,6 +5,8 @@ const { is } = require('sdk/system/xul-app');
|
|||
const { isPrivate } = require('sdk/private-browsing');
|
||||
const pbUtils = require('sdk/private-browsing/utils');
|
||||
const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
|
||||
const { promise: windowPromise, close, focus } = require('sdk/window/helpers');
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
|
||||
exports.testPrivateTabsAreListed = function (assert, done) {
|
||||
let originalTabCount = tabs.length;
|
||||
|
@ -26,7 +28,86 @@ exports.testPrivateTabsAreListed = function (assert, done) {
|
|||
assert.equal(tabs.length, originalTabCount + 1,
|
||||
'New non-private window\'s tab is visible in tabs list');
|
||||
}
|
||||
|
||||
tab.close(done);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
exports.testOpenTabWithPrivateActiveWindowNoIsPrivateOption = function(assert, done) {
|
||||
let window = getMostRecentBrowserWindow().OpenBrowserWindow({ private: true });
|
||||
|
||||
windowPromise(window, 'load').then(focus).then(function (window) {
|
||||
assert.ok(isPrivate(window), 'new window is private');
|
||||
|
||||
tabs.open({
|
||||
url: 'about:blank',
|
||||
onOpen: function(tab) {
|
||||
assert.ok(isPrivate(tab), 'new tab is private');
|
||||
assert.ok(isPrivate(getOwnerWindow(tab)), 'new tab window is private');
|
||||
assert.strictEqual(getOwnerWindow(tab), window, 'the tab window and the private window are the same');
|
||||
|
||||
close(window).then(done, assert.fail);
|
||||
}
|
||||
})
|
||||
}, assert.fail).then(null, assert.fail);
|
||||
}
|
||||
|
||||
exports.testOpenTabWithNonPrivateActiveWindowNoIsPrivateOption = function(assert, done) {
|
||||
let window = getMostRecentBrowserWindow().OpenBrowserWindow({ private: false });
|
||||
|
||||
windowPromise(window, 'load').then(focus).then(function (window) {
|
||||
assert.equal(isPrivate(window), false, 'new window is not private');
|
||||
|
||||
tabs.open({
|
||||
url: 'about:blank',
|
||||
onOpen: function(tab) {
|
||||
assert.equal(isPrivate(tab), false, 'new tab is not private');
|
||||
assert.equal(isPrivate(getOwnerWindow(tab)), false, 'new tab window is not private');
|
||||
assert.strictEqual(getOwnerWindow(tab), window, 'the tab window and the new window are the same');
|
||||
|
||||
close(window).then(done, assert.fail);
|
||||
}
|
||||
})
|
||||
}, assert.fail).then(null, assert.fail);
|
||||
}
|
||||
|
||||
exports.testOpenTabWithPrivateActiveWindowWithIsPrivateOptionTrue = function(assert, done) {
|
||||
let window = getMostRecentBrowserWindow().OpenBrowserWindow({ private: true });
|
||||
|
||||
windowPromise(window, 'load').then(focus).then(function (window) {
|
||||
assert.ok(isPrivate(window), 'new window is private');
|
||||
|
||||
tabs.open({
|
||||
url: 'about:blank',
|
||||
isPrivate: true,
|
||||
onOpen: function(tab) {
|
||||
assert.ok(isPrivate(tab), 'new tab is private');
|
||||
assert.ok(isPrivate(getOwnerWindow(tab)), 'new tab window is private');
|
||||
assert.strictEqual(getOwnerWindow(tab), window, 'the tab window and the private window are the same');
|
||||
|
||||
close(window).then(done, assert.fail);
|
||||
}
|
||||
})
|
||||
}, assert.fail).then(null, assert.fail);
|
||||
}
|
||||
|
||||
exports.testOpenTabWithNonPrivateActiveWindowWithIsPrivateOptionFalse = function(assert, done) {
|
||||
let window = getMostRecentBrowserWindow().OpenBrowserWindow({ private: false });
|
||||
|
||||
windowPromise(window, 'load').then(focus).then(function (window) {
|
||||
assert.equal(isPrivate(window), false, 'new window is not private');
|
||||
|
||||
tabs.open({
|
||||
url: 'about:blank',
|
||||
isPrivate: false,
|
||||
onOpen: function(tab) {
|
||||
assert.equal(isPrivate(tab), false, 'new tab is not private');
|
||||
assert.equal(isPrivate(getOwnerWindow(tab)), false, 'new tab window is not private');
|
||||
assert.strictEqual(getOwnerWindow(tab), window, 'the tab window and the new window are the same');
|
||||
|
||||
close(window).then(done, assert.fail);
|
||||
}
|
||||
})
|
||||
}, assert.fail).then(null, assert.fail);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
'use strict';
|
||||
|
||||
const { Cu } = require('chrome');
|
||||
const sp = require('sdk/simple-prefs');
|
||||
const app = require('sdk/system/xul-app');
|
||||
const self = require('sdk/self');
|
||||
const tabs = require('sdk/tabs');
|
||||
|
||||
const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
|
||||
|
||||
exports.testDefaultValues = function (assert) {
|
||||
assert.equal(sp.prefs.myHiddenInt, 5, 'myHiddenInt default is 5');
|
||||
assert.equal(sp.prefs.myInteger, 8, 'myInteger default is 8');
|
||||
assert.equal(sp.prefs.somePreference, 'TEST', 'somePreference default is correct');
|
||||
}
|
||||
|
||||
exports.testOptionsType = function(assert, done) {
|
||||
AddonManager.getAddonByID(self.id, function(aAddon) {
|
||||
assert.equal(aAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, 'options type is inline');
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
if (app.is('Firefox')) {
|
||||
exports.testAOM = function(assert, done) {
|
||||
tabs.open({
|
||||
url: 'about:addons',
|
||||
onReady: function(tab) {
|
||||
tab.attach({
|
||||
contentScript: 'AddonManager.getAddonByID("' + self.id + '", function(aAddon) {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.addEventListener("ViewChanged", function whenViewChanges() {\n' +
|
||||
'unsafeWindow.gViewController.viewObjects.detail.node.removeEventListener("ViewChanged", whenViewChanges, false);\n' +
|
||||
'setTimeout(function() {\n' + // TODO: figure out why this is necessary..
|
||||
'self.postMessage({\n' +
|
||||
'somePreference: getAttributes(unsafeWindow.document.querySelector("setting[title=\'some-title\']")),\n' +
|
||||
'myInteger: getAttributes(unsafeWindow.document.querySelector("setting[title=\'my-int\']")),\n' +
|
||||
'myHiddenInt: getAttributes(unsafeWindow.document.querySelector("setting[title=\'hidden-int\']"))\n' +
|
||||
'});\n' +
|
||||
'}, 250);\n' +
|
||||
'}, false);\n' +
|
||||
'unsafeWindow.gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true);\n' +
|
||||
'});\n' +
|
||||
'function getAttributes(ele) {\n' +
|
||||
'if (!ele) return {};\n' +
|
||||
'return {\n' +
|
||||
'pref: ele.getAttribute("pref"),\n' +
|
||||
'type: ele.getAttribute("type"),\n' +
|
||||
'title: ele.getAttribute("title"),\n' +
|
||||
'desc: ele.getAttribute("desc")\n' +
|
||||
'}\n' +
|
||||
'}\n',
|
||||
onMessage: function(msg) {
|
||||
// test somePreference
|
||||
assert.equal(msg.somePreference.type, 'string', 'some pref is a string');
|
||||
assert.equal(msg.somePreference.pref, 'extensions.'+self.id+'.somePreference', 'somePreference path is correct');
|
||||
assert.equal(msg.somePreference.title, 'some-title', 'somePreference title is correct');
|
||||
assert.equal(msg.somePreference.desc, 'Some short description for the preference', 'somePreference description is correct');
|
||||
|
||||
// test myInteger
|
||||
assert.equal(msg.myInteger.type, 'integer', 'myInteger is a int');
|
||||
assert.equal(msg.myInteger.pref, 'extensions.'+self.id+'.myInteger', 'extensions.test-simple-prefs.myInteger');
|
||||
assert.equal(msg.myInteger.title, 'my-int', 'myInteger title is correct');
|
||||
assert.equal(msg.myInteger.desc, 'How many of them we have.', 'myInteger desc is correct');
|
||||
|
||||
// test myHiddenInt
|
||||
assert.equal(msg.myHiddenInt.type, undefined, 'myHiddenInt was not displayed');
|
||||
assert.equal(msg.myHiddenInt.pref, undefined, 'myHiddenInt was not displayed');
|
||||
assert.equal(msg.myHiddenInt.title, undefined, 'myHiddenInt was not displayed');
|
||||
assert.equal(msg.myHiddenInt.desc, undefined, 'myHiddenInt was not displayed');
|
||||
|
||||
tab.close(done);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"id": "test-simple-prefs",
|
||||
"preferences": [{
|
||||
"name": "somePreference",
|
||||
"title": "some-title",
|
||||
"description": "Some short description for the preference",
|
||||
"type": "string",
|
||||
"value": "TEST"
|
||||
},
|
||||
{
|
||||
"description": "How many of them we have.",
|
||||
"name": "myInteger",
|
||||
"type": "integer",
|
||||
"value": 8,
|
||||
"title": "my-int"
|
||||
}, {
|
||||
"name": "myHiddenInt",
|
||||
"type": "integer",
|
||||
"hidden": true,
|
||||
"value": 5,
|
||||
"title": "hidden-int"
|
||||
}]
|
||||
}
|
|
@ -19,6 +19,7 @@ const { setTimeout } = require('sdk/timers');
|
|||
const { newURI } = require('sdk/url/utils');
|
||||
const { defer, all } = require('sdk/core/promise');
|
||||
const { once } = require('sdk/system/events');
|
||||
const { set } = require('sdk/preferences/service');
|
||||
const {
|
||||
Bookmark, Group, Separator,
|
||||
save, search,
|
||||
|
@ -45,12 +46,25 @@ function clearBookmarks (group) {
|
|||
? bmsrv.removeFolderChildren(group.id)
|
||||
: clearAllBookmarks();
|
||||
}
|
||||
exports.clearBookmarks = clearBookmarks;
|
||||
|
||||
function clearAllBookmarks () {
|
||||
[MENU, TOOLBAR, UNSORTED].forEach(clearBookmarks);
|
||||
}
|
||||
exports.clearAllBookmarks = clearAllBookmarks;
|
||||
|
||||
function clearHistory (done) {
|
||||
hsrv.removeAllPages();
|
||||
once('places-expiration-finished', done);
|
||||
}
|
||||
|
||||
// Cleans bookmarks and history and disables maintanance
|
||||
function resetPlaces (done) {
|
||||
// Set last maintenance to current time to prevent
|
||||
// Places DB maintenance occuring and locking DB
|
||||
set('places.database.lastMaintenance', Math.floor(Date.now() / 1000));
|
||||
clearAllBookmarks();
|
||||
clearHistory(done);
|
||||
}
|
||||
exports.resetPlaces = resetPlaces;
|
||||
|
||||
function compareWithHost (assert, item) {
|
||||
let id = item.id;
|
||||
|
@ -105,12 +119,6 @@ function createVisit (url) {
|
|||
return place;
|
||||
}
|
||||
|
||||
function clearHistory (done) {
|
||||
hsrv.removeAllPages();
|
||||
once('places-expiration-finished', done);
|
||||
}
|
||||
exports.clearHistory = clearHistory;
|
||||
|
||||
function createBookmark (data) {
|
||||
data = data || {};
|
||||
let item = {
|
||||
|
|
|
@ -111,12 +111,11 @@ exports.testTabProperties = function(test) {
|
|||
test.assertEqual(tab.url, url, "URL of the new tab matches");
|
||||
test.assert(tab.favicon, "favicon of the new tab is not empty");
|
||||
// TODO: remove need for this test by implementing the favicon feature
|
||||
// Poors man deepEqual with JSON.stringify...
|
||||
test.assertEqual(JSON.stringify(messages),
|
||||
JSON.stringify(['tab.favicon is deprecated, and ' +
|
||||
'currently favicon helpers are not yet supported ' +
|
||||
'by Fennec']),
|
||||
"favicon logs an error for now");
|
||||
test.assertEqual(messages[0].msg,
|
||||
"tab.favicon is deprecated, and " +
|
||||
"currently favicon helpers are not yet supported " +
|
||||
"by Fennec",
|
||||
"favicon logs an error for now");
|
||||
test.assertEqual(tab.style, null, "style of the new tab matches");
|
||||
test.assertEqual(tab.index, tabsLen, "index of the new tab matches");
|
||||
test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
|
||||
|
|
|
@ -85,3 +85,11 @@ exports.testUnique = function(test) {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.testFind = function(test) {
|
||||
let isOdd = (x) => x % 2;
|
||||
test.assertEqual(array.find([2, 4, 5, 7, 8, 9], isOdd), 5);
|
||||
test.assertEqual(array.find([2, 4, 6, 8], isOdd), undefined);
|
||||
test.assertEqual(array.find([2, 4, 6, 8], isOdd, null), null);
|
||||
};
|
||||
|
||||
|
|
|
@ -92,14 +92,4 @@ exports["test browser events ignore other wins"] = function(assert, done) {
|
|||
let window = open("data:text/html,not a browser");
|
||||
};
|
||||
|
||||
if (require("sdk/system/xul-app").is("Fennec")) {
|
||||
module.exports = {
|
||||
"test Unsupported Test": function UnsupportedTest (assert) {
|
||||
assert.pass(
|
||||
"Skipping this test until Fennec support is implemented." +
|
||||
"See bug 793071");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
require("test").run(exports);
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const hiddenFrames = require("sdk/frame/hidden-frame");
|
||||
|
||||
const { create: makeFrame } = require("sdk/frame/utils");
|
||||
const { window } = require("sdk/addon/window");
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { URL } = require("sdk/url");
|
||||
const testURI = require("sdk/self").data.url("test.html");
|
||||
const testHost = URL(testURI).scheme + '://' + URL(testURI).host;
|
||||
|
||||
/*
|
||||
* Utility function that allow to easily run a proxy test with a clean
|
||||
|
@ -12,41 +16,51 @@ const { Loader } = require('sdk/test/loader');
|
|||
*/
|
||||
function createProxyTest(html, callback) {
|
||||
return function (assert, done) {
|
||||
let url = 'data:text/html;charset=utf-8,' + encodeURI(html);
|
||||
let url = 'data:text/html;charset=utf-8,' + encodeURIComponent(html);
|
||||
let principalLoaded = false;
|
||||
|
||||
let hiddenFrame = hiddenFrames.add(hiddenFrames.HiddenFrame({
|
||||
onReady: function () {
|
||||
let element = makeFrame(window.document, {
|
||||
nodeName: "iframe",
|
||||
type: "content",
|
||||
allowJavascript: true,
|
||||
allowPlugins: true,
|
||||
allowAuth: true,
|
||||
uri: testURI
|
||||
});
|
||||
|
||||
function onDOMReady() {
|
||||
hiddenFrame.element.removeEventListener("DOMContentLoaded", onDOMReady,
|
||||
false);
|
||||
|
||||
let xrayWindow = hiddenFrame.element.contentWindow;
|
||||
let rawWindow = xrayWindow.wrappedJSObject;
|
||||
|
||||
let isDone = false;
|
||||
let helper = {
|
||||
xrayWindow: xrayWindow,
|
||||
rawWindow: rawWindow,
|
||||
createWorker: function (contentScript) {
|
||||
return createWorker(assert, xrayWindow, contentScript, helper.done);
|
||||
},
|
||||
done: function () {
|
||||
if (isDone)
|
||||
return;
|
||||
isDone = true;
|
||||
hiddenFrames.remove(hiddenFrame);
|
||||
done();
|
||||
}
|
||||
}
|
||||
callback(helper, assert);
|
||||
}
|
||||
|
||||
hiddenFrame.element.addEventListener("DOMContentLoaded", onDOMReady, false);
|
||||
hiddenFrame.element.setAttribute("src", url);
|
||||
element.addEventListener("DOMContentLoaded", onDOMReady, false);
|
||||
|
||||
function onDOMReady() {
|
||||
// Reload frame after getting principal from `testURI`
|
||||
if (!principalLoaded) {
|
||||
element.setAttribute("src", url);
|
||||
principalLoaded = true;
|
||||
return;
|
||||
}
|
||||
}));
|
||||
|
||||
assert.equal(element.getAttribute("src"), url, "correct URL loaded");
|
||||
element.removeEventListener("DOMContentLoaded", onDOMReady,
|
||||
false);
|
||||
let xrayWindow = element.contentWindow;
|
||||
let rawWindow = xrayWindow.wrappedJSObject;
|
||||
|
||||
let isDone = false;
|
||||
let helper = {
|
||||
xrayWindow: xrayWindow,
|
||||
rawWindow: rawWindow,
|
||||
createWorker: function (contentScript) {
|
||||
return createWorker(assert, xrayWindow, contentScript, helper.done);
|
||||
},
|
||||
done: function () {
|
||||
if (isDone)
|
||||
return;
|
||||
isDone = true;
|
||||
element.parentNode.removeChild(element);
|
||||
done();
|
||||
}
|
||||
};
|
||||
callback(helper, assert);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -165,9 +179,9 @@ exports["test postMessage"] = createProxyTest(html, function (helper, assert) {
|
|||
// xrays use current compartments when calling postMessage method.
|
||||
// Whereas js proxies was using postMessage method compartment,
|
||||
// not the caller one.
|
||||
assert.equal(event.source, helper.xrayWindow,
|
||||
"event.source is the top window");
|
||||
assert.equal(event.origin, "null", "origin is null");
|
||||
assert.strictEqual(event.source, helper.xrayWindow,
|
||||
"event.source is the top window");
|
||||
assert.equal(event.origin, testHost, "origin matches testHost");
|
||||
|
||||
assert.equal(event.data, "{\"foo\":\"bar\\n \\\"escaped\\\".\"}",
|
||||
"message data is correct");
|
||||
|
@ -216,7 +230,9 @@ exports["test Object Listener"] = createProxyTest(html, function (helper) {
|
|||
exports["test Object Listener 2"] = createProxyTest("", function (helper) {
|
||||
|
||||
helper.createWorker(
|
||||
'new ' + function ContentScriptScope() {
|
||||
('new ' + function ContentScriptScope() {
|
||||
// variable replaced with `testHost`
|
||||
let testHost = "TOKEN";
|
||||
// Verify object as DOM event listener
|
||||
let myMessageListener = {
|
||||
called: false,
|
||||
|
@ -228,7 +244,7 @@ exports["test Object Listener 2"] = createProxyTest("", function (helper) {
|
|||
this.called = true;
|
||||
assert(event.target == document.defaultView, "event.target is the wrapped window");
|
||||
assert(event.source == document.defaultView, "event.source is the wrapped window");
|
||||
assert(event.origin == "null", "origin is null");
|
||||
assert(event.origin == testHost, "origin matches testHost");
|
||||
assert(event.data == "ok", "message data is correct");
|
||||
done();
|
||||
}
|
||||
|
@ -237,7 +253,7 @@ exports["test Object Listener 2"] = createProxyTest("", function (helper) {
|
|||
window.addEventListener("message", myMessageListener, true);
|
||||
document.defaultView.postMessage("ok", '*');
|
||||
}
|
||||
);
|
||||
).replace("TOKEN", testHost));
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ const fs = require("sdk/io/fs");
|
|||
const url = require("sdk/url");
|
||||
const path = require("sdk/fs/path");
|
||||
const { Buffer } = require("sdk/io/buffer");
|
||||
const { is } = require("sdk/system/xul-app");
|
||||
|
||||
// Use profile directory to list / read / write files.
|
||||
const profilePath = pathFor("ProfD");
|
||||
|
@ -26,19 +27,18 @@ const renameToPath = path.join(profilePath, "sdk-fixture-rename-to");
|
|||
const profileEntries = [
|
||||
"compatibility.ini",
|
||||
"extensions",
|
||||
"extensions.ini",
|
||||
"prefs.js"
|
||||
// There are likely to be a lot more files but we can't really
|
||||
// on consistent list so we limit to this.
|
||||
];
|
||||
|
||||
exports["test readir"] = function(assert, end) {
|
||||
exports["test readdir"] = function(assert, end) {
|
||||
var async = false;
|
||||
fs.readdir(profilePath, function(error, entries) {
|
||||
assert.ok(async, "readdir is async");
|
||||
assert.ok(!error, "there is no error when reading directory");
|
||||
assert.ok(profileEntries.length <= entries.length,
|
||||
"got et least number of entries we expect");
|
||||
"got at least number of entries we expect");
|
||||
assert.ok(profileEntries.every(function(entry) {
|
||||
return entries.indexOf(entry) >= 0;
|
||||
}), "all profiles are present");
|
||||
|
@ -67,13 +67,13 @@ exports["test readdirSync"] = function(assert) {
|
|||
var async = false;
|
||||
var entries = fs.readdirSync(profilePath);
|
||||
assert.ok(profileEntries.length <= entries.length,
|
||||
"got et least number of entries we expect");
|
||||
"got at least number of entries we expect");
|
||||
assert.ok(profileEntries.every(function(entry) {
|
||||
return entries.indexOf(entry) >= 0;
|
||||
}), "all profiles are present");
|
||||
};
|
||||
|
||||
exports["test readirSync error"] = function(assert) {
|
||||
exports["test readdirSync error"] = function(assert) {
|
||||
var async = false;
|
||||
var path = profilePath + "-does-not-exists";
|
||||
try {
|
||||
|
@ -92,6 +92,7 @@ exports["test readFile"] = function(assert, end) {
|
|||
fs.readFile(filePathInProfile, function(error, content) {
|
||||
assert.ok(async, "readFile is async");
|
||||
assert.ok(!error, "error is falsy");
|
||||
|
||||
assert.ok(Buffer.isBuffer(content), "readFile returns buffer");
|
||||
assert.ok(typeof(content.length) === "number", "buffer has length");
|
||||
assert.ok(content.toString().indexOf("[Compatibility]") >= 0,
|
||||
|
@ -338,7 +339,6 @@ exports["test fs.truncate"] = function(assert, end) {
|
|||
let async = false;
|
||||
fs.truncate(path, 0, function(error) {
|
||||
assert.ok(async, "truncate is async");
|
||||
console.log(error);
|
||||
assert.ok(!error, "no error");
|
||||
assert.equal(fs.existsSync(path), true, "file was created");
|
||||
fs.unlinkSync(path);
|
||||
|
@ -459,4 +459,28 @@ exports["test fs.writeFile"] = function(assert, end) {
|
|||
async = true;
|
||||
};
|
||||
|
||||
exports["test fs.writeFile (with large files)"] = function(assert, end) {
|
||||
let path = writePath;
|
||||
let content = "";
|
||||
|
||||
for (var i = 0; i < 100000; i++) {
|
||||
content += "buffer\n";
|
||||
}
|
||||
|
||||
var async = false;
|
||||
fs.writeFile(path, content, function(error) {
|
||||
assert.ok(async, "fs write is async");
|
||||
assert.ok(!error, "error is falsy");
|
||||
assert.ok(fs.existsSync(path), "file was created");
|
||||
assert.equal(fs.readFileSync(path).toString(),
|
||||
content,
|
||||
"contet was written");
|
||||
fs.unlinkSync(path);
|
||||
assert.ok(!fs.exists(path), "file was removed");
|
||||
|
||||
end();
|
||||
});
|
||||
async = true;
|
||||
};
|
||||
|
||||
require("test").run(exports);
|
||||
|
|
|
@ -22,13 +22,13 @@ exports.testUnloadAndErrorLogging = function(test) {
|
|||
test.assertEqual(timesCalled, 1);
|
||||
sbobsvc.add("narg", badCb);
|
||||
observers.notify("narg", "yo yo");
|
||||
var lines = messages[0].split("\n");
|
||||
test.assertEqual(lines[0], "error: " + require("sdk/self").name + ": An exception occurred.");
|
||||
test.assertEqual(lines[0], "error: " + require("sdk/self").name + ": An exception occurred.");
|
||||
test.assertEqual(lines[1], "Error: foo");
|
||||
|
||||
test.assertEqual(messages[0], "console.error: " + require("sdk/self").name + ": \n");
|
||||
var lines = messages[1].split("\n");
|
||||
test.assertEqual(lines[0], " Message: Error: foo");
|
||||
test.assertEqual(lines[1], " Stack:");
|
||||
// Keep in mind to update "18" to the line of "throw new Error("foo")"
|
||||
test.assertEqual(lines[2], module.uri + " 18");
|
||||
test.assertEqual(lines[3], "Traceback (most recent call last):");
|
||||
test.assert(lines[2].indexOf(module.uri + ":18") != -1);
|
||||
|
||||
loader.unload();
|
||||
observers.notify("blarg", "yo yo");
|
||||
|
|
|
@ -19,6 +19,8 @@ const { openWebpage } = require('./private-browsing/helper');
|
|||
const { isTabPBSupported, isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils');
|
||||
const promise = require("sdk/core/promise");
|
||||
const { pb } = require('./private-browsing/helper');
|
||||
const { URL } = require("sdk/url");
|
||||
const testPageURI = require("sdk/self").data.url("test.html");
|
||||
|
||||
/* XXX This can be used to delay closing the test Firefox instance for interactive
|
||||
* testing or visual inspection. This test is registered first so that it runs
|
||||
|
@ -119,16 +121,16 @@ exports.testPageModIncludes = function(test) {
|
|||
};
|
||||
}
|
||||
|
||||
testPageMod(test, "about:buildconfig", [
|
||||
testPageMod(test, testPageURI, [
|
||||
createPageModTest("*", false),
|
||||
createPageModTest("*.google.com", false),
|
||||
createPageModTest("about:*", true),
|
||||
createPageModTest("about:", false),
|
||||
createPageModTest("about:buildconfig", true)
|
||||
createPageModTest("resource:*", true),
|
||||
createPageModTest("resource:", false),
|
||||
createPageModTest(testPageURI, true)
|
||||
],
|
||||
function (win, done) {
|
||||
test.waitUntil(function () win.localStorage["about:buildconfig"],
|
||||
"about:buildconfig page-mod to be executed")
|
||||
test.waitUntil(function () win.localStorage[testPageURI],
|
||||
testPageURI + " page-mod to be executed")
|
||||
.then(function () {
|
||||
asserts.forEach(function(fn) {
|
||||
fn(test, win);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
const { Loader } = require('sdk/test/loader');
|
||||
const Pages = require("sdk/page-worker");
|
||||
const Page = Pages.Page;
|
||||
const { URL } = require("sdk/url");
|
||||
const testURI = require("sdk/self").data.url("test.html");
|
||||
|
||||
const ERR_DESTROYED =
|
||||
"Couldn't find the worker to receive this message. " +
|
||||
|
@ -156,14 +158,23 @@ exports.testValidateOptions = function(assert) {
|
|||
|
||||
exports.testContentAndAllowGettersAndSetters = function(assert, done) {
|
||||
let content = "data:text/html;charset=utf-8,<script>window.localStorage.allowScript=3;</script>";
|
||||
|
||||
// Load up the page with testURI initially for the resource:// principal,
|
||||
// then load the actual data:* content, as data:* URIs no longer
|
||||
// have localStorage
|
||||
let page = Page({
|
||||
contentURL: content,
|
||||
contentScript: "self.postMessage(window.localStorage.allowScript)",
|
||||
contentURL: testURI,
|
||||
contentScript: "if (window.location.href==='"+testURI+"')" +
|
||||
" self.postMessage('reload');" +
|
||||
"else " +
|
||||
" self.postMessage(window.localStorage.allowScript)",
|
||||
contentScriptWhen: "end",
|
||||
onMessage: step0
|
||||
});
|
||||
|
||||
function step0(message) {
|
||||
if (message === 'reload')
|
||||
return page.contentURL = content;
|
||||
assert.equal(message, "3",
|
||||
"Correct value expected for allowScript - 3");
|
||||
assert.equal(page.contentURL, content,
|
||||
|
|
|
@ -25,9 +25,9 @@ const {
|
|||
MENU, TOOLBAR, UNSORTED
|
||||
} = require('sdk/places/bookmarks');
|
||||
const {
|
||||
invalidResolve, invalidReject, clearBookmarks, createTree,
|
||||
compareWithHost, clearAllBookmarks, createBookmark, createBookmarkItem,
|
||||
createBookmarkTree, addVisits
|
||||
invalidResolve, invalidReject, createTree,
|
||||
compareWithHost, createBookmark, createBookmarkItem,
|
||||
createBookmarkTree, addVisits, resetPlaces
|
||||
} = require('./places-helper');
|
||||
const { promisedEmitter } = require('sdk/places/utils');
|
||||
const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
|
||||
|
@ -941,13 +941,8 @@ exports.testCheckSaveOrder = function (assert, done) {
|
|||
});
|
||||
};
|
||||
|
||||
before(exports, name => {
|
||||
clearAllBookmarks();
|
||||
});
|
||||
|
||||
after(exports, name => {
|
||||
clearAllBookmarks();
|
||||
});
|
||||
before(exports, (name, assert, done) => resetPlaces(done));
|
||||
after(exports, (name, assert, done) => resetPlaces(done));
|
||||
|
||||
function saveP () {
|
||||
return promisedEmitter(save.apply(null, Array.slice(arguments)));
|
||||
|
|
|
@ -19,7 +19,7 @@ const host = 'http://localhost:' + port;
|
|||
const { onFaviconChange, serve, binFavicon } = require('./favicon-helpers');
|
||||
const { once } = require('sdk/system/events');
|
||||
const { defer } = require('sdk/core/promise');
|
||||
const { clearHistory } = require('./places-helper');
|
||||
const { resetPlaces } = require('./places-helper');
|
||||
const faviconService = Cc["@mozilla.org/browser/favicon-service;1"].
|
||||
getService(Ci.nsIFaviconService);
|
||||
|
||||
|
@ -181,7 +181,7 @@ function waitAndExpire (url) {
|
|||
|
||||
function complete(tab, srv, done) {
|
||||
tab.close(function () {
|
||||
clearHistory(() => {
|
||||
resetPlaces(() => {
|
||||
srv.stop(done);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,16 +14,15 @@ const { defer, all } = require('sdk/core/promise');
|
|||
const { has } = require('sdk/util/array');
|
||||
const { setTimeout } = require('sdk/timers');
|
||||
const { before, after } = require('sdk/test/utils');
|
||||
const { set } = require('sdk/preferences/service');
|
||||
const {
|
||||
search
|
||||
} = require('sdk/places/history');
|
||||
const {
|
||||
invalidResolve, invalidReject, clearBookmarks, createTree,
|
||||
compareWithHost, clearAllBookmarks, addVisits, clearHistory
|
||||
invalidResolve, invalidReject, createTree,
|
||||
compareWithHost, addVisits, resetPlaces
|
||||
} = require('./places-helper');
|
||||
const { promisedEmitter } = require('sdk/places/utils');
|
||||
const hsrv = Cc['@mozilla.org/browser/nav-history-service;1'].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
|
||||
exports.testEmptyQuery = function (assert, done) {
|
||||
let within = toBeWithin();
|
||||
|
@ -239,16 +238,11 @@ function toBeWithin (range) {
|
|||
};
|
||||
}
|
||||
|
||||
function clear (done) {
|
||||
clearAllBookmarks();
|
||||
clearHistory(done);
|
||||
}
|
||||
|
||||
function searchP () {
|
||||
return promisedEmitter(search.apply(null, Array.slice(arguments)));
|
||||
}
|
||||
|
||||
before(exports, (name, assert, done) => clear(done));
|
||||
after(exports, (name, assert, done) => clear(done));
|
||||
before(exports, (name, assert, done) => resetPlaces(done));
|
||||
after(exports, (name, assert, done) => resetPlaces(done));
|
||||
|
||||
require('test').run(exports);
|
||||
|
|
|
@ -14,13 +14,15 @@ const { defer, all } = require('sdk/core/promise');
|
|||
const { setTimeout } = require('sdk/timers');
|
||||
const { newURI } = require('sdk/url/utils');
|
||||
const { send } = require('sdk/addon/events');
|
||||
const { set } = require('sdk/preferences/service');
|
||||
const { before, after } = require('sdk/test/utils');
|
||||
|
||||
require('sdk/places/host/host-bookmarks');
|
||||
require('sdk/places/host/host-tags');
|
||||
require('sdk/places/host/host-query');
|
||||
const {
|
||||
invalidResolve, invalidReject, clearBookmarks, createTree,
|
||||
compareWithHost, clearAllBookmarks, createBookmark, createBookmarkTree
|
||||
invalidResolve, invalidReject, createTree,
|
||||
compareWithHost, createBookmark, createBookmarkTree, resetPlaces
|
||||
} = require('./places-helper');
|
||||
|
||||
const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
|
||||
|
@ -29,7 +31,6 @@ const hsrv = Cc['@mozilla.org/browser/nav-history-service;1'].
|
|||
getService(Ci.nsINavHistoryService);
|
||||
const tagsrv = Cc['@mozilla.org/browser/tagging-service;1'].
|
||||
getService(Ci.nsITaggingService);
|
||||
clearAllBookmarks();
|
||||
|
||||
exports.testBookmarksCreate = function (assert, done) {
|
||||
let items = [{
|
||||
|
@ -51,7 +52,6 @@ exports.testBookmarksCreate = function (assert, done) {
|
|||
compareWithHost(assert, data);
|
||||
}, invalidReject(assert));
|
||||
})).then(function () {
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
}, invalidReject(assert));
|
||||
};
|
||||
|
@ -72,7 +72,6 @@ exports.testBookmarksCreateFail = function (assert, done) {
|
|||
assert.ok(reason, 'bookmark create should fail');
|
||||
});
|
||||
})).then(function () {
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
@ -94,7 +93,6 @@ exports.testBookmarkLastUpdated = function (assert, done) {
|
|||
});
|
||||
}).then(function (data) {
|
||||
assert.ok(data.updated > timestamp, 'time has elapsed and updated the updated property');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
@ -110,7 +108,6 @@ exports.testBookmarkRemove = function (assert, done) {
|
|||
assert.throws(function () {
|
||||
bmsrv.getItemTitle(id);
|
||||
}, 'item should no longer exist');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
}, console.error);
|
||||
};
|
||||
|
@ -133,7 +130,6 @@ exports.testBookmarkGet = function (assert, done) {
|
|||
else
|
||||
assert.equal(bookmark[prop], data[prop], 'correctly fetched ' + prop);
|
||||
});
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
@ -151,7 +147,6 @@ exports.testTagsTag = function (assert, done) {
|
|||
assert.ok(~tags.indexOf('foxfire'), 'second tag found');
|
||||
assert.ok(~tags.indexOf('firefox'), 'default tag found');
|
||||
assert.equal(tags.length, 3, 'no extra tags');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
@ -171,7 +166,6 @@ exports.testTagsUntag = function (assert, done) {
|
|||
assert.ok(!~tags.indexOf('firefox'), 'first tag removed');
|
||||
assert.ok(!~tags.indexOf('tag2'), 'second tag removed');
|
||||
assert.equal(tags.length, 2, 'no extra tags');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
@ -186,7 +180,6 @@ exports.testTagsGetURLsByTag = function (assert, done) {
|
|||
}).then(function(urls) {
|
||||
assert.equal(item.url, urls[0], 'returned correct url');
|
||||
assert.equal(urls.length, 1, 'returned only one url');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
@ -203,7 +196,6 @@ exports.testTagsGetTagsByURL = function (assert, done) {
|
|||
assert.ok(~tags.indexOf('mozilla'), 'returned second tag');
|
||||
assert.ok(~tags.indexOf('metal'), 'returned third tag');
|
||||
assert.equal(tags.length, 3, 'returned all tags');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
@ -228,7 +220,6 @@ exports.testHostQuery = function (assert, done) {
|
|||
}).then(results => {
|
||||
assert.equal(results.length, 2, 'should only return two');
|
||||
assert.equal(results[0].url, 'http://firefox.com/', 'is sorted by URI desc');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
@ -253,7 +244,6 @@ exports.testHostMultiQuery = function (assert, done) {
|
|||
});
|
||||
}).then(results => {
|
||||
assert.equal(results.length, 0, 'query props should be AND\'d');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
@ -263,7 +253,6 @@ exports.testGetAllBookmarks = function (assert, done) {
|
|||
return send('sdk-places-bookmarks-get-all', {});
|
||||
}).then(res => {
|
||||
assert.equal(res.length, 8, 'all bookmarks returned');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
}, console.error);
|
||||
};
|
||||
|
@ -276,9 +265,12 @@ exports.testGetAllChildren = function (assert, done) {
|
|||
}).then(results => {
|
||||
assert.equal(results.length, 5,
|
||||
'should return all children and folders at a single depth');
|
||||
clearAllBookmarks();
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
before(exports, (name, assert, done) => resetPlaces(done));
|
||||
after(exports, (name, assert, done) => resetPlaces(done));
|
||||
|
||||
require('test').run(exports);
|
||||
|
|
|
@ -36,50 +36,61 @@ exports.testPlainTextConsole = function(test) {
|
|||
test.pass("PlainTextConsole instantiates");
|
||||
|
||||
con.log('testing', 1, [2, 3, 4]);
|
||||
test.assertEqual(lastPrint(), "info: " + name + ": testing 1 2,3,4\n",
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, 1, Array [2,3,4]\n",
|
||||
"PlainTextConsole.log() must work.");
|
||||
|
||||
con.info('testing', 1, [2, 3, 4]);
|
||||
test.assertEqual(lastPrint(), "info: " + name + ": testing 1 2,3,4\n",
|
||||
test.assertEqual(lastPrint(), "console.info: " + name + ": testing, 1, Array [2,3,4]\n",
|
||||
"PlainTextConsole.info() must work.");
|
||||
|
||||
con.warn('testing', 1, [2, 3, 4]);
|
||||
test.assertEqual(lastPrint(), "warn: " + name + ": testing 1 2,3,4\n",
|
||||
test.assertEqual(lastPrint(), "console.warn: " + name + ": testing, 1, Array [2,3,4]\n",
|
||||
"PlainTextConsole.warn() must work.");
|
||||
|
||||
con.error('testing', 1, [2, 3, 4]);
|
||||
test.assertEqual(lastPrint(), "error: " + name + ": testing 1 2,3,4\n",
|
||||
test.assertEqual(prints[0], "console.error: " + name + ": \n",
|
||||
"PlainTextConsole.error() must work.");
|
||||
test.assertEqual(prints[1], " testing\n")
|
||||
test.assertEqual(prints[2], " 1\n")
|
||||
test.assertEqual(prints[3], "Array\n - 0 = 2\n - 1 = 3\n - 2 = 4\n - length = 3\n");
|
||||
prints = [];
|
||||
|
||||
con.debug('testing', 1, [2, 3, 4]);
|
||||
test.assertEqual(lastPrint(), "debug: " + name + ": testing 1 2,3,4\n",
|
||||
test.assertEqual(prints[0], "console.debug: " + name + ": \n",
|
||||
"PlainTextConsole.debug() must work.");
|
||||
test.assertEqual(prints[1], " testing\n")
|
||||
test.assertEqual(prints[2], " 1\n")
|
||||
test.assertEqual(prints[3], "Array\n - 0 = 2\n - 1 = 3\n - 2 = 4\n - length = 3\n");
|
||||
prints = [];
|
||||
|
||||
con.log('testing', undefined);
|
||||
test.assertEqual(lastPrint(), "info: " + name + ": testing undefined\n",
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, undefined\n",
|
||||
"PlainTextConsole.log() must stringify undefined.");
|
||||
|
||||
con.log('testing', null);
|
||||
test.assertEqual(lastPrint(), "info: " + name + ": testing null\n",
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, null\n",
|
||||
"PlainTextConsole.log() must stringify null.");
|
||||
|
||||
// TODO: Fix console.jsm to detect custom toString.
|
||||
con.log("testing", { toString: function() "obj.toString()" });
|
||||
test.assertEqual(lastPrint(), "info: " + name + ": testing obj.toString()\n",
|
||||
"PlainTextConsole.log() must stringify custom toString.");
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, {}\n",
|
||||
"PlainTextConsole.log() doesn't printify custom toString.");
|
||||
|
||||
con.log("testing", { toString: function() { throw "fail!"; } });
|
||||
test.assertEqual(lastPrint(), "info: " + name + ": testing <toString() error>\n",
|
||||
test.assertEqual(lastPrint(), "console.log: " + name + ": testing, {}\n",
|
||||
"PlainTextConsole.log() must stringify custom bad toString.");
|
||||
|
||||
|
||||
con.exception(new Error("blah"));
|
||||
|
||||
var tbLines = prints[0].split("\n");
|
||||
test.assertEqual(tbLines[0], "error: " + name + ": An exception occurred.");
|
||||
test.assertEqual(tbLines[1], "Error: blah");
|
||||
test.assertEqual(tbLines[2], module.uri + " 74");
|
||||
test.assertEqual(tbLines[3], "Traceback (most recent call last):");
|
||||
|
||||
test.assertEqual(prints[0], "console.error: " + name + ": \n");
|
||||
let tbLines = prints[1].split("\n");
|
||||
test.assertEqual(tbLines[0], " Message: Error: blah");
|
||||
test.assertEqual(tbLines[1], " Stack:");
|
||||
test.assert(prints[1].indexOf(module.uri + ":84") !== -1);
|
||||
prints = []
|
||||
|
||||
prints = [];
|
||||
try {
|
||||
loadSubScript("invalid-url", {});
|
||||
test.fail("successed in calling loadSubScript with invalid-url");
|
||||
|
@ -87,16 +98,15 @@ exports.testPlainTextConsole = function(test) {
|
|||
catch(e) {
|
||||
con.exception(e);
|
||||
}
|
||||
var tbLines = prints[0].split("\n");
|
||||
test.assertEqual(tbLines[0], "error: " + name + ": An exception occurred.");
|
||||
test.assertEqual(tbLines[1], "Error creating URI (invalid URL scheme?)");
|
||||
test.assertEqual(tbLines[2], "Traceback (most recent call last):");
|
||||
|
||||
test.assertEqual(prints[0], "console.error: " + name + ": \n");
|
||||
test.assertEqual(prints[1], " Error creating URI (invalid URL scheme?)\n");
|
||||
prints = [];
|
||||
|
||||
con.trace();
|
||||
tbLines = prints[0].split("\n");
|
||||
test.assertEqual(tbLines[0], "info: " + name + ": Traceback (most recent call last):");
|
||||
test.assertEqual(tbLines[tbLines.length - 4].trim(), "con.trace();");
|
||||
let tbLines = prints[0].split("\n");
|
||||
test.assertEqual(tbLines[0], "console.trace: " + name + ": ");
|
||||
test.assert(tbLines[1].indexOf("_ain-text-console.js 105") == 0);
|
||||
prints = [];
|
||||
|
||||
// Whether or not console methods should print at the various log levels,
|
||||
// structured as a hash of levels, each of which contains a hash of methods,
|
||||
|
@ -113,11 +123,11 @@ exports.testPlainTextConsole = function(test) {
|
|||
|
||||
// The messages we use to test the various methods, as a hash of methods.
|
||||
let messages = {
|
||||
debug: "debug: " + name + ": \n",
|
||||
log: "info: " + name + ": \n",
|
||||
info: "info: " + name + ": \n",
|
||||
warn: "warn: " + name + ": \n",
|
||||
error: "error: " + name + ": \n",
|
||||
debug: "console.debug: " + name + ": \n \n",
|
||||
log: "console.log: " + name + ": \n",
|
||||
info: "console.info: " + name + ": \n",
|
||||
warn: "console.warn: " + name + ": \n",
|
||||
error: "console.error: " + name + ": \n \n",
|
||||
};
|
||||
|
||||
for (let level in levels) {
|
||||
|
@ -130,17 +140,20 @@ exports.testPlainTextConsole = function(test) {
|
|||
prefs.set(SDK_LOG_LEVEL_PREF, level);
|
||||
con[method]("");
|
||||
prefs.set(SDK_LOG_LEVEL_PREF, "all");
|
||||
test.assertEqual(lastPrint(), (methods[method] ? messages[method] : null),
|
||||
test.assertEqual(prints.join(""),
|
||||
(methods[method] ? messages[method] : ""),
|
||||
"at log level '" + level + "', " + method + "() " +
|
||||
(methods[method] ? "prints" : "doesn't print"));
|
||||
prints = [];
|
||||
}
|
||||
}
|
||||
|
||||
prefs.set(SDK_LOG_LEVEL_PREF, "off");
|
||||
prefs.set(ADDON_LOG_LEVEL_PREF, "all");
|
||||
con.debug("");
|
||||
test.assertEqual(lastPrint(), messages["debug"],
|
||||
test.assertEqual(prints.join(""), messages["debug"],
|
||||
"addon log level 'all' overrides SDK log level 'off'");
|
||||
prints = [];
|
||||
|
||||
prefs.set(SDK_LOG_LEVEL_PREF, "all");
|
||||
prefs.set(ADDON_LOG_LEVEL_PREF, "off");
|
||||
|
|
|
@ -10,6 +10,8 @@ const { Loader, LoaderWithHookedConsole2 } = require("sdk/test/loader");
|
|||
const nsIObserverService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
|
||||
let isConsoleEvent = (topic) =>
|
||||
!!~["console-api-log-event", "console-storage-cache-event"].indexOf(topic)
|
||||
|
||||
exports["test basic"] = function(assert) {
|
||||
let type = Date.now().toString(32);
|
||||
|
@ -48,10 +50,10 @@ exports["test error reporting"] = function(assert) {
|
|||
events.on(errorType, brokenHandler);
|
||||
events.emit(errorType, { data: "yo yo" });
|
||||
|
||||
assert.equal(messages.length, 1, "Got an exception");
|
||||
let text = messages[0];
|
||||
assert.ok(text.indexOf(self.name + ": An exception occurred.") >= 0,
|
||||
"error is logged");
|
||||
assert.equal(messages.length, 2, "Got an exception");
|
||||
assert.equal(messages[0], "console.error: " + self.name + ": \n",
|
||||
"error is logged");
|
||||
let text = messages[1];
|
||||
assert.ok(text.indexOf("Error: foo") >= 0, "error message is logged");
|
||||
assert.ok(text.indexOf(module.uri) >= 0, "module uri is logged");
|
||||
assert.ok(text.indexOf(lineNumber) >= 0, "error line is logged");
|
||||
|
@ -104,6 +106,9 @@ exports["test handle nsIObserverService notifications"] = function(assert) {
|
|||
let lastType = null;
|
||||
|
||||
function handler({ subject, data, type }) {
|
||||
// Ignores internal console events
|
||||
if (isConsoleEvent(type))
|
||||
return;
|
||||
timesCalled++;
|
||||
lastSubject = subject;
|
||||
lastData = data;
|
||||
|
@ -168,6 +173,9 @@ exports["test emit to nsIObserverService observers"] = function(assert) {
|
|||
return nsIObserver;
|
||||
},
|
||||
observe: function(subject, topic, data) {
|
||||
// Ignores internal console events
|
||||
if (isConsoleEvent(topic))
|
||||
return;
|
||||
timesCalled = timesCalled + 1;
|
||||
lastSubject = subject;
|
||||
lastData = data;
|
||||
|
@ -184,7 +192,6 @@ exports["test emit to nsIObserverService observers"] = function(assert) {
|
|||
assert.equal(lastSubject.wrappedJSObject.object, uri,
|
||||
"event.subject is notification subject");
|
||||
assert.equal(lastData, "some data", "event.data is notification data");
|
||||
|
||||
function customSubject() {}
|
||||
function customData() {}
|
||||
events.emit(topic, { subject: customSubject, data: customData });
|
||||
|
@ -206,13 +213,14 @@ exports["test emit to nsIObserverService observers"] = function(assert) {
|
|||
events.emit(topic, { data: "data again" });
|
||||
|
||||
assert.equal(timesCalled, 3, "emit notifies * observers");
|
||||
|
||||
assert.equal(lastTopic, topic, "event.type is notification");
|
||||
assert.equal(lastSubject, null,
|
||||
"event.subject is notification subject");
|
||||
assert.equal(lastData, "data again", "event.data is notification data");
|
||||
|
||||
nsIObserverService.removeObserver(nsIObserver, "*");
|
||||
|
||||
|
||||
events.emit(topic, { data: "last data" });
|
||||
assert.equal(timesCalled, 3, "removed observers no longer invoked");
|
||||
}
|
||||
|
|
|
@ -6,33 +6,17 @@ const { browserWindows } = require('sdk/windows');
|
|||
const tabs = require('sdk/tabs');
|
||||
const { pb } = require('./private-browsing/helper');
|
||||
const { isPrivate } = require('sdk/private-browsing');
|
||||
const { openTab, closeTab, getTabContentWindow } = require('sdk/tabs/utils');
|
||||
const { openTab, closeTab, getTabContentWindow, getOwnerWindow } = require('sdk/tabs/utils');
|
||||
const { open, close } = require('sdk/window/helpers');
|
||||
const { windows } = require('sdk/window/utils');
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { fromIterator } = require('sdk/util/array');
|
||||
|
||||
if (isGlobalPBSupported) {
|
||||
exports.testGetTabs = function(assert, done) {
|
||||
pb.once('start', function() {
|
||||
tabs.open({
|
||||
url: 'about:blank',
|
||||
inNewWindow: true,
|
||||
onOpen: function(tab) {
|
||||
assert.equal(getTabs().length, 2, 'there are two tabs');
|
||||
assert.equal(browserWindows.length, 2, 'there are two windows');
|
||||
pb.once('stop', function() {
|
||||
done();
|
||||
});
|
||||
pb.deactivate();
|
||||
}
|
||||
});
|
||||
});
|
||||
pb.activate();
|
||||
};
|
||||
}
|
||||
else if (isWindowPBSupported) {
|
||||
if (isWindowPBSupported) {
|
||||
exports.testGetTabs = function(assert, done) {
|
||||
let tabCount = getTabs().length;
|
||||
let windowCount = browserWindows.length;
|
||||
|
||||
open(null, {
|
||||
features: {
|
||||
private: true,
|
||||
|
@ -41,12 +25,21 @@ else if (isWindowPBSupported) {
|
|||
}
|
||||
}).then(function(window) {
|
||||
assert.ok(isPrivate(window), 'new tab is private');
|
||||
assert.equal(getTabs().length, 1, 'there is one tab found');
|
||||
assert.equal(browserWindows.length, 1, 'there is one window found');
|
||||
fromIterator(browserWindows).forEach(function(window) {
|
||||
assert.ok(!isPrivate(window), 'all found windows are not private');
|
||||
|
||||
assert.equal(getTabs().length, tabCount, 'there are no new tabs found');
|
||||
getTabs().forEach(function(tab) {
|
||||
assert.equal(isPrivate(tab), false, 'all found tabs are not private');
|
||||
assert.equal(isPrivate(getOwnerWindow(tab)), false, 'all found tabs are not private');
|
||||
assert.equal(isPrivate(getTabContentWindow(tab)), false, 'all found tabs are not private');
|
||||
});
|
||||
|
||||
assert.equal(browserWindows.length, windowCount, 'there are no new windows found');
|
||||
fromIterator(browserWindows).forEach(function(window) {
|
||||
assert.equal(isPrivate(window), false, 'all found windows are not private');
|
||||
});
|
||||
|
||||
assert.equal(windows(null, {includePrivate: true}).length, 2, 'there are really two windows');
|
||||
|
||||
close(window).then(done);
|
||||
});
|
||||
};
|
||||
|
@ -71,7 +64,4 @@ else if (isTabPBSupported) {
|
|||
};
|
||||
}
|
||||
|
||||
// Test disabled because of bug 855771
|
||||
module.exports = {};
|
||||
|
||||
require('test').run(exports);
|
||||
|
|
|
@ -5,116 +5,162 @@
|
|||
var timer = require("sdk/timers");
|
||||
const { Loader } = require("sdk/test/loader");
|
||||
|
||||
exports.testSetTimeout = function(test) {
|
||||
exports.testSetTimeout = function(assert, end) {
|
||||
timer.setTimeout(function() {
|
||||
test.pass("testSetTimeout passed");
|
||||
test.done();
|
||||
assert.pass("testSetTimeout passed");
|
||||
end();
|
||||
}, 1);
|
||||
test.waitUntilDone();
|
||||
};
|
||||
|
||||
exports.testParamedSetTimeout = function(test) {
|
||||
exports.testParamedSetTimeout = function(assert, end) {
|
||||
let params = [1, 'foo', { bar: 'test' }, null, undefined];
|
||||
timer.setTimeout.apply(null, [function() {
|
||||
test.assertEqual(arguments.length, params.length);
|
||||
assert.equal(arguments.length, params.length);
|
||||
for (let i = 0, ii = params.length; i < ii; i++)
|
||||
test.assertEqual(params[i], arguments[i]);
|
||||
test.done();
|
||||
assert.equal(params[i], arguments[i]);
|
||||
end();
|
||||
}, 1].concat(params));
|
||||
test.waitUntilDone();
|
||||
};
|
||||
|
||||
exports.testClearTimeout = function(test) {
|
||||
exports.testClearTimeout = function(assert, end) {
|
||||
var myFunc = function myFunc() {
|
||||
test.fail("myFunc() should not be called in testClearTimeout");
|
||||
assert.fail("myFunc() should not be called in testClearTimeout");
|
||||
};
|
||||
var id = timer.setTimeout(myFunc, 1);
|
||||
timer.setTimeout(function() {
|
||||
test.pass("testClearTimeout passed");
|
||||
test.done();
|
||||
assert.pass("testClearTimeout passed");
|
||||
end();
|
||||
}, 2);
|
||||
timer.clearTimeout(id);
|
||||
test.waitUntilDone();
|
||||
};
|
||||
|
||||
exports.testParamedClearTimeout = function(test) {
|
||||
exports.testParamedClearTimeout = function(assert, end) {
|
||||
let params = [1, 'foo', { bar: 'test' }, null, undefined];
|
||||
var myFunc = function myFunc() {
|
||||
test.fail("myFunc() should not be called in testClearTimeout");
|
||||
assert.fail("myFunc() should not be called in testClearTimeout");
|
||||
};
|
||||
var id = timer.setTimeout(myFunc, 1);
|
||||
timer.setTimeout.apply(null, [function() {
|
||||
test.assertEqual(arguments.length, params.length);
|
||||
assert.equal(arguments.length, params.length);
|
||||
for (let i = 0, ii = params.length; i < ii; i++)
|
||||
test.assertEqual(params[i], arguments[i]);
|
||||
test.done();
|
||||
assert.equal(params[i], arguments[i]);
|
||||
end();
|
||||
}, 1].concat(params));
|
||||
timer.clearTimeout(id);
|
||||
test.waitUntilDone();
|
||||
};
|
||||
|
||||
exports.testSetInterval = function (test) {
|
||||
exports.testSetInterval = function (assert, end) {
|
||||
var count = 0;
|
||||
var id = timer.setInterval(function () {
|
||||
count++;
|
||||
if (count >= 5) {
|
||||
timer.clearInterval(id);
|
||||
test.pass("testSetInterval passed");
|
||||
test.done();
|
||||
assert.pass("testSetInterval passed");
|
||||
end();
|
||||
}
|
||||
}, 1);
|
||||
test.waitUntilDone();
|
||||
};
|
||||
|
||||
exports.testParamedSetInerval = function(test) {
|
||||
exports.testParamedSetInerval = function(assert, end) {
|
||||
let params = [1, 'foo', { bar: 'test' }, null, undefined];
|
||||
let count = 0;
|
||||
let id = timer.setInterval.apply(null, [function() {
|
||||
count ++;
|
||||
if (count < 5) {
|
||||
test.assertEqual(arguments.length, params.length);
|
||||
assert.equal(arguments.length, params.length);
|
||||
for (let i = 0, ii = params.length; i < ii; i++)
|
||||
test.assertEqual(params[i], arguments[i]);
|
||||
assert.equal(params[i], arguments[i]);
|
||||
} else {
|
||||
timer.clearInterval(id);
|
||||
test.done();
|
||||
end();
|
||||
}
|
||||
}, 1].concat(params));
|
||||
test.waitUntilDone();
|
||||
};
|
||||
|
||||
exports.testClearInterval = function (test) {
|
||||
exports.testClearInterval = function (assert, end) {
|
||||
timer.clearInterval(timer.setInterval(function () {
|
||||
test.fail("setInterval callback should not be called");
|
||||
assert.fail("setInterval callback should not be called");
|
||||
}, 1));
|
||||
var id = timer.setInterval(function () {
|
||||
timer.clearInterval(id);
|
||||
test.pass("testClearInterval passed");
|
||||
test.done();
|
||||
assert.pass("testClearInterval passed");
|
||||
end();
|
||||
}, 2);
|
||||
test.waitUntilDone();
|
||||
};
|
||||
|
||||
exports.testParamedClearInterval = function(test) {
|
||||
exports.testParamedClearInterval = function(assert, end) {
|
||||
timer.clearInterval(timer.setInterval(function () {
|
||||
test.fail("setInterval callback should not be called");
|
||||
assert.fail("setInterval callback should not be called");
|
||||
}, 1, timer, {}, null));
|
||||
|
||||
let id = timer.setInterval(function() {
|
||||
timer.clearInterval(id);
|
||||
test.assertEqual(3, arguments.length);
|
||||
test.done();
|
||||
assert.equal(3, arguments.length);
|
||||
end();
|
||||
}, 2, undefined, 'test', {});
|
||||
test.waitUntilDone();
|
||||
};
|
||||
|
||||
|
||||
exports.testUnload = function(test) {
|
||||
exports.testImmediate = function(assert, end) {
|
||||
let actual = [];
|
||||
let ticks = 0;
|
||||
timer.setImmediate(function(...params) {
|
||||
actual.push(params);
|
||||
assert.equal(ticks, 1, "is a next tick");
|
||||
assert.deepEqual(actual, [["start", "immediates"]]);
|
||||
}, "start", "immediates");
|
||||
|
||||
timer.setImmediate(function(...params) {
|
||||
actual.push(params);
|
||||
assert.deepEqual(actual, [["start", "immediates"],
|
||||
["added"]]);
|
||||
assert.equal(ticks, 1, "is a next tick");
|
||||
timer.setImmediate(function(...params) {
|
||||
actual.push(params);
|
||||
assert.equal(ticks, 2, "is second tick");
|
||||
assert.deepEqual(actual, [["start", "immediates"],
|
||||
["added"],
|
||||
[],
|
||||
["last", "immediate", "handler"],
|
||||
["side-effect"]]);
|
||||
end();
|
||||
}, "side-effect");
|
||||
}, "added");
|
||||
|
||||
timer.setImmediate(function(...params) {
|
||||
actual.push(params);
|
||||
assert.equal(ticks, 1, "is a next tick");
|
||||
assert.deepEqual(actual, [["start", "immediates"],
|
||||
["added"],
|
||||
[]]);
|
||||
timer.clearImmediate(removeID);
|
||||
});
|
||||
|
||||
function removed() {
|
||||
assert.fail("should be removed");
|
||||
}
|
||||
let removeID = timer.setImmediate(removed);
|
||||
|
||||
timer.setImmediate(function(...params) {
|
||||
actual.push(params);
|
||||
assert.equal(ticks, 1, "is a next tick");
|
||||
assert.deepEqual(actual, [["start", "immediates"],
|
||||
["added"],
|
||||
[],
|
||||
["last", "immediate", "handler"]]);
|
||||
ticks = ticks + 1;
|
||||
}, "last", "immediate", "handler");
|
||||
|
||||
|
||||
ticks = ticks + 1;
|
||||
};
|
||||
|
||||
exports.testUnload = function(assert, end) {
|
||||
var loader = Loader(module);
|
||||
var sbtimer = loader.require("sdk/timers");
|
||||
|
||||
var myFunc = function myFunc() {
|
||||
test.fail("myFunc() should not be called in testUnload");
|
||||
assert.fail("myFunc() should not be called in testUnload");
|
||||
};
|
||||
|
||||
sbtimer.setTimeout(myFunc, 1);
|
||||
|
@ -123,9 +169,9 @@ exports.testUnload = function(test) {
|
|||
sbtimer.setInterval(myFunc, 1, {}, null, 'bar', undefined, 87);
|
||||
loader.unload();
|
||||
timer.setTimeout(function() {
|
||||
test.pass("timer testUnload passed");
|
||||
test.done();
|
||||
assert.pass("timer testUnload passed");
|
||||
end();
|
||||
}, 2);
|
||||
test.waitUntilDone();
|
||||
};
|
||||
|
||||
require("test").run(exports);
|
|
@ -1,7 +1,6 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Loader } = require("sdk/test/loader");
|
||||
|
@ -53,4 +52,4 @@ if (require("sdk/system/xul-app").is("Fennec")) {
|
|||
}
|
||||
}
|
||||
|
||||
require("test").run(exports);
|
||||
require("sdk/test").run(exports);
|
||||
|
|
|
@ -61,6 +61,34 @@ exports['test new top window with options'] = function(assert, done) {
|
|||
close(window).then(done);
|
||||
};
|
||||
|
||||
exports['test new top window with various URIs'] = function(assert, done) {
|
||||
let msg = 'only chrome, resource and data uris are allowed';
|
||||
assert.throws(function () {
|
||||
open('foo');
|
||||
}, msg);
|
||||
assert.throws(function () {
|
||||
open('http://foo');
|
||||
}, msg);
|
||||
assert.throws(function () {
|
||||
open('https://foo');
|
||||
}, msg);
|
||||
assert.throws(function () {
|
||||
open('ftp://foo');
|
||||
}, msg);
|
||||
assert.throws(function () {
|
||||
open('//foo');
|
||||
}, msg);
|
||||
|
||||
let chromeWindow = open('chrome://foo/content/');
|
||||
assert.ok(~windows().indexOf(chromeWindow), 'chrome URI works');
|
||||
|
||||
let resourceWindow = open('resource://foo');
|
||||
assert.ok(~windows().indexOf(resourceWindow), 'resource URI works');
|
||||
|
||||
// Wait for the window unload before ending test
|
||||
close(chromeWindow).then(close.bind(null, resourceWindow)).then(done);
|
||||
};
|
||||
|
||||
exports.testBackgroundify = function(assert, done) {
|
||||
let window = open('data:text/html;charset=utf-8,backgroundy');
|
||||
assert.ok(~windows().indexOf(window),
|
||||
|
|
|
@ -214,24 +214,6 @@
|
|||
</menupopup>
|
||||
</menu>
|
||||
<menuseparator/>
|
||||
<menuitem id="menu_stop"
|
||||
class="show-only-for-keyboard"
|
||||
label="&stopCmd.label;"
|
||||
accesskey="&stopCmd.accesskey;"
|
||||
command="Browser:Stop"
|
||||
#ifdef XP_MACOSX
|
||||
key="key_stop_mac"/>
|
||||
#else
|
||||
key="key_stop"/>
|
||||
#endif
|
||||
<menuitem id="menu_reload"
|
||||
class="show-only-for-keyboard"
|
||||
label="&reloadCmd.label;"
|
||||
accesskey="&reloadCmd.accesskey;"
|
||||
key="key_reload"
|
||||
command="Browser:ReloadOrDuplicate"
|
||||
onclick="checkForMiddleClick(this, event);"/>
|
||||
<menuseparator class="show-only-for-keyboard"/>
|
||||
<menu id="viewFullZoomMenu" label="&fullZoom.label;"
|
||||
accesskey="&fullZoom.accesskey;"
|
||||
onpopupshowing="FullZoom.updateMenu();">
|
||||
|
@ -332,34 +314,6 @@
|
|||
new HistoryMenu(event);"
|
||||
tooltip="bhTooltip"
|
||||
popupsinherittooltip="true">
|
||||
<menuitem id="historyMenuBack"
|
||||
class="show-only-for-keyboard"
|
||||
label="&backCmd.label;"
|
||||
#ifdef XP_MACOSX
|
||||
key="goBackKb2"
|
||||
#else
|
||||
key="goBackKb"
|
||||
#endif
|
||||
command="Browser:BackOrBackDuplicate"
|
||||
onclick="checkForMiddleClick(this, event);"/>
|
||||
<menuitem id="historyMenuForward"
|
||||
class="show-only-for-keyboard"
|
||||
label="&forwardCmd.label;"
|
||||
#ifdef XP_MACOSX
|
||||
key="goForwardKb2"
|
||||
#else
|
||||
key="goForwardKb"
|
||||
#endif
|
||||
command="Browser:ForwardOrForwardDuplicate"
|
||||
onclick="checkForMiddleClick(this, event);"/>
|
||||
<menuitem id="historyMenuHome"
|
||||
class="show-only-for-keyboard"
|
||||
label="&historyHomeCmd.label;"
|
||||
oncommand="BrowserGoHome(event);"
|
||||
onclick="checkForMiddleClick(this, event);"
|
||||
key="goHome"/>
|
||||
<menuseparator id="historyMenuHomeSeparator"
|
||||
class="show-only-for-keyboard"/>
|
||||
<menuitem id="menu_showAllHistory"
|
||||
label="&showAllHistoryCmd2.label;"
|
||||
#ifndef XP_MACOSX
|
||||
|
|
|
@ -123,6 +123,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||
browser_bug556061.js \
|
||||
browser_bug559991.js \
|
||||
browser_bug561623.js \
|
||||
browser_bug561636.js \
|
||||
browser_bug562649.js \
|
||||
browser_bug563588.js \
|
||||
browser_bug565575.js \
|
||||
|
@ -352,13 +353,6 @@ MOCHITEST_BROWSER_FILES += \
|
|||
$(NULL)
|
||||
endif
|
||||
|
||||
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
# Bug 766546.
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
browser_bug561636.js \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifdef MOZ_DATA_REPORTING
|
||||
MOCHITEST_BROWSER_FILES += \
|
||||
browser_datareporting_notification.js \
|
||||
|
|
|
@ -374,12 +374,15 @@ function()
|
|||
Services.obs.addObserver(gObserver, "invalidformsubmit", false);
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function(e) {
|
||||
let browser = e.currentTarget;
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
// Ignore load events from the iframe.
|
||||
if (tab.linkedBrowser.contentDocument == e.target) {
|
||||
let browser = e.currentTarget;
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
isnot(gBrowser.selectedTab.linkedBrowser, browser,
|
||||
"This tab should have been loaded in background");
|
||||
browser.contentDocument.getElementById('s').click();
|
||||
isnot(gBrowser.selectedTab.linkedBrowser, browser,
|
||||
"This tab should have been loaded in background");
|
||||
browser.contentDocument.getElementById('s').click();
|
||||
}
|
||||
}, true);
|
||||
|
||||
tab.linkedBrowser.loadURI(uri);
|
||||
|
|
|
@ -119,13 +119,6 @@ var PlacesOrganizer = {
|
|||
for (var i=0; i < elements.length; i++) {
|
||||
document.getElementById(elements[i]).setAttribute("disabled", "true");
|
||||
}
|
||||
|
||||
// 3. Disable the keyboard shortcut for the History menu back/forward
|
||||
// in order to support those in the Library
|
||||
var historyMenuBack = document.getElementById("historyMenuBack");
|
||||
historyMenuBack.removeAttribute("key");
|
||||
var historyMenuForward = document.getElementById("historyMenuForward");
|
||||
historyMenuForward.removeAttribute("key");
|
||||
#endif
|
||||
|
||||
// remove the "Properties" context-menu item, we've our own details pane
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||
|
||||
Current extension version is: 0.8.291
|
||||
Current extension version is: 0.8.377
|
||||
|
||||
|
|
|
@ -206,6 +206,10 @@ ChromeActions.prototype = {
|
|||
// The data may not be downloaded so we need just retry getting the pdf with
|
||||
// the original url.
|
||||
var originalUri = NetUtil.newURI(data.originalUrl);
|
||||
var filename = data.filename;
|
||||
if (typeof filename !== 'string' || !/\.pdf$/i.test(filename)) {
|
||||
filename = 'document.pdf';
|
||||
}
|
||||
var blobUri = data.blobUrl ? NetUtil.newURI(data.blobUrl) : originalUri;
|
||||
var extHelperAppSvc =
|
||||
Cc['@mozilla.org/uriloader/external-helper-app-service;1'].
|
||||
|
@ -234,7 +238,9 @@ ChromeActions.prototype = {
|
|||
// contentDisposition/contentDispositionFilename is readonly before FF18
|
||||
channel.contentDisposition = Ci.nsIChannel.DISPOSITION_ATTACHMENT;
|
||||
if (self.contentDispositionFilename) {
|
||||
channel.contentDispositionFilename = self.contentDispositionFilename;
|
||||
channel.contentDispositionFilename = self.contentDispositionFilename;
|
||||
} else {
|
||||
channel.contentDispositionFilename = filename;
|
||||
}
|
||||
} catch (e) {}
|
||||
channel.setURI(originalUri);
|
||||
|
@ -353,7 +359,7 @@ ChromeActions.prototype = {
|
|||
}
|
||||
}];
|
||||
notificationBox.appendNotification(message, 'pdfjs-fallback', null,
|
||||
notificationBox.PRIORITY_WARNING_LOW,
|
||||
notificationBox.PRIORITY_INFO_LOW,
|
||||
buttons,
|
||||
function eventsCallback(eventType) {
|
||||
// Currently there is only one event "removed" but if there are any other
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -42,17 +42,6 @@ select {
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
#viewerContainer:-webkit-full-screen {
|
||||
top: 0px;
|
||||
border-top: 2px solid transparent;
|
||||
background-color: #404040;
|
||||
background-image: url(images/texture.png);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
#viewerContainer:-moz-full-screen {
|
||||
top: 0px;
|
||||
border-top: 2px solid transparent;
|
||||
|
@ -76,10 +65,6 @@ select {
|
|||
}
|
||||
|
||||
|
||||
:-webkit-full-screen .page {
|
||||
margin-bottom: 100%;
|
||||
}
|
||||
|
||||
:-moz-full-screen .page {
|
||||
margin-bottom: 100%;
|
||||
}
|
||||
|
@ -88,10 +73,6 @@ select {
|
|||
margin-bottom: 100%;
|
||||
}
|
||||
|
||||
:-webkit-full-screen a:not(.internalLink) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:-moz-full-screen a:not(.internalLink) {
|
||||
display: none;
|
||||
}
|
||||
|
@ -137,30 +118,15 @@ html[dir='rtl'] .innerCenter {
|
|||
bottom: 0;
|
||||
width: 200px;
|
||||
visibility: hidden;
|
||||
-webkit-transition-duration: 200ms;
|
||||
-webkit-transition-timing-function: ease;
|
||||
-moz-transition-duration: 200ms;
|
||||
-moz-transition-timing-function: ease;
|
||||
-ms-transition-duration: 200ms;
|
||||
-ms-transition-timing-function: ease;
|
||||
-o-transition-duration: 200ms;
|
||||
-o-transition-timing-function: ease;
|
||||
transition-duration: 200ms;
|
||||
transition-timing-function: ease;
|
||||
|
||||
}
|
||||
html[dir='ltr'] #sidebarContainer {
|
||||
-webkit-transition-property: left;
|
||||
-moz-transition-property: left;
|
||||
-ms-transition-property: left;
|
||||
-o-transition-property: left;
|
||||
transition-property: left;
|
||||
left: -200px;
|
||||
}
|
||||
html[dir='rtl'] #sidebarContainer {
|
||||
-webkit-transition-property: right;
|
||||
-ms-transition-property: right;
|
||||
-o-transition-property: right;
|
||||
transition-property: right;
|
||||
right: -200px;
|
||||
}
|
||||
|
@ -183,30 +149,14 @@ html[dir='rtl'] #outerContainer.sidebarOpen > #sidebarContainer {
|
|||
bottom: 0;
|
||||
left: 0;
|
||||
min-width: 320px;
|
||||
-webkit-transition-duration: 200ms;
|
||||
-webkit-transition-timing-function: ease;
|
||||
-moz-transition-duration: 200ms;
|
||||
-moz-transition-timing-function: ease;
|
||||
-ms-transition-duration: 200ms;
|
||||
-ms-transition-timing-function: ease;
|
||||
-o-transition-duration: 200ms;
|
||||
-o-transition-timing-function: ease;
|
||||
transition-duration: 200ms;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
|
||||
-webkit-transition-property: left;
|
||||
-moz-transition-property: left;
|
||||
-ms-transition-property: left;
|
||||
-o-transition-property: left;
|
||||
transition-property: left;
|
||||
left: 200px;
|
||||
}
|
||||
html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
|
||||
-webkit-transition-property: right;
|
||||
-moz-transition-property: right;
|
||||
-ms-transition-property: right;
|
||||
-o-transition-property: right;
|
||||
transition-property: right;
|
||||
right: 200px;
|
||||
}
|
||||
|
@ -236,9 +186,7 @@ html[dir='rtl'] #sidebarContent {
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
.loadingInProgress #viewerContainer {
|
||||
top: 39px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
|
@ -299,30 +247,9 @@ html[dir='rtl'] #sidebarContent {
|
|||
height: 100%;
|
||||
background-color: #ddd;
|
||||
overflow: hidden;
|
||||
-moz-transition: width 200ms;
|
||||
-ms-transition: width 200ms;
|
||||
-webkit-transition: width 200ms;
|
||||
transition: width 200ms;
|
||||
}
|
||||
|
||||
@-moz-keyframes progressIndeterminate {
|
||||
0% { left: 0%; }
|
||||
50% { left: 100%; }
|
||||
100% { left: 100%; }
|
||||
}
|
||||
|
||||
@-ms-keyframes progressIndeterminate {
|
||||
0% { left: 0%; }
|
||||
50% { left: 100%; }
|
||||
100% { left: 100%; }
|
||||
}
|
||||
|
||||
@-webkit-keyframes progressIndeterminate {
|
||||
0% { left: 0%; }
|
||||
50% { left: 100%; }
|
||||
100% { left: 100%; }
|
||||
}
|
||||
|
||||
@keyframes progressIndeterminate {
|
||||
0% { left: 0%; }
|
||||
50% { left: 100%; }
|
||||
|
@ -331,9 +258,6 @@ html[dir='rtl'] #sidebarContent {
|
|||
|
||||
#loadingBar .progress.indeterminate {
|
||||
background-color: #999;
|
||||
-moz-transition: none;
|
||||
-ms-transition: none;
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
|
@ -345,11 +269,9 @@ html[dir='rtl'] #sidebarContent {
|
|||
width: 50px;
|
||||
|
||||
background-image: linear-gradient(to right, #999 0%, #fff 50%, #999 100%);
|
||||
background-size: 100% 100% no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
-moz-animation: progressIndeterminate 2s linear infinite;
|
||||
-ms-animation: progressIndeterminate 2s linear infinite;
|
||||
-webkit-animation: progressIndeterminate 2s linear infinite;
|
||||
animation: progressIndeterminate 2s linear infinite;
|
||||
}
|
||||
|
||||
|
@ -378,7 +300,6 @@ html[dir='rtl'] .findbar {
|
|||
}
|
||||
|
||||
.findbar label {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
|
@ -530,18 +451,6 @@ html[dir='rtl'] .splitToolbarButton > .toolbarButton {
|
|||
box-shadow: 0 1px 0 hsla(0,0%,100%,.05) inset,
|
||||
0 0 1px hsla(0,0%,100%,.15) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.05);
|
||||
-webkit-transition-property: background-color, border-color, box-shadow;
|
||||
-webkit-transition-duration: 150ms;
|
||||
-webkit-transition-timing-function: ease;
|
||||
-moz-transition-property: background-color, border-color, box-shadow;
|
||||
-moz-transition-duration: 150ms;
|
||||
-moz-transition-timing-function: ease;
|
||||
-ms-transition-property: background-color, border-color, box-shadow;
|
||||
-ms-transition-duration: 150ms;
|
||||
-ms-transition-timing-function: ease;
|
||||
-o-transition-property: background-color, border-color, box-shadow;
|
||||
-o-transition-duration: 150ms;
|
||||
-o-transition-timing-function: ease;
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease;
|
||||
|
@ -596,18 +505,6 @@ html[dir='rtl'] .splitToolbarButtonSeparator {
|
|||
padding: 12px 0;
|
||||
margin: 1px 0;
|
||||
box-shadow: 0 0 0 1px hsla(0,0%,100%,.03);
|
||||
-webkit-transition-property: padding;
|
||||
-webkit-transition-duration: 10ms;
|
||||
-webkit-transition-timing-function: ease;
|
||||
-moz-transition-property: padding;
|
||||
-moz-transition-duration: 10ms;
|
||||
-moz-transition-timing-function: ease;
|
||||
-ms-transition-property: padding;
|
||||
-ms-transition-duration: 10ms;
|
||||
-ms-transition-timing-function: ease;
|
||||
-o-transition-property: padding;
|
||||
-o-transition-duration: 10ms;
|
||||
-o-transition-timing-function: ease;
|
||||
transition-property: padding;
|
||||
transition-duration: 10ms;
|
||||
transition-timing-function: ease;
|
||||
|
@ -622,23 +519,9 @@ html[dir='rtl'] .splitToolbarButtonSeparator {
|
|||
color: hsl(0,0%,95%);
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
/* Opera does not support user-select, use <... unselectable="on"> instead */
|
||||
cursor: default;
|
||||
-webkit-transition-property: background-color, border-color, box-shadow;
|
||||
-webkit-transition-duration: 150ms;
|
||||
-webkit-transition-timing-function: ease;
|
||||
-moz-transition-property: background-color, border-color, box-shadow;
|
||||
-moz-transition-duration: 150ms;
|
||||
-moz-transition-timing-function: ease;
|
||||
-ms-transition-property: background-color, border-color, box-shadow;
|
||||
-ms-transition-duration: 150ms;
|
||||
-ms-transition-timing-function: ease;
|
||||
-o-transition-property: background-color, border-color, box-shadow;
|
||||
-o-transition-duration: 150ms;
|
||||
-o-transition-timing-function: ease;
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease;
|
||||
|
@ -674,18 +557,6 @@ html[dir='rtl'] .dropdownToolbarButton {
|
|||
box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
|
||||
0 0 1px hsla(0,0%,0%,.2) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.05);
|
||||
-webkit-transition-property: background-color, border-color, box-shadow;
|
||||
-webkit-transition-duration: 10ms;
|
||||
-webkit-transition-timing-function: linear;
|
||||
-moz-transition-property: background-color, border-color, box-shadow;
|
||||
-moz-transition-duration: 10ms;
|
||||
-moz-transition-timing-function: linear;
|
||||
-ms-transition-property: background-color, border-color, box-shadow;
|
||||
-ms-transition-duration: 10ms;
|
||||
-ms-transition-timing-function: linear;
|
||||
-o-transition-property: background-color, border-color, box-shadow;
|
||||
-o-transition-duration: 10ms;
|
||||
-o-transition-timing-function: linear;
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 10ms;
|
||||
transition-timing-function: linear;
|
||||
|
@ -699,18 +570,6 @@ html[dir='rtl'] .dropdownToolbarButton {
|
|||
box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
|
||||
0 0 1px hsla(0,0%,0%,.2) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.05);
|
||||
-webkit-transition-property: background-color, border-color, box-shadow;
|
||||
-webkit-transition-duration: 10ms;
|
||||
-webkit-transition-timing-function: linear;
|
||||
-moz-transition-property: background-color, border-color, box-shadow;
|
||||
-moz-transition-duration: 10ms;
|
||||
-moz-transition-timing-function: linear;
|
||||
-ms-transition-property: background-color, border-color, box-shadow;
|
||||
-ms-transition-duration: 10ms;
|
||||
-ms-transition-timing-function: linear;
|
||||
-o-transition-property: background-color, border-color, box-shadow;
|
||||
-o-transition-duration: 10ms;
|
||||
-o-transition-timing-function: linear;
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 10ms;
|
||||
transition-timing-function: linear;
|
||||
|
@ -740,7 +599,6 @@ html[dir='rtl'] .dropdownToolbarButton {
|
|||
}
|
||||
|
||||
.dropdownToolbarButton > select {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none; /* in the future this might matter, see bugzilla bug #649849 */
|
||||
min-width: 140px;
|
||||
font-size: 12px;
|
||||
|
@ -783,7 +641,6 @@ html[dir='rtl'] .toolbarButton:first-child {
|
|||
}
|
||||
|
||||
.toolbarButtonFlexibleSpacer {
|
||||
-webkit-box-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
min-width: 30px;
|
||||
}
|
||||
|
@ -887,7 +744,6 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||
}
|
||||
|
||||
.toolbarButton.bookmark {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin-top: 3px;
|
||||
|
@ -935,9 +791,9 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
outline-style: none;
|
||||
-moz-transition-property: background-color, border-color, box-shadow;
|
||||
-moz-transition-duration: 150ms;
|
||||
-moz-transition-timing-function: ease;
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
.toolbarField[type=checkbox] {
|
||||
|
@ -951,12 +807,6 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||
width: 40px;
|
||||
}
|
||||
|
||||
.toolbarField.pageNumber::-webkit-inner-spin-button,
|
||||
.toolbarField.pageNumber::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.toolbarField:hover {
|
||||
background-color: hsla(0,0%,100%,.11);
|
||||
border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.43) hsla(0,0%,0%,.45);
|
||||
|
@ -977,7 +827,6 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
text-align: left;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
@ -1001,7 +850,7 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||
}
|
||||
|
||||
.thumbnailImage {
|
||||
-moz-transition-duration: 150ms;
|
||||
transition-duration: 150ms;
|
||||
border: 1px solid transparent;
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
opacity: 0.8;
|
||||
|
@ -1011,7 +860,7 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||
.thumbnailSelectionRing {
|
||||
border-radius: 2px;
|
||||
padding: 7px;
|
||||
-moz-transition-duration: 150ms;
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
a:focus > .thumbnail > .thumbnailSelectionRing > .thumbnailImage,
|
||||
|
@ -1052,7 +901,6 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
|
|||
bottom: 0;
|
||||
padding: 4px 4px 0;
|
||||
overflow: auto;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
|
@ -1361,6 +1209,9 @@ canvas {
|
|||
#sidebarContainer, .toolbar, #loadingBox, #errorWrapper, .textLayer {
|
||||
display: none;
|
||||
}
|
||||
#viewerContainer {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#mainContainer, #viewerContainer, .page, .page canvas {
|
||||
position: static;
|
||||
|
@ -1371,6 +1222,7 @@ canvas {
|
|||
.page {
|
||||
float: left;
|
||||
display: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -174,22 +174,22 @@ limitations under the License.
|
|||
data-l10n-id="page_rotate_cw" ></menuitem>
|
||||
</menu>
|
||||
|
||||
<div id="viewerContainer">
|
||||
<div id="viewerContainer">
|
||||
<div id="viewer" contextmenu="viewerContextMenu"></div>
|
||||
</div>
|
||||
|
||||
<div id="errorWrapper" hidden='true'>
|
||||
<div id="errorMessageLeft">
|
||||
<span id="errorMessage"></span>
|
||||
<button id="errorShowMore" onclick="" oncontextmenu="return false;" data-l10n-id="error_more_info">
|
||||
<button id="errorShowMore" data-l10n-id="error_more_info">
|
||||
More Information
|
||||
</button>
|
||||
<button id="errorShowLess" onclick="" oncontextmenu="return false;" data-l10n-id="error_less_info" hidden='true'>
|
||||
<button id="errorShowLess" data-l10n-id="error_less_info" hidden='true'>
|
||||
Less Information
|
||||
</button>
|
||||
</div>
|
||||
<div id="errorMessageRight">
|
||||
<button id="errorClose" oncontextmenu="return false;" data-l10n-id="error_close">
|
||||
<button id="errorClose" data-l10n-id="error_close">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, PDFFindBar */
|
||||
/* globals PDFFindController, ProgressBar, getFileName, CustomStyle */
|
||||
/* globals getOutputScale, TextLayerBuilder */
|
||||
/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, PDFFindBar, CustomStyle,
|
||||
PDFFindController, ProgressBar, TextLayerBuilder, DownloadManager,
|
||||
getFileName, getOutputScale, scrollIntoView, getPDFFileNameFromURL,
|
||||
PDFHistory */
|
||||
|
||||
'use strict';
|
||||
|
||||
|
@ -46,6 +47,7 @@ var FindStates = {
|
|||
FIND_PENDING: 3
|
||||
};
|
||||
|
||||
PDFJS.imageResourcesPath = './images/';
|
||||
PDFJS.workerSrc = '../build/pdf.js';
|
||||
|
||||
var mozL10n = document.mozL10n || document.webL10n;
|
||||
|
@ -126,6 +128,61 @@ function getOutputScale() {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls specified element into view of its parent.
|
||||
* element {Object} The element to be visible.
|
||||
* spot {Object} The object with the top property -- offset from the top edge.
|
||||
*/
|
||||
function scrollIntoView(element, spot) {
|
||||
// Assuming offsetParent is available (it's not available when viewer is in
|
||||
// hidden iframe or object). We have to scroll: if the offsetParent is not set
|
||||
// producing the error. See also animationStartedClosure.
|
||||
var parent = element.offsetParent;
|
||||
var offsetY = element.offsetTop + element.clientTop;
|
||||
if (!parent) {
|
||||
console.error('offsetParent is not set -- cannot scroll');
|
||||
return;
|
||||
}
|
||||
while (parent.clientHeight == parent.scrollHeight) {
|
||||
offsetY += parent.offsetTop;
|
||||
parent = parent.offsetParent;
|
||||
if (!parent)
|
||||
return; // no need to scroll
|
||||
}
|
||||
if (spot)
|
||||
offsetY += spot.top;
|
||||
parent.scrollTop = offsetY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename or guessed filename from the url (see issue 3455).
|
||||
* url {String} The original PDF location.
|
||||
* @return {String} Guessed PDF file name.
|
||||
*/
|
||||
function getPDFFileNameFromURL(url) {
|
||||
var reURI = /^(?:([^:]+:)?\/\/[^\/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
|
||||
// SCHEME HOST 1.PATH 2.QUERY 3.REF
|
||||
// Pattern to get last matching NAME.pdf
|
||||
var reFilename = /[^\/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
|
||||
var splitURI = reURI.exec(url);
|
||||
var suggestedFilename = reFilename.exec(splitURI[1]) ||
|
||||
reFilename.exec(splitURI[2]) ||
|
||||
reFilename.exec(splitURI[3]);
|
||||
if (suggestedFilename) {
|
||||
suggestedFilename = suggestedFilename[0];
|
||||
if (suggestedFilename.indexOf('%') != -1) {
|
||||
// URL-encoded %2Fpath%2Fto%2Ffile.pdf should be file.pdf
|
||||
try {
|
||||
suggestedFilename =
|
||||
reFilename.exec(decodeURIComponent(suggestedFilename))[0];
|
||||
} catch(e) { // Possible (extremely rare) errors:
|
||||
// URIError "Malformed URI", e.g. for "%AA.pdf"
|
||||
// TypeError "null has no properties", e.g. for "%2F.pdf"
|
||||
}
|
||||
}
|
||||
}
|
||||
return suggestedFilename || 'document.pdf';
|
||||
}
|
||||
|
||||
var ProgressBar = (function ProgressBarClosure() {
|
||||
|
||||
|
@ -135,15 +192,18 @@ var ProgressBar = (function ProgressBarClosure() {
|
|||
|
||||
function ProgressBar(id, opts) {
|
||||
|
||||
// Fetch the sub-elements for later
|
||||
// Fetch the sub-elements for later.
|
||||
this.div = document.querySelector(id + ' .progress');
|
||||
|
||||
// Get options, with sensible defaults
|
||||
// Get the loading bar element, so it can be resized to fit the viewer.
|
||||
this.bar = this.div.parentNode;
|
||||
|
||||
// Get options, with sensible defaults.
|
||||
this.height = opts.height || 100;
|
||||
this.width = opts.width || 100;
|
||||
this.units = opts.units || '%';
|
||||
|
||||
// Initialize heights
|
||||
// Initialize heights.
|
||||
this.div.style.height = this.height + this.units;
|
||||
this.percent = 0;
|
||||
}
|
||||
|
@ -170,6 +230,22 @@ var ProgressBar = (function ProgressBarClosure() {
|
|||
this._indeterminate = isNaN(val);
|
||||
this._percent = clamp(val, 0, 100);
|
||||
this.updateBar();
|
||||
},
|
||||
|
||||
setWidth: function ProgressBar_setWidth(viewer) {
|
||||
if (viewer) {
|
||||
var container = viewer.parentNode;
|
||||
var scrollbarWidth = container.offsetWidth - viewer.offsetWidth;
|
||||
if (scrollbarWidth > 0) {
|
||||
this.bar.setAttribute('style', 'width: calc(100% - ' +
|
||||
scrollbarWidth + 'px);');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
hide: function ProgressBar_hide() {
|
||||
this.bar.classList.add('hidden');
|
||||
this.bar.removeAttribute('style');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -190,46 +266,8 @@ var Cache = function cacheCache(size) {
|
|||
|
||||
|
||||
|
||||
function scrollIntoView(element, spot) {
|
||||
// Assuming offsetParent is available (it's not available when viewer is in
|
||||
// hidden iframe or object). We have to scroll: if the offsetParent is not set
|
||||
// producing the error. See also animationStartedClosure.
|
||||
var parent = element.offsetParent;
|
||||
var offsetY = element.offsetTop + element.clientTop;
|
||||
if (!parent) {
|
||||
console.error('offsetParent is not set -- cannot scroll');
|
||||
return;
|
||||
}
|
||||
while (parent.clientHeight == parent.scrollHeight) {
|
||||
offsetY += parent.offsetTop;
|
||||
parent = parent.offsetParent;
|
||||
if (!parent)
|
||||
return; // no need to scroll
|
||||
}
|
||||
if (spot)
|
||||
offsetY += spot.top;
|
||||
parent.scrollTop = offsetY;
|
||||
}
|
||||
|
||||
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var FirefoxCom = (function FirefoxComClosure() {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
/**
|
||||
* Creates an event that the extension is listening for and will
|
||||
|
@ -284,6 +322,38 @@ var FirefoxCom = (function FirefoxComClosure() {
|
|||
};
|
||||
})();
|
||||
|
||||
var DownloadManager = (function DownloadManagerClosure() {
|
||||
function DownloadManager() {}
|
||||
|
||||
DownloadManager.prototype = {
|
||||
downloadUrl: function DownloadManager_downloadUrl(url, filename) {
|
||||
FirefoxCom.request('download', {
|
||||
originalUrl: url,
|
||||
filename: filename
|
||||
});
|
||||
},
|
||||
|
||||
download: function DownloadManager_download(blob, url, filename) {
|
||||
var blobUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
FirefoxCom.request('download', {
|
||||
blobUrl: blobUrl,
|
||||
originalUrl: url,
|
||||
filename: filename
|
||||
},
|
||||
function response(err) {
|
||||
if (err && this.onerror) {
|
||||
this.onerror(err);
|
||||
}
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return DownloadManager;
|
||||
})();
|
||||
|
||||
|
||||
// Settings Manager - This is a utility for saving settings
|
||||
// First we see if localStorage is available
|
||||
|
@ -874,7 +944,7 @@ var PDFHistory = {
|
|||
|
||||
var state = window.history.state;
|
||||
if (this._isStateObjectDefined(state)) {
|
||||
// This case corresponds to navigating back to the document
|
||||
// This corresponds to navigating back to the document
|
||||
// from another page in the browser history.
|
||||
if (state.target.dest) {
|
||||
this.initialDestination = state.target.dest;
|
||||
|
@ -885,7 +955,7 @@ var PDFHistory = {
|
|||
this.uid = state.uid + 1;
|
||||
this.current = state.target;
|
||||
} else {
|
||||
// This case corresponds to the loading of a new document.
|
||||
// This corresponds to the loading of a new document.
|
||||
if (state && state.fingerprint &&
|
||||
this.fingerprint !== state.fingerprint) {
|
||||
// Reinitialize the browsing history when a new document
|
||||
|
@ -909,10 +979,14 @@ var PDFHistory = {
|
|||
} else {
|
||||
// Handle the user modifying the hash of a loaded document.
|
||||
self.previousHash = window.location.hash.substring(1);
|
||||
|
||||
// If the history is empty when the hash changes,
|
||||
// update the previous entry in the browser history.
|
||||
if (self.uid === 0) {
|
||||
var previousParams = (self.previousHash && self.currentBookmark &&
|
||||
self.previousHash !== self.currentBookmark) ?
|
||||
{ hash: self.currentBookmark } : { page: 1 };
|
||||
{ hash: self.currentBookmark, page: self.currentPage } :
|
||||
{ page: 1 };
|
||||
self.historyUnlocked = false;
|
||||
self.allowHashChange = false;
|
||||
window.history.back();
|
||||
|
@ -921,23 +995,29 @@ var PDFHistory = {
|
|||
self.historyUnlocked = true;
|
||||
}
|
||||
self._pushToHistory({ hash: self.previousHash }, false, true);
|
||||
if (self.currentBookmark) {
|
||||
self.previousBookmark = self.currentBookmark;
|
||||
}
|
||||
self._updatePreviousBookmark();
|
||||
}
|
||||
}, false);
|
||||
|
||||
window.addEventListener('beforeunload',
|
||||
function pdfHistoryBeforeunload(evt) {
|
||||
function pdfHistoryBeforeUnload() {
|
||||
var previousParams = self._getPreviousParams(null, true);
|
||||
if (previousParams) {
|
||||
self._pushToHistory(previousParams, false);
|
||||
}
|
||||
if (PDFView.isPresentationMode) {
|
||||
// Prevent the user from accidentally navigating away from
|
||||
// the document when presentation mode is active.
|
||||
evt.preventDefault();
|
||||
var replacePrevious = (!self.current.dest &&
|
||||
self.current.hash !== self.previousHash);
|
||||
self._pushToHistory(previousParams, false, replacePrevious);
|
||||
self._updatePreviousBookmark();
|
||||
}
|
||||
// Remove the event listener when navigating away from the document,
|
||||
// since 'beforeunload' prevents Firefox from caching the document.
|
||||
window.removeEventListener('beforeunload', pdfHistoryBeforeUnload, false);
|
||||
}
|
||||
window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false);
|
||||
|
||||
window.addEventListener('pageshow', function pdfHistoryPageShow(evt) {
|
||||
// If the entire viewer (including the PDF file) is cached in the browser,
|
||||
// we need to reattach the 'beforeunload' event listener since
|
||||
// the 'DOMContentLoaded' event is not fired on 'pageshow'.
|
||||
window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false);
|
||||
}, false);
|
||||
},
|
||||
|
||||
|
@ -966,16 +1046,21 @@ var PDFHistory = {
|
|||
return temp;
|
||||
},
|
||||
|
||||
_updatePreviousBookmark: function pdfHistory_updatePreviousBookmark() {
|
||||
if (this.updatePreviousBookmark &&
|
||||
this.currentBookmark && this.currentPage) {
|
||||
this.previousBookmark = this.currentBookmark;
|
||||
this.previousPage = this.currentPage;
|
||||
this.updatePreviousBookmark = false;
|
||||
}
|
||||
},
|
||||
|
||||
updateCurrentBookmark: function pdfHistoryUpdateCurrentBookmark(bookmark,
|
||||
pageNum) {
|
||||
if (this.initialized) {
|
||||
this.currentBookmark = bookmark.substring(1);
|
||||
this.currentPage = pageNum | 0;
|
||||
if (this.updatePreviousBookmark) {
|
||||
this.previousBookmark = this.currentBookmark;
|
||||
this.previousPage = this.currentPage;
|
||||
this.updatePreviousBookmark = false;
|
||||
}
|
||||
this._updatePreviousBookmark();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -998,10 +1083,20 @@ var PDFHistory = {
|
|||
if (params.page) {
|
||||
params.page |= 0;
|
||||
}
|
||||
if (isInitialBookmark && this.uid === 0) {
|
||||
this._pushToHistory(params, false);
|
||||
this.previousHash = window.location.hash.substring(1);
|
||||
if (isInitialBookmark) {
|
||||
var target = window.history.state.target;
|
||||
if (!target) {
|
||||
// Invoked when the user specifies an initial bookmark,
|
||||
// thus setting PDFView.initialBookmark, when the document is loaded.
|
||||
this._pushToHistory(params, false);
|
||||
this.previousHash = window.location.hash.substring(1);
|
||||
}
|
||||
this.updatePreviousBookmark = this.nextHashParam ? false : true;
|
||||
if (target) {
|
||||
// If the current document is reloaded,
|
||||
// avoid creating duplicate entries in the history.
|
||||
this._updatePreviousBookmark();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.nextHashParam && this.nextHashParam === params.hash) {
|
||||
|
@ -1014,8 +1109,11 @@ var PDFHistory = {
|
|||
if (this.current.hash) {
|
||||
if (this.current.hash !== params.hash) {
|
||||
this._pushToHistory(params, true);
|
||||
} else if (!this.current.page && params.page) {
|
||||
this._pushToHistory(params, false, true);
|
||||
} else {
|
||||
if (!this.current.page && params.page) {
|
||||
this._pushToHistory(params, false, true);
|
||||
}
|
||||
this.updatePreviousBookmark = true;
|
||||
}
|
||||
} else {
|
||||
this._pushToHistory(params, true);
|
||||
|
@ -1064,7 +1162,8 @@ var PDFHistory = {
|
|||
if (addPrevious && !overwrite) {
|
||||
var previousParams = this._getPreviousParams();
|
||||
if (previousParams) {
|
||||
this._pushToHistory(previousParams, false);
|
||||
var replacePrevious = (this.current.hash !== this.previousHash);
|
||||
this._pushToHistory(previousParams, false, replacePrevious);
|
||||
}
|
||||
}
|
||||
if (overwrite || this.uid === 0) {
|
||||
|
@ -1135,6 +1234,7 @@ var PDFHistory = {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
var PDFView = {
|
||||
pages: [],
|
||||
thumbnails: [],
|
||||
|
@ -1387,16 +1487,21 @@ var PDFView = {
|
|||
return support;
|
||||
},
|
||||
|
||||
get loadingBar() {
|
||||
var bar = new ProgressBar('#loadingBar', {});
|
||||
Object.defineProperty(this, 'loadingBar', { value: bar,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: false });
|
||||
return bar;
|
||||
},
|
||||
|
||||
get isHorizontalScrollbarEnabled() {
|
||||
var div = document.getElementById('viewerContainer');
|
||||
return div.scrollWidth > div.clientWidth;
|
||||
},
|
||||
|
||||
initPassiveLoading: function pdfViewInitPassiveLoading() {
|
||||
if (!PDFView.loadingBar) {
|
||||
PDFView.loadingBar = new ProgressBar('#loadingBar', {});
|
||||
}
|
||||
|
||||
var pdfDataRangeTransport = {
|
||||
rangeListeners: [],
|
||||
progressListeners: [],
|
||||
|
@ -1495,10 +1600,6 @@ var PDFView = {
|
|||
}
|
||||
}
|
||||
|
||||
if (!PDFView.loadingBar) {
|
||||
PDFView.loadingBar = new ProgressBar('#loadingBar', {});
|
||||
}
|
||||
|
||||
this.pdfDocument = null;
|
||||
var self = this;
|
||||
self.loading = true;
|
||||
|
@ -1555,32 +1656,30 @@ var PDFView = {
|
|||
|
||||
download: function pdfViewDownload() {
|
||||
function noData() {
|
||||
FirefoxCom.request('download', { originalUrl: url });
|
||||
downloadManager.downloadUrl(url, filename);
|
||||
}
|
||||
|
||||
var url = this.url.split('#')[0];
|
||||
// Document isn't ready just try to download with the url.
|
||||
if (!this.pdfDocument) {
|
||||
var filename = getPDFFileNameFromURL(url);
|
||||
var downloadManager = new DownloadManager();
|
||||
downloadManager.onerror = function (err) {
|
||||
// This error won't really be helpful because it's likely the
|
||||
// fallback won't work either (or is already open).
|
||||
PDFView.error('PDF failed to download.');
|
||||
};
|
||||
|
||||
if (!this.pdfDocument) { // the PDF is not ready yet
|
||||
noData();
|
||||
return;
|
||||
}
|
||||
|
||||
this.pdfDocument.getData().then(
|
||||
function getDataSuccess(data) {
|
||||
var blob = PDFJS.createBlob(data.buffer, 'application/pdf');
|
||||
var blobUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url },
|
||||
function response(err) {
|
||||
if (err) {
|
||||
// This error won't really be helpful because it's likely the
|
||||
// fallback won't work either (or is already open).
|
||||
PDFView.error('PDF failed to download.');
|
||||
}
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
}
|
||||
);
|
||||
downloadManager.download(blob, url, filename);
|
||||
},
|
||||
noData // Error occurred try downloading with just the url.
|
||||
);
|
||||
).then(null, noData);
|
||||
},
|
||||
|
||||
fallback: function pdfViewFallback() {
|
||||
|
@ -1598,19 +1697,12 @@ var PDFView = {
|
|||
},
|
||||
|
||||
navigateTo: function pdfViewNavigateTo(dest) {
|
||||
var destString = '';
|
||||
var self = this;
|
||||
PDFJS.Promise.all([this.pagesPromise,
|
||||
this.destinationsPromise]).then(function() {
|
||||
var destString = '';
|
||||
if (typeof dest === 'string') {
|
||||
destString = dest;
|
||||
dest = self.destinations[dest];
|
||||
}
|
||||
if (!(dest instanceof Array)) {
|
||||
return; // invalid destination
|
||||
}
|
||||
|
||||
var goToDestination = function(destRef) {
|
||||
self.pendingRefStr = null;
|
||||
// dest array looks like that: <page-ref> </XYZ|FitXXX> <args..>
|
||||
var destRef = dest[0];
|
||||
var pageNumber = destRef instanceof Object ?
|
||||
self.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] :
|
||||
(destRef + 1);
|
||||
|
@ -1623,7 +1715,24 @@ var PDFView = {
|
|||
|
||||
// Update the browsing history.
|
||||
PDFHistory.push({ dest: dest, hash: destString, page: pageNumber });
|
||||
} else {
|
||||
self.pendingRefStrLoaded = new PDFJS.Promise();
|
||||
self.pendingRefStr = destRef.num + ' ' + destRef.gen + ' R';
|
||||
self.pendingRefStrLoaded.then(function() {
|
||||
goToDestination(destRef);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.destinationsPromise.then(function() {
|
||||
if (typeof dest === 'string') {
|
||||
destString = dest;
|
||||
dest = self.destinations[dest];
|
||||
}
|
||||
if (!(dest instanceof Array)) {
|
||||
return; // invalid destination
|
||||
}
|
||||
goToDestination(dest[0]);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1728,8 +1837,7 @@ var PDFView = {
|
|||
errorWrapper.setAttribute('hidden', 'true');
|
||||
|
||||
pdfDocument.dataLoaded().then(function() {
|
||||
var loadingBar = document.getElementById('loadingBar');
|
||||
loadingBar.classList.add('hidden');
|
||||
PDFView.loadingBar.hide();
|
||||
var outerContainer = document.getElementById('outerContainer');
|
||||
outerContainer.classList.remove('loadingInProgress');
|
||||
});
|
||||
|
@ -1791,6 +1899,8 @@ var PDFView = {
|
|||
event.initCustomEvent('documentload', true, true, {});
|
||||
window.dispatchEvent(event);
|
||||
|
||||
PDFView.loadingBar.setWidth(container);
|
||||
|
||||
for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
|
||||
var pagePromise = pdfDocument.getPage(pageNum);
|
||||
pagePromise.then(function(pdfPage) {
|
||||
|
@ -1809,6 +1919,10 @@ var PDFView = {
|
|||
var pageRef = pdfPage.ref;
|
||||
var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
|
||||
pagesRefMap[refStr] = pdfPage.pageNumber;
|
||||
|
||||
if (self.pendingRefStr && self.pendingRefStr === refStr) {
|
||||
self.pendingRefStrLoaded.resolve();
|
||||
}
|
||||
});
|
||||
pagePromises.push(pagePromise);
|
||||
}
|
||||
|
@ -3097,11 +3211,9 @@ var TextLayerBuilder = function textLayerBuilder(options) {
|
|||
|
||||
if (width > 0) {
|
||||
var textScale = textDiv.dataset.canvasWidth / width;
|
||||
|
||||
var rotation = textDiv.dataset.angle;
|
||||
var transform = 'scale(' + textScale + ', 1)';
|
||||
if (bidiTexts[i].dir === 'ttb') {
|
||||
transform = 'rotate(90deg) ' + transform;
|
||||
}
|
||||
transform = 'rotate(' + rotation + 'deg) ' + transform;
|
||||
CustomStyle.setProp('transform' , textDiv, transform);
|
||||
CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
|
||||
|
||||
|
@ -3141,13 +3253,14 @@ var TextLayerBuilder = function textLayerBuilder(options) {
|
|||
|
||||
// vScale and hScale already contain the scaling to pixel units
|
||||
var fontHeight = geom.fontSize * Math.abs(geom.vScale);
|
||||
textDiv.dataset.canvasWidth = geom.canvasWidth * geom.hScale;
|
||||
textDiv.dataset.canvasWidth = geom.canvasWidth * Math.abs(geom.hScale);
|
||||
textDiv.dataset.fontName = geom.fontName;
|
||||
textDiv.dataset.angle = geom.angle * (180 / Math.PI);
|
||||
|
||||
textDiv.style.fontSize = fontHeight + 'px';
|
||||
textDiv.style.fontFamily = geom.fontFamily;
|
||||
textDiv.style.left = geom.x + 'px';
|
||||
textDiv.style.top = (geom.y - fontHeight) + 'px';
|
||||
textDiv.style.left = (geom.x + (fontHeight * Math.sin(geom.angle))) + 'px';
|
||||
textDiv.style.top = (geom.y - (fontHeight * Math.cos(geom.angle))) + 'px';
|
||||
|
||||
// The content of the div is set in the `setTextContent` function.
|
||||
|
||||
|
@ -3175,7 +3288,7 @@ var TextLayerBuilder = function textLayerBuilder(options) {
|
|||
|
||||
textDiv.textContent = bidiText.str;
|
||||
// bidiText.dir may be 'ttb' for vertical texts.
|
||||
textDiv.dir = bidiText.dir === 'rtl' ? 'rtl' : 'ltr';
|
||||
textDiv.dir = bidiText.dir;
|
||||
}
|
||||
|
||||
this.setupRenderLayoutTimer();
|
||||
|
@ -3877,12 +3990,18 @@ window.addEventListener('keydown', function keydown(evt) {
|
|||
if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {
|
||||
// either CTRL or META key with optional SHIFT.
|
||||
switch (evt.keyCode) {
|
||||
case 70:
|
||||
case 70: // f
|
||||
if (!PDFView.supportsIntegratedFind) {
|
||||
PDFFindBar.toggle();
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
case 71: // g
|
||||
if (!PDFView.supportsIntegratedFind) {
|
||||
PDFFindBar.dispatchEvent('again', cmd === 5 || cmd === 12);
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
case 61: // FF/Mac '='
|
||||
case 107: // FF '+' and '='
|
||||
case 187: // Chrome '+'
|
||||
|
@ -3904,14 +4023,12 @@ window.addEventListener('keydown', function keydown(evt) {
|
|||
}
|
||||
}
|
||||
|
||||
// CTRL or META with or without SHIFT.
|
||||
if (cmd == 1 || cmd == 8 || cmd == 5 || cmd == 12) {
|
||||
// CTRL+ALT or Option+Command
|
||||
if (cmd === 3 || cmd === 10) {
|
||||
switch (evt.keyCode) {
|
||||
case 71: // g
|
||||
if (!PDFView.supportsIntegratedFind) {
|
||||
PDFFindBar.dispatchEvent('again', cmd == 5 || cmd == 12);
|
||||
handled = true;
|
||||
}
|
||||
case 80: // p
|
||||
PDFView.presentationMode();
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ browser.contentHandlers.types.0.uri=http://add.my.yahoo.com/rss?url=%s
|
|||
# profile database. Note that "new" is defined as "has a different URL"; this
|
||||
# means that it's not possible to update the name of existing handler, so
|
||||
# don't make any spelling errors here.
|
||||
gecko.handlerService.defaultHandlersVersion=3
|
||||
gecko.handlerService.defaultHandlersVersion=4
|
||||
|
||||
# The default set of protocol handlers for webcal:
|
||||
gecko.handlerService.schemes.webcal.0.name=30 Boxes
|
||||
gecko.handlerService.schemes.webcal.0.uriTemplate=http://30boxes.com/external/widget?refer=ff&url=%s
|
||||
gecko.handlerService.schemes.webcal.0.uriTemplate=https://30boxes.com/external/widget?refer=ff&url=%s
|
||||
|
||||
# The default set of protocol handlers for mailto:
|
||||
gecko.handlerService.schemes.mailto.0.name=Yahoo! Mail
|
||||
|
|
|
@ -317,7 +317,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
|||
<!ENTITY historyUndoWindowMenu.label "Recently Closed Windows">
|
||||
<!ENTITY historyRestoreLastSession.label "Restore Previous Session">
|
||||
|
||||
<!ENTITY historyHomeCmd.label "Home">
|
||||
<!ENTITY showAllHistoryCmd2.label "Show All History">
|
||||
<!ENTITY showAllHistoryCmd.commandkey "H">
|
||||
|
||||
|
|
|
@ -37,9 +37,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "CrossSlide",
|
||||
"resource:///modules/CrossSlide.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "OS",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "View",
|
||||
"resource:///modules/View.jsm");
|
||||
|
||||
|
|
|
@ -567,7 +567,8 @@
|
|||
</vbox>
|
||||
<cssthrobber id="sync-connected-throbber"
|
||||
class="syncThrobber"
|
||||
collapsed="true" />
|
||||
collapsed="true"
|
||||
disabled="true" />
|
||||
</hbox>
|
||||
<label id="sync-disconnect-label"
|
||||
class="text-link"
|
||||
|
|
|
@ -371,24 +371,20 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
|||
list-style-image: url("moz-icon://stock/gtk-preferences?size=menu");
|
||||
}
|
||||
|
||||
#menu_stop,
|
||||
#context-stop {
|
||||
list-style-image: url("moz-icon://stock/gtk-stop?size=menu");
|
||||
}
|
||||
|
||||
#menu_stop[disabled],
|
||||
#context-stop[disabled] {
|
||||
list-style-image: url("moz-icon://stock/gtk-stop?size=menu&state=disabled");
|
||||
}
|
||||
|
||||
#menu_reload,
|
||||
#placesContext_reload,
|
||||
#context-reload,
|
||||
#context-reloadframe {
|
||||
list-style-image: url("moz-icon://stock/gtk-refresh?size=menu");
|
||||
}
|
||||
|
||||
#menu_reload[disabled],
|
||||
#context-reload[disabled] {
|
||||
list-style-image: url("moz-icon://stock/gtk-refresh?size=menu&state=disabled");
|
||||
}
|
||||
|
@ -405,50 +401,38 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
|||
list-style-image: url("moz-icon://stock/gtk-zoom-100?size=menu");
|
||||
}
|
||||
|
||||
#historyMenuBack,
|
||||
#context-back {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu");
|
||||
}
|
||||
|
||||
#historyMenuBack[disabled],
|
||||
#context-back[disabled] {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu&state=disabled");
|
||||
}
|
||||
|
||||
#historyMenuBack:-moz-locale-dir(rtl),
|
||||
#context-back:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu");
|
||||
}
|
||||
|
||||
#historyMenuBack[disabled]:-moz-locale-dir(rtl),
|
||||
#context-back[disabled]:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu&state=disabled");
|
||||
}
|
||||
|
||||
#historyMenuForward,
|
||||
#context-forward {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu");
|
||||
}
|
||||
|
||||
#historyMenuForward[disabled],
|
||||
#context-forward[disabled] {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu&state=disabled");
|
||||
}
|
||||
|
||||
#historyMenuForward:-moz-locale-dir(rtl),
|
||||
#context-forward:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu");
|
||||
}
|
||||
|
||||
#historyMenuForward[disabled]:-moz-locale-dir(rtl),
|
||||
#context-forward[disabled]:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled");
|
||||
}
|
||||
|
||||
#historyMenuHome {
|
||||
list-style-image: url("moz-icon://stock/gtk-home?size=menu");
|
||||
}
|
||||
|
||||
#appmenu_history,
|
||||
#appmenu_showAllHistory,
|
||||
#menu_showAllHistory {
|
||||
|
|
|
@ -538,17 +538,23 @@ CSPRep.fromStringSpecCompliant = function(aStr, self, docRequest, csp) {
|
|||
// specifying either default-src or script-src, and to blocking inline
|
||||
// styles by specifying either default-src or style-src.
|
||||
if ("default-src" in dirs) {
|
||||
aCSPR._allowInlineScripts = false;
|
||||
aCSPR._allowInlineStyles = false;
|
||||
aCSPR._allowEval = false;
|
||||
} else {
|
||||
if ("script-src" in dirs) {
|
||||
// Parse the source list (look ahead) so we can set the defaults properly,
|
||||
// honoring the 'unsafe-inline' and 'unsafe-eval' keywords
|
||||
var defaultSrcValue = CSPSourceList.fromString(dirs["default-src"], null, self);
|
||||
if (!defaultSrcValue._allowUnsafeInline) {
|
||||
aCSPR._allowInlineScripts = false;
|
||||
aCSPR._allowEval = false;
|
||||
}
|
||||
if ("style-src" in dirs) {
|
||||
aCSPR._allowInlineStyles = false;
|
||||
}
|
||||
if (!defaultSrcValue._allowUnsafeEval) {
|
||||
aCSPR._allowEval = false;
|
||||
}
|
||||
}
|
||||
if ("script-src" in dirs) {
|
||||
aCSPR._allowInlineScripts = false;
|
||||
aCSPR._allowEval = false;
|
||||
}
|
||||
if ("style-src" in dirs) {
|
||||
aCSPR._allowInlineStyles = false;
|
||||
}
|
||||
|
||||
directive:
|
||||
|
|
|
@ -633,6 +633,9 @@ MOCHITEST_FILES_C= \
|
|||
test_declare_stylesheet_obsolete.html \
|
||||
variable_style_sheet.sjs \
|
||||
test_processing_instruction_update_stylesheet.xhtml \
|
||||
test_CSP_bug888172.html \
|
||||
file_CSP_bug888172.html \
|
||||
file_CSP_bug888172.sjs \
|
||||
$(NULL)
|
||||
|
||||
# OOP tests don't work on Windows (bug 763081) or native-fennec
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
<ol>
|
||||
<li id="unsafe-inline-script">Inline script (green if allowed, black if blocked)</li>
|
||||
<li id="unsafe-eval-script">Eval script (green if allowed, black if blocked)</li>
|
||||
<li id="unsafe-inline-style">Inline style (green if allowed, black if blocked)</li>
|
||||
</ol>
|
||||
|
||||
<script>
|
||||
// Use inline script to set a style attribute
|
||||
document.getElementById("unsafe-inline-script").style.color = "green";
|
||||
|
||||
// Use eval to set a style attribute
|
||||
// try/catch is used because CSP causes eval to throw an exception when it
|
||||
// is blocked, which would derail the rest of the tests in this file.
|
||||
try {
|
||||
eval('document.getElementById("unsafe-eval-script").style.color = "green";');
|
||||
} catch (e) {}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
li#unsafe-inline-style {
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,43 @@
|
|||
// SJS file for CSP mochitests
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
function loadHTMLFromFile(path) {
|
||||
// Load the HTML to return in the response from file.
|
||||
// Since it's relative to the cwd of the test runner, we start there and
|
||||
// append to get to the actual path of the file.
|
||||
var testHTMLFile =
|
||||
Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties).
|
||||
get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||
var dirs = path.split("/");
|
||||
for (var i = 0; i < dirs.length; i++) {
|
||||
testHTMLFile.append(dirs[i]);
|
||||
}
|
||||
var testHTMLFileStream =
|
||||
Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
|
||||
var testHTML = NetUtil.readInputStreamToString(testHTMLFileStream, testHTMLFileStream.available());
|
||||
return testHTML;
|
||||
}
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
var query = {};
|
||||
request.queryString.split('&').forEach(function (val) {
|
||||
var [name, value] = val.split('=');
|
||||
query[name] = unescape(value);
|
||||
});
|
||||
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
// Deliver the CSP policy encoded in the URI
|
||||
if (query['csp'])
|
||||
response.setHeader("Content-Security-Policy", unescape(query['csp']), false);
|
||||
|
||||
// Send HTML to test allowed/blocked behaviors
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(loadHTMLFromFile("tests/content/base/test/file_CSP_bug888172.html"));
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 888172 - CSP 1.0 does not process 'unsafe-inline' or 'unsafe-eval' for default-src</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
|
||||
<iframe style="width:100%;" id='testframe1'></iframe>
|
||||
<iframe style="width:100%;" id='testframe2'></iframe>
|
||||
<iframe style="width:100%;" id='testframe3'></iframe>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// set up and go
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// utilities for check functions
|
||||
// black means the style wasn't applied, applied styles are green
|
||||
var green = 'rgb(0, 128, 0)';
|
||||
var black = 'rgb(0, 0, 0)';
|
||||
|
||||
function getElementColorById(doc, id) {
|
||||
return window.getComputedStyle(doc.contentDocument.getElementById(id)).color;
|
||||
}
|
||||
|
||||
// We test both script and style execution by observing changes in computed styles
|
||||
function checkDefaultSrcOnly() {
|
||||
var testframe = document.getElementById('testframe1');
|
||||
|
||||
ok(getElementColorById(testframe, 'unsafe-inline-script') === green, "Inline script should be allowed");
|
||||
ok(getElementColorById(testframe, 'unsafe-eval-script') === green, "Eval should be allowed");
|
||||
ok(getElementColorById(testframe, 'unsafe-inline-style') === green, "Inline style should be allowed");
|
||||
}
|
||||
|
||||
function checkDefaultSrcWithScriptSrc() {
|
||||
var testframe = document.getElementById('testframe2');
|
||||
|
||||
ok(getElementColorById(testframe, 'unsafe-inline-script') === black, "Inline script should be blocked");
|
||||
ok(getElementColorById(testframe, 'unsafe-eval-script') === black, "Eval should be blocked");
|
||||
ok(getElementColorById(testframe, 'unsafe-inline-style') === green, "Inline style should be allowed");
|
||||
}
|
||||
|
||||
function checkDefaultSrcWithStyleSrc() {
|
||||
var testframe = document.getElementById('testframe3');
|
||||
|
||||
ok(getElementColorById(testframe, 'unsafe-inline-script') === green, "Inline script should be allowed");
|
||||
ok(getElementColorById(testframe, 'unsafe-eval-script') === green, "Eval should be allowed");
|
||||
ok(getElementColorById(testframe, 'unsafe-inline-style') === black, "Inline style should be blocked");
|
||||
|
||||
// last test calls finish
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{'set':[["security.csp.speccompliant", true]]},
|
||||
function () {
|
||||
document.getElementById('testframe1').src = 'file_CSP_bug888172.sjs?csp=' +
|
||||
escape("Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval'");
|
||||
document.getElementById('testframe1').addEventListener('load', checkDefaultSrcOnly, false);
|
||||
|
||||
document.getElementById('testframe2').src = 'file_CSP_bug888172.sjs?csp=' +
|
||||
escape("Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval'; script-src 'self'");
|
||||
document.getElementById('testframe2').addEventListener('load', checkDefaultSrcWithScriptSrc, false);
|
||||
|
||||
document.getElementById('testframe3').src = 'file_CSP_bug888172.sjs?csp=' +
|
||||
escape("Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self'");
|
||||
document.getElementById('testframe3').addEventListener('load', checkDefaultSrcWithStyleSrc, false);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -360,10 +360,10 @@ MediaPluginReader::ImageBufferCallback::operator()(size_t aWidth, size_t aHeight
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<mozilla::layers::SharedRGBImage> rgbImage;
|
||||
nsRefPtr<mozilla::layers::DeprecatedSharedRGBImage> rgbImage;
|
||||
switch(aColorFormat) {
|
||||
case MPAPI::RGB565:
|
||||
rgbImage = mozilla::layers::SharedRGBImage::Create(mImageContainer,
|
||||
rgbImage = mozilla::layers::DeprecatedSharedRGBImage::Create(mImageContainer,
|
||||
nsIntSize(aWidth, aHeight),
|
||||
gfxASurface::ImageFormatRGB16_565);
|
||||
mImage = rgbImage;
|
||||
|
|
|
@ -93,7 +93,7 @@ nsXULPDGlobalObject_finalize(JSFreeOp *fop, JSObject *obj)
|
|||
nativeThis->OnFinalize(obj);
|
||||
|
||||
// The addref was part of JSObject construction
|
||||
NS_RELEASE(nativeThis);
|
||||
nsContentUtils::DeferredFinalize(nativeThis);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,10 @@ AlarmsManager.prototype = {
|
|||
throw Components.results.NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!aDate) {
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
let isIgnoreTimezone = true;
|
||||
switch (aRespectTimezone) {
|
||||
case "honorTimezone":
|
||||
|
@ -64,13 +68,13 @@ AlarmsManager.prototype = {
|
|||
break;
|
||||
|
||||
default:
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
break;
|
||||
}
|
||||
|
||||
let request = this.createRequest();
|
||||
this._cpmm.sendAsyncMessage(
|
||||
"AlarmsManager:Add",
|
||||
"AlarmsManager:Add",
|
||||
{ requestId: this.getRequestId(request),
|
||||
date: aDate,
|
||||
ignoreTimezone: isIgnoreTimezone,
|
||||
|
|
|
@ -25,23 +25,26 @@
|
|||
} catch (e) {
|
||||
ok(false,
|
||||
"Unexpected exception trying to add alarm for tomorrow.");
|
||||
|
||||
// Proceed to next test.
|
||||
return testPastDate();
|
||||
}
|
||||
domRequest.onsuccess = function(e) {
|
||||
navigator.mozAlarms.remove(e.target.result);
|
||||
ok(true, "Add alarm for future date.");
|
||||
|
||||
// Awesome, no error so proceed to next test
|
||||
// Awesome, no error so proceed to next test.
|
||||
testPastDate();
|
||||
};
|
||||
domRequest.onerror = function(e) {
|
||||
ok(false, "Unable to add alarm for tomorrow`.");
|
||||
|
||||
// Proceed to next test.
|
||||
testPastDate();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Verify passing a Date that's already past fails
|
||||
// Verify passing a Date that's already past doesn't fail (it should fire immediately).
|
||||
function testPastDate() {
|
||||
var yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
@ -52,61 +55,61 @@
|
|||
} catch (e) {
|
||||
ok(false,
|
||||
"Unexpected exception trying to add alarm for yesterday.");
|
||||
return testNull();
|
||||
|
||||
// Move on to the next test.
|
||||
testNullDate();
|
||||
}
|
||||
domRequest.onsuccess = function(e) {
|
||||
navigator.mozAlarms.remove(e.target.result);
|
||||
|
||||
ok(true, "Should be able to add alarm for already past date, which should fire immediately.");
|
||||
testNull();
|
||||
|
||||
// Move on to the next test.
|
||||
testNullDate();
|
||||
};
|
||||
domRequest.onerror = function(e) {
|
||||
ok(false, "Unable to add alarm for yesterday.");
|
||||
|
||||
// Errors as it should, on to the next test
|
||||
testNull();
|
||||
// Move on to the next test.
|
||||
testNullDate();
|
||||
}
|
||||
}
|
||||
|
||||
// Verify passing null does indeed fail
|
||||
function testNull() {
|
||||
var domRequest;
|
||||
function testNullDate() {
|
||||
try {
|
||||
domRequest = navigator.mozAlarms.add(null, "honorTimezone", {});
|
||||
navigator.mozAlarms.add(null, "honorTimezone", {});
|
||||
ok(false, "Expected an exception to be thrown for alarm with null date.");
|
||||
} catch(e) {
|
||||
ok(false, "Unexpected exception thrown while testing null case.");
|
||||
|
||||
// Exception thrown
|
||||
return SimpleTest.finish();
|
||||
ok(true, "Exception thrown for alarm with null date.");
|
||||
}
|
||||
domRequest.onsuccess = function(e) {
|
||||
// Null should not be valid
|
||||
ok(false, "Null should not be accepted as input for `date` param.");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
domRequest.onerror = function(e) {
|
||||
// Null should not be valid
|
||||
ok(true, "Passing null for date value causes failure.");
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
// Move on to the next test.
|
||||
testInvalidTimeZone()
|
||||
}
|
||||
|
||||
function testInvalidTimeZone() {
|
||||
try {
|
||||
navigator.mozAlarms.add(new Date(), "badTimeZoneArg", {});
|
||||
ok(false, "Expected an exception to be thrown while testing bad time zone arg.");
|
||||
} catch(e) {
|
||||
ok(true, "Exception thrown while testing bad time zone arg.");
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.mozAlarms.enabled", true]]}, function() {
|
||||
|
||||
// Currently applicable only on FxOS
|
||||
if (navigator.userAgent.indexOf("Mobile") != -1 &&
|
||||
navigator.appVersion.indexOf("Android") == -1) {
|
||||
|
||||
navigator.appVersion.indexOf("Android") == -1)
|
||||
{
|
||||
testFutureDate();
|
||||
|
||||
} else {
|
||||
ok(true, "mozAlarms on Firefox OS only.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -59,11 +59,6 @@ AppsService.prototype = {
|
|||
return DOMApplicationRegistry.getManifestURLByLocalId(aLocalId);
|
||||
},
|
||||
|
||||
getAppFromObserverMessage: function getAppFromObserverMessage(aMessage) {
|
||||
debug("getAppFromObserverMessage( " + aMessage + " )");
|
||||
return DOMApplicationRegistry.getAppFromObserverMessage(aMessage);
|
||||
},
|
||||
|
||||
getCoreAppsBasePath: function getCoreAppsBasePath() {
|
||||
debug("getCoreAppsBasePath()");
|
||||
return DOMApplicationRegistry.getCoreAppsBasePath();
|
||||
|
|
|
@ -104,11 +104,6 @@ this.DOMApplicationRegistry = {
|
|||
return AppsUtils.getManifestURLByLocalId(this.webapps, aLocalId);
|
||||
},
|
||||
|
||||
getAppFromObserverMessage: function getAppFromObserverMessage(aMessage) {
|
||||
debug("getAppFromObserverMessage " + aMessage);
|
||||
return AppsUtils.getAppFromObserverMessage(this.webapps. aMessage);
|
||||
},
|
||||
|
||||
getCoreAppsBasePath: function getCoreAppsBasePath() {
|
||||
debug("getCoreAppsBasePath() not yet supported on child!");
|
||||
return null;
|
||||
|
|
|
@ -176,21 +176,6 @@ this.AppsUtils = {
|
|||
return "";
|
||||
},
|
||||
|
||||
getAppFromObserverMessage: function(aApps, aMessage) {
|
||||
let data = JSON.parse(aMessage);
|
||||
|
||||
for (let id in aApps) {
|
||||
let app = aApps[id];
|
||||
if (app.origin != data.origin) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return this.cloneAsMozIApplication(app);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getCoreAppsBasePath: function getCoreAppsBasePath() {
|
||||
debug("getCoreAppsBasePath()");
|
||||
try {
|
||||
|
|
|
@ -2982,10 +2982,6 @@ this.DOMApplicationRegistry = {
|
|||
return AppsUtils.getAppLocalIdByManifestURL(this.webapps, aManifestURL);
|
||||
},
|
||||
|
||||
getAppFromObserverMessage: function(aMessage) {
|
||||
return AppsUtils.getAppFromObserverMessage(this.webapps, aMessage);
|
||||
},
|
||||
|
||||
getCoreAppsBasePath: function() {
|
||||
return AppsUtils.getCoreAppsBasePath();
|
||||
},
|
||||
|
|
|
@ -17,7 +17,7 @@ interface nsIURI;
|
|||
* This service allows accessing some DOMApplicationRegistry methods from
|
||||
* non-javascript code.
|
||||
*/
|
||||
[scriptable, uuid(27b995cf-bec8-47de-aa48-6117c950fce3)]
|
||||
[scriptable, uuid(9b23d8f0-b2f3-46af-bff4-3df6c3cb69db)]
|
||||
interface nsIAppsService : nsISupports
|
||||
{
|
||||
mozIDOMApplication getAppByManifestURL(in DOMString manifestURL);
|
||||
|
@ -40,13 +40,6 @@ interface nsIAppsService : nsISupports
|
|||
*/
|
||||
DOMString getManifestURLByLocalId(in unsigned long localId);
|
||||
|
||||
/**
|
||||
* Returns the app that is related to the message.
|
||||
* This is a helper to not have to worry about what is the actual structure
|
||||
* of the message when listening to one.
|
||||
*/
|
||||
mozIApplication getAppFromObserverMessage(in DOMString message);
|
||||
|
||||
/**
|
||||
* Returns the CSP associated to this localId.
|
||||
*/
|
||||
|
|
|
@ -137,3 +137,8 @@ PESupportsConditionExpectedCloseParen=Expected ')' while parsing supports condit
|
|||
PESupportsConditionExpectedStart2=Expected 'not', '(', or function while parsing supports condition but found '%1$S'.
|
||||
PESupportsConditionExpectedNot=Expected 'not' while parsing supports condition but found '%1$S'.
|
||||
PESupportsGroupRuleStart=Expected '{' to begin @supports rule but found '%1$S'.
|
||||
PEFilterEOF=filter
|
||||
PEExpectedNoneOrURL=Expected 'none' or URL but found '%1$S'.
|
||||
PEExpectedNoneOrURLOrFilterFunction=Expected 'none', URL, or filter function but found '%1$S'.
|
||||
PEExpectedNonnegativeNP=Expected non-negative number or percentage.
|
||||
PEFilterFunctionArgumentsParsingError=Error in parsing arguments for filter function.
|
||||
|
|
|
@ -345,19 +345,29 @@ this.PushService = {
|
|||
break;
|
||||
case "webapps-uninstall":
|
||||
debug("webapps-uninstall");
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
var app = appsService.getAppFromObserverMessage(aData);
|
||||
if (!app) {
|
||||
debug("webapps-uninstall: No app found " + aData.origin);
|
||||
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(aData);
|
||||
} catch (ex) {
|
||||
debug("webapps-uninstall: JSON parsing error: " + aData);
|
||||
return;
|
||||
}
|
||||
|
||||
this._db.getAllByManifestURL(app.manifestURL, function(records) {
|
||||
let manifestURL = data.manifestURL;
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
if (appsService.getAppLocalIdByManifestURL(manifestURL) ==
|
||||
Ci.nsIScriptSecurityManager.NO_APP_ID) {
|
||||
debug("webapps-uninstall: No app found " + manifestURL);
|
||||
return;
|
||||
}
|
||||
|
||||
this._db.getAllByManifestURL(manifestURL, function(records) {
|
||||
debug("Got " + records.length);
|
||||
for (var i = 0; i < records.length; i++) {
|
||||
this._db.delete(records[i].channelID, null, function() {
|
||||
debug("app uninstall: " + app.manifestURL +
|
||||
debug("app uninstall: " + manifestURL +
|
||||
" Could not delete entry " + records[i].channelID);
|
||||
});
|
||||
// courtesy, but don't establish a connection
|
||||
|
@ -368,7 +378,7 @@ this.PushService = {
|
|||
}
|
||||
}
|
||||
}.bind(this), function() {
|
||||
debug("Error in getAllByManifestURL: url " + app.manifestURL);
|
||||
debug("Error in getAllByManifestURL: url " + manifestURL);
|
||||
});
|
||||
|
||||
break;
|
||||
|
|
|
@ -582,6 +582,18 @@ Factory::CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
TemporaryRef<DataSourceSurface>
|
||||
Factory::CreateDataSourceSurface(const IntSize &aSize,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
RefPtr<SourceSurfaceAlignedRawData> newSurf = new SourceSurfaceAlignedRawData();
|
||||
if (newSurf->Init(aSize, aFormat)) {
|
||||
return newSurf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TemporaryRef<DrawEventRecorder>
|
||||
Factory::CreateEventRecorderForFile(const char *aFilename)
|
||||
{
|
||||
|
|
|
@ -26,5 +26,17 @@ SourceSurfaceRawData::InitWrappingData(uint8_t *aData,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SourceSurfaceAlignedRawData::Init(const IntSize &aSize,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
mStride = GetAlignedStride<16>(aSize.width * BytesPerPixel(aFormat));
|
||||
mArray.Realloc(mStride * aSize.height);
|
||||
mSize = aSize;
|
||||
mFormat = aFormat;
|
||||
|
||||
return mArray != nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,28 @@ private:
|
|||
bool mOwnData;
|
||||
};
|
||||
|
||||
class SourceSurfaceAlignedRawData : public DataSourceSurface
|
||||
{
|
||||
public:
|
||||
SourceSurfaceAlignedRawData() {}
|
||||
|
||||
virtual uint8_t *GetData() { return mArray; }
|
||||
virtual int32_t Stride() { return mStride; }
|
||||
|
||||
virtual SurfaceType GetType() const { return SURFACE_DATA; }
|
||||
virtual IntSize GetSize() const { return mSize; }
|
||||
virtual SurfaceFormat GetFormat() const { return mFormat; }
|
||||
|
||||
bool Init(const IntSize &aSize,
|
||||
SurfaceFormat aFormat);
|
||||
|
||||
private:
|
||||
AlignedArray<uint8_t> mArray;
|
||||
int32_t mStride;
|
||||
SurfaceFormat mFormat;
|
||||
IntSize mSize;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ struct AlignedArray
|
|||
mStorage = new (std::nothrow) T[aSize + (alignment - 1)];
|
||||
if (uintptr_t(mStorage) % alignment) {
|
||||
// Our storage does not start at a <alignment>-byte boundary. Make sure mData does!
|
||||
mPtr = (uint32_t*)(uintptr_t(mStorage) +
|
||||
mPtr = (T*)(uintptr_t(mStorage) +
|
||||
(alignment - (uintptr_t(mStorage) % alignment)));
|
||||
} else {
|
||||
mPtr = mStorage;
|
||||
|
|
|
@ -34,6 +34,11 @@ In this order:
|
|||
angle-cross-compilation.patch
|
||||
Fixes cross compilation on case sensitive OSes.
|
||||
|
||||
angle-line-loop-overflow.patch
|
||||
Fixes a forgotten overflow check on drawing line loop
|
||||
ANGLE bug : http://code.google.com/p/angleproject/issues/detail?id=444
|
||||
ANGLE revision : 07dda9519cf4
|
||||
|
||||
In addition to these patches, the Makefile.in files are ours, they're not present in
|
||||
upsteam ANGLE. Therefore, changes made to the Makefile.in files should not be stored
|
||||
in the local .patch files.
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# HG changeset patch
|
||||
# Parent 308e3cf5ba75fdf8ed3bdd3dc766410b708b98ef
|
||||
|
||||
diff --git a/gfx/angle/src/libGLESv2/IndexDataManager.cpp b/gfx/angle/src/libGLESv2/IndexDataManager.cpp
|
||||
--- a/gfx/angle/src/libGLESv2/IndexDataManager.cpp
|
||||
+++ b/gfx/angle/src/libGLESv2/IndexDataManager.cpp
|
||||
@@ -375,17 +375,18 @@ void StreamingIndexBuffer::reserveSpace(
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
|
||||
}
|
||||
|
||||
mWritePosition = 0;
|
||||
}
|
||||
- else if (mWritePosition + requiredSpace > mBufferSize) // Recycle
|
||||
+ else if (mWritePosition + requiredSpace > mBufferSize ||
|
||||
+ mWritePosition + requiredSpace < mWritePosition) // Recycle
|
||||
{
|
||||
void *dummy;
|
||||
mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
|
||||
mIndexBuffer->Unlock();
|
||||
|
||||
mWritePosition = 0;
|
||||
}
|
||||
}
|
|
@ -380,7 +380,8 @@ void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
|
|||
|
||||
mWritePosition = 0;
|
||||
}
|
||||
else if (mWritePosition + requiredSpace > mBufferSize) // Recycle
|
||||
else if (mWritePosition + requiredSpace > mBufferSize ||
|
||||
mWritePosition + requiredSpace < mWritePosition) // Recycle
|
||||
{
|
||||
void *dummy;
|
||||
mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
|
||||
|
|
|
@ -224,36 +224,40 @@ struct EffectChain
|
|||
RefPtr<Effect> mSecondaryEffects[EFFECT_MAX_SECONDARY];
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a Textured effect corresponding to aFormat and using
|
||||
* aSource as the (first) texture source.
|
||||
*
|
||||
* Note that aFormat can be different form aSource->GetFormat if, we are
|
||||
* creating an effect that takes several texture sources (like with YCBCR
|
||||
* where aFormat would be FOMRAT_YCBCR and each texture source would be
|
||||
* a one-channel A8 texture)
|
||||
*/
|
||||
inline TemporaryRef<TexturedEffect>
|
||||
CreateTexturedEffect(DeprecatedTextureHost *aDeprecatedTextureHost,
|
||||
DeprecatedTextureHost *aDeprecatedTextureHostOnWhite,
|
||||
CreateTexturedEffect(gfx::SurfaceFormat aFormat,
|
||||
TextureSource* aSource,
|
||||
const gfx::Filter& aFilter)
|
||||
{
|
||||
if (aDeprecatedTextureHostOnWhite) {
|
||||
MOZ_ASSERT(aDeprecatedTextureHost->GetFormat() == gfx::FORMAT_R8G8B8X8 ||
|
||||
aDeprecatedTextureHost->GetFormat() == gfx::FORMAT_B8G8R8X8);
|
||||
return new EffectComponentAlpha(aDeprecatedTextureHost, aDeprecatedTextureHostOnWhite, aFilter);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aSource);
|
||||
RefPtr<TexturedEffect> result;
|
||||
switch (aDeprecatedTextureHost->GetFormat()) {
|
||||
switch (aFormat) {
|
||||
case gfx::FORMAT_B8G8R8A8:
|
||||
result = new EffectBGRA(aDeprecatedTextureHost, true, aFilter);
|
||||
result = new EffectBGRA(aSource, true, aFilter);
|
||||
break;
|
||||
case gfx::FORMAT_B8G8R8X8:
|
||||
result = new EffectBGRX(aDeprecatedTextureHost, true, aFilter);
|
||||
result = new EffectBGRX(aSource, true, aFilter);
|
||||
break;
|
||||
case gfx::FORMAT_R8G8B8X8:
|
||||
result = new EffectRGBX(aDeprecatedTextureHost, true, aFilter);
|
||||
result = new EffectRGBX(aSource, true, aFilter);
|
||||
break;
|
||||
case gfx::FORMAT_R5G6B5:
|
||||
result = new EffectRGBX(aDeprecatedTextureHost, true, aFilter);
|
||||
result = new EffectRGBX(aSource, true, aFilter);
|
||||
break;
|
||||
case gfx::FORMAT_R8G8B8A8:
|
||||
result = new EffectRGBA(aDeprecatedTextureHost, true, aFilter);
|
||||
result = new EffectRGBA(aSource, true, aFilter);
|
||||
break;
|
||||
case gfx::FORMAT_YUV:
|
||||
result = new EffectYCbCr(aDeprecatedTextureHost, aFilter);
|
||||
result = new EffectYCbCr(aSource, aFilter);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unhandled program type");
|
||||
|
@ -262,13 +266,40 @@ CreateTexturedEffect(DeprecatedTextureHost *aDeprecatedTextureHost,
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a textured effect based on aSource format and the presence of
|
||||
* aSourceOnWhite.
|
||||
*
|
||||
* aSourceOnWhite can be null.
|
||||
*/
|
||||
inline TemporaryRef<TexturedEffect>
|
||||
CreateTexturedEffect(DeprecatedTextureHost *aDeprecatedTextureHost,
|
||||
CreateTexturedEffect(TextureSource* aSource,
|
||||
TextureSource* aSourceOnWhite,
|
||||
const gfx::Filter& aFilter)
|
||||
{
|
||||
return CreateTexturedEffect(aDeprecatedTextureHost, nullptr, aFilter);
|
||||
MOZ_ASSERT(aSource);
|
||||
if (aSourceOnWhite) {
|
||||
MOZ_ASSERT(aSource->GetFormat() == gfx::FORMAT_R8G8B8X8 ||
|
||||
aSourceOnWhite->GetFormat() == gfx::FORMAT_B8G8R8X8);
|
||||
return new EffectComponentAlpha(aSource, aSourceOnWhite, aFilter);
|
||||
}
|
||||
|
||||
return CreateTexturedEffect(aSource->GetFormat(), aSource, aFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a textured effect based on aSource format.
|
||||
*
|
||||
* This version excudes the possibility of component alpha.
|
||||
*/
|
||||
inline TemporaryRef<TexturedEffect>
|
||||
CreateTexturedEffect(TextureSource *aTexture,
|
||||
const gfx::Filter& aFilter)
|
||||
{
|
||||
return CreateTexturedEffect(aTexture, nullptr, aFilter);
|
||||
}
|
||||
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace layers {
|
|||
|
||||
class ImageClient;
|
||||
class SharedPlanarYCbCrImage;
|
||||
class DeprecatedSharedPlanarYCbCrImage;
|
||||
|
||||
struct ImageBackendData
|
||||
{
|
||||
|
@ -720,6 +721,7 @@ public:
|
|||
PlanarYCbCrImage(BufferRecycleBin *aRecycleBin);
|
||||
|
||||
virtual SharedPlanarYCbCrImage *AsSharedPlanarYCbCrImage() { return nullptr; }
|
||||
virtual DeprecatedSharedPlanarYCbCrImage *AsDeprecatedSharedPlanarYCbCrImage() { return nullptr; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
|
|
@ -24,7 +24,7 @@ enum ImageFormat {
|
|||
GRALLOC_PLANAR_YCBCR,
|
||||
|
||||
/**
|
||||
* The SHARED_RGB format creates a SharedRGBImage, which stores RGB data in
|
||||
* The SHARED_RGB format creates a DeprecatedSharedRGBImage, which stores RGB data in
|
||||
* shared memory. Some Android hardware video decoders require this format.
|
||||
* Currently only used on Android.
|
||||
*/
|
||||
|
|
|
@ -111,7 +111,16 @@ public:
|
|||
bool RemoveTile(int x, int y, Tile& aRemovedTile);
|
||||
|
||||
uint16_t GetTileLength() const { return TILEDLAYERBUFFER_TILE_SIZE; }
|
||||
uint32_t GetScaledTileLength() const { return TILEDLAYERBUFFER_TILE_SIZE / mResolution; }
|
||||
uint32_t GetScaledTileLength() const {
|
||||
// volatile variables to help investigate bug 881018
|
||||
volatile float resolution = mResolution;
|
||||
volatile float fScaledLength = TILEDLAYERBUFFER_TILE_SIZE / mResolution;
|
||||
volatile uint32_t uiScaledLength = TILEDLAYERBUFFER_TILE_SIZE / mResolution;
|
||||
if (!uiScaledLength) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
return uiScaledLength;
|
||||
}
|
||||
|
||||
unsigned int GetTileCount() const { return mRetainedTiles.Length(); }
|
||||
|
||||
|
@ -225,7 +234,6 @@ TiledLayerBuffer<Derived, Tile>::GetTile(const nsIntPoint& aTileOrigin) const
|
|||
// TODO Cache firstTileOriginX/firstTileOriginY
|
||||
// Find the tile x/y of the first tile and the target tile relative to the (0, 0)
|
||||
// origin, the difference is the tile x/y relative to the start of the tile buffer.
|
||||
volatile float resolution = mResolution; // bug 881018 investigation
|
||||
int firstTileX = floor_div(mValidRegion.GetBounds().x, GetScaledTileLength());
|
||||
int firstTileY = floor_div(mValidRegion.GetBounds().y, GetScaledTileLength());
|
||||
return GetTile(floor_div(aTileOrigin.x, GetScaledTileLength()) - firstTileX,
|
||||
|
|
|
@ -28,10 +28,10 @@ ImageClient::CreateImageClient(CompositableType aCompositableHostType,
|
|||
RefPtr<ImageClient> result = nullptr;
|
||||
switch (aCompositableHostType) {
|
||||
case BUFFER_IMAGE_SINGLE:
|
||||
result = new ImageClientSingle(aForwarder, aFlags, BUFFER_IMAGE_SINGLE);
|
||||
result = new DeprecatedImageClientSingle(aForwarder, aFlags, BUFFER_IMAGE_SINGLE);
|
||||
break;
|
||||
case BUFFER_IMAGE_BUFFERED:
|
||||
result = new ImageClientSingle(aForwarder, aFlags, BUFFER_IMAGE_BUFFERED);
|
||||
result = new DeprecatedImageClientSingle(aForwarder, aFlags, BUFFER_IMAGE_BUFFERED);
|
||||
break;
|
||||
case BUFFER_BRIDGE:
|
||||
result = new ImageClientBridge(aForwarder, aFlags);
|
||||
|
@ -66,9 +66,9 @@ ImageClient::UpdatePictureRect(nsIntRect aRect)
|
|||
GetForwarder()->UpdatePictureRect(this, aRect);
|
||||
}
|
||||
|
||||
ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags,
|
||||
CompositableType aType)
|
||||
DeprecatedImageClientSingle::DeprecatedImageClientSingle(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags,
|
||||
CompositableType aType)
|
||||
: ImageClient(aFwd, aType)
|
||||
, mTextureInfo(aType)
|
||||
{
|
||||
|
@ -76,7 +76,7 @@ ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd,
|
|||
}
|
||||
|
||||
bool
|
||||
ImageClientSingle::EnsureDeprecatedTextureClient(DeprecatedTextureClientType aType)
|
||||
DeprecatedImageClientSingle::EnsureDeprecatedTextureClient(DeprecatedTextureClientType aType)
|
||||
{
|
||||
// We should not call this method if using ImageBridge or tiled texture
|
||||
// clients since SupportsType always fails
|
||||
|
@ -88,7 +88,7 @@ ImageClientSingle::EnsureDeprecatedTextureClient(DeprecatedTextureClientType aTy
|
|||
}
|
||||
|
||||
bool
|
||||
ImageClientSingle::UpdateImage(ImageContainer* aContainer,
|
||||
DeprecatedImageClientSingle::UpdateImage(ImageContainer* aContainer,
|
||||
uint32_t aContentFlags)
|
||||
{
|
||||
AutoLockImage autoLock(aContainer);
|
||||
|
@ -106,11 +106,11 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer,
|
|||
EnsureDeprecatedTextureClient(TEXTURE_YCBCR)) {
|
||||
PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
|
||||
|
||||
if (ycbcr->AsSharedPlanarYCbCrImage()) {
|
||||
if (ycbcr->AsDeprecatedSharedPlanarYCbCrImage()) {
|
||||
AutoLockDeprecatedTextureClient lock(mDeprecatedTextureClient);
|
||||
|
||||
SurfaceDescriptor sd;
|
||||
if (!ycbcr->AsSharedPlanarYCbCrImage()->ToSurfaceDescriptor(sd)) {
|
||||
if (!ycbcr->AsDeprecatedSharedPlanarYCbCrImage()->ToSurfaceDescriptor(sd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer,
|
|||
AutoLockDeprecatedTextureClient lock(mDeprecatedTextureClient);
|
||||
|
||||
SurfaceDescriptor desc;
|
||||
if (!static_cast<SharedRGBImage*>(image)->ToSurfaceDescriptor(desc)) {
|
||||
if (!static_cast<DeprecatedSharedRGBImage*>(image)->ToSurfaceDescriptor(desc)) {
|
||||
return false;
|
||||
}
|
||||
mDeprecatedTextureClient->SetDescriptor(desc);
|
||||
|
@ -209,7 +209,7 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer,
|
|||
}
|
||||
|
||||
void
|
||||
ImageClientSingle::Updated()
|
||||
DeprecatedImageClientSingle::Updated()
|
||||
{
|
||||
mForwarder->UpdateTexture(this, 1, mDeprecatedTextureClient->GetDescriptor());
|
||||
}
|
||||
|
@ -247,10 +247,10 @@ ImageClient::CreateImage(const uint32_t *aFormats,
|
|||
for (uint32_t i = 0; i < aNumFormats; i++) {
|
||||
switch (aFormats[i]) {
|
||||
case PLANAR_YCBCR:
|
||||
img = new SharedPlanarYCbCrImage(GetForwarder());
|
||||
img = new DeprecatedSharedPlanarYCbCrImage(GetForwarder());
|
||||
return img.forget();
|
||||
case SHARED_RGB:
|
||||
img = new SharedRGBImage(GetForwarder());
|
||||
img = new DeprecatedSharedRGBImage(GetForwarder());
|
||||
return img.forget();
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
case GONK_IO_SURFACE:
|
||||
|
|
|
@ -72,12 +72,12 @@ protected:
|
|||
* ContentClientDoubleBuffered, or using multiple clients for YCbCr or tiled
|
||||
* images).
|
||||
*/
|
||||
class ImageClientSingle : public ImageClient
|
||||
class DeprecatedImageClientSingle : public ImageClient
|
||||
{
|
||||
public:
|
||||
ImageClientSingle(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags,
|
||||
CompositableType aType);
|
||||
DeprecatedImageClientSingle(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags,
|
||||
CompositableType aType);
|
||||
|
||||
virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags);
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ void
|
|||
DeprecatedTextureClientShmemYCbCr::SetDescriptorFromReply(const SurfaceDescriptor& aDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(aDescriptor.type() == SurfaceDescriptor::TYCbCrImage);
|
||||
SharedPlanarYCbCrImage* shYCbCr = SharedPlanarYCbCrImage::FromSurfaceDescriptor(aDescriptor);
|
||||
DeprecatedSharedPlanarYCbCrImage* shYCbCr = DeprecatedSharedPlanarYCbCrImage::FromSurfaceDescriptor(aDescriptor);
|
||||
if (shYCbCr) {
|
||||
shYCbCr->Release();
|
||||
mDescriptor = SurfaceDescriptor();
|
||||
|
|
|
@ -54,10 +54,10 @@ CompositableHost::Create(const TextureInfo& aTextureInfo)
|
|||
RefPtr<CompositableHost> result;
|
||||
switch (aTextureInfo.mCompositableType) {
|
||||
case BUFFER_IMAGE_BUFFERED:
|
||||
result = new ImageHostBuffered(aTextureInfo);
|
||||
result = new DeprecatedImageHostBuffered(aTextureInfo);
|
||||
return result;
|
||||
case BUFFER_IMAGE_SINGLE:
|
||||
result = new ImageHostSingle(aTextureInfo);
|
||||
result = new DeprecatedImageHostSingle(aTextureInfo);
|
||||
return result;
|
||||
case BUFFER_TILED:
|
||||
result = new TiledContentHost(aTextureInfo);
|
||||
|
|
|
@ -17,7 +17,7 @@ using namespace gfx;
|
|||
namespace layers {
|
||||
|
||||
void
|
||||
ImageHostSingle::SetCompositor(Compositor* aCompositor) {
|
||||
DeprecatedImageHostSingle::SetCompositor(Compositor* aCompositor) {
|
||||
CompositableHost::SetCompositor(aCompositor);
|
||||
if (mDeprecatedTextureHost) {
|
||||
mDeprecatedTextureHost->SetCompositor(aCompositor);
|
||||
|
@ -25,10 +25,10 @@ ImageHostSingle::SetCompositor(Compositor* aCompositor) {
|
|||
}
|
||||
|
||||
void
|
||||
ImageHostSingle::EnsureDeprecatedTextureHost(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aSurface,
|
||||
ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo)
|
||||
DeprecatedImageHostSingle::EnsureDeprecatedTextureHost(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aSurface,
|
||||
ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo)
|
||||
{
|
||||
if (mDeprecatedTextureHost &&
|
||||
mDeprecatedTextureHost->GetBuffer() &&
|
||||
|
@ -43,10 +43,10 @@ ImageHostSingle::EnsureDeprecatedTextureHost(TextureIdentifier aTextureId,
|
|||
}
|
||||
|
||||
void
|
||||
ImageHostSingle::MakeDeprecatedTextureHost(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aSurface,
|
||||
ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo)
|
||||
DeprecatedImageHostSingle::MakeDeprecatedTextureHost(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aSurface,
|
||||
ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo)
|
||||
{
|
||||
mDeprecatedTextureHost = DeprecatedTextureHost::CreateDeprecatedTextureHost(aSurface.type(),
|
||||
mTextureInfo.mDeprecatedTextureHostFlags,
|
||||
|
@ -61,14 +61,14 @@ ImageHostSingle::MakeDeprecatedTextureHost(TextureIdentifier aTextureId,
|
|||
}
|
||||
|
||||
void
|
||||
ImageHostSingle::Composite(EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Point& aOffset,
|
||||
const gfx::Filter& aFilter,
|
||||
const gfx::Rect& aClipRect,
|
||||
const nsIntRegion* aVisibleRegion,
|
||||
TiledLayerProperties* aLayerProperties)
|
||||
DeprecatedImageHostSingle::Composite(EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Point& aOffset,
|
||||
const gfx::Filter& aFilter,
|
||||
const gfx::Rect& aClipRect,
|
||||
const nsIntRegion* aVisibleRegion,
|
||||
TiledLayerProperties* aLayerProperties)
|
||||
{
|
||||
if (!mDeprecatedTextureHost) {
|
||||
NS_WARNING("Can't composite an invalid or null DeprecatedTextureHost");
|
||||
|
@ -138,10 +138,10 @@ ImageHostSingle::Composite(EffectChain& aEffectChain,
|
|||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
void
|
||||
ImageHostSingle::PrintInfo(nsACString& aTo, const char* aPrefix)
|
||||
DeprecatedImageHostSingle::PrintInfo(nsACString& aTo, const char* aPrefix)
|
||||
{
|
||||
aTo += aPrefix;
|
||||
aTo += nsPrintfCString("ImageHostSingle (0x%p)", this);
|
||||
aTo += nsPrintfCString("DeprecatedImageHostSingle (0x%p)", this);
|
||||
|
||||
AppendToString(aTo, mPictureRect, " [picture-rect=", "]");
|
||||
|
||||
|
@ -155,8 +155,8 @@ ImageHostSingle::PrintInfo(nsACString& aTo, const char* aPrefix)
|
|||
#endif
|
||||
|
||||
bool
|
||||
ImageHostBuffered::Update(const SurfaceDescriptor& aImage,
|
||||
SurfaceDescriptor* aResult) {
|
||||
DeprecatedImageHostBuffered::Update(const SurfaceDescriptor& aImage,
|
||||
SurfaceDescriptor* aResult) {
|
||||
if (!GetDeprecatedTextureHost()) {
|
||||
*aResult = aImage;
|
||||
return false;
|
||||
|
@ -166,24 +166,24 @@ ImageHostBuffered::Update(const SurfaceDescriptor& aImage,
|
|||
}
|
||||
|
||||
void
|
||||
ImageHostBuffered::MakeDeprecatedTextureHost(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aSurface,
|
||||
ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo)
|
||||
DeprecatedImageHostBuffered::MakeDeprecatedTextureHost(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aSurface,
|
||||
ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo)
|
||||
{
|
||||
ImageHostSingle::MakeDeprecatedTextureHost(aTextureId,
|
||||
aSurface,
|
||||
aAllocator,
|
||||
aTextureInfo);
|
||||
DeprecatedImageHostSingle::MakeDeprecatedTextureHost(aTextureId,
|
||||
aSurface,
|
||||
aAllocator,
|
||||
aTextureInfo);
|
||||
if (mDeprecatedTextureHost) {
|
||||
mDeprecatedTextureHost->SetBuffer(new SurfaceDescriptor(null_t()), aAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageHostSingle::Dump(FILE* aFile,
|
||||
const char* aPrefix,
|
||||
bool aDumpHtml)
|
||||
DeprecatedImageHostSingle::Dump(FILE* aFile,
|
||||
const char* aPrefix,
|
||||
bool aDumpHtml)
|
||||
{
|
||||
if (!aFile) {
|
||||
aFile = stderr;
|
||||
|
|
|
@ -37,10 +37,10 @@ protected:
|
|||
};
|
||||
|
||||
// ImageHost with a single DeprecatedTextureHost
|
||||
class ImageHostSingle : public ImageHost
|
||||
class DeprecatedImageHostSingle : public ImageHost
|
||||
{
|
||||
public:
|
||||
ImageHostSingle(const TextureInfo& aTextureInfo)
|
||||
DeprecatedImageHostSingle(const TextureInfo& aTextureInfo)
|
||||
: ImageHost(aTextureInfo)
|
||||
, mDeprecatedTextureHost(nullptr)
|
||||
, mHasPictureRect(false)
|
||||
|
@ -115,11 +115,11 @@ protected:
|
|||
// Double buffered ImageHost. We have a single TextureHost and double buffering
|
||||
// is done at the TextureHost/Client level. This is in contrast with buffered
|
||||
// ContentHosts which do their own double buffering
|
||||
class ImageHostBuffered : public ImageHostSingle
|
||||
class DeprecatedImageHostBuffered : public DeprecatedImageHostSingle
|
||||
{
|
||||
public:
|
||||
ImageHostBuffered(const TextureInfo& aTextureInfo)
|
||||
: ImageHostSingle(aTextureInfo)
|
||||
DeprecatedImageHostBuffered(const TextureInfo& aTextureInfo)
|
||||
: DeprecatedImageHostSingle(aTextureInfo)
|
||||
{}
|
||||
|
||||
virtual bool Update(const SurfaceDescriptor& aImage,
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче