Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-01-27 14:14:56 +01:00
commit 13915a840a
131 changed files with 4991 additions and 4083 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 957070 requires a clobber to resolve a reference to a program class member.
bug 960811 - clobber to rebuild preprocessed files when enabling synthetic APKs

View File

@ -34760,43 +34760,8 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
var consoleTimer = {};
var workerConsole = {
log: function log() {
var args = Array.prototype.slice.call(arguments);
globalScope.postMessage({
action: 'console_log',
data: args
});
},
error: function error() {
var args = Array.prototype.slice.call(arguments);
globalScope.postMessage({
action: 'console_error',
data: args
});
throw 'pdf.js execution error';
},
time: function time(name) {
consoleTimer[name] = Date.now();
},
timeEnd: function timeEnd(name) {
var time = consoleTimer[name];
if (!time) {
error('Unknown timer name ' + name);
}
this.log('Timer:', name, Date.now() - time);
}
};
// Worker thread?
if (typeof window === 'undefined') {
if (!('console' in globalScope)) {
globalScope.console = workerConsole;
}
// Listen for unsupported features so we can pass them on to the main thread.
PDFJS.UnsupportedManager.listen(function (msg) {

View File

@ -1070,6 +1070,15 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png);
}
/* Wide items like the Cut/Copy/Paste and Zoom controls are special in that their icons
are 16x16 when in the panel, but 18x18 when in a toolbar. */
#edit-controls@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon,
#zoom-controls@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon,
toolbarpaletteitem[place="palette"] > #edit-controls > toolbarbutton > .toolbarbutton-icon,
toolbarpaletteitem[place="palette"] > #zoom-controls > toolbarbutton > .toolbarbutton-icon {
width: 16px;
}
#edit-controls@inAnyPanel@ > #cut-button,
toolbarpaletteitem[place="palette"] > #edit-controls > #cut-button {
-moz-image-region: rect(0px, 64px, 32px, 32px);

View File

@ -5,11 +5,6 @@
%include ../../shared/customizableui/panelUIOverlay.inc.css
@media (min-resolution: 2dppx) {
#customization-palette toolbarbutton > .toolbarbutton-icon,
#PanelUI-contents toolbarbutton > .toolbarbutton-icon {
width: 20px;
}
#PanelUI-customize {
list-style-image: url(chrome://browser/skin/menuPanel-customize@2x.png);
}

View File

@ -104,7 +104,7 @@ toolbarpaletteitem[place="toolbar"] {
#wrapper-edit-controls[place="palette"] > #edit-controls > separator,
#wrapper-zoom-controls[place="palette"] > #zoom-controls > toolbarbutton,
#wrapper-zoom-controls[place="palette"] > #zoom-controls > separator {
margin-top: 24px;
margin-top: 20px;
}
#wrapper-edit-controls[place="palette"] > #edit-controls > toolbarbutton,

View File

@ -18,10 +18,9 @@ toolkit/library
gfx
toolkit/components/build
toolkit/components
security/build
security/manager
security/dbm
security/nss
security/certverifier
security/build
accessible
dom
content

View File

