mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
13915a840a
2
CLOBBER
2
CLOBBER
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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") {
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
224
dom/encoding/test/unit/test_misc.js
Normal file
224
dom/encoding/test/unit/test_misc.js
Normal 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
@ -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"
|
||||
);
|
166
dom/encoding/test/unit/test_utf.js
Normal file
166
dom/encoding/test/unit/test_utf.js
Normal 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");
|
@ -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]
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
35
dom/webidl/WorkerConsole.webidl
Normal file
35
dom/webidl/WorkerConsole.webidl
Normal 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;
|
||||
};
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
interface WorkerGlobalScope : EventTarget {
|
||||
readonly attribute WorkerGlobalScope self;
|
||||
readonly attribute WorkerConsole console;
|
||||
readonly attribute WorkerLocation location;
|
||||
|
||||
void close();
|
||||
|
@ -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
561
dom/workers/Console.cpp
Normal 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
112
dom/workers/Console.h
Normal 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
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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',
|
||||
|
104
dom/workers/test/console_worker.js
Normal file
104
dom/workers/test/console_worker.js
Normal 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});
|
||||
}
|
||||
}
|
@ -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]
|
||||
|
44
dom/workers/test/test_console.html
Normal file
44
dom/workers/test/test_console.html
Normal 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>
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -25,5 +25,10 @@ GetCurrentSwitchState(SwitchDevice aDevice) {
|
||||
return SWITCH_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
void
|
||||
NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
|
@ -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
|
||||
|
@ -171,6 +171,7 @@ parent:
|
||||
DisableSwitchNotifications(SwitchDevice aDevice);
|
||||
sync GetCurrentSwitchState(SwitchDevice aDevice)
|
||||
returns (SwitchState aState);
|
||||
NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState);
|
||||
|
||||
FactoryReset();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'mozIJSSubScriptLoader.idl',
|
||||
'nsIJSEngineTelemetryStats.idl',
|
||||
'nsIJSRuntimeService.idl',
|
||||
'nsIScriptError.idl',
|
||||
'nsIXPConnect.idl',
|
||||
|
@ -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;
|
||||
};
|
@ -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();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/***************************************************************************/
|
||||
/***************************************************************************/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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>");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
|
@ -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
|
File diff suppressed because it is too large
Load Diff
23
security/certverifier/ExtendedValidation.h
Normal file
23
security/certverifier/ExtendedValidation.h
Normal 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
|
272
security/certverifier/NSSCertDBTrustDomain.cpp
Normal file
272
security/certverifier/NSSCertDBTrustDomain.cpp
Normal 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
|
48
security/certverifier/NSSCertDBTrustDomain.h
Normal file
48
security/certverifier/NSSCertDBTrustDomain.h
Normal 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
|
21
security/certverifier/moz.build
Normal file
21
security/certverifier/moz.build
Normal 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'
|
104
security/insanity/include/insanity/ScopedPtr.h
Normal file
104
security/insanity/include/insanity/ScopedPtr.h
Normal 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
|
38
security/insanity/include/insanity/pkixtypes.h
Normal file
38
security/insanity/include/insanity/pkixtypes.h
Normal 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
@ -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
|
||||
|
29
security/manager/ssl/src/SharedCertVerifier.h
Normal file
29
security/manager/ssl/src/SharedCertVerifier.h
Normal 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
|
@ -136,7 +136,6 @@ SharedSSLState::SharedSSLState()
|
||||
, mMutex("SharedSSLState::mMutex")
|
||||
, mSocketCreated(false)
|
||||
, mOCSPStaplingEnabled(false)
|
||||
, mOCSPFetchingEnabled(false)
|
||||
{
|
||||
mIOLayerHelpers.Init();
|
||||
mClientAuthRemember->Init();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user