@ -214,19 +214,22 @@ ConsoleAPI.prototype = {
/**
* Queue a call to a console method. See the CALL_DELAY constant.
* This method is the entry point for the console.* for workers.
*
* @param string aMethod
* The console method the code has invoked.
* @param object aArguments
* The arguments passed to the console method.
* @param array aStack
* The stack of the console method. Used by console.* for workers.
*/
queueCall: function CA_queueCall(aMethod, aArguments)
queueCall: function CA_queueCall(aMethod, aArguments, aStack = null)
{
let window = this._window.get();
let metaForCall = {
private: PrivateBrowsingUtils.isWindowPrivate(window),
timeStamp: Date.now(),
stack: this.getStackTrace(aMethod != "trace" ? 1 : null),
stack: (aStack ? aStack : this.getStackTrace(aMethod != "trace" ? 1 : null)),
};
if (aMethod == "time" || aMethod == "timeEnd") {

View File

@ -1528,6 +1528,12 @@ DOMInterfaces = {
],
},
'WorkerConsole': {
'headerFile': 'mozilla/dom/workers/bindings/Console.h',
'workers': True,
'implicitJSContext': [ 'trace', 'time', 'timeEnd' ],
},
'WorkerLocation': {
'headerFile': 'mozilla/dom/workers/bindings/Location.h',
'workers': True,

View File

@ -281,7 +281,7 @@ public:
virtual ~JSStackFrame();
static already_AddRefed<nsIStackFrame>
CreateStack(JSContext* cx);
CreateStack(JSContext* aCx, int32_t aMaxDepth = -1);
static already_AddRefed<nsIStackFrame>
CreateStackFrameLocation(uint32_t aLanguage,
const char* aFilename,
@ -495,11 +495,14 @@ NS_IMETHODIMP JSStackFrame::ToString(nsACString& _retval)
}
/* static */ already_AddRefed<nsIStackFrame>
JSStackFrame::CreateStack(JSContext* cx)
JSStackFrame::CreateStack(JSContext* aCx, int32_t aMaxDepth)
{
static const unsigned MAX_FRAMES = 100;
if (aMaxDepth < 0) {
aMaxDepth = MAX_FRAMES;
}
JS::StackDescription* desc = JS::DescribeStack(cx, MAX_FRAMES);
JS::StackDescription* desc = JS::DescribeStack(aCx, aMaxDepth);
if (!desc) {
return nullptr;
}
@ -530,9 +533,9 @@ JSStackFrame::CreateStackFrameLocation(uint32_t aLanguage,
}
already_AddRefed<nsIStackFrame>
CreateStack(JSContext* cx)
CreateStack(JSContext* aCx, int32_t aMaxDepth)
{
return JSStackFrame::CreateStack(cx);
return JSStackFrame::CreateStack(aCx, aMaxDepth);
}
already_AddRefed<nsIStackFrame>

View File

@ -36,8 +36,10 @@ GetCurrentJSStack();
// Internal stuff not intended to be widely used.
namespace exceptions {
// aMaxDepth can be used to define a maximal depth for the stack trace. If the
// value is -1, a default maximal depth will be selected.
already_AddRefed<nsIStackFrame>
CreateStack(JSContext* cx);
CreateStack(JSContext* aCx, int32_t aMaxDepth = -1);
already_AddRefed<nsIStackFrame>
CreateStackFrameLocation(uint32_t aLanguage,

View File

@ -315,7 +315,7 @@ class IDLUnresolvedIdentifier(IDLObject):
assert len(name) > 0
if name[:2] == "__" and name != "__content" and not allowDoubleUnderscore:
if name[:2] == "__" and name != "__content" and name != "___noSuchMethod__" and not allowDoubleUnderscore:
raise WebIDLError("Identifiers beginning with __ are reserved",
[location])
if name[0] == '_' and not allowDoubleUnderscore:
@ -3155,7 +3155,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
return self._hasOverloads
def isIdentifierLess(self):
return self.identifier.name[:2] == "__"
return self.identifier.name[:2] == "__" and self.identifier.name != "__noSuchMethod__"
def resolve(self, parentScope):
assert isinstance(parentScope, IDLScope)

View File

@ -1,54 +1,95 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* This is a shim for the W3C testharness.js, mapping those of
* its functions that we need to the testing/xpcshell/head.js API.
* See <http://www.w3.org/2008/webapps/wiki/Harness> for documentation.
* This shim does some tests a little differently than the W3C test
* harness; equality comparisons, especially, are less precise.
* The difference does not presently affect any test results.
*
* We use the lower-level do_report_result throughout this file,
* rather than the high-level xpcshell/head.js API that has near
* equivalents for the W3C assert_* functions, because only
* do_report_result allows us to provide Components.stack.caller.
*/
const { 'classes': Cc, 'interfaces': Ci } = Components;
function assert_equals(a, b, msg) {
dump("assert_equals(" + a + ", " + b + ", \"" + msg + "\")");
do_check_eq(a, b, Components.stack.caller);
let text = msg + ": " + _wrap_with_quotes_if_necessary(a) +
" == " + _wrap_with_quotes_if_necessary(b);
do_report_result(a == b, text, Components.stack.caller, false);
}
function assert_not_equals(a, b, msg) {
dump("assert_not_equals(" + a + ", " + b + ", \"" + msg + "\")");
do_check_neq(a, b, Components.stack.caller);
let text = msg + ": " + _wrap_with_quotes_if_necessary(a) +
" != " + _wrap_with_quotes_if_necessary(b);
do_report_result(a != b, text, Components.stack.caller, false);
}
function assert_array_equals(a, b, msg) {
dump("assert_array_equals(\"" + msg + "\")");
do_check_eq(a.length, b.length, Components.stack.caller);
for (var i = 0; i < a.length; ++i) {
do_report_result(a.length == b.length,
msg + ": (length) " + a.length + " == " + b.length,
Components.stack.caller, false);
for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) {
do_check_eq(a[i], b[i], Components.stack.caller);
do_report_result(false,
msg + ": [" + i + "] " +
_wrap_with_quotes_if_necessary(a[i]) +
" === " +
_wrap_with_quotes_if_necessary(b[i]),
Components.stack.caller, false);
}
}
// If we get here, all array elements are equal.
do_report_result(true, msg + ": all array elements equal",
Components.stack.caller, false);
}
function assert_true(cond, msg) {
dump("assert_true(" + cond + ", \"" + msg + "\")");
do_check_true(!!cond, Components.stack.caller);
do_report_result(!!cond, msg + ": " + uneval(cond),
Components.stack.caller, false);
}
function assert_throws(ex, func) {
dump("assert_throws(\"" + ex + "\", " + func + ")");
if (!('name' in ex))
do_throw("first argument to assert_throws must be of the form " +
"{'name': something}");
let msg = "expected to catch an exception named " + ex.name;
try {
func();
do_check_true(false, Components.stack.caller);
} catch (e) {
do_check_eq(e.name, ex.name, Components.stack.caller);
if ('name' in e)
do_report_result(e.name == ex.name,
msg + ", got " + e.name,
Components.stack.caller, false);
else
do_report_result(false,
msg + ", got " + legible_exception(ex),
Components.stack.caller, false);
return;
}
// Call this here, not in the 'try' clause, so do_report_result's own
// throw doesn't get caught by our 'catch' clause.
do_report_result(false, msg + ", but returned normally",
Components.stack.caller, false);
}
var tests = [];
let tests = [];
function test(func, msg) {
tests.push({msg: msg, func: func});
tests.push({msg: msg, func: func,
filename: Components.stack.caller.filename });
}
function run_test() {
tests.forEach(function(t) {
dump("test(\"" + t.msg + "\")");
_log("test_info", {source_file: t.filename,
diagnostic: "test group: " + t.msg});
t.func();
});
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,224 @@
// NOTE: Requires testharness.js
// http://www.w3.org/2008/webapps/wiki/Harness
test(
function() {
var badStrings = [
{ input: '\ud800', expected: '\ufffd' }, // Surrogate half
{ input: '\udc00', expected: '\ufffd' }, // Surrogate half
{ input: 'abc\ud800def', expected: 'abc\ufffddef' }, // Surrogate half
{ input: 'abc\udc00def', expected: 'abc\ufffddef' }, // Surrogate half
{ input: '\udc00\ud800', expected: '\ufffd\ufffd' } // Wrong order
];
badStrings.forEach(
function(t) {
var encoded = new TextEncoder('utf-8').encode(t.input);
var decoded = new TextDecoder('utf-8').decode(encoded);
assert_equals(t.expected, decoded);
});
},
"bad data"
);
test(
function() {
var bad = [
{ encoding: 'utf-8', input: [0xC0] }, // ends early
{ encoding: 'utf-8', input: [0xC0, 0x00] }, // invalid trail
{ encoding: 'utf-8', input: [0xC0, 0xC0] }, // invalid trail
{ encoding: 'utf-8', input: [0xE0] }, // ends early
{ encoding: 'utf-8', input: [0xE0, 0x00] }, // invalid trail
{ encoding: 'utf-8', input: [0xE0, 0xC0] }, // invalid trail
{ encoding: 'utf-8', input: [0xE0, 0x80, 0x00] }, // invalid trail
{ encoding: 'utf-8', input: [0xE0, 0x80, 0xC0] }, // invalid trail
{ encoding: 'utf-8', input: [0xFC, 0x80, 0x80, 0x80, 0x80, 0x80] }, // > 0x10FFFF
{ encoding: 'utf-16le', input: [0x00] }, // truncated code unit
{ encoding: 'utf-16le', input: [0x00, 0xd8] }, // surrogate half
{ encoding: 'utf-16le', input: [0x00, 0xd8, 0x00, 0x00] }, // surrogate half
{ encoding: 'utf-16le', input: [0x00, 0xdc, 0x00, 0x00] }, // trail surrogate
{ encoding: 'utf-16le', input: [0x00, 0xdc, 0x00, 0xd8] } // swapped surrogates
// TODO: Single byte encoding cases
];
bad.forEach(
function(t) {
assert_throws({name: 'EncodingError'}, function () {
new TextDecoder(t.encoding, {fatal: true}).decode(new Uint8Array(t.input));
});
});
},
"fatal flag"
);
test(
function() {
var encodings = [
{ label: 'utf-8', encoding: 'utf-8' },
{ label: 'utf-16', encoding: 'utf-16le' },
{ label: 'utf-16le', encoding: 'utf-16le' },
{ label: 'utf-16be', encoding: 'utf-16be' },
{ label: 'ascii', encoding: 'windows-1252' },
{ label: 'iso-8859-1', encoding: 'windows-1252' }
];
encodings.forEach(
function(test) {
assert_equals(new TextDecoder(test.label.toLowerCase()).encoding, test.encoding);
assert_equals(new TextDecoder(test.label.toUpperCase()).encoding, test.encoding);
});
},
"Encoding names are case insensitive"
);
test(
function() {
var utf8_bom = [0xEF, 0xBB, 0xBF];
var utf8 = [0x7A, 0xC2, 0xA2, 0xE6, 0xB0, 0xB4, 0xF0, 0x9D, 0x84, 0x9E, 0xF4, 0x8F, 0xBF, 0xBD];
var utf16le_bom = [0xff, 0xfe];
var utf16le = [0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C, 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xDB, 0xFD, 0xDF];
var utf16be_bom = [0xfe, 0xff];
var utf16be = [0x00, 0x7A, 0x00, 0xA2, 0x6C, 0x34, 0xD8, 0x34, 0xDD, 0x1E, 0xDB, 0xFF, 0xDF, 0xFD];
var string = "z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD"; // z, cent, CJK water, G-Clef, Private-use character
// missing BOMs
assert_equals(new TextDecoder('utf-8').decode(new Uint8Array(utf8)), string);
assert_equals(new TextDecoder('utf-16le').decode(new Uint8Array(utf16le)), string);
assert_equals(new TextDecoder('utf-16be').decode(new Uint8Array(utf16be)), string);
// matching BOMs
assert_equals(new TextDecoder('utf-8').decode(new Uint8Array(utf8_bom.concat(utf8))), string);
assert_equals(new TextDecoder('utf-16le').decode(new Uint8Array(utf16le_bom.concat(utf16le))), string)
assert_equals(new TextDecoder('utf-16be').decode(new Uint8Array(utf16be_bom.concat(utf16be))), string);
// matching BOMs split
var decoder8 = new TextDecoder('utf-8');
assert_equals(decoder8.decode(new Uint8Array(utf8_bom.slice(0, 1)), {stream: true}), '');
assert_equals(decoder8.decode(new Uint8Array(utf8_bom.slice(1).concat(utf8))), string);
assert_equals(decoder8.decode(new Uint8Array(utf8_bom.slice(0, 2)), {stream: true}), '');
assert_equals(decoder8.decode(new Uint8Array(utf8_bom.slice(2).concat(utf8))), string);
var decoder16le = new TextDecoder('utf-16le');
assert_equals(decoder16le.decode(new Uint8Array(utf16le_bom.slice(0, 1)), {stream: true}), '');
assert_equals(decoder16le.decode(new Uint8Array(utf16le_bom.slice(1).concat(utf16le))), string);
var decoder16be = new TextDecoder('utf-16be');
assert_equals(decoder16be.decode(new Uint8Array(utf16be_bom.slice(0, 1)), {stream: true}), '');
assert_equals(decoder16be.decode(new Uint8Array(utf16be_bom.slice(1).concat(utf16be))), string);
// mismatching BOMs
assert_not_equals(new TextDecoder('utf-8').decode(new Uint8Array(utf16le_bom.concat(utf8))), string);
assert_not_equals(new TextDecoder('utf-8').decode(new Uint8Array(utf16be_bom.concat(utf8))), string);
assert_not_equals(new TextDecoder('utf-16le').decode(new Uint8Array(utf8_bom.concat(utf16le))), string);
assert_not_equals(new TextDecoder('utf-16le').decode(new Uint8Array(utf16be_bom.concat(utf16le))), string);
assert_not_equals(new TextDecoder('utf-16be').decode(new Uint8Array(utf8_bom.concat(utf16be))), string);
assert_not_equals(new TextDecoder('utf-16be').decode(new Uint8Array(utf16le_bom.concat(utf16be))), string);
},
"Byte-order marks"
);
test(
function () {
assert_equals(new TextDecoder("utf-8").encoding, "utf-8"); // canonical case
assert_equals(new TextDecoder("UTF-16").encoding, "utf-16le"); // canonical case and name
assert_equals(new TextDecoder("UTF-16BE").encoding, "utf-16be"); // canonical case and name
assert_equals(new TextDecoder("iso8859-1").encoding, "windows-1252"); // canonical case and name
assert_equals(new TextDecoder("iso-8859-1").encoding, "windows-1252"); // canonical case and name
},
"Encoding names"
);
test(
function () {
["utf-8", "utf-16le", "utf-16be"].forEach(function (encoding) {
var string = "\x00123ABCabc\x80\xFF\u0100\u1000\uFFFD\uD800\uDC00\uDBFF\uDFFF";
var encoded = new TextEncoder(encoding).encode(string);
for (var len = 1; len <= 5; ++len) {
var out = "", decoder = new TextDecoder(encoding);
for (var i = 0; i < encoded.length; i += len) {
var sub = [];
for (var j = i; j < encoded.length && j < i + len; ++j) {
sub.push(encoded[j]);
}
out += decoder.decode(new Uint8Array(sub), {stream: true});
}
out += decoder.decode();
assert_equals(out, string, "streaming decode " + encoding);
}
});
},
"Streaming Decode"
);
test(
function () {
var jis = [0x82, 0xC9, 0x82, 0xD9, 0x82, 0xF1];
var expected = "\u306B\u307B\u3093"; // Nihon
assert_equals(new TextDecoder("shift_jis").decode(new Uint8Array(jis)), expected);
},
"Shift_JIS Decode"
);
test(
function () {
var encodings = ["utf-8", "ibm866", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-8-i", "iso-8859-10", "iso-8859-13", "iso-8859-14", "iso-8859-15", "iso-8859-16", "koi8-r", "koi8-u", "macintosh", "windows-874", "windows-1250", "windows-1251", "windows-1252", "windows-1253", "windows-1254", "windows-1255", "windows-1256", "windows-1257", "windows-1258", "x-mac-cyrillic", "gbk", "gb18030", "hz-gb-2312", "big5", "euc-jp", "iso-2022-jp", "shift_jis", "euc-kr", "x-user-defined"];
encodings.forEach(function (encoding) {
var string = '', bytes = [];
for (var i = 0; i < 128; ++i) {
// Encodings that have escape codes in 0x00-0x7F
if (encoding === "hz-gb-2312" && i === 0x7E)
continue;
if (encoding === "iso-2022-jp" && i === 0x1B)
continue;
string += String.fromCharCode(i);
bytes.push(i);
}
var ascii_encoded = new TextEncoder('utf-8').encode(string);
assert_equals(new TextDecoder(encoding).decode(ascii_encoded), string, encoding);
//assert_array_equals(new TextEncoder(encoding).encode(string), bytes, encoding);
});
},
"Supersets of ASCII decode ASCII correctly"
);
test(
function () {
assert_throws({name: 'EncodingError'}, function() { new TextDecoder("utf-8", {fatal: true}).decode(new Uint8Array([0xff])); });
// This should not hang:
new TextDecoder("utf-8").decode(new Uint8Array([0xff]));
assert_throws({name: 'EncodingError'}, function() { new TextDecoder("utf-16", {fatal: true}).decode(new Uint8Array([0x00])); });
// This should not hang:
new TextDecoder("utf-16").decode(new Uint8Array([0x00]));
assert_throws({name: 'EncodingError'}, function() { new TextDecoder("utf-16be", {fatal: true}).decode(new Uint8Array([0x00])); });
// This should not hang:
new TextDecoder("utf-16be").decode(new Uint8Array([0x00]));
},
"Non-fatal errors at EOF"
);
test(
function () {
var utf_encodings = ["utf-8", "utf-16le", "utf-16be"];
var legacy_encodings = ["ibm866", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-8-i", "iso-8859-10", "iso-8859-13", "iso-8859-14", "iso-8859-15", "iso-8859-16", "koi8-r", "koi8-u", "macintosh", "windows-874", "windows-1250", "windows-1251", "windows-1252", "windows-1253", "windows-1254", "windows-1255", "windows-1256", "windows-1257", "windows-1258", "x-mac-cyrillic", "gbk", "gb18030", "hz-gb-2312", "big5", "euc-jp", "iso-2022-jp", "shift_jis", "euc-kr", "x-user-defined"];
utf_encodings.forEach(function(encoding) {
assert_equals(new TextDecoder(encoding).encoding, encoding);
assert_equals(new TextEncoder(encoding).encoding, encoding);
});
legacy_encodings.forEach(function(encoding) {
assert_equals(new TextDecoder(encoding).encoding, encoding);
assert_throws({name: 'TypeError'}, function() { new TextEncoder(encoding); });
});
},
"Non-UTF encodings supported only for decode, not encode"
);

File diff suppressed because one or more lines are too long

View File

@ -1,358 +0,0 @@
// NOTE: Requires testharness.js
// http://www.w3.org/2008/webapps/wiki/Harness
function testEncodeDecode(encoding, min, max) {
function cpname(n) {
return 'U+' + ((n <= 0xFFFF) ?
('0000' + n.toString(16).toUpperCase()).slice(-4) :
n.toString(16).toUpperCase());
}
test(
function() {
var string, i, j, BATCH_SIZE = 0x1000;
for (i = min; i < max; i += BATCH_SIZE) {
string = '';
for (j = i; j < i + BATCH_SIZE && j < max; j += 1) {
if (0xd800 <= j && j <= 0xdfff) {
// surrogate half
continue;
} else if (j > 0xffff) {
// outside BMP - encode as surrogate pair
string += String.fromCharCode(
0xd800 + ((j >> 10) & 0x3ff),
0xdc00 + (j & 0x3ff));
} else {
string += String.fromCharCode(i);
}
}
var encoded = TextEncoder(encoding).encode(string);
var decoded = TextDecoder(encoding).decode(encoded);
assert_equals(string, decoded, 'Round trip ' + cpname(i) + " - " + cpname(j));
}
},
encoding + " - Encode/Decode Range " + cpname(min) + " - " + cpname(max)
);
}
testEncodeDecode('UTF-8', 0, 0x10FFFF);
testEncodeDecode('UTF-16LE', 0, 0x10FFFF);
testEncodeDecode('UTF-16BE', 0, 0x10FFFF);
// Inspired by:
// http://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html
function encode_utf8(string) {
var utf8 = unescape(encodeURIComponent(string));
var octets = [], i;
for (i = 0; i < utf8.length; i += 1) {
octets.push(utf8.charCodeAt(i));
}
return octets;
}
function decode_utf8(octets) {
var utf8 = String.fromCharCode.apply(null, octets);
return decodeURIComponent(escape(utf8));
}
test(
function() {
var actual, expected, str, i, j, BATCH_SIZE = 0x1000;
for (i = 0; i < 0x10FFFF; i += BATCH_SIZE) {
str = '';
for (j = i; j < i + BATCH_SIZE; j += 1) {
if (0xd800 <= j && j <= 0xdfff) {
// surrogate half
continue;
} else if (j > 0xffff) {
// outside BMP - encode as surrogate pair
str += String.fromCharCode(
0xd800 + ((j >> 10) & 0x3ff),
0xdc00 + (j & 0x3ff));
} else {
str += String.fromCharCode(i);
}
}
expected = encode_utf8(str);
actual = TextEncoder('UTF-8').encode(str);
assert_array_equals(actual, expected, 'expected equal encodings');
}
},
"UTF-8 encoding (compare against unescape/encodeURIComponent)"
);
test(
function() {
var encoded, actual, expected, str, i, j, BATCH_SIZE = 0x1000;
for (i = 0; i < 0x10FFFF; i += BATCH_SIZE) {
str = '';
for (j = i; j < i + BATCH_SIZE; j += 1) {
if (0xd800 <= j && j <= 0xdfff) {
// surrogate half
continue;
} else if (j > 0xffff) {
// outside BMP - encode as surrogate pair
str += String.fromCharCode(
0xd800 + ((j >> 10) & 0x3ff),
0xdc00 + (j & 0x3ff));
} else {
str += String.fromCharCode(i);
}
}
encoded = encode_utf8(str);
expected = decode_utf8(encoded);
actual = TextDecoder('UTF-8').decode(new Uint8Array(encoded));
assert_equals(actual, expected, 'expected equal decodings');
}
},
"UTF-8 decoding (compare against decodeURIComponent/escape)"
);
function testEncodeDecodeSample(encoding, string, expected) {
test(
function() {
var encoded = TextEncoder(encoding).encode(string);
assert_array_equals(encoded, expected, 'expected equal encodings ' + encoding);
var decoded = TextDecoder(encoding).decode(new Uint8Array(expected));
assert_equals(decoded, string, 'expected equal decodings ' + encoding);
},
encoding + " - Encode/Decode - reference sample"
);
}
testEncodeDecodeSample(
"utf-8",
"z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD", // z, cent, CJK water, G-Clef, Private-use character
[0x7A, 0xC2, 0xA2, 0xE6, 0xB0, 0xB4, 0xF0, 0x9D, 0x84, 0x9E, 0xF4, 0x8F, 0xBF, 0xBD]
);
testEncodeDecodeSample(
"utf-16le",
"z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD", // z, cent, CJK water, G-Clef, Private-use character
[0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C, 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xDB, 0xFD, 0xDF]
);
testEncodeDecodeSample(
"utf-16be",
"z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD", // z, cent, CJK water, G-Clef, Private-use character
[0x00, 0x7A, 0x00, 0xA2, 0x6C, 0x34, 0xD8, 0x34, 0xDD, 0x1E, 0xDB, 0xFF, 0xDF, 0xFD]
);
testEncodeDecodeSample(
"utf-16",
"z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD", // z, cent, CJK water, G-Clef, Private-use character
[0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C, 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xDB, 0xFD, 0xDF]
);
test(
function() {
var badStrings = [
{ input: '\ud800', expected: '\ufffd' }, // Surrogate half
{ input: '\udc00', expected: '\ufffd' }, // Surrogate half
{ input: 'abc\ud800def', expected: 'abc\ufffddef' }, // Surrogate half
{ input: 'abc\udc00def', expected: 'abc\ufffddef' }, // Surrogate half
{ input: '\udc00\ud800', expected: '\ufffd\ufffd' } // Wrong order
];
badStrings.forEach(
function(t) {
var encoded = TextEncoder('utf-8').encode(t.input);
var decoded = TextDecoder('utf-8').decode(encoded);
assert_equals(t.expected, decoded);
});
},
"bad data"
);
test(
function() {
var bad = [
{ encoding: 'utf-8', input: [0xC0] }, // ends early
{ encoding: 'utf-8', input: [0xC0, 0x00] }, // invalid trail
{ encoding: 'utf-8', input: [0xC0, 0xC0] }, // invalid trail
{ encoding: 'utf-8', input: [0xE0] }, // ends early
{ encoding: 'utf-8', input: [0xE0, 0x00] }, // invalid trail
{ encoding: 'utf-8', input: [0xE0, 0xC0] }, // invalid trail
{ encoding: 'utf-8', input: [0xE0, 0x80, 0x00] }, // invalid trail
{ encoding: 'utf-8', input: [0xE0, 0x80, 0xC0] }, // invalid trail
{ encoding: 'utf-8', input: [0xFC, 0x80, 0x80, 0x80, 0x80, 0x80] }, // > 0x10FFFF
{ encoding: 'utf-16', input: [0x00] }, // truncated code unit
{ encoding: 'utf-16', input: [0x00, 0xd8] }, // surrogate half
{ encoding: 'utf-16', input: [0x00, 0xd8, 0x00, 0x00] }, // surrogate half
{ encoding: 'utf-16', input: [0x00, 0xdc, 0x00, 0x00] }, // trail surrogate
{ encoding: 'utf-16', input: [0x00, 0xdc, 0x00, 0xd8] } // swapped surrogates
// TODO: Single byte encoding cases
];
bad.forEach(
function(t) {
assert_throws({name: 'EncodingError'}, function () {
TextDecoder(t.encoding, {fatal: true}).decode(new Uint8Array(t.input));
});
});
},
"fatal flag"
);
test(
function() {
var encodings = [
{ label: 'utf-8', encoding: 'utf-8' },
{ label: 'utf-16', encoding: 'utf-16le' },
{ label: 'utf-16le', encoding: 'utf-16le' },
{ label: 'utf-16be', encoding: 'utf-16be' },
{ label: 'ascii', encoding: 'windows-1252' },
{ label: 'iso-8859-1', encoding: 'windows-1252' }
];
encodings.forEach(
function(test) {
assert_equals(TextDecoder(test.label.toLowerCase()).encoding, test.encoding);
assert_equals(TextDecoder(test.label.toUpperCase()).encoding, test.encoding);
});
},
"Encoding names are case insensitive"
);
test(
function() {
var utf8_bom = [0xEF, 0xBB, 0xBF];
var utf8 = [0x7A, 0xC2, 0xA2, 0xE6, 0xB0, 0xB4, 0xF0, 0x9D, 0x84, 0x9E, 0xF4, 0x8F, 0xBF, 0xBD];
var utf16le_bom = [0xff, 0xfe];
var utf16le = [0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C, 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xDB, 0xFD, 0xDF];
var utf16be_bom = [0xfe, 0xff];
var utf16be = [0x00, 0x7A, 0x00, 0xA2, 0x6C, 0x34, 0xD8, 0x34, 0xDD, 0x1E, 0xDB, 0xFF, 0xDF, 0xFD];
var string = "z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD"; // z, cent, CJK water, G-Clef, Private-use character
// missing BOMs
assert_equals(TextDecoder('utf-8').decode(new Uint8Array(utf8)), string);
assert_equals(TextDecoder('utf-16le').decode(new Uint8Array(utf16le)), string);
assert_equals(TextDecoder('utf-16be').decode(new Uint8Array(utf16be)), string);
// matching BOMs
assert_equals(TextDecoder('utf-8').decode(new Uint8Array(utf8_bom.concat(utf8))), string);
assert_equals(TextDecoder('utf-16le').decode(new Uint8Array(utf16le_bom.concat(utf16le))), string);
assert_equals(TextDecoder('utf-16be').decode(new Uint8Array(utf16be_bom.concat(utf16be))), string);
// mismatching BOMs
assert_not_equals(TextDecoder('utf-8').decode(new Uint8Array(utf16le_bom.concat(utf8))), string);
assert_not_equals(TextDecoder('utf-8').decode(new Uint8Array(utf16be_bom.concat(utf8))), string);
assert_not_equals(TextDecoder('utf-16le').decode(new Uint8Array(utf8_bom.concat(utf16le))), string);
assert_not_equals(TextDecoder('utf-16le').decode(new Uint8Array(utf16be_bom.concat(utf16le))), string);
assert_not_equals(TextDecoder('utf-16be').decode(new Uint8Array(utf8_bom.concat(utf16be))), string);
assert_not_equals(TextDecoder('utf-16be').decode(new Uint8Array(utf16le_bom.concat(utf16be))), string);
},
"Byte-order marks"
);
test(
function () {
assert_equals(TextDecoder("utf-8").encoding, "utf-8"); // canonical case
assert_equals(TextDecoder("UTF-16").encoding, "utf-16le"); // canonical case and name
assert_equals(TextDecoder("UTF-16BE").encoding, "utf-16be"); // canonical case and name
assert_equals(TextDecoder("iso8859-1").encoding, "windows-1252"); // canonical case and name
assert_equals(TextDecoder("iso-8859-1").encoding, "windows-1252"); // canonical case and name
},
"Encoding names"
);
test(
function () {
["utf-8", "utf-16le", "utf-16be"].forEach(function (encoding) {
var string = "\x00123ABCabc\x80\xFF\u0100\u1000\uFFFD\uD800\uDC00\uDBFF\uDFFF";
var encoded = TextEncoder(encoding).encode(string);
for (var len = 1; len <= 5; ++len) {
var out = "", decoder = TextDecoder(encoding);
for (var i = 0; i < encoded.length; i += len) {
var sub = [];
for (var j = i; j < encoded.length && j < i + len; ++j) {
sub.push(encoded[j]);
}
out += decoder.decode(new Uint8Array(sub), {stream: true});
}
out += decoder.decode();
assert_equals(out, string, "streaming decode " + encoding);
}
});
},
"Streaming Decode"
);
test(
function () {
var jis = [0x82, 0xC9, 0x82, 0xD9, 0x82, 0xF1];
var expected = "\u306B\u307B\u3093"; // Nihon
assert_equals(TextDecoder("shift_jis").decode(new Uint8Array(jis)), expected);
},
"Shift_JIS Decode"
);
test(
function () {
var encodings = ["utf-8", "ibm866", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-8-i", "iso-8859-10", "iso-8859-13", "iso-8859-14", "iso-8859-15", "iso-8859-16", "koi8-r", "koi8-u", "macintosh", "windows-874", "windows-1250", "windows-1251", "windows-1252", "windows-1253", "windows-1254", "windows-1255", "windows-1256", "windows-1257", "windows-1258", "x-mac-cyrillic", "gbk", "gb18030", "hz-gb-2312", "big5", "euc-jp", "iso-2022-jp", "shift_jis", "euc-kr", "x-user-defined"];
encodings.forEach(function (encoding) {
var string = '', bytes = [];
for (var i = 0; i < 128; ++i) {
// Encodings that have escape codes in 0x00-0x7F
if (encoding === "hz-gb-2312" && i === 0x7E)
continue;
if (encoding === "iso-2022-jp" && i === 0x1B)
continue;
string += String.fromCharCode(i);
bytes.push(i);
}
var ascii_encoded = TextEncoder('utf-8').encode(string);
assert_equals(TextDecoder(encoding).decode(ascii_encoded), string, encoding);
//assert_array_equals(TextEncoder(encoding).encode(string), bytes, encoding);
});
},
"Supersets of ASCII decode ASCII correctly"
);
test(
function () {
assert_throws({name: 'EncodingError'}, function() { TextDecoder("utf-8", {fatal: true}).decode(new Uint8Array([0xff])); });
// This should not hang:
TextDecoder("utf-8").decode(new Uint8Array([0xff]));
assert_throws({name: 'EncodingError'}, function() { TextDecoder("utf-16", {fatal: true}).decode(new Uint8Array([0x00])); });
// This should not hang:
TextDecoder("utf-16").decode(new Uint8Array([0x00]));
assert_throws({name: 'EncodingError'}, function() { TextDecoder("utf-16be", {fatal: true}).decode(new Uint8Array([0x00])); });
// This should not hang:
TextDecoder("utf-16be").decode(new Uint8Array([0x00]));
},
"Non-fatal errors at EOF"
);
test(
function () {
var utf_encodings = ["utf-8", "utf-16le", "utf-16be"];
var legacy_encodings = ["ibm866", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-8-i", "iso-8859-10", "iso-8859-13", "iso-8859-14", "iso-8859-15", "iso-8859-16", "koi8-r", "koi8-u", "macintosh", "windows-874", "windows-1250", "windows-1251", "windows-1252", "windows-1253", "windows-1254", "windows-1255", "windows-1256", "windows-1257", "windows-1258", "x-mac-cyrillic", "gbk", "gb18030", "hz-gb-2312", "big5", "euc-jp", "iso-2022-jp", "shift_jis", "euc-kr", "x-user-defined"];
utf_encodings.forEach(function(encoding) {
assert_equals(TextDecoder(encoding).encoding, encoding);
assert_equals(TextEncoder(encoding).encoding, encoding);
});
legacy_encodings.forEach(function(encoding) {
assert_equals(TextDecoder(encoding).encoding, encoding);
assert_throws({name: 'TypeError'}, function() { TextEncoder(encoding); });
});
},
"Non-UTF encodings supported only for decode, not encode"
);

View File

@ -0,0 +1,166 @@
// NOTE: Requires testharness.js
// http://www.w3.org/2008/webapps/wiki/Harness
// Extension to testharness.js API which avoids logging enormous strings
// on a coding failure.
function assert_string_equals(actual, expected, description) {
// short circuit success case
if (actual === expected) {
assert_true(true, description + ": <actual> === <expected>");
return;
}
// length check
assert_equals(actual.length, expected.length,
description + ": string lengths")
var i, a, b;
for (i = 0; i < actual.length; i++) {
a = actual.charCodeAt(i);
b = expected.charCodeAt(i);
if (a !== b)
assert_true(false,
description +
": code unit " + i.toString() + " unequal: " +
cpname(a) + " != " + cpname(b)); // doesn't return
}
// It should be impossible to get here, because the initial
// comparison failed, so either the length comparison or the
// codeunit-by-codeunit comparison should also fail.
assert_true(false, description + ": failed to detect string difference");
}
// Inspired by:
// http://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html
function encode_utf8(string) {
var utf8 = unescape(encodeURIComponent(string));
var octets = new Uint8Array(utf8.length), i;
for (i = 0; i < utf8.length; i += 1) {
octets[i] = utf8.charCodeAt(i);
}
return octets;
}
function decode_utf8(octets) {
var utf8 = String.fromCharCode.apply(null, octets);
return decodeURIComponent(escape(utf8));
}
// Helpers for test_utf_roundtrip.
function cpname(n) {
if (n+0 !== n)
return n.toString();
var w = (n <= 0xFFFF) ? 4 : 6;
return 'U+' + ('000000' + n.toString(16).toUpperCase()).slice(-w);
}
function genblock(from, len) {
var i, j, point, offset;
var size, block;
// determine size required:
// 1 unit for each point from U+000000 through U+00D7FF
// 0 units U+00D800 through U+00DFFF
// 1 unit U+00E000 through U+00FFFF
// 2 units U+010000 through U+10FFFF
function overlap(min1, max1, min2, max2) {
return Math.max(0, Math.min(max1, max2) - Math.max(min1, min2));
}
size = (overlap(from, from+len, 0x000000, 0x00D800) +
overlap(from, from+len, 0x00E000, 0x010000) +
overlap(from, from+len, 0x010000, 0x110000)*2);
block = new Uint16Array(size);
for (i = 0, j = 0; i < len; i++) {
point = from + i;
if (0xD800 <= point && point <= 0xDFFF)
continue;
else if (point <= 0xFFFF)
block[j++] = point;
else {
offset = point - 0x10000;
block[j++] = 0xD800 + (offset >> 10);
block[j++] = 0xDC00 + (offset & 0x3FF);
}
}
return String.fromCharCode.apply(null, block);
}
function test_utf_roundtrip () {
var MIN_CODEPOINT = 0;
var MAX_CODEPOINT = 0x10FFFF;
var BLOCK_SIZE = 0x1000;
var block, block_tag, i, j, encoded, decoded, exp_encoded, exp_decoded;
var TE_U16LE = new TextEncoder("UTF-16LE");
var TD_U16LE = new TextDecoder("UTF-16LE");
var TE_U16BE = new TextEncoder("UTF-16BE");
var TD_U16BE = new TextDecoder("UTF-16BE");
var TE_U8 = new TextEncoder("UTF-8");
var TD_U8 = new TextDecoder("UTF-8");
for (i = MIN_CODEPOINT; i < MAX_CODEPOINT; i += BLOCK_SIZE) {
block_tag = cpname(i) + " - " + cpname(i + BLOCK_SIZE - 1);
block = genblock(i, BLOCK_SIZE);
// test UTF-16LE, UTF-16BE, and UTF-8 encodings against themselves
encoded = TE_U16LE.encode(block);
decoded = TD_U16LE.decode(encoded);
assert_string_equals(block, decoded, "UTF-16LE round trip " + block_tag);
encoded = TE_U16BE.encode(block);
decoded = TD_U16BE.decode(encoded);
assert_string_equals(block, decoded, "UTF-16BE round trip " + block_tag);
encoded = TE_U8.encode(block);
decoded = TD_U8.decode(encoded);
assert_string_equals(block, decoded, "UTF-8 round trip " + block_tag);
// test TextEncoder(UTF-8) against the older idiom
exp_encoded = encode_utf8(block);
assert_array_equals(encoded, exp_encoded,
"UTF-8 reference encoding " + block_tag);
exp_decoded = decode_utf8(exp_encoded);
assert_string_equals(decoded, exp_decoded,
"UTF-8 reference decoding " + block_tag);
}
}
function test_utf_samples () {
// z, cent, CJK water, G-Clef, Private-use character
var sample = "z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD";
var cases = [
{ encoding: "utf-8",
expected: [0x7A, 0xC2, 0xA2, 0xE6, 0xB0, 0xB4, 0xF0, 0x9D, 0x84, 0x9E, 0xF4, 0x8F, 0xBF, 0xBD] },
{ encoding: "utf-16le",
expected: [0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C, 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xDB, 0xFD, 0xDF] },
{ encoding: "utf-16",
expected: [0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C, 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xDB, 0xFD, 0xDF] },
{ encoding: "utf-16be",
expected: [0x00, 0x7A, 0x00, 0xA2, 0x6C, 0x34, 0xD8, 0x34, 0xDD, 0x1E, 0xDB, 0xFF, 0xDF, 0xFD] }
];
cases.forEach(
function(t) {
var encoded = new TextEncoder(t.encoding).encode(sample);
assert_array_equals(encoded, t.expected,
"expected equal encodings - " + t.encoding);
var decoded = new TextDecoder(t.encoding)
.decode(new Uint8Array(t.expected));
assert_equals(decoded, sample,
"expected equal decodings - " + t.encoding);
});
}
test(test_utf_samples,
"UTF-8, UTF-16LE, UTF-16BE - Encode/Decode - reference sample");
test(test_utf_roundtrip,
"UTF-8, UTF-16LE, UTF-16BE - Encode/Decode - full roundtrip and "+
"agreement with encode/decodeURIComponent");

View File

@ -2,6 +2,9 @@
head = head.js
tail =
[test_misc.js]
[test_utf.js]
[test_big5.js]
[test_euc-jp.js]
[test_euc-kr.js]
@ -9,4 +12,3 @@ tail =
[test_hz-gb-2312.js]
[test_iso-2022-jp.js]
[test_shift_jis.js]
[test_singlebytes.js]

View File

@ -25,6 +25,16 @@ public:
mFlags.mCancelable = false;
}
virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
{
MOZ_ASSERT(eventStructType == NS_MUTATION_EVENT,
"Duplicate() must be overridden by sub class");
InternalMutationEvent* result = new InternalMutationEvent(false, message);
result->AssignMutationEventData(*this, true);
result->mFlags = mFlags;
return result;
}
nsCOMPtr<nsIDOMNode> mRelatedNode;
nsCOMPtr<nsIAtom> mAttrName;
nsCOMPtr<nsIAtom> mPrevAttrValue;

View File

@ -554,270 +554,12 @@ nsDOMEvent::InitEvent(const nsAString& aEventTypeArg, bool aCanBubbleArg, bool a
NS_IMETHODIMP
nsDOMEvent::DuplicatePrivateData()
{
// FIXME! Simplify this method and make it somehow easily extendable,
// Bug 329127
NS_ASSERTION(mEvent, "No WidgetEvent for nsDOMEvent duplication!");
if (mEventIsInternal) {
return NS_OK;
}
WidgetEvent* newEvent = nullptr;
uint32_t msg = mEvent->message;
switch (mEvent->eventStructType) {
case NS_EVENT:
{
newEvent = new WidgetEvent(false, msg);
newEvent->AssignEventData(*mEvent, true);
break;
}
case NS_GUI_EVENT:
{
WidgetGUIEvent* oldGUIEvent = mEvent->AsGUIEvent();
// Not copying widget, it is a weak reference.
WidgetGUIEvent* guiEvent = new WidgetGUIEvent(false, msg, nullptr);
guiEvent->AssignGUIEventData(*oldGUIEvent, true);
newEvent = guiEvent;
break;
}
case NS_INPUT_EVENT:
{
WidgetInputEvent* oldInputEvent = mEvent->AsInputEvent();
WidgetInputEvent* inputEvent = new WidgetInputEvent(false, msg, nullptr);
inputEvent->AssignInputEventData(*oldInputEvent, true);
newEvent = inputEvent;
break;
}
case NS_KEY_EVENT:
{
WidgetKeyboardEvent* oldKeyEvent = mEvent->AsKeyboardEvent();
WidgetKeyboardEvent* keyEvent =
new WidgetKeyboardEvent(false, msg, nullptr);
keyEvent->AssignKeyEventData(*oldKeyEvent, true);
newEvent = keyEvent;
break;
}
case NS_MOUSE_EVENT:
{
WidgetMouseEvent* oldMouseEvent = mEvent->AsMouseEvent();
WidgetMouseEvent* mouseEvent =
new WidgetMouseEvent(false, msg, nullptr, oldMouseEvent->reason);
mouseEvent->AssignMouseEventData(*oldMouseEvent, true);
newEvent = mouseEvent;
break;
}
case NS_DRAG_EVENT:
{
WidgetDragEvent* oldDragEvent = mEvent->AsDragEvent();
WidgetDragEvent* dragEvent = new WidgetDragEvent(false, msg, nullptr);
dragEvent->AssignDragEventData(*oldDragEvent, true);
newEvent = dragEvent;
break;
}
case NS_CLIPBOARD_EVENT:
{
InternalClipboardEvent* oldClipboardEvent = mEvent->AsClipboardEvent();
InternalClipboardEvent* clipboardEvent =
new InternalClipboardEvent(false, msg);
clipboardEvent->AssignClipboardEventData(*oldClipboardEvent, true);
newEvent = clipboardEvent;
break;
}
case NS_SCRIPT_ERROR_EVENT:
{
InternalScriptErrorEvent* oldScriptErrorEvent =
mEvent->AsScriptErrorEvent();
InternalScriptErrorEvent* scriptErrorEvent =
new InternalScriptErrorEvent(false, msg);
scriptErrorEvent->AssignScriptErrorEventData(*oldScriptErrorEvent, true);
newEvent = scriptErrorEvent;
break;
}
case NS_TEXT_EVENT:
{
WidgetTextEvent* oldTextEvent = mEvent->AsTextEvent();
WidgetTextEvent* textEvent = new WidgetTextEvent(false, msg, nullptr);
textEvent->AssignTextEventData(*oldTextEvent, true);
newEvent = textEvent;
break;
}
case NS_COMPOSITION_EVENT:
{
WidgetCompositionEvent* compositionEvent =
new WidgetCompositionEvent(false, msg, nullptr);
WidgetCompositionEvent* oldCompositionEvent =
mEvent->AsCompositionEvent();
compositionEvent->AssignCompositionEventData(*oldCompositionEvent, true);
newEvent = compositionEvent;
break;
}
case NS_MOUSE_SCROLL_EVENT:
{
WidgetMouseScrollEvent* oldMouseScrollEvent =
mEvent->AsMouseScrollEvent();
WidgetMouseScrollEvent* mouseScrollEvent =
new WidgetMouseScrollEvent(false, msg, nullptr);
mouseScrollEvent->AssignMouseScrollEventData(*oldMouseScrollEvent, true);
newEvent = mouseScrollEvent;
break;
}
case NS_WHEEL_EVENT:
{
WidgetWheelEvent* oldWheelEvent = mEvent->AsWheelEvent();
WidgetWheelEvent* wheelEvent = new WidgetWheelEvent(false, msg, nullptr);
wheelEvent->AssignWheelEventData(*oldWheelEvent, true);
newEvent = wheelEvent;
break;
}
case NS_SCROLLPORT_EVENT:
{
InternalScrollPortEvent* oldScrollPortEvent = mEvent->AsScrollPortEvent();
InternalScrollPortEvent* scrollPortEvent =
new InternalScrollPortEvent(false, msg, nullptr);
scrollPortEvent->AssignScrollPortEventData(*oldScrollPortEvent, true);
newEvent = scrollPortEvent;
break;
}
case NS_SCROLLAREA_EVENT:
{
InternalScrollAreaEvent* oldScrollAreaEvent = mEvent->AsScrollAreaEvent();
InternalScrollAreaEvent* scrollAreaEvent =
new InternalScrollAreaEvent(false, msg, nullptr);
scrollAreaEvent->AssignScrollAreaEventData(*oldScrollAreaEvent, true);
newEvent = scrollAreaEvent;
break;
}
case NS_MUTATION_EVENT:
{
InternalMutationEvent* mutationEvent =
new InternalMutationEvent(false, msg);
InternalMutationEvent* oldMutationEvent = mEvent->AsMutationEvent();
mutationEvent->AssignMutationEventData(*oldMutationEvent, true);
newEvent = mutationEvent;
break;
}
case NS_FORM_EVENT:
{
InternalFormEvent* oldFormEvent = mEvent->AsFormEvent();
InternalFormEvent* formEvent = new InternalFormEvent(false, msg);
formEvent->AssignFormEventData(*oldFormEvent, true);
newEvent = formEvent;
break;
}
case NS_FOCUS_EVENT:
{
InternalFocusEvent* newFocusEvent = new InternalFocusEvent(false, msg);
InternalFocusEvent* oldFocusEvent = mEvent->AsFocusEvent();
newFocusEvent->AssignFocusEventData(*oldFocusEvent, true);
newEvent = newFocusEvent;
break;
}
case NS_COMMAND_EVENT:
{
WidgetCommandEvent* oldCommandEvent = mEvent->AsCommandEvent();
WidgetCommandEvent* commandEvent =
new WidgetCommandEvent(false, mEvent->userType,
oldCommandEvent->command, nullptr);
commandEvent->AssignCommandEventData(*oldCommandEvent, true);
newEvent = commandEvent;
break;
}
case NS_UI_EVENT:
{
InternalUIEvent* oldUIEvent = mEvent->AsUIEvent();
InternalUIEvent* uiEvent =
new InternalUIEvent(false, msg, oldUIEvent->detail);
uiEvent->AssignUIEventData(*oldUIEvent, true);
newEvent = uiEvent;
break;
}
case NS_SVGZOOM_EVENT:
{
WidgetGUIEvent* oldGUIEvent = mEvent->AsGUIEvent();
WidgetGUIEvent* guiEvent = new WidgetGUIEvent(false, msg, nullptr);
guiEvent->eventStructType = NS_SVGZOOM_EVENT;
guiEvent->AssignGUIEventData(*oldGUIEvent, true);
newEvent = guiEvent;
break;
}
case NS_SMIL_TIME_EVENT:
{
InternalUIEvent* oldUIEvent = mEvent->AsUIEvent();
InternalUIEvent* uiEvent = new InternalUIEvent(false, msg, 0);
uiEvent->eventStructType = NS_SMIL_TIME_EVENT;
uiEvent->AssignUIEventData(*oldUIEvent, true);
newEvent = uiEvent;
break;
}
case NS_SIMPLE_GESTURE_EVENT:
{
WidgetSimpleGestureEvent* oldSimpleGestureEvent =
mEvent->AsSimpleGestureEvent();
WidgetSimpleGestureEvent* simpleGestureEvent =
new WidgetSimpleGestureEvent(false, msg, nullptr, 0, 0.0);
simpleGestureEvent->
AssignSimpleGestureEventData(*oldSimpleGestureEvent, true);
newEvent = simpleGestureEvent;
break;
}
case NS_TRANSITION_EVENT:
{
InternalTransitionEvent* oldTransitionEvent = mEvent->AsTransitionEvent();
InternalTransitionEvent* transitionEvent =
new InternalTransitionEvent(false, msg,
oldTransitionEvent->propertyName,
oldTransitionEvent->elapsedTime,
oldTransitionEvent->pseudoElement);
transitionEvent->AssignTransitionEventData(*oldTransitionEvent, true);
newEvent = transitionEvent;
break;
}
case NS_ANIMATION_EVENT:
{
InternalAnimationEvent* oldAnimationEvent = mEvent->AsAnimationEvent();
InternalAnimationEvent* animationEvent =
new InternalAnimationEvent(false, msg,
oldAnimationEvent->animationName,
oldAnimationEvent->elapsedTime,
oldAnimationEvent->pseudoElement);
animationEvent->AssignAnimationEventData(*oldAnimationEvent, true);
newEvent = animationEvent;
break;
}
case NS_TOUCH_EVENT:
{
WidgetTouchEvent* oldTouchEvent = mEvent->AsTouchEvent();
WidgetTouchEvent* touchEvent = new WidgetTouchEvent(false, oldTouchEvent);
touchEvent->AssignTouchEventData(*oldTouchEvent, true);
newEvent = touchEvent;
break;
}
case NS_POINTER_EVENT:
{
WidgetPointerEvent* oldPointerEvent = mEvent->AsPointerEvent();
WidgetPointerEvent* pointerEvent =
new WidgetPointerEvent(false, msg, nullptr,
oldPointerEvent->pointerId,
oldPointerEvent->width,
oldPointerEvent->height,
oldPointerEvent->tiltX,
oldPointerEvent->tiltY,
oldPointerEvent->isPrimary);
pointerEvent->buttons = oldPointerEvent->buttons;
newEvent = pointerEvent;
break;
}
default:
{
NS_WARNING("Unknown event type!!!");
return NS_ERROR_FAILURE;
}
}
newEvent->mFlags = mEvent->mFlags;
mEvent = newEvent;
mEvent = mEvent->Duplicate();
mPresContext = nullptr;
mEventIsInternal = true;
mPrivateDataDuplicated = true;

View File

@ -0,0 +1,35 @@
/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
interface WorkerConsole {
void log(any... data);
void info(any... data);
void warn(any... data);
void error(any... data);
void _exception(any... data);
void debug(any... data);
void trace();
void dir(optional any data);
void group(any... data);
void groupCollapsed(any... data);
void groupEnd(any... data);
void time(optional any time);
void timeEnd(optional any time);
void profile(any... data);
void profileEnd(any... data);
void assert(boolean condition, any... data);
void ___noSuchMethod__();
};
// This dictionary is used internally to send the stack trace from the worker to
// the main thread Console API implementation.
dictionary WorkerConsoleStack {
DOMString filename = "";
unsigned long lineNumber = 0;
DOMString functionName = "";
unsigned long language = 0;
};

View File

@ -14,6 +14,7 @@
interface WorkerGlobalScope : EventTarget {
readonly attribute WorkerGlobalScope self;
readonly attribute WorkerConsole console;
readonly attribute WorkerLocation location;
void close();

View File

@ -428,6 +428,7 @@ WEBIDL_FILES = [
'WheelEvent.webidl',
'WifiOptions.webidl',
'Worker.webidl',
'WorkerConsole.webidl',
'WorkerGlobalScope.webidl',
'WorkerLocation.webidl',
'WorkerNavigator.webidl',

561
dom/workers/Console.cpp Normal file
View File

@ -0,0 +1,561 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* 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/. */
#include "Console.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "js/OldDebugAPI.h"
#include "nsJSUtils.h"
#include "WorkerRunnable.h"
#include "nsComponentManagerUtils.h"
#include "nsIDOMGlobalPropertyInitializer.h"
#include "mozilla/dom/WorkerConsoleBinding.h"
#include "mozilla/dom/Exceptions.h"
#define CONSOLE_TAG JS_SCTAG_USER_MIN
// From dom/base/ConsoleAPI.js
#define DEFAULT_MAX_STACKTRACE_DEPTH 200
using namespace mozilla::dom::exceptions;
BEGIN_WORKERS_NAMESPACE
class ConsoleProxy
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLProxy)
bool
Init(JSContext* aCx, nsPIDOMWindow* aWindow)
{
AssertIsOnMainThread();
// Console API:
nsCOMPtr<nsISupports> cInstance =
do_CreateInstance("@mozilla.org/console-api;1");
nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
do_QueryInterface(cInstance);
NS_ENSURE_TRUE(gpi, false);
// We don't do anything with the return value.
JS::Rooted<JS::Value> prop_val(aCx);
if (NS_FAILED(gpi->Init(aWindow, &prop_val))) {
return false;
}
mXpcwrappedjs = do_QueryInterface(cInstance);
NS_ENSURE_TRUE(mXpcwrappedjs, false);
return true;
}
nsIXPConnectWrappedJS*
GetWrappedJS() const
{
AssertIsOnMainThread();
return mXpcwrappedjs;
}
void ReleaseWrappedJS()
{
AssertIsOnMainThread();
mXpcwrappedjs = nullptr;
}
private:
nsCOMPtr<nsIXPConnectWrappedJS> mXpcwrappedjs;
};
/**
* Console API in workers uses the Structured Clone Algorithm to move any value
* from the worker thread to the main-thread. Some object cannot be moved and,
* in these cases, we convert them to strings.
* It's not the best, but at least we are able to show something.
*/
// This method is called by the Structured Clone Algorithm when some data has
// to be read.
static JSObject*
ConsoleStructuredCloneCallbacksRead(JSContext* aCx,
JSStructuredCloneReader* /* unused */,
uint32_t aTag, uint32_t aData,
void* aClosure)
{
AssertIsOnMainThread();
if (aTag != CONSOLE_TAG) {
return nullptr;
}
nsTArray<nsString>* strings = static_cast<nsTArray<nsString>*>(aClosure);
if (strings->Length() <= aData) {
return nullptr;
}
JS::Rooted<JS::Value> value(aCx);
if (!xpc::StringToJsval(aCx, strings->ElementAt(aData), &value)) {
return nullptr;
}
JS::Rooted<JSObject*> obj(aCx);
if (!JS_ValueToObject(aCx, value, &obj)) {
return nullptr;
}
return obj;
}
// This method is called by the Structured Clone Algorithm when some data has
// to be written.
static bool
ConsoleStructuredCloneCallbacksWrite(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj,
void* aClosure)
{
JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
if (!jsString) {
return false;
}
nsDependentJSString string;
if (!string.init(aCx, jsString)) {
return false;
}
nsTArray<nsString>* strings = static_cast<nsTArray<nsString>*>(aClosure);
if (!JS_WriteUint32Pair(aWriter, CONSOLE_TAG, strings->Length())) {
return false;
}
strings->AppendElement(string);
return true;
}
static void
ConsoleStructuredCloneCallbacksError(JSContext* /* aCx */,
uint32_t /* aErrorId */)
{
NS_WARNING("Failed to clone data for the Console API in workers.");
}
JSStructuredCloneCallbacks gConsoleCallbacks = {
ConsoleStructuredCloneCallbacksRead,
ConsoleStructuredCloneCallbacksWrite,
ConsoleStructuredCloneCallbacksError
};
class ConsoleStackData
{
public:
ConsoleStackData()
: mLineNumber(0)
{}
nsCString mFilename;
uint32_t mLineNumber;
nsCString mFunctionName;
};
class ConsoleRunnable MOZ_FINAL : public nsRunnable
{
public:
explicit ConsoleRunnable(WorkerConsole* aConsole,
WorkerPrivate* aWorkerPrivate)
: mConsole(aConsole)
, mWorkerPrivate(aWorkerPrivate)
, mMethod(nullptr)
{
mWorkerPrivate->AssertIsOnWorkerThread();
}
bool
Dispatch(JSContext* aCx,
const char* aMethod,
JS::Handle<JS::Value> aArguments,
nsTArray<ConsoleStackData>& aStackData)
{
mMethod = aMethod;
mStackData.SwapElements(aStackData);
if (!mArguments.write(aCx, aArguments, &gConsoleCallbacks, &mStrings)) {
JS_ClearPendingException(aCx);
return false;
}
mWorkerPrivate->AssertIsOnWorkerThread();
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
mSyncLoopTarget = syncLoop.EventTarget();
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
JS_ReportError(aCx,
"Failed to dispatch to main thread for the "
"Console API (method %s)!", mMethod);
return false;
}
return syncLoop.Run();
}
private:
NS_IMETHOD Run()
{
AssertIsOnMainThread();
RunConsole();
nsRefPtr<MainThreadStopSyncLoopRunnable> response =
new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
mSyncLoopTarget.forget(),
true);
if (!response->Dispatch(nullptr)) {
NS_WARNING("Failed to dispatch response!");
}
return NS_OK;
}
void
RunConsole()
{
// This class is used to clear any exception at the end of this method.
class ClearException
{
public:
ClearException(JSContext* aCx)
: mCx(aCx)
{
}
~ClearException()
{
JS_ClearPendingException(mCx);
}
private:
JSContext* mCx;
};
// Walk up to our containing page
WorkerPrivate* wp = mWorkerPrivate;
while (wp->GetParent()) {
wp = wp->GetParent();
}
AutoPushJSContext cx(wp->ParentJSContext());
JSAutoRequest ar(cx);
ClearException ce(cx);
nsRefPtr<ConsoleProxy> proxy = mConsole->GetProxy();
if (!proxy) {
nsPIDOMWindow* window = wp->GetWindow();
NS_ENSURE_TRUE_VOID(window);
proxy = new ConsoleProxy();
if (!proxy->Init(cx, window)) {
return;
}
mConsole->SetProxy(proxy);
}
JS::Rooted<JSObject*> consoleObj(cx, proxy->GetWrappedJS()->GetJSObject());
NS_ENSURE_TRUE_VOID(consoleObj);
JSAutoCompartment ac(cx, consoleObj);
// 3 args for the queueCall.
nsDependentCString method(mMethod);
JS::Rooted<JS::Value> methodValue(cx);
if (!ByteStringToJsval(cx, method, &methodValue)) {
return;
}
JS::Rooted<JS::Value> argumentsValue(cx);
if (!mArguments.read(cx, &argumentsValue, &gConsoleCallbacks, &mStrings)) {
return;
}
JS::Rooted<JS::Value> stackValue(cx);
{
JS::Rooted<JSObject*> stackObj(cx,
JS_NewArrayObject(cx, mStackData.Length(), nullptr));
if (!stackObj) {
return;
}
for (uint32_t i = 0; i < mStackData.Length(); ++i) {
WorkerConsoleStack stack;
CopyUTF8toUTF16(mStackData[i].mFilename, stack.mFilename);
CopyUTF8toUTF16(mStackData[i].mFunctionName, stack.mFunctionName);
stack.mLineNumber = mStackData[i].mLineNumber;
stack.mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
JS::Rooted<JS::Value> value(cx);
if (!stack.ToObject(cx, JS::NullPtr(), &value)) {
return;
}
if (!JS_DefineElement(cx, stackObj, i, value, nullptr, nullptr, 0)) {
return;
}
}
stackValue = JS::ObjectValue(*stackObj);
}
JS::AutoValueVector argv(cx);
if (!argv.resize(3)) {
return;
}
argv[0] = methodValue;
argv[1] = argumentsValue;
argv[2] = stackValue;
JS::Rooted<JS::Value> ret(cx);
JS_CallFunctionName(cx, consoleObj, "queueCall", argv.length(),
argv.begin(), ret.address());
}
WorkerConsole* mConsole;
WorkerPrivate* mWorkerPrivate;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
const char* mMethod;
JSAutoStructuredCloneBuffer mArguments;
nsTArray<ConsoleStackData> mStackData;
nsTArray<nsString> mStrings;
};
class TeardownRunnable : public nsRunnable
{
public:
TeardownRunnable(ConsoleProxy* aProxy)
: mProxy(aProxy)
{
}
NS_IMETHOD Run()
{
AssertIsOnMainThread();
mProxy->ReleaseWrappedJS();
mProxy = nullptr;
return NS_OK;
}
private:
nsRefPtr<ConsoleProxy> mProxy;
};
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerConsole)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerConsole, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerConsole, Release)
/* static */ already_AddRefed<WorkerConsole>
WorkerConsole::Create()
{
nsRefPtr<WorkerConsole> console = new WorkerConsole();
return console.forget();
}
JSObject*
WorkerConsole::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return WorkerConsoleBinding_workers::Wrap(aCx, aScope, this);
}
WorkerConsole::WorkerConsole()
{
MOZ_COUNT_CTOR(WorkerConsole);
SetIsDOMBinding();
}
WorkerConsole::~WorkerConsole()
{
MOZ_COUNT_DTOR(WorkerConsole);
if (mProxy) {
nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mProxy);
mProxy = nullptr;
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
NS_ERROR("Failed to dispatch teardown runnable!");
}
}
}
void
WorkerConsole::SetProxy(ConsoleProxy* aProxy)
{
MOZ_ASSERT(!mProxy);
mProxy = aProxy;
}
void
WorkerConsole::Method(JSContext* aCx, const char* aMethodName,
const Sequence<JS::Value>& aData,
uint32_t aStackLevel)
{
nsCOMPtr<nsIStackFrame> stack = CreateStack(aCx, aStackLevel);
if (!stack) {
return;
}
// nsIStackFrame is not thread-safe so we take what we need and we store in
// an array of ConsoleStackData objects.
nsTArray<ConsoleStackData> stackData;
while (stack) {
ConsoleStackData& data = *stackData.AppendElement();
if (NS_FAILED(stack->GetFilename(data.mFilename))) {
return;
}
int32_t lineNumber;
if (NS_FAILED(stack->GetLineNumber(&lineNumber))) {
return;
}
data.mLineNumber = lineNumber;
if (NS_FAILED(stack->GetName(data.mFunctionName))) {
return;
}
nsCOMPtr<nsIStackFrame> caller;
if (NS_FAILED(stack->GetCaller(getter_AddRefs(caller)))) {
return;
}
stack.swap(caller);
}
JS::Rooted<JSObject*> arguments(aCx,
JS_NewArrayObject(aCx, aData.Length(), nullptr));
if (!arguments) {
return;
}
for (uint32_t i = 0; i < aData.Length(); ++i) {
if (!JS_DefineElement(aCx, arguments, i, aData[i], nullptr, nullptr,
JSPROP_ENUMERATE)) {
return;
}
}
JS::Rooted<JS::Value> argumentsValue(aCx, JS::ObjectValue(*arguments));
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
MOZ_ASSERT(worker);
nsRefPtr<ConsoleRunnable> runnable = new ConsoleRunnable(this, worker);
runnable->Dispatch(aCx, aMethodName, argumentsValue, stackData);
}
#define METHOD(name, jsName) \
void \
WorkerConsole::name(JSContext* aCx, \
const Sequence<JS::Value>& aData) \
{ \
Method(aCx, jsName, aData, 1); \
}
METHOD(Log, "log")
METHOD(Info, "info")
METHOD(Warn, "warn")
METHOD(Error, "error")
METHOD(Exception, "exception")
METHOD(Debug, "debug")
void
WorkerConsole::Trace(JSContext* aCx)
{
Sequence<JS::Value> data;
Method(aCx, "trace", data, DEFAULT_MAX_STACKTRACE_DEPTH);
}
void
WorkerConsole::Dir(JSContext* aCx,
const Optional<JS::Handle<JS::Value>>& aValue)
{
Sequence<JS::Value> data;
if (aValue.WasPassed()) {
data.AppendElement(aValue.Value());
}
Method(aCx, "dir", data, 1);
}
METHOD(Group, "group")
METHOD(GroupCollapsed, "groupCollapsed")
METHOD(GroupEnd, "groupEnd")
void
WorkerConsole::Time(JSContext* aCx,
const Optional<JS::Handle<JS::Value>>& aTimer)
{
Sequence<JS::Value> data;
if (aTimer.WasPassed()) {
data.AppendElement(aTimer.Value());
}
Method(aCx, "time", data, 1);
}
void
WorkerConsole::TimeEnd(JSContext* aCx,
const Optional<JS::Handle<JS::Value>>& aTimer)
{
Sequence<JS::Value> data;
if (aTimer.WasPassed()) {
data.AppendElement(aTimer.Value());
}
Method(aCx, "timeEnd", data, 1);
}
METHOD(Profile, "profile")
METHOD(ProfileEnd, "profileEnd")
void
WorkerConsole::Assert(JSContext* aCx, bool aCondition,
const Sequence<JS::Value>& aData)
{
if (!aCondition) {
Method(aCx, "assert", aData, 1);
}
}
void
WorkerConsole::__noSuchMethod__()
{
// Nothing to do.
}
#undef METHOD
END_WORKERS_NAMESPACE

112
dom/workers/Console.h Normal file
View File

@ -0,0 +1,112 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* 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/. */
#ifndef mozilla_dom_workers_Console_h
#define mozilla_dom_workers_Console_h
#include "Workers.h"
#include "WorkerPrivate.h"
#include "nsWrapperCache.h"
BEGIN_WORKERS_NAMESPACE
class ConsoleProxy;
class ConsoleStackData;
class WorkerConsole MOZ_FINAL : public nsWrapperCache
{
WorkerConsole();
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WorkerConsole)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WorkerConsole)
static already_AddRefed<WorkerConsole>
Create();
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
nsISupports* GetParentObject() const
{
return nullptr;
}
~WorkerConsole();
ConsoleProxy*
GetProxy() const
{
return mProxy;
}
void
SetProxy(ConsoleProxy* aProxy);
// WebIDL methods
void
Log(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Info(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Warn(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Error(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Exception(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Debug(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Trace(JSContext* aCx);
void
Dir(JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aValue);
void
Group(JSContext* aCx, const Sequence<JS::Value>& aData);
void
GroupCollapsed(JSContext* aCx, const Sequence<JS::Value>& aData);
void
GroupEnd(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Time(JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aTimer);
void
TimeEnd(JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aTimer);
void
Profile(JSContext* aCx, const Sequence<JS::Value>& aData);
void
ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Assert(JSContext* aCx, bool aCondition, const Sequence<JS::Value>& aData);
void
__noSuchMethod__();
private:
void
Method(JSContext* aCx, const char* aMethodName,
const Sequence<JS::Value>& aData, uint32_t aMaxStackDepth);
nsRefPtr<ConsoleProxy> mProxy;
};
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_Console_h

View File

@ -3759,8 +3759,11 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
return NS_ERROR_FAILURE;
}
// StartAssignment() is used instead getter_AddRefs because, getter_AddRefs
// does QI in debug build and, if this worker runs in a child process,
// HttpChannelChild will crash because it's not thread-safe.
rv = ChannelFromScriptURLWorkerThread(aCx, aParent, aScriptURL,
getter_AddRefs(loadInfo.mChannel));
loadInfo.mChannel.StartAssignment());
NS_ENSURE_SUCCESS(rv, rv);
// Now that we've spun the loop there's no guarantee that our parent is

View File

@ -15,6 +15,7 @@
#include <android/log.h>
#endif
#include "Console.h"
#include "Location.h"
#include "Navigator.h"
#include "Principal.h"
@ -77,6 +78,19 @@ WorkerGlobalScope::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
MOZ_CRASH("We should never get here!");
}
WorkerConsole*
WorkerGlobalScope::Console()
{
mWorkerPrivate->AssertIsOnWorkerThread();
if (!mConsole) {
mConsole = WorkerConsole::Create();
MOZ_ASSERT(mConsole);
}
return mConsole;
}
already_AddRefed<WorkerLocation>
WorkerGlobalScope::Location()
{

View File

@ -20,12 +20,14 @@ class Function;
BEGIN_WORKERS_NAMESPACE
class WorkerPrivate;
class WorkerConsole;
class WorkerLocation;
class WorkerNavigator;
class WorkerGlobalScope : public nsDOMEventTargetHelper,
public nsIGlobalObject
{
nsRefPtr<WorkerConsole> mConsole;
nsRefPtr<WorkerLocation> mLocation;
nsRefPtr<WorkerNavigator> mNavigator;
@ -58,6 +60,9 @@ public:
return nsRefPtr<WorkerGlobalScope>(this).forget();
}
WorkerConsole*
Console();
already_AddRefed<WorkerLocation>
Location();

View File

@ -19,6 +19,7 @@ EXPORTS.mozilla.dom.workers += [
# Stuff needed for the bindings, not really public though.
EXPORTS.mozilla.dom.workers.bindings += [
'Console.h',
'FileReaderSync.h',
'Location.h',
'MessagePort.h',
@ -32,6 +33,7 @@ EXPORTS.mozilla.dom.workers.bindings += [
SOURCES += [
'ChromeWorkerScope.cpp',
'Console.cpp',
'File.cpp',
'FileReaderSync.cpp',
'Location.cpp',

View File

@ -0,0 +1,104 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
onmessage = function(event) {
// TEST: does console exist?
postMessage({event: 'console exists', status: !!console, last : false});
postMessage({event: 'trace without function', status: true, last : false});
for (var i = 0; i < 10; ++i) {
console.what('1', 123, 321);
}
for (var i = 0; i < 10; ++i) {
console.log(i, i, i);
}
function trace1() {
function trace2() {
function trace3() {
console.trace("trace " + i);
}
trace3();
}
trace2();
}
trace1();
foobar585956c = function(a) {
console.trace();
return a+"c";
};
function foobar585956b(a) {
return foobar585956c(a+"b");
}
function foobar585956a(omg) {
return foobar585956b(omg + "a");
}
function foobar646025(omg) {
console.log(omg, "o", "d");
}
function startTimer(timer) {
console.time(timer);
}
function stopTimer(timer) {
console.timeEnd(timer);
}
function testGroups() {
console.groupCollapsed("a", "group");
console.group("b", "group");
console.groupEnd("b", "group");
}
foobar585956a('omg');
foobar646025('omg');
testGroups();
startTimer('foo');
setTimeout(function() {
stopTimer('foo');
nextSteps(event);
}, 10);
}
function nextSteps(event) {
function namelessTimer() {
console.time();
console.timeEnd();
}
namelessTimer();
var str = "Test Message."
console.foobar(str); // if this throws, we don't execute following funcs
console.log(str);
console.info(str);
console.warn(str);
console.error(str);
console.exception(str);
console.assert(true, str);
console.assert(false, str);
console.profile(str);
console.profileEnd(str);
postMessage({event: '4 messages', status: true, last : false});
// Recursive:
if (event.data == true) {
var worker = new Worker('console_worker.js');
worker.onmessage = function(event) {
postMessage(event.data);
}
worker.postMessage(false);
} else {
postMessage({event: 'bye bye', status: true, last : true});
}
}

View File

@ -7,6 +7,7 @@ support-files =
closeOnGC_worker.js
close_worker.js
content_worker.js
console_worker.js
csp_worker.js
errorPropagation_iframe.html
errorPropagation_worker.js
@ -20,6 +21,7 @@ support-files =
importScripts_worker_imported4.js
instanceof_worker.js
json_worker.js
jsversion_worker.js
loadEncoding_worker.js
location_worker.js
longThread_worker.js
@ -59,7 +61,6 @@ support-files =
xhr_implicit_cancel_worker.js
xhr_worker.js
url_exceptions_worker.js
jsversion_worker.js
urlSearchParams_worker.js
subdir/relativeLoad_sub_worker.js
subdir/relativeLoad_sub_worker2.js
@ -73,6 +74,7 @@ support-files =
[test_clearTimeouts.html]
[test_close.html]
[test_closeOnGC.html]
[test_console.html]
[test_contentWorker.html]
[test_csp.html]
[test_csp.html^headers^]
@ -85,6 +87,7 @@ support-files =
[test_importScripts.html]
[test_instanceof.html]
[test_json.html]
[test_jsversion.html]
[test_loadEncoding.html]
[test_loadError.html]
[test_location.html]
@ -125,4 +128,3 @@ support-files =
skip-if = (os == "win") || (os == "mac")
[test_url_exceptions.html]
[test_urlSearchParams.html]
[test_jsversion.html]

View File

@ -0,0 +1,44 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
Tests of DOM Worker Console
-->
<head>
<title>Test for DOM Worker Console</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>
<pre id="test">
<script class="testbody" language="javascript">
var worker = new Worker("console_worker.js");
worker.onmessage = function(event) {
is(event.target, worker, "Worker and target match!");
ok(event.data.status, event.data.event);
if (!event.data.status || event.data.last)
SimpleTest.finish();
};
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.message);
SimpleTest.finish();
}
worker.postMessage(true);
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -511,29 +511,29 @@ CompositorD3D9::EnsureSwapChain()
if (!mSwapChain) {
mSwapChain = mDeviceManager->
CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW));
// We could not create a swap chain, return false
if (!mSwapChain) {
// Check the state of the device too
DeviceManagerState state = mDeviceManager->VerifyReadyForRendering();
if (state == DeviceMustRecreate) {
mDeviceManager = nullptr;
mParent->SendInvalidateAll();
} else if (state == DeviceRetry) {
mParent->SendInvalidateAll();
}
mParent->SendInvalidateAll();
return false;
}
}
// We have a swap chain, lets initialise it
DeviceManagerState state = mSwapChain->PrepareForRendering();
if (state == DeviceOK) {
return true;
}
// Swap chain could not be initialised, handle the failure
if (state == DeviceMustRecreate) {
mDeviceManager = nullptr;
mSwapChain = nullptr;
mParent->SendInvalidateAll();
} else if (state == DeviceRetry) {
mParent->SendInvalidateAll();
}
mParent->SendInvalidateAll();
return false;
}
@ -553,6 +553,7 @@ CompositorD3D9::Ready()
if (EnsureSwapChain()) {
// We don't need to call VerifyReadyForRendering because that is
// called by mSwapChain->PrepareForRendering() via EnsureSwapChain().
CheckResetCount();
return true;
}
@ -560,7 +561,7 @@ CompositorD3D9::Ready()
}
NS_ASSERTION(!mCurrentRT && !mDefaultRT,
"Shouldn't have any render targets around, they must be released before our device");
"Shouldn't have any render targets around, they must be released before our device");
mSwapChain = nullptr;
mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();

View File

@ -672,11 +672,11 @@ DeviceManagerD3D9::SetShaderMode(ShaderMode aMode, Layer* aMask, bool aIs2D)
void
DeviceManagerD3D9::DestroyDevice()
{
++mDeviceResetCount;
mDeviceWasRemoved = true;
if (!IsD3D9Ex()) {
ReleaseTextureResources();
}
LayerManagerD3D9::OnDeviceManagerDestroy(this);
gfxWindowsPlatform::GetPlatform()->OnDeviceManagerDestroy(this);
}
@ -695,7 +695,6 @@ DeviceManagerD3D9::VerifyReadyForRendering()
if (FAILED(hr)) {
DestroyDevice();
++mDeviceResetCount;
return DeviceMustRecreate;
}
}
@ -724,6 +723,11 @@ DeviceManagerD3D9::VerifyReadyForRendering()
pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
pp.hDeviceWindow = mFocusWnd;
// Whatever happens from now on, either we reset the device, or we should
// pretend we reset the device so that the layer manager or compositor
// doesn't ignore it.
++mDeviceResetCount;
// if we got this far, we know !SUCCEEDEED(hr), that means hr is one of
// D3DERR_DEVICELOST, D3DERR_DEVICENOTRESET, D3DERR_DRIVERINTERNALERROR.
// It is only worth resetting if we get D3DERR_DEVICENOTRESET. If we get
@ -733,9 +737,6 @@ DeviceManagerD3D9::VerifyReadyForRendering()
HMONITOR hMonitorWindow;
hMonitorWindow = MonitorFromWindow(mFocusWnd, MONITOR_DEFAULTTOPRIMARY);
if (hMonitorWindow != mDeviceMonitor) {
/* The monitor has changed. We have to assume that the
* DEVICENOTRESET will not be comming. */
/* jrmuizel: I'm not sure how to trigger this case. Usually, we get
* DEVICENOTRESET right away and Reset() succeeds without going through a
* set of DEVICELOSTs. This is presumeably because we don't call
@ -743,18 +744,19 @@ DeviceManagerD3D9::VerifyReadyForRendering()
* Hopefully comparing HMONITORs is not overly aggressive.
* See bug 626678.
*/
/* The monitor has changed. We have to assume that the
* DEVICENOTRESET will not be coming. */
DestroyDevice();
return DeviceMustRecreate;
}
return DeviceRetry;
return DeviceFail;
}
if (hr == D3DERR_DEVICENOTRESET) {
hr = mDevice->Reset(&pp);
++mDeviceResetCount;
}
if (FAILED(hr) || !CreateVertexBuffer()) {
DestroyDevice();
++mDeviceResetCount;
return DeviceMustRecreate;
}

View File

@ -34,12 +34,14 @@ const int CBvLayerQuad = 10;
const int CBfLayerOpacity = 0;
const int CBvColor = 0;
// TODO lower case this
enum DeviceManagerState {
// The device and swap chain are OK.
DeviceOK,
// The device or swap chain are in a bad state, and we should not render.
DeviceFail,
// The device is lost, the user should forget the current device manager
// and create a new one.
DeviceMustRecreate,
DeviceRetry
};

View File

@ -22,8 +22,6 @@
namespace mozilla {
namespace layers {
DeviceManagerD3D9 *LayerManagerD3D9::mDefaultDeviceManager = nullptr;
LayerManagerD3D9::LayerManagerD3D9(nsIWidget *aWidget)
: mWidget(aWidget)
, mDeviceResetCount(0)
@ -57,15 +55,9 @@ LayerManagerD3D9::Initialize(bool force)
}
}
if (!mDefaultDeviceManager) {
mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
if (!mDeviceManager) {
return false;
}
mDefaultDeviceManager = mDeviceManager;
} else {
mDeviceManager = mDefaultDeviceManager;
mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
if (!mDeviceManager) {
return false;
}
mSwapChain = mDeviceManager->
@ -233,10 +225,10 @@ LayerManagerD3D9::ReportFailure(const nsACString &aMsg, HRESULT aCode)
void
LayerManagerD3D9::Render()
{
DeviceManagerState state = mSwapChain->PrepareForRendering();
if (state != DeviceOK) {
if (mSwapChain->PrepareForRendering() != DeviceOK) {
return;
}
deviceManager()->SetupRenderState();
SetupPipeline();

View File

@ -124,11 +124,6 @@ public:
*/
Nv3DVUtils *GetNv3DVUtils() { return mDeviceManager ? mDeviceManager->GetNv3DVUtils() : nullptr; }
static void OnDeviceManagerDestroy(DeviceManagerD3D9 *aDeviceManager) {
if(aDeviceManager == mDefaultDeviceManager)
mDefaultDeviceManager = nullptr;
}
virtual const char* Name() const { return "D3D9"; }
void ReportFailure(const nsACString &aMsg, HRESULT aCode);
@ -137,9 +132,6 @@ public:
void SetCompositingDisabled(bool aCompositingDisabled) { mCompositingDisabled = aCompositingDisabled; }
private:
/* Default device manager instance */
static DeviceManagerD3D9 *mDefaultDeviceManager;
/* Device manager instance for this layer manager */
nsRefPtr<DeviceManagerD3D9> mDeviceManager;

View File

@ -750,6 +750,11 @@ SwitchState GetCurrentSwitchState(SwitchDevice aDevice)
RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice), SWITCH_STATE_UNKNOWN);
}
void NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
{
PROXY_IF_SANDBOXED(NotifySwitchStateFromInputDevice(aDevice, aState));
}
typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
static SwitchObserverList *sSwitchObserverLists = nullptr;

View File

@ -437,6 +437,12 @@ void NotifySwitchChange(const hal::SwitchEvent& aEvent);
*/
hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice);
/**
* Notify switch status change from input device.
*/
void NotifySwitchStateFromInputDevice(hal::SwitchDevice aDevice,
hal::SwitchState aState);
/**
* Register an observer that is notified when a programmed alarm
* expires.

View File

@ -25,5 +25,10 @@ GetCurrentSwitchState(SwitchDevice aDevice) {
return SWITCH_STATE_UNKNOWN;
}
void
NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
{
}
} // namespace hal_impl
} // namespace mozilla

View File

@ -17,6 +17,7 @@
#include <android/log.h>
#include <fcntl.h>
#include <sysutils/NetlinkEvent.h>
#include <cutils/properties.h>
#include "base/message_loop.h"
@ -280,6 +281,20 @@ public:
}
}
void Notify(SwitchDevice aDevice, SwitchState aState)
{
EventInfo& info = mEventInfo[aDevice];
if (aState == info.mEvent.status()) {
return;
}
info.mEvent.status() = aState;
if (info.mEnabled) {
NS_DispatchToMainThread(new SwitchEventRunnable(info.mEvent));
}
}
SwitchState GetCurrentInformation(SwitchDevice aDevice)
{
return mEventInfo[aDevice].mEvent.status();
@ -311,7 +326,18 @@ private:
void Init()
{
mHandler.AppendElement(new SwitchHandlerHeadphone(SWITCH_HEADSET_DEVPATH));
char value[PROPERTY_VALUE_MAX];
property_get("ro.moz.devinputjack", value, "0");
bool headphonesFromInputDev = !strcmp(value, "1");
if (!headphonesFromInputDev) {
mHandler.AppendElement(new SwitchHandlerHeadphone(SWITCH_HEADSET_DEVPATH));
} else {
// If headphone status will be notified from input dev then initialize
// status to "off" and wait for event notification.
mEventInfo[SWITCH_HEADPHONES].mEvent.device() = SWITCH_HEADPHONES;
mEventInfo[SWITCH_HEADPHONES].mEvent.status() = SWITCH_STATE_OFF;
}
mHandler.AppendElement(new SwitchHandler(SWITCH_USB_DEVPATH_GB, SWITCH_USB));
mHandler.AppendElement(new SwitchHandlerUsbIcs(SWITCH_USB_DEVPATH_ICS));
@ -417,5 +443,18 @@ GetCurrentSwitchState(SwitchDevice aDevice)
return sSwitchObserver->GetCurrentInformation(aDevice);
}
static void
NotifySwitchStateIOThread(SwitchDevice aDevice, SwitchState aState)
{
sSwitchObserver->Notify(aDevice, aState);
}
void NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
{
InitializeResourceIfNeed();
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(NotifySwitchStateIOThread, aDevice, aState));
}
} // hal_impl
} //mozilla

View File

@ -171,6 +171,7 @@ parent:
DisableSwitchNotifications(SwitchDevice aDevice);
sync GetCurrentSwitchState(SwitchDevice aDevice)
returns (SwitchState aState);
NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState);
FactoryReset();

View File

@ -327,6 +327,12 @@ GetCurrentSwitchState(SwitchDevice aDevice)
return state;
}
void
NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
{
Hal()->SendNotifySwitchStateFromInputDevice(aDevice, aState);
}
bool
EnableAlarm()
{
@ -816,6 +822,14 @@ public:
return true;
}
virtual bool
RecvNotifySwitchStateFromInputDevice(const SwitchDevice& aDevice,
const SwitchState& aState) MOZ_OVERRIDE
{
hal::NotifySwitchStateFromInputDevice(aDevice, aState);
return true;
}
void Notify(const int64_t& aClockDeltaMS)
{
unused << SendNotifySystemClockChange(aClockDeltaMS);

View File

@ -6,7 +6,6 @@
XPIDL_SOURCES += [
'mozIJSSubScriptLoader.idl',
'nsIJSEngineTelemetryStats.idl',
'nsIJSRuntimeService.idl',
'nsIScriptError.idl',
'nsIXPConnect.idl',

View File

@ -1,21 +0,0 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* 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/. */
#include "nsISupports.idl"
/**
* Telemetry uses this interface on the @mozilla.org/js/xpc/XPConnect;1 service
* to extract JS engine stats.
*/
[scriptable, uuid(5a6ea52b-4e23-402f-93e3-59f29b2f1a88)]
interface nsIJSEngineTelemetryStats : nsISupports
{
/**
* The value returned by this attribute is included as the 'js' property of
* the telemetry ping JSON blob.
*/
[implicit_jscontext]
readonly attribute jsval telemetryValue;
};

View File

@ -120,7 +120,7 @@ interface ScheduledGCCallback : nsISupports
/**
* interface of Components.utils
*/
[scriptable, uuid(872b0aa4-c234-4c46-b72c-1bc861d6c5eb)]
[scriptable, uuid(c9ab0d20-8499-11e3-baa7-0800200c9a66)]
interface nsIXPCComponents_Utils : nsISupports
{
@ -258,7 +258,7 @@ interface nsIXPCComponents_Utils : nsISupports
* Force an immediate cycle collection cycle.
*/
void forceCC();
/*
* To be called from JS only.
*
@ -271,7 +271,7 @@ interface nsIXPCComponents_Utils : nsISupports
* is running. Call the provided function once this has occurred.
*/
void schedulePreciseGC(in ScheduledGCCallback callback);
/*
* Schedule a shrinking garbage collection cycle for a point in the future
* when no JS is running. Call the provided function once this has occured.
@ -548,6 +548,9 @@ interface nsIXPCComponents_Utils : nsISupports
* "WatchdogHibernateStop" - Watchdog stops hibernating
*/
PRTime getWatchdogTimestamp(in AString aCategory);
[implicit_jscontext]
jsval getJSEngineTelemetryValue();
};
/**

View File

@ -121,7 +121,8 @@ Dump(JSContext *cx, unsigned argc, Value *vp)
if (!chars)
return false;
NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const char16_t*>(chars));
NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const char16_t*>(chars),
length);
#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
#endif

View File

@ -3442,6 +3442,29 @@ nsXPCComponents_Utils::GetWatchdogTimestamp(const nsAString& aCategory, PRTime *
return NS_OK;
}
NS_IMETHODIMP
nsXPCComponents_Utils::GetJSEngineTelemetryValue(JSContext *cx, MutableHandleValue rval)
{
RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
if (!obj)
return NS_ERROR_OUT_OF_MEMORY;
unsigned attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
size_t i = JS_SetProtoCalled(cx);
RootedValue v(cx, DoubleValue(i));
if (!JS_DefineProperty(cx, obj, "setProto", v, nullptr, nullptr, attrs))
return NS_ERROR_OUT_OF_MEMORY;
i = JS_GetCustomIteratorCount(cx);
v.setDouble(i);
if (!JS_DefineProperty(cx, obj, "customIter", v, nullptr, nullptr, attrs))
return NS_ERROR_OUT_OF_MEMORY;
rval.setObject(*obj);
return NS_OK;
}
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/

View File

@ -255,20 +255,30 @@ static bool
Print(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setUndefined();
RootedString str(cx);
nsAutoCString utf8str;
size_t length;
const jschar *chars;
for (unsigned i = 0; i < args.length(); i++) {
str = ToString(cx, args[i]);
if (!str)
return false;
JSAutoByteString strBytes(cx, str);
if (!strBytes)
chars = JS_GetStringCharsAndLength(cx, str, &length);
if (!chars)
return false;
fprintf(gOutFile, "%s%s", i ? " " : "", strBytes.ptr());
fflush(gOutFile);
if (i)
utf8str.Append(' ');
AppendUTF16toUTF8(Substring(reinterpret_cast<const char16_t*>(chars),
length),
utf8str);
}
fputc('\n', gOutFile);
args.rval().setUndefined();
utf8str.Append('\n');
fputs(utf8str.get(), gOutFile);
fflush(gOutFile);
return true;
}
@ -276,7 +286,6 @@ static bool
Dump(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setUndefined();
if (!args.length())
@ -286,14 +295,22 @@ Dump(JSContext *cx, unsigned argc, jsval *vp)
if (!str)
return false;
JSAutoByteString bytes(cx, str);
if (!bytes)
size_t length;
const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
if (!chars)
return false;
NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const char16_t*>(chars),
length);
#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", bytes.ptr());
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
#endif
fputs(bytes.ptr(), gOutFile);
#ifdef XP_WIN
if (IsDebuggerPresent()) {
OutputDebugStringW(reinterpret_cast<const wchar_t*>(chars));
}
#endif
fputs(utf8str.get(), gOutFile);
fflush(gOutFile);
return true;
}

View File

@ -49,12 +49,11 @@ using namespace JS;
using mozilla::dom::indexedDB::IndexedDatabaseManager;
NS_IMPL_ISUPPORTS5(nsXPConnect,
NS_IMPL_ISUPPORTS4(nsXPConnect,
nsIXPConnect,
nsISupportsWeakReference,
nsIThreadObserver,
nsIJSRuntimeService,
nsIJSEngineTelemetryStats)
nsIJSRuntimeService)
nsXPConnect* nsXPConnect::gSelf = nullptr;
bool nsXPConnect::gOnceAliveNowDead = false;
@ -1407,29 +1406,6 @@ nsXPConnect::SetDebugModeWhenPossible(bool mode, bool allowSyncDisable)
return NS_OK;
}
NS_IMETHODIMP
nsXPConnect::GetTelemetryValue(JSContext *cx, MutableHandleValue rval)
{
RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
if (!obj)
return NS_ERROR_OUT_OF_MEMORY;
unsigned attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
size_t i = JS_SetProtoCalled(cx);
RootedValue v(cx, DoubleValue(i));
if (!JS_DefineProperty(cx, obj, "setProto", v, nullptr, nullptr, attrs))
return NS_ERROR_OUT_OF_MEMORY;
i = JS_GetCustomIteratorCount(cx);
v.setDouble(i);
if (!JS_DefineProperty(cx, obj, "customIter", v, nullptr, nullptr, attrs))
return NS_ERROR_OUT_OF_MEMORY;
rval.setObject(*obj);
return NS_OK;
}
NS_IMETHODIMP
nsXPConnect::NotifyDidPaint()
{

View File

@ -125,7 +125,6 @@
#include "nsAutoJSValHolder.h"
#include "MainThreadUtils.h"
#include "nsIJSEngineTelemetryStats.h"
#include "nsIConsoleService.h"
#include "nsIScriptError.h"
@ -269,8 +268,7 @@ AddToCCKind(JSGCTraceKind kind)
class nsXPConnect : public nsIXPConnect,
public nsIThreadObserver,
public nsSupportsWeakReference,
public nsIJSRuntimeService,
public nsIJSEngineTelemetryStats
public nsIJSRuntimeService
{
public:
// all the interface method declarations...
@ -278,7 +276,6 @@ public:
NS_DECL_NSIXPCONNECT
NS_DECL_NSITHREADOBSERVER
NS_DECL_NSIJSRUNTIMESERVICE
NS_DECL_NSIJSENGINETELEMETRYSTATS
// non-interface implementation
public:

View File

@ -49,6 +49,7 @@
#include "mozilla/Preferences.h"
#include "ActiveLayerTracker.h"
#include "nsContentUtils.h"
#include "nsPrintfCString.h"
#include <stdint.h>
#include <algorithm>
@ -1595,6 +1596,16 @@ nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder,
aCtx->FillRect(mVisibleRect);
}
#ifdef MOZ_DUMP_PAINTING
void
nsDisplaySolidColor::WriteDebugInfo(nsACString& aTo)
{
aTo += nsPrintfCString(" (rgba %d,%d,%d,%d)",
NS_GET_R(mColor), NS_GET_G(mColor),
NS_GET_B(mColor), NS_GET_A(mColor));
}
#endif
static void
RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
{
@ -2261,9 +2272,9 @@ nsDisplayThemedBackground::~nsDisplayThemedBackground()
#ifdef MOZ_DUMP_PAINTING
void
nsDisplayThemedBackground::WriteDebugInfo(FILE *aOutput)
nsDisplayThemedBackground::WriteDebugInfo(nsACString& aTo)
{
fprintf_stderr(aOutput, "(themed, appearance:%d) ", mAppearance);
aTo += nsPrintfCString(" (themed, appearance:%d)", mAppearance);
}
#endif
@ -2446,6 +2457,16 @@ nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder* aBuilder,
aOutFrames->AppendElement(mFrame);
}
#ifdef MOZ_DUMP_PAINTING
void
nsDisplayBackgroundColor::WriteDebugInfo(nsACString& aTo)
{
aTo += nsPrintfCString(" (rgba %d,%d,%d,%d)",
NS_GET_R(mColor), NS_GET_G(mColor),
NS_GET_B(mColor), NS_GET_A(mColor));
}
#endif
nsRect
nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
*aSnap = false;
@ -3195,6 +3216,14 @@ bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* a
return true;
}
#ifdef MOZ_DUMP_PAINTING
void
nsDisplayOpacity::WriteDebugInfo(nsACString& aTo)
{
aTo += nsPrintfCString(" (opacity %f)", mFrame->StyleDisplay()->mOpacity);
}
#endif
nsDisplayMixBlendMode::nsDisplayMixBlendMode(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
uint32_t aFlags)
@ -3699,6 +3728,15 @@ nsDisplayScrollLayer::GetScrollLayerCount()
#endif
}
#ifdef MOZ_DUMP_PAINTING
void
nsDisplayScrollLayer::WriteDebugInfo(nsACString& aTo)
{
aTo += nsPrintfCString(" (scrollframe %p scrolledframe %p)",
mScrollFrame, mScrolledFrame);
}
#endif
nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
nsDisplayListBuilder* aBuilder,
nsIFrame* aScrolledFrame,
@ -4856,7 +4894,7 @@ bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem
#ifdef MOZ_DUMP_PAINTING
void
nsDisplaySVGEffects::PrintEffects(FILE* aOutput)
nsDisplaySVGEffects::PrintEffects(nsACString& aTo)
{
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrSpecialSibling(mFrame);
@ -4865,32 +4903,32 @@ nsDisplaySVGEffects::PrintEffects(FILE* aOutput)
bool isOK = true;
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
bool first = true;
fprintf_stderr(aOutput, " effects=(");
aTo += " effects=(";
if (mFrame->StyleDisplay()->mOpacity != 1.0f) {
first = false;
fprintf_stderr(aOutput, "opacity(%f)", mFrame->StyleDisplay()->mOpacity);
aTo += nsPrintfCString("opacity(%f)", mFrame->StyleDisplay()->mOpacity);
}
if (clipPathFrame) {
if (!first) {
fprintf_stderr(aOutput, ", ");
aTo += ", ";
}
fprintf_stderr(aOutput, "clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
aTo += nsPrintfCString("clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
first = false;
}
if (effectProperties.GetFilterFrame(&isOK)) {
if (!first) {
fprintf_stderr(aOutput, ", ");
aTo += ", ";
}
fprintf_stderr(aOutput, "filter");
aTo += "filter";
first = false;
}
if (effectProperties.GetMaskFrame(&isOK)) {
if (!first) {
fprintf_stderr(aOutput, ", ");
aTo += ", ";
}
fprintf_stderr(aOutput, "mask");
aTo += "mask";
}
fprintf_stderr(aOutput, ")");
aTo += ")";
}
#endif

View File

@ -1178,7 +1178,7 @@ public:
*/
virtual const char* Name() = 0;
virtual void WriteDebugInfo(FILE *aOutput) {}
virtual void WriteDebugInfo(nsACString& aTo) {}
#endif
nsDisplayItem* GetAbove() { return mAbove; }
@ -1990,12 +1990,7 @@ public:
}
#ifdef MOZ_DUMP_PAINTING
virtual void WriteDebugInfo(FILE *aOutput) MOZ_OVERRIDE
{
fprintf_stderr(aOutput, "(rgba %d,%d,%d,%d)",
NS_GET_R(mColor), NS_GET_G(mColor),
NS_GET_B(mColor), NS_GET_A(mColor));
}
virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE;
#endif
NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR)
@ -2154,7 +2149,7 @@ public:
nsRegion* aInvalidRegion) MOZ_OVERRIDE;
#ifdef MOZ_DUMP_PAINTING
virtual void WriteDebugInfo(FILE *aOutput) MOZ_OVERRIDE;
virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE;
#endif
protected:
nsRect GetBoundsInternal();
@ -2207,12 +2202,7 @@ public:
NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR)
#ifdef MOZ_DUMP_PAINTING
virtual void WriteDebugInfo(FILE *aOutput) MOZ_OVERRIDE {
fprintf_stderr(aOutput, "(rgba %d,%d,%d,%d)",
NS_GET_R(mColor), NS_GET_G(mColor),
NS_GET_B(mColor), NS_GET_A(mColor));
}
virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE;
#endif
protected:
@ -2601,9 +2591,7 @@ public:
bool NeedsActiveLayer();
NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
#ifdef MOZ_DUMP_PAINTING
virtual void WriteDebugInfo(FILE *aOutput) MOZ_OVERRIDE {
fprintf_stderr(aOutput, "(opacity %f)", mFrame->StyleDisplay()->mOpacity);
}
virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE;
#endif
bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
@ -2835,6 +2823,10 @@ public:
virtual nsIFrame* GetScrolledFrame() { return mScrolledFrame; }
#ifdef MOZ_DUMP_PAINTING
virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE;
#endif
protected:
nsIFrame* mScrollFrame;
nsIFrame* mScrolledFrame;
@ -2967,7 +2959,7 @@ public:
LayerManager* aManager);
#ifdef MOZ_DUMP_PAINTING
void PrintEffects(FILE* aOutput);
void PrintEffects(nsACString& aTo);
#endif
private:

View File

@ -12,6 +12,7 @@
#include "nsFrame.h"
#include "nsDisplayList.h"
#include "FrameLayerBuilder.h"
#include "nsPrintfCString.h"
#include <stdio.h>
@ -120,11 +121,80 @@ nsLayoutDebugger::GetStyleSize(nsIPresShell* aPresentation,
#endif
#ifdef MOZ_DUMP_PAINTING
static int sPrintDisplayListIndent = 0;
static void
PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
FILE* aOutput, uint32_t aIndent, bool aDumpHtml);
static void
PrintDisplayItemTo(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem,
FILE* aOutput, uint32_t aIndent, bool aDumpSublist, bool aDumpHtml)
{
nsCString str;
if (!aDumpHtml) {
for (uint32_t indent = 0; indent < aIndent; indent++) {
str += " ";
}
}
nsIFrame* f = aItem->Frame();
nsAutoString fName;
#ifdef DEBUG
f->GetFrameName(fName);
#endif
bool snap;
nsRect rect = aItem->GetBounds(aBuilder, &snap);
nscolor color;
nsRect vis = aItem->GetVisibleRect();
nsRect component = aItem->GetComponentAlphaBounds(aBuilder);
nsDisplayList* list = aItem->GetChildren();
const DisplayItemClip& clip = aItem->GetClip();
nsRegion opaque;
#ifdef DEBUG
if (!list || list->DidComputeVisibility()) {
opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
}
#endif
if (aDumpHtml && aItem->Painted()) {
nsCString string(aItem->Name());
string.Append("-");
string.AppendInt((uint64_t)aItem);
str += nsPrintfCString("<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
}
str += nsPrintfCString("%s %p(%s) bounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s",
aItem->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
rect.x, rect.y, rect.width, rect.height,
vis.x, vis.y, vis.width, vis.height,
component.x, component.y, component.width, component.height,
clip.ToString().get(),
aItem->IsUniform(aBuilder, &color) ? " uniform" : "");
nsRegionRectIterator iter(opaque);
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
str += nsPrintfCString(" (opaque %d,%d,%d,%d)", r->x, r->y, r->width, r->height);
}
aItem->WriteDebugInfo(str);
if (aDumpHtml && aItem->Painted()) {
str += "</a>";
}
uint32_t key = aItem->GetPerFrameKey();
Layer* layer = mozilla::FrameLayerBuilder::GetDebugOldLayerFor(f, key);
if (layer) {
if (aDumpHtml) {
str += nsPrintfCString(" <a href=\"#%p\">layer=%p</a>", layer, layer);
} else {
str += nsPrintfCString(" layer=%p", layer);
}
}
if (aItem->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) {
(static_cast<nsDisplaySVGEffects*>(aItem))->PrintEffects(str);
}
fprintf_stderr(aOutput, "%s\n", str.get());
if (aDumpSublist && list) {
PrintDisplayListTo(aBuilder, *list, aOutput, aIndent+1, aDumpHtml);
}
}
static void
PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
FILE* aOutput, bool aDumpHtml)
FILE* aOutput, uint32_t aIndent, bool aDumpHtml)
{
if (aDumpHtml) {
fprintf_stderr(aOutput, "<ul>");
@ -133,71 +203,10 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
for (nsDisplayItem* i = aList.GetBottom(); i != nullptr; i = i->GetAbove()) {
if (aDumpHtml) {
fprintf_stderr(aOutput, "<li>");
} else {
sPrintDisplayListIndent ++;
for (int indent = 0; indent < sPrintDisplayListIndent; indent++) {
fprintf_stderr(aOutput, " ");
}
}
nsIFrame* f = i->Frame();
nsAutoString fName;
#ifdef DEBUG
f->GetFrameName(fName);
#endif
bool snap;
nsRect rect = i->GetBounds(aBuilder, &snap);
nscolor color;
nsRect vis = i->GetVisibleRect();
nsRect component = i->GetComponentAlphaBounds(aBuilder);
nsDisplayList* list = i->GetChildren();
const DisplayItemClip& clip = i->GetClip();
nsRegion opaque;
#ifdef DEBUG
if (!list || list->DidComputeVisibility()) {
opaque = i->GetOpaqueRegion(aBuilder, &snap);
}
#endif
if (aDumpHtml && i->Painted()) {
nsCString string(i->Name());
string.Append("-");
string.AppendInt((uint64_t)i);
fprintf_stderr(aOutput, "<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
}
fprintf_stderr(aOutput, "%s %p(%s) bounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s",
i->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
rect.x, rect.y, rect.width, rect.height,
vis.x, vis.y, vis.width, vis.height,
component.x, component.y, component.width, component.height,
clip.ToString().get(),
i->IsUniform(aBuilder, &color) ? " uniform" : "");
nsRegionRectIterator iter(opaque);
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
fprintf_stderr(aOutput, " (opaque %d,%d,%d,%d)", r->x, r->y, r->width, r->height);
}
i->WriteDebugInfo(aOutput);
if (aDumpHtml && i->Painted()) {
fprintf_stderr(aOutput, "</a>");
}
uint32_t key = i->GetPerFrameKey();
Layer* layer = mozilla::FrameLayerBuilder::GetDebugOldLayerFor(f, key);
if (layer) {
if (aDumpHtml) {
fprintf_stderr(aOutput, " <a href=\"#%p\">layer=%p</a>", layer, layer);
} else {
fprintf_stderr(aOutput, " layer=%p", layer);
}
}
if (i->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) {
(static_cast<nsDisplaySVGEffects*>(i))->PrintEffects(aOutput);
}
fprintf_stderr(aOutput, "\n");
if (list) {
PrintDisplayListTo(aBuilder, *list, aOutput, aDumpHtml);
}
PrintDisplayItemTo(aBuilder, i, aOutput, aIndent, true, aDumpHtml);
if (aDumpHtml) {
fprintf_stderr(aOutput, "</li>");
} else {
sPrintDisplayListIndent --;
}
}
@ -206,13 +215,23 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
}
}
void
nsFrame::PrintDisplayItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem,
FILE* aFile,
bool aDumpSublist,
bool aDumpHtml)
{
PrintDisplayItemTo(aBuilder, aItem, aFile, 0, aDumpSublist, aDumpHtml);
}
void
nsFrame::PrintDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayList& aList,
FILE* aFile,
bool aDumpHtml)
{
PrintDisplayListTo(aBuilder, aList, aFile, aDumpHtml);
PrintDisplayListTo(aBuilder, aList, aFile, 0, aDumpHtml);
}
static void
@ -226,7 +245,7 @@ PrintDisplayListSetItem(nsDisplayListBuilder* aBuilder,
fprintf_stderr(aFile, "<li>");
}
fprintf_stderr(aFile, "%s", aItemName);
PrintDisplayListTo(aBuilder, aList, aFile, aDumpHtml);
PrintDisplayListTo(aBuilder, aList, aFile, 0, aDumpHtml);
if (aDumpHtml) {
fprintf_stderr(aFile, "</li>");
}

View File

@ -328,34 +328,36 @@ nsBlockFrame::GetSplittableType() const
#ifdef DEBUG_FRAME_DUMP
void
nsBlockFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
nsBlockFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
{
ListGeneric(out, aIndent, aFlags);
nsCString str;
ListGeneric(str, aPrefix, aFlags);
fputs("<\n", out);
fprintf_stderr(out, "%s<\n", str.get());
aIndent++;
nsCString pfx(aPrefix);
pfx += " ";
// Output the lines
if (!mLines.empty()) {
const_line_iterator line = begin_lines(), line_end = end_lines();
for ( ; line != line_end; ++line) {
line->List(out, aIndent, aFlags);
line->List(out, pfx.get(), aFlags);
}
}
// Output the overflow lines.
const FrameLines* overflowLines = GetOverflowLines();
if (overflowLines && !overflowLines->mLines.empty()) {
IndentBy(out, aIndent);
fprintf(out, "Overflow-lines %p/%p <\n", overflowLines, &overflowLines->mFrames);
fprintf_stderr(out, "%sOverflow-lines %p/%p <\n", pfx.get(), overflowLines, &overflowLines->mFrames);
nsCString nestedPfx(pfx);
nestedPfx += " ";
const_line_iterator line = overflowLines->mLines.begin(),
line_end = overflowLines->mLines.end();
for ( ; line != line_end; ++line) {
line->List(out, aIndent + 1, aFlags);
line->List(out, nestedPfx.get(), aFlags);
}
IndentBy(out, aIndent);
fputs(">\n", out);
fprintf_stderr(out, "%s>\n", pfx.get());
}
// skip the principal list - we printed the lines above
@ -366,21 +368,20 @@ nsBlockFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
if (skip.Contains(lists.CurrentID())) {
continue;
}
IndentBy(out, aIndent);
fprintf(out, "%s %p <\n", mozilla::layout::ChildListName(lists.CurrentID()),
&GetChildList(lists.CurrentID()));
fprintf_stderr(out, "%s%s %p <\n", pfx.get(),
mozilla::layout::ChildListName(lists.CurrentID()),
&GetChildList(lists.CurrentID()));
nsCString nestedPfx(pfx);
nestedPfx += " ";
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
nsIFrame* kid = childFrames.get();
kid->List(out, aIndent + 1, aFlags);
kid->List(out, nestedPfx.get(), aFlags);
}
IndentBy(out, aIndent);
fputs(">\n", out);
fprintf_stderr(out, "%s>\n", pfx.get());
}
aIndent--;
IndentBy(out, aIndent);
fputs(">\n", out);
fprintf_stderr(out, "%s>\n", aPrefix);
}
NS_IMETHODIMP

View File

@ -172,7 +172,7 @@ public:
virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
#ifdef DEBUG_FRAME_DUMP
void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
#endif

View File

@ -29,6 +29,7 @@
#include "nsBlockFrame.h"
#include "mozilla/AutoRestore.h"
#include "nsIFrameInlines.h"
#include "nsPrintfCString.h"
#include <algorithm>
#ifdef DEBUG
@ -1821,26 +1822,28 @@ nsOverflowContinuationTracker::EndFinish(nsIFrame* aChild)
#ifdef DEBUG_FRAME_DUMP
void
nsContainerFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
nsContainerFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
{
ListGeneric(out, aIndent, aFlags);
nsCString str;
ListGeneric(str, aPrefix, aFlags);
// Output the children
bool outputOneList = false;
ChildListIterator lists(this);
for (; !lists.IsDone(); lists.Next()) {
if (outputOneList) {
IndentBy(out, aIndent);
str += aPrefix;
}
if (lists.CurrentID() != kPrincipalList) {
if (!outputOneList) {
fputs("\n", out);
IndentBy(out, aIndent);
str += "\n";
str += aPrefix;
}
fputs(mozilla::layout::ChildListName(lists.CurrentID()), out);
fprintf(out, " %p ", &GetChildList(lists.CurrentID()));
str += nsPrintfCString("%s %p ", mozilla::layout::ChildListName(lists.CurrentID()),
&GetChildList(lists.CurrentID()));
}
fputs("<\n", out);
fprintf_stderr(out, "%s<\n", str.get());
str = "";
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
nsIFrame* kid = childFrames.get();
@ -1848,15 +1851,16 @@ nsContainerFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");
// Have the child frame list
kid->List(out, aIndent + 1, aFlags);
nsCString pfx(aPrefix);
pfx += " ";
kid->List(out, pfx.get(), aFlags);
}
IndentBy(out, aIndent);
fputs(">\n", out);
fprintf_stderr(out, "%s>\n", aPrefix);
outputOneList = true;
}
if (!outputOneList) {
fputs("<>\n", out);
fprintf_stderr(out, "%s<>\n", str.get());
}
}
#endif

View File

@ -76,7 +76,7 @@ public:
bool aRespectClusters = true) MOZ_OVERRIDE;
#ifdef DEBUG_FRAME_DUMP
void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
#endif
// nsContainerFrame methods

View File

@ -431,10 +431,10 @@ nsFloatManager::List(FILE* out) const
for (uint32_t i = 0; i < mFloats.Length(); ++i) {
const FloatInfo &fi = mFloats[i];
printf("Float %u: frame=%p rect={%d,%d,%d,%d} ymost={l:%d, r:%d}\n",
i, static_cast<void*>(fi.mFrame),
fi.mRect.x, fi.mRect.y, fi.mRect.width, fi.mRect.height,
fi.mLeftYMost, fi.mRightYMost);
fprintf_stderr(out, "Float %u: frame=%p rect={%d,%d,%d,%d} ymost={l:%d, r:%d}\n",
i, static_cast<void*>(fi.mFrame),
fi.mRect.x, fi.mRect.y, fi.mRect.width, fi.mRect.height,
fi.mLeftYMost, fi.mRightYMost);
}
return NS_OK;
}

View File

@ -84,6 +84,7 @@
#include "mozilla/MouseEvents.h"
#include "mozilla/css/ImageLoader.h"
#include "mozilla/gfx/Tools.h"
#include "nsPrintfCString.h"
using namespace mozilla;
using namespace mozilla::css;
@ -5265,90 +5266,105 @@ int32_t nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
void
DebugListFrameTree(nsIFrame* aFrame)
{
((nsFrame*)aFrame)->List(stdout, 0);
((nsFrame*)aFrame)->List(stdout);
}
void
nsIFrame::ListTag(nsACString& aTo) const
{
ListTag(aTo, this);
}
/* static */
void
nsIFrame::ListTag(nsACString& aTo, const nsIFrame* aFrame) {
nsAutoString tmp;
aFrame->GetFrameName(tmp);
aTo += NS_ConvertUTF16toUTF8(tmp).get();
aTo += nsPrintfCString("@%p", static_cast<const void*>(aFrame));
}
// Debugging
void
nsIFrame::ListGeneric(FILE* out, int32_t aIndent, uint32_t aFlags) const
nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix, uint32_t aFlags) const
{
IndentBy(out, aIndent);
ListTag(out);
aTo =+ aPrefix;
ListTag(aTo);
if (HasView()) {
fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
aTo += nsPrintfCString(" [view=%p]", static_cast<void*>(GetView()));
}
if (GetNextSibling()) {
fprintf(out, " next=%p", static_cast<void*>(GetNextSibling()));
aTo += nsPrintfCString(" next=%p", static_cast<void*>(GetNextSibling()));
}
if (GetPrevContinuation()) {
bool fluid = GetPrevInFlow() == GetPrevContinuation();
fprintf(out, " prev-%s=%p", fluid?"in-flow":"continuation",
aTo += nsPrintfCString(" prev-%s=%p", fluid?"in-flow":"continuation",
static_cast<void*>(GetPrevContinuation()));
}
if (GetNextContinuation()) {
bool fluid = GetNextInFlow() == GetNextContinuation();
fprintf(out, " next-%s=%p", fluid?"in-flow":"continuation",
aTo += nsPrintfCString(" next-%s=%p", fluid?"in-flow":"continuation",
static_cast<void*>(GetNextContinuation()));
}
void* IBsibling = Properties().Get(IBSplitSpecialSibling());
if (IBsibling) {
fprintf(out, " IBSplitSpecialSibling=%p", IBsibling);
aTo += nsPrintfCString(" IBSplitSpecialSibling=%p", IBsibling);
}
void* IBprevsibling = Properties().Get(IBSplitSpecialPrevSibling());
if (IBprevsibling) {
fprintf(out, " IBSplitSpecialPrevSibling=%p", IBprevsibling);
aTo += nsPrintfCString(" IBSplitSpecialPrevSibling=%p", IBprevsibling);
}
fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
aTo += nsPrintfCString(" {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
nsIFrame* f = const_cast<nsIFrame*>(this);
if (f->HasOverflowAreas()) {
nsRect vo = f->GetVisualOverflowRect();
if (!vo.IsEqualEdges(mRect)) {
fprintf(out, " vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height);
aTo += nsPrintfCString(" vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height);
}
nsRect so = f->GetScrollableOverflowRect();
if (!so.IsEqualEdges(mRect)) {
fprintf(out, " scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height);
aTo += nsPrintfCString(" scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height);
}
}
if (0 != mState) {
fprintf(out, " [state=%016llx]", (unsigned long long)mState);
aTo += nsPrintfCString(" [state=%016llx]", (unsigned long long)mState);
}
if (IsTransformed()) {
fprintf(out, " transformed");
aTo += nsPrintfCString(" transformed");
}
if (ChildrenHavePerspective()) {
fprintf(out, " perspective");
aTo += nsPrintfCString(" perspective");
}
if (Preserves3DChildren()) {
fprintf(out, " preserves-3d-children");
aTo += nsPrintfCString(" preserves-3d-children");
}
if (Preserves3D()) {
fprintf(out, " preserves-3d");
aTo += nsPrintfCString(" preserves-3d");
}
if (mContent) {
fprintf(out, " [content=%p]", static_cast<void*>(mContent));
aTo += nsPrintfCString(" [content=%p]", static_cast<void*>(mContent));
}
fprintf(out, " [sc=%p", static_cast<void*>(mStyleContext));
aTo += nsPrintfCString(" [sc=%p", static_cast<void*>(mStyleContext));
if (mStyleContext) {
nsIAtom* pseudoTag = mStyleContext->GetPseudo();
if (pseudoTag) {
nsAutoString atomString;
pseudoTag->ToString(atomString);
fprintf(out, "%s", NS_LossyConvertUTF16toASCII(atomString).get());
aTo += nsPrintfCString("%s", NS_LossyConvertUTF16toASCII(atomString).get());
}
if (mParent && mStyleContext->GetParent() != mParent->StyleContext()) {
fprintf(out, ",parent=%p", mStyleContext->GetParent());
aTo += nsPrintfCString(",parent=%p", mStyleContext->GetParent());
}
}
fputs("]", out);
aTo += "]";
}
void
nsIFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
nsIFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
{
ListGeneric(out, aIndent, aFlags);
fputs("\n", out);
nsCString str;
ListGeneric(str, aPrefix, aFlags);
fprintf_stderr(out, "%s\n", str.get());
}
NS_IMETHODIMP
@ -5380,17 +5396,17 @@ nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
void
nsIFrame::DumpFrameTree()
{
RootFrameList(PresContext(), stdout, 0);
RootFrameList(PresContext(), stdout);
}
void
nsIFrame::DumpFrameTreeLimited()
{
List(stdout, 0);
List(stdout);
}
void
nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, const char* aPrefix)
{
if (!aPresContext || !out)
return;
@ -5399,7 +5415,7 @@ nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
if (shell) {
nsIFrame* frame = shell->FrameManager()->GetRootFrame();
if(frame) {
frame->List(out, aIndent);
frame->List(out, aPrefix);
}
}
}

View File

@ -711,6 +711,12 @@ public:
#ifdef MOZ_DUMP_PAINTING
public:
static void PrintDisplayItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem,
FILE* aFile = stdout,
bool aDumpSublist = false,
bool aDumpHtml = false);
static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayList& aList,
FILE* aFile = stdout,

View File

@ -335,12 +335,12 @@ nsFrameList::UnhookFrameFromSiblings(nsIFrame* aFrame)
void
nsFrameList::List(FILE* out) const
{
fputs("<\n", out);
fprintf_stderr(out, "<\n");
for (nsIFrame* frame = mFirstChild; frame;
frame = frame->GetNextSibling()) {
frame->List(out, 1);
frame->List(out, " ");
}
fputs(">\n", out);
fprintf_stderr(out, ">\n");
}
#endif

View File

@ -3252,22 +3252,23 @@ public:
ListTag(out, this);
}
static void ListTag(FILE* out, const nsIFrame* aFrame) {
nsAutoString tmp;
aFrame->GetFrameName(tmp);
fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
fprintf(out, "@%p", static_cast<const void*>(aFrame));
nsAutoCString t;
ListTag(t, aFrame);
fputs(t.get(), out);
}
void ListGeneric(FILE* out, int32_t aIndent, uint32_t aFlags) const;
void ListTag(nsACString& aTo) const;
static void ListTag(nsACString& aTo, const nsIFrame* aFrame);
void ListGeneric(nsACString& aTo, const char* aPrefix = "", uint32_t aFlags = 0) const;
enum {
TRAVERSE_SUBDOCUMENT_FRAMES = 0x01
};
virtual void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const;
virtual void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
/**
* lists the frames beginning from the root frame
* - calls root frame's List(...)
*/
static void RootFrameList(nsPresContext* aPresContext,
FILE* out, int32_t aIndent);
FILE* out = stderr, const char* aPrefix = "");
virtual void DumpFrameTree();
void DumpFrameTreeLimited();

View File

@ -1753,9 +1753,10 @@ nsImageFrame::GetFrameName(nsAString& aResult) const
}
void
nsImageFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
nsImageFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
{
ListGeneric(out, aIndent, aFlags);
nsCString str;
ListGeneric(str, aPrefix, aFlags);
// output the img src url
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
@ -1768,10 +1769,10 @@ nsImageFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
currentRequest->GetURI(getter_AddRefs(uri));
nsAutoCString uristr;
uri->GetAsciiSpec(uristr);
fprintf(out, " [src=%s]", uristr.get());
str += nsPrintfCString(" [src=%s]", uristr.get());
}
}
fputs("\n", out);
fprintf_stderr(out, "%s\n", str.get());
}
#endif

View File

@ -113,7 +113,7 @@ public:
#ifdef DEBUG_FRAME_DUMP
NS_IMETHOD GetFrameName(nsAString& aResult) const;
void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const;
void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
#endif
virtual int GetSkipSides(const nsHTMLReflowState* aReflowState = nullptr) const MOZ_OVERRIDE;

View File

@ -16,6 +16,7 @@
#include "nsIFrameInlines.h"
#include "mozilla/Assertions.h"
#include "mozilla/Likely.h"
#include "nsPrintfCString.h"
#ifdef DEBUG
static int32_t ctorCount;
@ -169,22 +170,22 @@ nsLineBox::Cleanup()
#ifdef DEBUG_FRAME_DUMP
static void
ListFloats(FILE* out, int32_t aIndent, const nsFloatCacheList& aFloats)
ListFloats(FILE* out, const char* aPrefix, const nsFloatCacheList& aFloats)
{
nsFloatCache* fc = aFloats.Head();
while (fc) {
nsFrame::IndentBy(out, aIndent);
nsCString str(aPrefix);
nsIFrame* frame = fc->mFloat;
fprintf(out, "floatframe@%p ", static_cast<void*>(frame));
str += nsPrintfCString("floatframe@%p ", static_cast<void*>(frame));
if (frame) {
nsAutoString frameName;
frame->GetFrameName(frameName);
fputs(NS_LossyConvertUTF16toASCII(frameName).get(), out);
str += NS_ConvertUTF16toUTF8(frameName).get();
}
else {
fputs("\n###!!! NULL out-of-flow frame", out);
str += "\n###!!! NULL out-of-flow frame";
}
fprintf(out, "\n");
fprintf_stderr(out, "%s\n", str.get());
fc = fc->Next();
}
}
@ -222,20 +223,30 @@ nsLineBox::StateToString(char* aBuf, int32_t aBufSize) const
void
nsLineBox::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
{
nsFrame::IndentBy(out, aIndent);
nsCString str;
while (aIndent-- > 0) {
str += " ";
}
List(out, str.get(), aFlags);
}
void
nsLineBox::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
{
nsCString str(aPrefix);
char cbuf[100];
fprintf(out, "line %p: count=%d state=%s ",
str += nsPrintfCString("line %p: count=%d state=%s ",
static_cast<const void*>(this), GetChildCount(),
StateToString(cbuf, sizeof(cbuf)));
if (IsBlock() && !GetCarriedOutBottomMargin().IsZero()) {
fprintf(out, "bm=%d ", GetCarriedOutBottomMargin().get());
str += nsPrintfCString("bm=%d ", GetCarriedOutBottomMargin().get());
}
fprintf(out, "{%d,%d,%d,%d} ",
str += nsPrintfCString("{%d,%d,%d,%d} ",
mBounds.x, mBounds.y, mBounds.width, mBounds.height);
if (mData &&
(!mData->mOverflowAreas.VisualOverflow().IsEqualEdges(mBounds) ||
!mData->mOverflowAreas.ScrollableOverflow().IsEqualEdges(mBounds))) {
fprintf(out, "vis-overflow=%d,%d,%d,%d scr-overflow=%d,%d,%d,%d ",
str += nsPrintfCString("vis-overflow=%d,%d,%d,%d scr-overflow=%d,%d,%d,%d ",
mData->mOverflowAreas.VisualOverflow().x,
mData->mOverflowAreas.VisualOverflow().y,
mData->mOverflowAreas.VisualOverflow().width,
@ -245,22 +256,22 @@ nsLineBox::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
mData->mOverflowAreas.ScrollableOverflow().width,
mData->mOverflowAreas.ScrollableOverflow().height);
}
fprintf(out, "<\n");
fprintf_stderr(out, "%s<\n", str.get());
nsIFrame* frame = mFirstChild;
int32_t n = GetChildCount();
nsCString pfx(aPrefix);
pfx += " ";
while (--n >= 0) {
frame->List(out, aIndent + 1, aFlags);
frame->List(out, pfx.get(), aFlags);
frame = frame->GetNextSibling();
}
if (HasFloats()) {
nsFrame::IndentBy(out, aIndent);
fputs("> floats <\n", out);
ListFloats(out, aIndent + 1, mInlineData->mFloats);
fprintf_stderr(out, "%s> floats <\n", aPrefix);
ListFloats(out, pfx.get(), mInlineData->mFloats);
}
nsFrame::IndentBy(out, aIndent);
fputs(">\n", out);
fprintf_stderr(out, "%s>\n", aPrefix);
}
#endif

View File

@ -500,6 +500,7 @@ public:
char* StateToString(char* aBuf, int32_t aBufSize) const;
void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const;
void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
nsIFrame* LastChild() const;
#endif

View File

@ -237,14 +237,15 @@ nsPlaceholderFrame::GetFrameName(nsAString& aResult) const
}
void
nsPlaceholderFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
nsPlaceholderFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
{
ListGeneric(out, aIndent, aFlags);
nsCString str;
ListGeneric(str, aPrefix, aFlags);
if (mOutOfFlowFrame) {
fprintf(out, " outOfFlowFrame=");
nsFrame::ListTag(out, mOutOfFlowFrame);
str += " outOfFlowFrame=";
nsFrame::ListTag(str, mOutOfFlowFrame);
}
fputs("\n", out);
fprintf_stderr(out, "%s\n", str.get());
}
#endif

View File

@ -112,7 +112,7 @@ public:
#endif // DEBUG || (MOZ_REFLOW_PERF_DSP && MOZ_REFLOW_PERF)
#ifdef DEBUG_FRAME_DUMP
void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
#endif // DEBUG

View File

@ -528,16 +528,19 @@ nsSubDocumentFrame::GetIntrinsicHeight()
#ifdef DEBUG_FRAME_DUMP
void
nsSubDocumentFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
nsSubDocumentFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
{
ListGeneric(out, aIndent, aFlags);
fputs("\n", out);
nsCString str;
ListGeneric(str, aPrefix, aFlags);
fprintf_stderr(out, "%s\n", str.get());
nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
if (aFlags & TRAVERSE_SUBDOCUMENT_FRAMES) {
nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame();
if (subdocRootFrame) {
subdocRootFrame->List(out, aIndent + 1);
nsCString pfx(aPrefix);
pfx += " ";
subdocRootFrame->List(out, pfx.get(), aFlags);
}
}
}

View File

@ -24,7 +24,7 @@ public:
nsSubDocumentFrame(nsStyleContext* aContext);
#ifdef DEBUG_FRAME_DUMP
void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
#endif

View File

@ -8503,21 +8503,22 @@ nsTextFrame::GetFrameName(nsAString& aResult) const
}
void
nsTextFrame::List(FILE* out, int32_t aIndent, uint32_t aFlags) const
nsTextFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
{
ListGeneric(out, aIndent, aFlags);
nsCString str;
ListGeneric(str, aPrefix, aFlags);
fprintf(out, " [run=%p]", static_cast<void*>(mTextRun));
str += nsPrintfCString(" [run=%p]", static_cast<void*>(mTextRun));
// Output the first/last content offset and prev/next in flow info
bool isComplete = uint32_t(GetContentEnd()) == GetContent()->TextLength();
fprintf(out, "[%d,%d,%c] ", GetContentOffset(), GetContentLength(),
str += nsPrintfCString("[%d,%d,%c] ", GetContentOffset(), GetContentLength(),
isComplete ? 'T':'F');
if (IsSelected()) {
fprintf(out, " SELECTED");
str += " SELECTED";
}
fputs("\n", out);
fprintf_stderr(out, "%s\n", str.get());
}
#endif

View File

@ -125,7 +125,7 @@ public:
virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE;
#ifdef DEBUG_FRAME_DUMP
void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const MOZ_OVERRIDE;
void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
void ToCString(nsCString& aBuf, int32_t* aTotalContentLength) const;
#endif

View File

@ -65,3 +65,6 @@ fi
# Enable the production cert for verifying signed packaged apps.
MOZ_B2G_CERTDATA=1
# Enable the "synthetic APKs" implementation of Open Web Apps.
MOZ_ANDROID_SYNTHAPKS=1

View File

@ -202,6 +202,7 @@ DataChannelConnection::DataChannelConnection(DataConnectionListener *listener) :
mDeferTimeout = 10;
mTimerRunning = false;
LOG(("Constructor DataChannelConnection=%p, listener=%p", this, mListener.get()));
mInternalIOThread = nullptr;
}
DataChannelConnection::~DataChannelConnection()
@ -219,6 +220,10 @@ DataChannelConnection::~DataChannelConnection()
RUN_ON_THREAD(mSTS, WrapRunnableNM(ReleaseTransportFlow, mTransportFlow.forget()),
NS_DISPATCH_NORMAL);
}
if (mInternalIOThread) {
mInternalIOThread->Shutdown();
}
}
void
@ -2252,15 +2257,53 @@ DataChannelConnection::SendBinary(DataChannel *channel, const char *data,
return SendMsgInternal(channel, data, len, ppid_final);
}
class ReadBlobRunnable : public nsRunnable {
public:
ReadBlobRunnable(DataChannelConnection* aConnection, uint16_t aStream,
nsIInputStream* aBlob) :
mConnection(aConnection),
mStream(aStream),
mBlob(aBlob)
{ }
NS_IMETHODIMP Run() {
mConnection->ReadBlob(mStream, mBlob);
return NS_OK;
}
private:
// The lifetime of DataChannelConnection will be longer than ReadBlobRunnable.
// In ~DataChannelConnection(), it calls mInternalIOThread::Shutdown to make
// sure all the jobs are ran.
DataChannelConnection* mConnection;
uint16_t mStream;
// Use RefCount for preventing the object is deleted when SendBlob returns.
nsRefPtr<nsIInputStream> mBlob;
};
int32_t
DataChannelConnection::SendBlob(uint16_t stream, nsIInputStream *aBlob)
{
DataChannel *channel = mStreams[stream];
NS_ENSURE_TRUE(channel, 0);
// Spawn a thread to send the data
if (!mInternalIOThread) {
nsresult res = NS_NewThread(getter_AddRefs(mInternalIOThread));
if (NS_FAILED(res)) {
return -1;
}
}
LOG(("Sending blob to stream %u", stream));
nsCOMPtr<nsIRunnable> runnable = new ReadBlobRunnable(this, stream, aBlob);
mInternalIOThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
return 0;
}
int32_t
DataChannelConnection::ReadBlob(uint16_t aStream, nsIInputStream* aBlob)
{
DataChannel *channel = mStreams[aStream];
NS_ENSURE_TRUE(channel, 0);
// XXX to do this safely, we must enqueue these atomically onto the
// output socket. We need a sender thread(s?) to enque data into the
// socket and to avoid main-thread IO that might block. Even on a
@ -2269,29 +2312,20 @@ DataChannelConnection::SendBlob(uint16_t stream, nsIInputStream *aBlob)
// For now as a hack, send as a single blast of queued packets which may
// be deferred until buffer space is available.
nsAutoPtr<nsCString> temp(new nsCString());
nsCString temp;
uint64_t len;
aBlob->Available(&len);
nsresult rv = NS_ReadInputStreamToString(aBlob, *temp, len);
nsresult rv = NS_ReadInputStreamToString(aBlob, temp, len);
NS_ENSURE_SUCCESS(rv, 0);
aBlob->Close();
//aBlob->Release(); We didn't AddRef() the way WebSocket does in OutboundMessage (yet)
// Consider if it makes sense to split the message ourselves for
// transmission, at least on RELIABLE channels. Sending large blobs via
// unreliable channels requires some level of application involvement, OR
// sending them at big, single messages, which if large will probably not
// get through.
// XXX For now, send as one large binary message. We should also signal
// (via PPID) that it's a blob.
const char *data = temp.get()->BeginReading();
len = temp.get()->Length();
return SendBinary(channel, data, len,
DATA_CHANNEL_PPID_BINARY, DATA_CHANNEL_PPID_BINARY_LAST);
nsCOMPtr<nsIThread> mainThread;
NS_GetMainThread(getter_AddRefs(mainThread));
RUN_ON_THREAD(mainThread, WrapRunnable(nsRefPtr<DataChannelConnection>(this),
&DataChannelConnection::SendBinaryMsg,
aStream, temp),
NS_DISPATCH_NORMAL);
return 0;
}
int32_t

View File

@ -189,6 +189,8 @@ public:
friend class DataChannel;
Mutex mLock;
int32_t ReadBlob(uint16_t aStream, nsIInputStream* aBlob);
protected:
friend class DataChannelOnMessageAvailable;
// Avoid cycles with PeerConnectionImpl
@ -287,6 +289,7 @@ private:
nsCOMPtr<nsITimer> mDeferredTimer;
uint32_t mDeferTimeout; // in ms
bool mTimerRunning;
nsCOMPtr<nsIThread> mInternalIOThread;
};
#define ENSURE_DATACONNECTION \

View File

@ -1,53 +1,72 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "CertVerifier.h"
#include "nsNSSComponent.h"
#include "nsServiceManagerUtils.h"
#include <stdint.h>
#include "insanity/pkixtypes.h"
#include "ExtendedValidation.h"
#include "NSSCertDBTrustDomain.h"
#include "cert.h"
#include "ocsp.h"
#include "secerr.h"
#include "prerror.h"
#include "sslerr.h"
// ScopedXXX in this file are insanity::pkix::ScopedXXX, not
// mozilla::ScopedXXX.
using namespace insanity::pkix;
using namespace mozilla::psm;
#ifdef PR_LOGGING
extern PRLogModuleInfo* gPIPNSSLog;
#ifdef MOZ_LOGGING
static PRLogModuleInfo* gCertVerifierLog = nullptr;
#endif
namespace mozilla { namespace psm {
extern SECStatus getFirstEVPolicy(CERTCertificate *cert, SECOidTag &outOidTag);
extern CERTCertList* getRootsForOid(SECOidTag oid_tag);
const CertVerifier::Flags CertVerifier::FLAG_LOCAL_ONLY = 1;
const CertVerifier::Flags CertVerifier::FLAG_NO_DV_FALLBACK_FOR_EV = 2;
CertVerifier::CertVerifier(missing_cert_download_config mcdc,
CertVerifier::CertVerifier(implementation_config ic,
missing_cert_download_config mcdc,
crl_download_config cdc,
ocsp_download_config odc,
ocsp_strict_config osc,
ocsp_get_config ogc)
: mMissingCertDownloadEnabled(mcdc == missing_cert_download_on)
: mImplementation(ic)
, mMissingCertDownloadEnabled(mcdc == missing_cert_download_on)
, mCRLDownloadEnabled(cdc == crl_download_allowed)
, mOCSPDownloadEnabled(odc == ocsp_on)
, mOCSPStrict(osc == ocsp_strict)
, mOCSPGETEnabled(ogc == ocsp_get_enabled)
{
MOZ_COUNT_CTOR(CertVerifier);
}
CertVerifier::~CertVerifier()
{
MOZ_COUNT_DTOR(CertVerifier);
}
void
InitCertVerifierLog()
{
#ifdef MOZ_LOGGING
if (!gCertVerifierLog) {
gCertVerifierLog = PR_NewLogModule("certverifier");
}
#endif
}
static SECStatus
ClassicVerifyCert(CERTCertificate * cert,
ClassicVerifyCert(CERTCertificate* cert,
const SECCertificateUsage usage,
const PRTime time,
nsIInterfaceRequestor * pinArg,
/*optional out*/ CERTCertList **validationChain,
/*optional out*/ CERTVerifyLog *verifyLog)
void* pinArg,
/*optional out*/ ScopedCERTCertList* validationChain,
/*optional out*/ CERTVerifyLog* verifyLog)
{
SECStatus rv;
SECCertUsage enumUsage;
@ -94,20 +113,18 @@ ClassicVerifyCert(CERTCertificate * cert,
}
}
if (usage == certificateUsageSSLServer) {
/* SSL server cert verification has always used CERT_VerifyCert, so we
* continue to use it for SSL cert verification to minimize the risk of
* there being any differnce in results between CERT_VerifyCert and
* CERT_VerifyCertificate.
*/
// SSL server cert verification has always used CERT_VerifyCert, so we
// continue to use it for SSL cert verification to minimize the risk of
// there being any differnce in results between CERT_VerifyCert and
// CERT_VerifyCertificate.
rv = CERT_VerifyCert(CERT_GetDefaultCertDB(), cert, true,
certUsageSSLServer, time, pinArg, verifyLog);
} else {
rv = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), cert, true,
usage, time, pinArg,
verifyLog, nullptr);
usage, time, pinArg, verifyLog, nullptr);
}
if (rv == SECSuccess && validationChain) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: getting chain in 'classic' \n"));
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("VerifyCert: getting chain in 'classic' \n"));
*validationChain = CERT_GetCertChainFromCert(cert, time, enumUsage);
if (!*validationChain) {
rv = SECFailure;
@ -116,17 +133,37 @@ ClassicVerifyCert(CERTCertificate * cert,
return rv;
}
#ifndef NSS_NO_LIBPKIX
static void
destroyCertListThatShouldNotExist(CERTCertList** certChain)
{
PR_ASSERT(certChain);
PR_ASSERT(!*certChain);
if (certChain && *certChain) {
// There SHOULD not be a validation chain on failure, asserion here for
// the debug builds AND a fallback for production builds
CERT_DestroyCertList(*certChain);
*certChain = nullptr;
}
}
#endif
SECStatus
CertVerifier::VerifyCert(CERTCertificate * cert,
CertVerifier::VerifyCert(CERTCertificate* cert,
/*optional*/ const SECItem* stapledOCSPResponse,
const SECCertificateUsage usage,
const PRTime time,
nsIInterfaceRequestor * pinArg,
void* pinArg,
const Flags flags,
/*optional out*/ CERTCertList **validationChain,
/*optional out*/ SECOidTag *evOidPolicy,
/*optional out*/ CERTVerifyLog *verifyLog)
/*optional out*/ ScopedCERTCertList* validationChain,
/*optional out*/ SECOidTag* evOidPolicy,
/*optional out*/ CERTVerifyLog* verifyLog)
{
if (!cert) {
if (!cert ||
((flags & FLAG_NO_DV_FALLBACK_FOR_EV) &&
(usage != certificateUsageSSLServer || !evOidPolicy)))
{
PR_NOT_REACHED("Invalid arguments to CertVerifier::VerifyCert");
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
@ -147,28 +184,21 @@ CertVerifier::VerifyCert(CERTCertificate * cert,
case certificateUsageStatusResponder:
break;
default:
NS_WARNING("Calling VerifyCert with invalid usage");
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
#ifndef NSS_NO_LIBPKIX
ScopedCERTCertList trustAnchors;
SECStatus rv;
SECOidTag evPolicy = SEC_OID_UNKNOWN;
#ifdef NSS_NO_LIBPKIX
if (flags & FLAG_NO_DV_FALLBACK_FOR_EV) {
return SECSuccess;
}
return ClassicVerifyCert(cert, usage, time, pinArg, validationChain,
verifyLog);
#else
// Do EV checking only for sslserver usage
if (usage == certificateUsageSSLServer) {
SECStatus srv = getFirstEVPolicy(cert, evPolicy);
SECStatus srv = GetFirstEVPolicy(cert, evPolicy);
if (srv == SECSuccess) {
if (evPolicy != SEC_OID_UNKNOWN) {
trustAnchors = getRootsForOid(evPolicy);
trustAnchors = GetRootsForOid(evPolicy);
}
if (!trustAnchors) {
return SECFailure;
@ -184,8 +214,8 @@ CertVerifier::VerifyCert(CERTCertificate * cert,
evPolicy = SEC_OID_UNKNOWN;
}
}
MOZ_ASSERT_IF(evPolicy != SEC_OID_UNKNOWN, trustAnchors);
PR_ASSERT(evPolicy == SEC_OID_UNKNOWN || trustAnchors);
size_t i = 0;
size_t validationChainLocation = 0;
@ -197,14 +227,14 @@ CertVerifier::VerifyCert(CERTCertificate * cert,
++i;
}
if (validationChain) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: setting up validation chain outparam.\n"));
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("VerifyCert: setting up validation chain outparam.\n"));
validationChainLocation = i;
cvout[i].type = cert_po_certList;
cvout[i].value.pointer.cert = nullptr;
cvout[i].value.pointer.chain = nullptr;
++i;
validationTrustAnchorLocation = i;
cvout[i].type = cert_po_trustAnchor;
cvout[i].value.pointer.chain = nullptr;
cvout[i].value.pointer.cert = nullptr;
++i;
}
cvout[i].type = cert_po_end;
@ -274,9 +304,9 @@ CertVerifier::VerifyCert(CERTCertificate * cert,
cvin[i].value.arraySize = 1;
cvin[i].value.array.oids = &evPolicy;
++i;
MOZ_ASSERT(trustAnchors);
PR_ASSERT(trustAnchors);
cvin[i].type = cert_pi_trustAnchors;
cvin[i].value.pointer.chain = trustAnchors;
cvin[i].value.pointer.chain = trustAnchors.get();
++i;
cvin[i].type = cert_pi_end;
@ -286,25 +316,21 @@ CertVerifier::VerifyCert(CERTCertificate * cert,
if (evOidPolicy) {
*evOidPolicy = evPolicy;
}
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("VerifyCert: successful CERT_PKIXVerifyCert(ev) \n"));
goto pkix_done;
}
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("VerifyCert: failed CERT_PKIXVerifyCert(ev)\n"));
if (validationChain && *validationChain) {
// There SHOULD not be a validation chain on failure, asserion here for
// the debug builds AND a fallback for production builds
MOZ_ASSERT(false,
"certPKIXVerifyCert returned failure AND a validationChain");
CERT_DestroyCertList(*validationChain);
*validationChain = nullptr;
if (validationChain) {
destroyCertListThatShouldNotExist(
&cvout[validationChainLocation].value.pointer.chain);
}
if (verifyLog) {
// Cleanup the log so that it is ready the the next validation
CERTVerifyLogNode *i_node;
CERTVerifyLogNode* i_node;
for (i_node = verifyLog->head; i_node; i_node = i_node->next) {
//destroy cert if any.
if (i_node->cert) {
@ -318,20 +344,29 @@ CertVerifier::VerifyCert(CERTCertificate * cert,
}
}
#endif
// If we're here, PKIX EV verification failed.
// If requested, don't do DV fallback.
if (flags & FLAG_NO_DV_FALLBACK_FOR_EV) {
PR_ASSERT(*evOidPolicy == SEC_OID_UNKNOWN);
return SECSuccess;
}
if (!nsNSSComponent::globalConstFlagUsePKIXVerification){
if (mImplementation == classic) {
// XXX: we do not care about the localOnly flag (currently) as the
// caller that wants localOnly should disable and reenable the fetching.
return ClassicVerifyCert(cert, usage, time, pinArg, validationChain,
verifyLog);
}
#ifdef NSS_NO_LIBPKIX
PR_NOT_REACHED("libpkix implementation chosen but not even compiled in");
PR_SetError(PR_INVALID_STATE_ERROR, 0);
return SECFailure;
#else
PR_ASSERT(mImplementation == libpkix);
// The current flags check the chain the same way as the leafs
rev.leafTests.cert_rev_flags_per_method[cert_revocation_method_crl] =
rev.chainTests.cert_rev_flags_per_method[cert_revocation_method_crl] =
@ -376,7 +411,7 @@ CertVerifier::VerifyCert(CERTCertificate * cert,
// ocsp enabled controls network fetching, too
| ((mOCSPDownloadEnabled && !localOnly) ?
CERT_REV_M_ALLOW_NETWORK_FETCHING : CERT_REV_M_FORBID_NETWORK_FETCHING)
| (mOCSPGETEnabled ? 0 : CERT_REV_M_FORCE_POST_METHOD_FOR_OCSP);
;
@ -391,12 +426,12 @@ CertVerifier::VerifyCert(CERTCertificate * cert,
// Skip EV parameters
cvin[evParamLocation].type = cert_pi_end;
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: calling CERT_PKIXVerifyCert(dv) \n"));
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("VerifyCert: calling CERT_PKIXVerifyCert(dv) \n"));
rv = CERT_PKIXVerifyCert(cert, usage, cvin, cvout, pinArg);
pkix_done:
if (validationChain) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: validation chain requested\n"));
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("VerifyCert: validation chain requested\n"));
ScopedCERTCertificate trustAnchor(cvout[validationTrustAnchorLocation].value.pointer.cert);
if (rv == SECSuccess) {
@ -404,30 +439,27 @@ pkix_done:
PR_SetError(PR_UNKNOWN_ERROR, 0);
return SECFailure;
}
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: I have a chain\n"));
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("VerifyCert: I have a chain\n"));
*validationChain = cvout[validationChainLocation].value.pointer.chain;
if (trustAnchor) {
// we should only add the issuer to the chain if it is not already
// present. On CA cert checking, the issuer is the same cert, so in
// that case we do not add the cert to the chain.
if (!CERT_CompareCerts(trustAnchor, cert)) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("VerifyCert: adding issuer to tail for display\n"));
if (!CERT_CompareCerts(trustAnchor.get(), cert)) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("VerifyCert: adding issuer to tail for display\n"));
// note: rv is reused to catch errors on cert creation!
ScopedCERTCertificate tempCert(CERT_DupCertificate(trustAnchor));
rv = CERT_AddCertToListTail(*validationChain, tempCert);
ScopedCERTCertificate tempCert(CERT_DupCertificate(trustAnchor.get()));
rv = CERT_AddCertToListTail(validationChain->get(), tempCert.get());
if (rv == SECSuccess) {
tempCert.forget(); // ownership traferred to validationChain
tempCert.release(); // ownership traferred to validationChain
} else {
CERT_DestroyCertList(*validationChain);
*validationChain = nullptr;
}
}
}
} else {
// Validation was a fail, clean up if needed
if (cvout[validationChainLocation].value.pointer.chain) {
CERT_DestroyCertList(cvout[validationChainLocation].value.pointer.chain);
}
destroyCertListThatShouldNotExist(
&cvout[validationChainLocation].value.pointer.chain);
}
}
@ -435,17 +467,55 @@ pkix_done:
#endif
}
TemporaryRef<CertVerifier>
GetDefaultCertVerifier()
SECStatus
CertVerifier::VerifySSLServerCert(CERTCertificate* peerCert,
/*optional*/ const SECItem* stapledOCSPResponse,
PRTime time,
/*optional*/ void* pinarg,
const char* hostname,
bool saveIntermediatesInPermanentDatabase,
/*optional out*/ insanity::pkix::ScopedCERTCertList* certChainOut,
/*optional out*/ SECOidTag* evOidPolicy)
{
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
PR_ASSERT(peerCert);
// XXX: PR_ASSERT(pinarg)
PR_ASSERT(hostname);
PR_ASSERT(hostname[0]);
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID));
RefPtr<CertVerifier> certVerifier;
if (nssComponent) {
(void) nssComponent->GetDefaultCertVerifier(certVerifier);
if (certChainOut) {
*certChainOut = nullptr;
}
return certVerifier;
if (evOidPolicy) {
*evOidPolicy = SEC_OID_UNKNOWN;
}
if (!hostname || !hostname[0]) {
PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
return SECFailure;
}
ScopedCERTCertList validationChain;
SECStatus rv = VerifyCert(peerCert, stapledOCSPResponse,
certificateUsageSSLServer, time,
pinarg, 0, &validationChain, evOidPolicy);
if (rv != SECSuccess) {
return rv;
}
rv = CERT_VerifyCertName(peerCert, hostname);
if (rv != SECSuccess) {
return rv;
}
if (saveIntermediatesInPermanentDatabase) {
SaveIntermediateCerts(validationChain);
}
if (certChainOut) {
*certChainOut = validationChain.release();
}
return SECSuccess;
}
} } // namespace mozilla::psm

View File

@ -1,3 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
@ -5,21 +7,14 @@
#ifndef mozilla_psm__CertVerifier_h
#define mozilla_psm__CertVerifier_h
#include "mozilla/RefPtr.h"
#include "CryptoUtil.h"
#include "nsISupportsImpl.h"
#include "certt.h"
class nsIInterfaceRequestor;
class nsNSSComponent;
#include "insanity/pkixtypes.h"
namespace mozilla { namespace psm {
class CertVerifier
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CertVerifier)
typedef unsigned int Flags;
// XXX: FLAG_LOCAL_ONLY is ignored in the classic verification case
static const Flags FLAG_LOCAL_ONLY;
@ -28,14 +23,33 @@ public:
// *evOidPolicy == SEC_OID_UNKNOWN means the cert is NOT EV
// Only one usage per verification is supported.
SECStatus VerifyCert(CERTCertificate * cert,
SECStatus VerifyCert(CERTCertificate* cert,
/*optional*/ const SECItem* stapledOCSPResponse,
const SECCertificateUsage usage,
const PRTime time,
nsIInterfaceRequestor * pinArg,
void* pinArg,
const Flags flags = 0,
/*optional out*/ CERTCertList **validationChain = nullptr,
/*optional out*/ SECOidTag *evOidPolicy = nullptr ,
/*optional out*/ CERTVerifyLog *verifyLog = nullptr);
/*optional out*/ insanity::pkix::ScopedCERTCertList* validationChain = nullptr,
/*optional out*/ SECOidTag* evOidPolicy = nullptr ,
/*optional out*/ CERTVerifyLog* verifyLog = nullptr);
SECStatus VerifySSLServerCert(
CERTCertificate* peerCert,
/*optional*/ const SECItem* stapledOCSPResponse,
PRTime time,
/*optional*/ void* pinarg,
const char* hostname,
bool saveIntermediatesInPermanentDatabase = false,
/*optional out*/ insanity::pkix::ScopedCERTCertList* certChainOut = nullptr,
/*optional out*/ SECOidTag* evOidPolicy = nullptr);
enum implementation_config {
classic = 0,
#ifndef NSS_NO_LIBPKIX
libpkix = 1,
#endif
};
enum missing_cert_download_config { missing_cert_download_off = 0, missing_cert_download_on };
enum crl_download_config { crl_local_only = 0, crl_download_allowed };
@ -45,22 +59,21 @@ public:
bool IsOCSPDownloadEnabled() const { return mOCSPDownloadEnabled; }
private:
CertVerifier(missing_cert_download_config ac, crl_download_config cdc,
ocsp_download_config odc, ocsp_strict_config osc,
ocsp_get_config ogc);
CertVerifier(implementation_config ic, missing_cert_download_config ac,
crl_download_config cdc, ocsp_download_config odc,
ocsp_strict_config osc, ocsp_get_config ogc);
~CertVerifier();
public:
const implementation_config mImplementation;
const bool mMissingCertDownloadEnabled;
const bool mCRLDownloadEnabled;
const bool mOCSPDownloadEnabled;
const bool mOCSPStrict;
const bool mOCSPGETEnabled;
friend class ::nsNSSComponent;
};
MOZ_WARN_UNUSED_RESULT TemporaryRef<CertVerifier> GetDefaultCertVerifier();
void InitCertVerifierLog();
} } // namespace mozilla::psm
#endif // mozilla_psm__CertVerifier_h

View File

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* 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/. */
#ifndef mozilla_psm_ExtendedValidation_h
#define mozilla_psm_ExtendedValidation_h
#include "certt.h"
#include "prtypes.h"
namespace mozilla { namespace psm {
#ifndef NSS_NO_LIBPKIX
void EnsureIdentityInfoLoaded();
SECStatus GetFirstEVPolicy(CERTCertificate *cert, SECOidTag &outOidTag);
CERTCertList* GetRootsForOid(SECOidTag oid_tag);
void CleanupIdentityInfo();
#endif
} } // namespace mozilla::psm
#endif // mozilla_psm_ExtendedValidation_h

View File

@ -0,0 +1,272 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "NSSCertDBTrustDomain.h"
#include <stdint.h>
#include "insanity/ScopedPtr.h"
#include "certdb.h"
#include "nss.h"
#include "ocsp.h"
#include "pk11pub.h"
#include "prerror.h"
#include "prmem.h"
#include "prprf.h"
#include "secerr.h"
#include "secmod.h"
using namespace insanity::pkix;
namespace mozilla { namespace psm {
const char BUILTIN_ROOTS_MODULE_DEFAULT_NAME[] = "Builtin Roots Module";
namespace {
inline void PORT_Free_string(char* str) { PORT_Free(str); }
typedef ScopedPtr<SECMODModule, SECMOD_DestroyModule> ScopedSECMODModule;
static char*
nss_addEscape(const char* string, char quote)
{
char* newString = 0;
int escapes = 0, size = 0;
const char* src;
char* dest;
for (src = string; *src; src++) {
if ((*src == quote) || (*src == '\\')) {
escapes++;
}
size++;
}
newString = (char*) PORT_ZAlloc(escapes + size + 1);
if (!newString) {
return nullptr;
}
for (src = string, dest = newString; *src; src++, dest++) {
if ((*src == quote) || (*src == '\\')) {
*dest++ = '\\';
}
*dest = *src;
}
return newString;
}
} // unnamed namespace
SECStatus
InitializeNSS(const char* dir, bool readOnly)
{
// The NSS_INIT_NOROOTINIT flag turns off the loading of the root certs
// module by NSS_Initialize because we will load it in InstallLoadableRoots
// later. It also allows us to work around a bug in the system NSS in
// Ubuntu 8.04, which loads any nonexistent "<configdir>/libnssckbi.so" as
// "/usr/lib/nss/libnssckbi.so".
uint32_t flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
if (readOnly) {
flags |= NSS_INIT_READONLY;
}
return ::NSS_Initialize(dir, "", "", SECMOD_DB, flags);
}
void
DisableMD5()
{
NSS_SetAlgorithmPolicy(SEC_OID_MD5,
0, NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_CMS_SIGNATURE);
NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
0, NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_CMS_SIGNATURE);
NSS_SetAlgorithmPolicy(SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC,
0, NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_CMS_SIGNATURE);
}
SECStatus
LoadLoadableRoots(/*optional*/ const char* dir, const char* modNameUTF8)
{
PR_ASSERT(modNameUTF8);
if (!modNameUTF8) {
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
return SECFailure;
}
ScopedPtr<char, PR_FreeLibraryName> fullLibraryPath(
PR_GetLibraryName(dir, "nssckbi"));
if (!fullLibraryPath) {
return SECFailure;
}
ScopedPtr<char, PORT_Free_string> escaped_fullLibraryPath(
nss_addEscape(fullLibraryPath.get(), '\"'));
if (!escaped_fullLibraryPath) {
return SECFailure;
}
// If a module exists with the same name, delete it.
int modType;
SECMOD_DeleteModule(modNameUTF8, &modType);
ScopedPtr<char, PR_smprintf_free> pkcs11ModuleSpec(
PR_smprintf("name=\"%s\" library=\"%s\"", modNameUTF8,
escaped_fullLibraryPath.get()));
if (!pkcs11ModuleSpec) {
return SECFailure;
}
ScopedSECMODModule rootsModule(SECMOD_LoadUserModule(pkcs11ModuleSpec.get(),
nullptr, false));
if (!rootsModule) {
return SECFailure;
}
if (!rootsModule->loaded) {
PR_SetError(PR_INVALID_STATE_ERROR, 0);
return SECFailure;
}
return SECSuccess;
}
void
UnloadLoadableRoots(const char* modNameUTF8)
{
PR_ASSERT(modNameUTF8);
ScopedSECMODModule rootsModule(SECMOD_FindModule(modNameUTF8));
if (rootsModule) {
SECMOD_UnloadUserModule(rootsModule.get());
}
}
void
SetClassicOCSPBehavior(CertVerifier::ocsp_download_config enabled,
CertVerifier::ocsp_strict_config strict,
CertVerifier::ocsp_get_config get)
{
CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB());
if (enabled == CertVerifier::ocsp_off) {
CERT_DisableOCSPChecking(CERT_GetDefaultCertDB());
} else {
CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
}
SEC_OcspFailureMode failureMode = strict == CertVerifier::ocsp_strict
? ocspMode_FailureIsVerificationFailure
: ocspMode_FailureIsNotAVerificationFailure;
(void) CERT_SetOCSPFailureMode(failureMode);
CERT_ForcePostMethodForOCSP(get != CertVerifier::ocsp_get_enabled);
int OCSPTimeoutSeconds = 3;
if (strict == CertVerifier::ocsp_strict) {
OCSPTimeoutSeconds = 10;
}
CERT_SetOCSPTimeout(OCSPTimeoutSeconds);
}
char*
DefaultServerNicknameForCert(CERTCertificate* cert)
{
char* nickname = nullptr;
int count;
bool conflict;
char* servername = nullptr;
servername = CERT_GetCommonName(&cert->subject);
if (!servername) {
// Certs without common names are strange, but they do exist...
// Let's try to use another string for the nickname
servername = CERT_GetOrgUnitName(&cert->subject);
if (!servername) {
servername = CERT_GetOrgName(&cert->subject);
if (!servername) {
servername = CERT_GetLocalityName(&cert->subject);
if (!servername) {
servername = CERT_GetStateName(&cert->subject);
if (!servername) {
servername = CERT_GetCountryName(&cert->subject);
if (!servername) {
// We tried hard, there is nothing more we can do.
// A cert without any names doesn't really make sense.
return nullptr;
}
}
}
}
}
}
count = 1;
while (1) {
if (count == 1) {
nickname = PR_smprintf("%s", servername);
}
else {
nickname = PR_smprintf("%s #%d", servername, count);
}
if (!nickname) {
break;
}
conflict = SEC_CertNicknameConflict(nickname, &cert->derSubject,
cert->dbhandle);
if (!conflict) {
break;
}
PR_Free(nickname);
count++;
}
PR_FREEIF(servername);
return nickname;
}
void
SaveIntermediateCerts(const ScopedCERTCertList& certList)
{
if (!certList) {
return;
}
bool isEndEntity = true;
for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
!CERT_LIST_END(node, certList);
node = CERT_LIST_NEXT(node)) {
if (isEndEntity) {
// Skip the end-entity; we only want to store intermediates
isEndEntity = false;
continue;
}
if (node->cert->slot) {
// This cert was found on a token, no need to remember it in the temp db.
continue;
}
if (node->cert->isperm) {
// We don't need to remember certs already stored in perm db.
continue;
}
// We have found a signer cert that we want to remember.
char* nickname = DefaultServerNicknameForCert(node->cert);
if (nickname && *nickname) {
ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalKeySlot());
if (slot) {
PK11_ImportCert(slot.get(), node->cert, CK_INVALID_HANDLE,
nickname, false);
}
}
PR_FREEIF(nickname);
}
}
} } // namespace mozilla::psm

View File

@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_psm__NSSCertDBTrustDomain_h
#define mozilla_psm__NSSCertDBTrustDomain_h
#include "insanity/pkixtypes.h"
#include "secmodt.h"
#include "CertVerifier.h"
namespace mozilla { namespace psm {
SECStatus InitializeNSS(const char* dir, bool readOnly);
void DisableMD5();
extern const char BUILTIN_ROOTS_MODULE_DEFAULT_NAME[];
// The dir parameter is the path to the directory containing the NSS builtin
// roots module. Usually this is the same as the path to the other NSS shared
// libraries. If it is null then the (library) path will be searched.
//
// The modNameUTF8 parameter should usually be
// BUILTIN_ROOTS_MODULE_DEFAULT_NAME.
SECStatus LoadLoadableRoots(/*optional*/ const char* dir,
const char* modNameUTF8);
void UnloadLoadableRoots(const char* modNameUTF8);
// Controls the OCSP fetching behavior of the classic verification mode. In the
// classic mode, the OCSP fetching behavior is set globally instead of per
// validation.
void
SetClassicOCSPBehavior(CertVerifier::ocsp_download_config enabled,
CertVerifier::ocsp_strict_config strict,
CertVerifier::ocsp_get_config get);
// Caller must free the result with PR_Free
char* DefaultServerNicknameForCert(CERTCertificate* cert);
void SaveIntermediateCerts(const insanity::pkix::ScopedCERTCertList& certList);
} } // namespace mozilla::psm
#endif // mozilla_psm__NSSCertDBTrustDomain_h

View File

@ -0,0 +1,21 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
UNIFIED_SOURCES += [
'CertVerifier.cpp',
'NSSCertDBTrustDomain.cpp',
]
if not CONFIG['NSS_NO_LIBPKIX']:
UNIFIED_SOURCES += [
'ExtendedValidation.cpp',
]
LOCAL_INCLUDES += [
'../insanity/include',
]
FINAL_LIBRARY = 'xul'

View File

@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* Copyright 2013 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.
*/
#ifndef insanity_pkix__ScopedPtr_h
#define insanity_pkix__ScopedPtr_h
// GCC does not understand nullptr until 4.6
#ifdef __GNUC__
#if __GNUC__ * 100 + __GNUC_MINOR__ < 406
#define nullptr __null
#endif
#endif
namespace insanity { namespace pkix {
// Similar to boost::scoped_ptr and std::unique_ptr. Does not support copying
// or assignment.
template <typename T, void (*Destroyer)(T*)>
class ScopedPtr
{
public:
explicit ScopedPtr(T* value = nullptr) : mValue(value) { }
~ScopedPtr()
{
if (mValue) {
Destroyer(mValue);
}
}
void operator=(T* newValue)
{
if (mValue) {
Destroyer(mValue);
}
mValue = newValue;
}
T& operator*() const { return *mValue; }
T* operator->() const { return mValue; }
operator bool() const { return mValue; }
T* get() const { return mValue; }
T* release()
{
T* result = mValue;
mValue = nullptr;
return result;
}
void reset() { *this = nullptr; }
protected:
T* mValue;
ScopedPtr(const ScopedPtr&) /* = delete */;
void operator=(const ScopedPtr&) /* = delete */;
};
template <typename T, void(*Destroyer)(T*)>
inline bool
operator==(T* a, const ScopedPtr<T, Destroyer>& b)
{
return a == b.get();
}
template <typename T, void(*Destroyer)(T*)>
inline bool
operator==(const ScopedPtr<T, Destroyer>& a, T* b)
{
return a.get() == b;
}
template <typename T, void(*Destroyer)(T*)>
inline bool
operator!=(T* a, const ScopedPtr<T, Destroyer>& b)
{
return a != b.get();
}
template <typename T, void(*Destroyer)(T*)>
inline bool
operator!=(const ScopedPtr<T, Destroyer>& a, T* b)
{
return a.get() != b;
}
} } // namespace insanity::pkix
#endif // insanity_pkix__ScopedPtr_h

View File

@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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.
*/
#ifndef insanity_pkix__pkixtypes_h
#define insanity_pkix__pkixtypes_h
#include "insanity/ScopedPtr.h"
#include "plarena.h"
#include "cert.h"
#include "keyhi.h"
namespace insanity { namespace pkix {
typedef ScopedPtr<PLArenaPool, PL_FreeArenaPool> ScopedPLArenaPool;
typedef ScopedPtr<CERTCertificate, CERT_DestroyCertificate>
ScopedCERTCertificate;
typedef ScopedPtr<CERTCertList, CERT_DestroyCertList> ScopedCERTCertList;
typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey>
ScopedSECKEYPublicKey;
} } // namespace insanity::pkix
#endif // insanity_pkix__pkixtypes_h

File diff suppressed because it is too large Load Diff

View File

@ -11,13 +11,14 @@
namespace mozilla { namespace psm {
SECStatus AuthCertificateHook(void *arg, PRFileDesc *fd,
SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd,
PRBool checkSig, PRBool isServer);
// EnsureServerVerificationInitialized() posts an event to a cert
// verification thread to run nsINSSComponent::EnsureIdentityInfoLoaded()
// exactly once. It must be called from socket thread.
void EnsureServerVerificationInitialized();
} } // namespace mozilla::psm
#endif

View File

@ -0,0 +1,29 @@
/* 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/. */
#ifndef mozilla_psm__SharedCertVerifier_h
#define mozilla_psm__SharedCertVerifier_h
#include "certt.h"
#include "CertVerifier.h"
#include "mozilla/RefPtr.h"
namespace mozilla { namespace psm {
class SharedCertVerifier : public mozilla::psm::CertVerifier,
public mozilla::AtomicRefCounted<SharedCertVerifier>
{
public:
SharedCertVerifier(implementation_config ic, missing_cert_download_config ac,
crl_download_config cdc, ocsp_download_config odc,
ocsp_strict_config osc, ocsp_get_config ogc)
: mozilla::psm::CertVerifier(ic, ac, cdc, odc, osc, ogc)
{
}
~SharedCertVerifier();
};
} } // namespace mozilla::psm
#endif // mozilla_psm__SharedCertVerifier_h

View File

@ -136,7 +136,6 @@ SharedSSLState::SharedSSLState()
, mMutex("SharedSSLState::mMutex")
, mSocketCreated(false)
, mOCSPStaplingEnabled(false)
, mOCSPFetchingEnabled(false)
{
mIOLayerHelpers.Init();
mClientAuthRemember->Init();

View File

@ -36,9 +36,8 @@ public:
// Main-thread only
void ResetStoredData();
void NotePrivateBrowsingStatus();
void SetOCSPOptions(bool fetchingEnabled, bool staplingEnabled)
void SetOCSPStaplingEnabled(bool staplingEnabled)
{
mOCSPFetchingEnabled = fetchingEnabled;
mOCSPStaplingEnabled = staplingEnabled;
}
@ -48,7 +47,6 @@ public:
static void NoteCertOverrideServiceInstantiated();
static void NoteCertDBServiceInstantiated();
bool IsOCSPStaplingEnabled() const { return mOCSPStaplingEnabled; }
bool IsOCSPFetchingEnabled() const { return mOCSPFetchingEnabled; }
private:
void Cleanup();
@ -63,7 +61,6 @@ private:
Mutex mMutex;
bool mSocketCreated;
bool mOCSPStaplingEnabled;
bool mOCSPFetchingEnabled;
};
SharedSSLState* PublicSSLState();

View File

@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TransportSecurityInfo.h"
#include "insanity/pkixtypes.h"
#include "nsNSSComponent.h"
#include "nsIWebProgressListener.h"
#include "nsNSSCertificate.h"
@ -20,7 +22,6 @@
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "PSMRunnable.h"
#include "ScopedNSSTypes.h"
#include "secerr.h"
@ -43,8 +44,7 @@ TransportSecurityInfo::TransportSecurityInfo()
mSubRequestsNoSecurity(0),
mErrorCode(0),
mErrorMessageType(PlainErrorMessage),
mPort(0),
mIsCertIssuerBlacklisted(false)
mPort(0)
{
}
@ -758,7 +758,7 @@ AppendErrorTextMismatch(const nsString &host,
const char16_t *params[1];
nsresult rv;
ScopedCERTCertificate nssCert;
insanity::pkix::ScopedCERTCertificate nssCert;
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
if (cert2)
@ -783,7 +783,7 @@ AppendErrorTextMismatch(const nsString &host,
bool useSAN = false;
if (nssCert)
useSAN = GetSubjectAltNames(nssCert, component, allNames, nameCount);
useSAN = GetSubjectAltNames(nssCert.get(), component, allNames, nameCount);
if (!useSAN) {
char *certName = nullptr;

View File

@ -73,13 +73,6 @@ public:
nsSSLStatus* SSLStatus() { return mSSLStatus; }
void SetStatusErrorBits(nsIX509Cert & cert, uint32_t collected_errors);
bool IsCertIssuerBlacklisted() const {
return mIsCertIssuerBlacklisted;
}
void SetCertIssuerBlacklisted() {
mIsCertIssuerBlacklisted = true;
}
private:
mutable ::mozilla::Mutex mMutex;
@ -102,7 +95,6 @@ private:
int32_t mPort;
nsXPIDLCString mHostName;
PRErrorCode mIsCertIssuerBlacklisted;
/* SSL Status */
mozilla::RefPtr<nsSSLStatus> mSSLStatus;

View File

@ -16,7 +16,6 @@ EXPORTS.mozilla += [
]
UNIFIED_SOURCES += [
'CertVerifier.cpp',
'CryptoTask.cpp',
'nsCertificatePrincipal.cpp',
'nsCertOverrideService.cpp',
@ -27,7 +26,6 @@ UNIFIED_SOURCES += [
'nsCMSSecureMessage.cpp',
'nsCrypto.cpp',
'nsDataSignatureVerifier.cpp',
'nsIdentityChecking.cpp',
'nsKeygenHandler.cpp',
'nsKeygenThread.cpp',
'nsKeyModule.cpp',
@ -93,6 +91,12 @@ UNIFIED_SOURCES += [
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'../../../certverifier',
'../../../insanity/include',
]
DEFINES['NSS_ENABLE_ECC'] = 'True'
for var in ('DLL_PREFIX', 'DLL_SUFFIX'):
DEFINES[var] = '"%s"' % CONFIG[var]

View File

@ -3,9 +3,11 @@
* 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/. */
#include "nsISupports.h"
#include "nsCMS.h"
#include "CertVerifier.h"
#include "insanity/pkixtypes.h"
#include "nsISupports.h"
#include "nsNSSHelper.h"
#include "nsNSSCertificate.h"
#include "smime.h"
@ -14,7 +16,6 @@
#include "nsIArray.h"
#include "nsArrayUtils.h"
#include "nsCertVerificationThread.h"
#include "ScopedNSSTypes.h"
#include "prlog.h"
@ -213,7 +214,7 @@ nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, uint32_
NSSCMSSignedData *sigd = nullptr;
NSSCMSSignerInfo *si;
int32_t nsigners;
RefPtr<CertVerifier> certVerifier;
RefPtr<SharedCertVerifier> certVerifier;
nsresult rv = NS_ERROR_FAILURE;
if (!NSS_CMSMessage_IsSigned(m_cmsMsg)) {
@ -263,7 +264,7 @@ nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, uint32_
NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
{
SECStatus srv = certVerifier->VerifyCert(si->cert,
SECStatus srv = certVerifier->VerifyCert(si->cert, nullptr,
certificateUsageEmailSigner,
PR_Now(), nullptr /*XXX pinarg*/);
if (srv != SECSuccess) {
@ -514,8 +515,8 @@ NS_IMETHODIMP nsCMSMessage::CreateEncrypted(nsIArray * aRecipientCerts)
if (!nssRecipientCert)
return NS_ERROR_FAILURE;
ScopedCERTCertificate c(nssRecipientCert->GetCert());
recipientCerts.set(i, c);
insanity::pkix::ScopedCERTCertificate c(nssRecipientCert->GetCert());
recipientCerts.set(i, c.get());
}
// Find a bulk key algorithm //
@ -552,8 +553,8 @@ NS_IMETHODIMP nsCMSMessage::CreateEncrypted(nsIArray * aRecipientCerts)
// Create and attach recipient information //
for (i=0; i < recipientCertCount; i++) {
ScopedCERTCertificate rc(recipientCerts.get(i));
if ((recipientInfo = NSS_CMSRecipientInfo_Create(m_cmsMsg, rc)) == nullptr) {
insanity::pkix::ScopedCERTCertificate rc(recipientCerts.get(i));
if ((recipientInfo = NSS_CMSRecipientInfo_Create(m_cmsMsg, rc.get())) == nullptr) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create recipient info\n"));
goto loser;
}
@ -583,8 +584,8 @@ NS_IMETHODIMP nsCMSMessage::CreateSigned(nsIX509Cert* aSigningCert, nsIX509Cert*
NSSCMSContentInfo *cinfo;
NSSCMSSignedData *sigd;
NSSCMSSignerInfo *signerinfo;
ScopedCERTCertificate scert;
ScopedCERTCertificate ecert;
insanity::pkix::ScopedCERTCertificate scert;
insanity::pkix::ScopedCERTCertificate ecert;
nsCOMPtr<nsIX509Cert2> aSigningCert2 = do_QueryInterface(aSigningCert);
nsresult rv = NS_ERROR_FAILURE;
@ -639,7 +640,7 @@ NS_IMETHODIMP nsCMSMessage::CreateSigned(nsIX509Cert* aSigningCert, nsIX509Cert*
/*
* create & attach signer information
*/
if ((signerinfo = NSS_CMSSignerInfo_Create(m_cmsMsg, scert, SEC_OID_SHA1))
if ((signerinfo = NSS_CMSSignerInfo_Create(m_cmsMsg, scert.get(), SEC_OID_SHA1))
== nullptr) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signer info\n"));
goto loser;
@ -665,15 +666,15 @@ NS_IMETHODIMP nsCMSMessage::CreateSigned(nsIX509Cert* aSigningCert, nsIX509Cert*
}
if (ecert) {
if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ecert,
CERT_GetDefaultCertDB())
if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ecert.get(),
CERT_GetDefaultCertDB())
!= SECSuccess) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime enc key prefs\n"));
goto loser;
}
if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ecert,
CERT_GetDefaultCertDB())
if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ecert.get(),
CERT_GetDefaultCertDB())
!= SECSuccess) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add MS smime enc key prefs\n"));
goto loser;
@ -681,10 +682,10 @@ NS_IMETHODIMP nsCMSMessage::CreateSigned(nsIX509Cert* aSigningCert, nsIX509Cert*
// If signing and encryption cert are identical, don't add it twice.
bool addEncryptionCert =
(ecert && (!scert || !CERT_CompareCerts(ecert, scert)));
(ecert && (!scert || !CERT_CompareCerts(ecert.get(), scert.get())));
if (addEncryptionCert &&
NSS_CMSSignedData_AddCertificate(sigd, ecert) != SECSuccess) {
NSS_CMSSignedData_AddCertificate(sigd, ecert.get()) != SECSuccess) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add own encryption certificate\n"));
goto loser;
}

View File

@ -5,7 +5,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCertOverrideService.h"
#include "insanity/pkixtypes.h"
#include "nsIX509Cert.h"
#include "NSSCertDBTrustDomain.h"
#include "nsNSSCertificate.h"
#include "nsNSSCertHelper.h"
#include "nsCRT.h"
@ -29,7 +32,7 @@
#include "ssl.h" // For SSL_ClearSessionCache
using namespace mozilla;
using mozilla::psm::SharedSSLState;
using namespace mozilla::psm;
static const char kCertOverrideFileName[] = "cert_override.txt";
@ -391,11 +394,11 @@ GetCertFingerprintByOidTag(nsIX509Cert *aCert,
if (!cert2)
return NS_ERROR_FAILURE;
ScopedCERTCertificate nsscert(cert2->GetCert());
insanity::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
if (!nsscert)
return NS_ERROR_FAILURE;
return GetCertFingerprintByOidTag(nsscert, aOidTag, fp);
return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp);
}
static nsresult
@ -429,11 +432,11 @@ GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
if (!cert2)
return NS_ERROR_FAILURE;
ScopedCERTCertificate nsscert(cert2->GetCert());
insanity::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
if (!nsscert)
return NS_ERROR_FAILURE;
return GetCertFingerprintByDottedOidString(nsscert, dottedOid, fp);
return GetCertFingerprintByDottedOidString(nsscert.get(), dottedOid, fp);
}
NS_IMETHODIMP
@ -452,11 +455,11 @@ nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, in
if (!cert2)
return NS_ERROR_FAILURE;
ScopedCERTCertificate nsscert(cert2->GetCert());
insanity::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
if (!nsscert)
return NS_ERROR_FAILURE;
char* nickname = nsNSSCertificate::defaultServerNickname(nsscert);
char* nickname = DefaultServerNicknameForCert(nsscert.get());
if (!aTemporary && nickname && *nickname)
{
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
@ -465,7 +468,7 @@ nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, in
return NS_ERROR_FAILURE;
}
SECStatus srv = PK11_ImportCert(slot, nsscert, CK_INVALID_HANDLE,
SECStatus srv = PK11_ImportCert(slot, nsscert.get(), CK_INVALID_HANDLE,
nickname, false);
if (srv != SECSuccess) {
PR_Free(nickname);
@ -475,7 +478,7 @@ nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, in
PR_FREEIF(nickname);
nsAutoCString fpStr;
nsresult rv = GetCertFingerprintByOidTag(nsscert,
nsresult rv = GetCertFingerprintByOidTag(nsscert.get(),
mOidTagForStoringNewHashes, fpStr);
if (NS_FAILED(rv))
return rv;

Some files were not shown because too many files have changed in this diff Show More