Merge mozilla-central to autoland. a=merge CLOSED TREE

This commit is contained in:
Brindusan Cristian 2018-04-25 00:57:49 +03:00
commit 9265429dcd
365 changed files with 8323 additions and 24765 deletions

View File

@ -70,6 +70,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/EventStates.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/MouseEvents.h"
@ -758,10 +759,12 @@ Accessible::TakeFocus()
}
}
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(focusContent));
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm)
if (fm) {
AutoHandlingUserInputStatePusher inputStatePusher(true, nullptr, focusContent->OwnerDoc());
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(focusContent));
fm->SetFocus(element, 0);
}
}
void

View File

@ -40,6 +40,7 @@
#include "nsFocusManager.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/EventStates.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/TextEditor.h"
@ -325,6 +326,7 @@ DocAccessible::TakeFocus()
// Focus the document.
nsFocusManager* fm = nsFocusManager::GetFocusManager();
nsCOMPtr<nsIDOMElement> newFocus;
AutoHandlingUserInputStatePusher inputStatePusher(true, nullptr, mDocumentNode);
fm->MoveFocus(mDocumentNode->GetWindow(), nullptr,
nsFocusManager::MOVEFOCUS_ROOT, 0, getter_AddRefs(newFocus));
}

View File

@ -163,7 +163,10 @@
atEnd: true
},
{ focused: "input[type=text]" }),
new ExpectedTextSelectionChanged(0, 0)],
new ExpectedTextSelectionChanged(0, 0,
// Bug 1455749: Fix granularity control in text entries.
{ android_todo: true }
)],
[ContentMessages.simpleMovePrevious,
new ExpectedCursorChange(
[ "So we don't get dessert?", {string: "label"} ]),

View File

@ -1273,11 +1273,7 @@ pref("browser.newtabpage.enabled", true);
// Activity Stream prefs that control to which page to redirect
pref("browser.newtabpage.activity-stream.prerender", true);
#ifndef RELEASE_OR_BETA
#ifdef MOZILLA_OFFICIAL
pref("browser.newtabpage.activity-stream.debug", false);
#else
pref("browser.newtabpage.activity-stream.debug", true);
#endif
#endif
pref("browser.library.activity-stream.enabled", true);

View File

@ -197,7 +197,7 @@ skip-if = os == 'mac' # Save as PDF not supported on Mac OS X
[browser_ext_themes_validation.js]
[browser_ext_url_overrides_newtab.js]
[browser_ext_user_events.js]
skip-if = debug
skip-if = debug || os == "linux" #Bug 1381305
[browser_ext_webRequest.js]
[browser_ext_webNavigation_frameId0.js]
[browser_ext_webNavigation_getFrames.js]

View File

@ -13,7 +13,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"nsIAboutNewTabService");
const IS_RELEASE_OR_BETA = AppConstants.RELEASE_OR_BETA;
const MOZILLA_OFFICIAL = AppConstants.MOZILLA_OFFICIAL;
const ACTIVITY_STREAM_PRERENDER_URL = "resource://activity-stream/prerendered/en-US/activity-stream-prerendered.html";
const ACTIVITY_STREAM_PRERENDER_DEBUG_URL = "resource://activity-stream/prerendered/static/activity-stream-prerendered-debug.html";
@ -135,16 +134,6 @@ add_task(function test_locale() {
"The locale for testing should be en-US");
});
add_task(async function test_debug_mode() {
if (!IS_RELEASE_OR_BETA && !MOZILLA_OFFICIAL) { // Check if local build
Assert.equal(aboutNewTabService.activityStreamDebug, true,
"Debug mode is set for builds that are not official");
} else {
Assert.equal(aboutNewTabService.activityStreamDebug, false,
"Debug mode is not set for any other builds");
}
});
/**
* Tests reponse to updates to prefs
*/
@ -206,9 +195,6 @@ function setBoolPrefAndWaitForChange(pref, value, testMessage) {
function setupASPrerendered() {
// Don't run in debug mode regardless of build type
Services.prefs.setBoolPref(ACTIVITY_STREAM_DEBUG_PREF, false);
if (Services.prefs.getBoolPref(ACTIVITY_STREAM_PRERENDER_PREF)) {
return Promise.resolve();
}

View File

@ -175,6 +175,16 @@ https://trac.torproject.org/projects/tor/ticket/1517
// and check if it is rounded
for (let timeStampCode of timeStampCodesDOM) {
let timeStamp = eval(timeStampCode);
// Audio Contexts increment in intervals of (minimum) 5.4ms, so we don't
// clamp/jitter if the timer precision is les than that.
// (Technically on MBPs they increment in intervals of 2.6 but this is
// non-standard and will eventually be changed. We don't cover this situation
// because we don't really support arbitrary Timer Precision, especially in
// the 2.6 - 5.4ms interval.)
if (timeStampCode.includes("audioContext") && expectedPrecision < 5.4)
continue;
ok(isRounded(timeStamp, expectedPrecision),
"pref: " + prefname + " - '" +
"'" + timeStampCode +

View File

@ -670,7 +670,7 @@ function prompt(aBrowser, aRequest) {
stream.getTracks().forEach(t => t.stop());
return;
}
video.src = chromeWin.URL.createObjectURL(stream);
video.srcObject = stream;
video.stream = stream;
doc.getElementById("webRTC-preview").hidden = false;
video.onloadedmetadata = function(e) {

View File

@ -150,7 +150,7 @@ skip-if = (os == "win" && ccov) # Bug 1453549
skip-if = ccov # Bug 1441545
[browser_dbg-babel-stepping.js]
[browser_dbg-babel-preview.js]
skip-if = (os == "win" && ccov) # Bug 1448523
skip-if = (os == "win" && ccov) || (os == "win" && !debug) # Bug 1448523, Bug 1448450
[browser_dbg-breaking.js]
[browser_dbg-breaking-from-console.js]
[browser_dbg-breakpoints.js]

View File

@ -5,7 +5,7 @@ code, and optionally help with indentation.
# Upgrade
Currently used version is 5.36.0. To upgrade: download a new version of
Currently used version is 5.37.0. To upgrade: download a new version of
CodeMirror from the project's page [1] and replace all JavaScript and
CSS files inside the codemirror directory [2].

View File

@ -137,12 +137,14 @@
CodeMirror.registerHelper("fold", "xml", function(cm, start) {
var iter = new Iter(cm, start.line, 0);
for (;;) {
var openTag = toNextTag(iter), end;
if (!openTag || !(end = toTagEnd(iter)) || iter.line != start.line) return;
var openTag = toNextTag(iter)
if (!openTag || iter.line != start.line) return
var end = toTagEnd(iter)
if (!end) return
if (!openTag[1] && end != "selfClose") {
var startPos = Pos(iter.line, iter.ch);
var endPos = findMatchingClose(iter, openTag[2]);
return endPos && {from: startPos, to: endPos.from};
return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null
}
}
});

View File

@ -90,7 +90,7 @@
var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
var searchFor = hasBoundary ? new RegExp("\\b" + query.replace(/[\\\[+*?(){|^$]/g, "\\$&") + "\\b") : query;
var searchFor = hasBoundary ? new RegExp("\\b" + query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") + "\\b") : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
{className: "CodeMirror-selection-highlight-scrollbar"});
}

File diff suppressed because one or more lines are too long

View File

@ -307,6 +307,7 @@
"Backspace": function(cm) { killRegion(cm, false) || killTo(cm, byChar, -1, false); },
"Alt-F": move(byWord, 1), "Alt-B": move(byWord, -1),
"Alt-Right": move(byWord, 1), "Alt-Left": move(byWord, -1),
"Alt-D": function(cm) { killTo(cm, byWord, 1, "grow"); },
"Alt-Backspace": function(cm) { killTo(cm, byWord, -1, "grow"); },

View File

@ -93,6 +93,8 @@
{ keys: 'gE', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }},
{ keys: '{', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: false, toJumplist: true }},
{ keys: '}', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: true, toJumplist: true }},
{ keys: '(', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: false }},
{ keys: ')', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: true }},
{ keys: '<C-f>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }},
{ keys: '<C-b>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }},
{ keys: '<C-d>', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true }},
@ -423,6 +425,9 @@
function isWhiteSpaceString(k) {
return (/^\s*$/).test(k);
}
function isEndOfSentenceSymbol(k) {
return '.?!'.indexOf(k) != -1;
}
function inArray(val, arr) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == val) {
@ -866,7 +871,7 @@
if (vim.insertMode) { command = handleKeyInsertMode(); }
else { command = handleKeyNonInsertMode(); }
if (command === false) {
return undefined;
return !vim.insertMode && key.length === 1 ? function() { return true; } : undefined;
} else if (command === true) {
// TODO: Look into using CodeMirror's multi-key handling.
// Return no-op since we are caching the key. Counts as handled, but
@ -1811,6 +1816,10 @@
var dir = motionArgs.forward ? 1 : -1;
return findParagraph(cm, head, motionArgs.repeat, dir);
},
moveBySentence: function(cm, head, motionArgs) {
var dir = motionArgs.forward ? 1 : -1;
return findSentence(cm, head, motionArgs.repeat, dir);
},
moveByScroll: function(cm, head, motionArgs, vim) {
var scrollbox = cm.getScrollInfo();
var curEnd = null;
@ -3534,6 +3543,179 @@
return { start: start, end: end };
}
function findSentence(cm, cur, repeat, dir) {
/*
Takes an index object
{
line: the line string,
ln: line number,
pos: index in line,
dir: direction of traversal (-1 or 1)
}
and modifies the line, ln, and pos members to represent the
next valid position or sets them to null if there are
no more valid positions.
*/
function nextChar(cm, idx) {
if (idx.pos + idx.dir < 0 || idx.pos + idx.dir >= idx.line.length) {
idx.ln += idx.dir;
if (!isLine(cm, idx.ln)) {
idx.line = null;
idx.ln = null;
idx.pos = null;
return;
}
idx.line = cm.getLine(idx.ln);
idx.pos = (idx.dir > 0) ? 0 : idx.line.length - 1;
}
else {
idx.pos += idx.dir;
}
}
/*
Performs one iteration of traversal in forward direction
Returns an index object of the new location
*/
function forward(cm, ln, pos, dir) {
var line = cm.getLine(ln);
var stop = (line === "");
var curr = {
line: line,
ln: ln,
pos: pos,
dir: dir,
}
var last_valid = {
ln: curr.ln,
pos: curr.pos,
}
var skip_empty_lines = (curr.line === "");
// Move one step to skip character we start on
nextChar(cm, curr);
while (curr.line !== null) {
last_valid.ln = curr.ln;
last_valid.pos = curr.pos;
if (curr.line === "" && !skip_empty_lines) {
return { ln: curr.ln, pos: curr.pos, };
}
else if (stop && curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) {
return { ln: curr.ln, pos: curr.pos, };
}
else if (isEndOfSentenceSymbol(curr.line[curr.pos])
&& !stop
&& (curr.pos === curr.line.length - 1
|| isWhiteSpaceString(curr.line[curr.pos + 1]))) {
stop = true;
}
nextChar(cm, curr);
}
/*
Set the position to the last non whitespace character on the last
valid line in the case that we reach the end of the document.
*/
var line = cm.getLine(last_valid.ln);
last_valid.pos = 0;
for(var i = line.length - 1; i >= 0; --i) {
if (!isWhiteSpaceString(line[i])) {
last_valid.pos = i;
break;
}
}
return last_valid;
}
/*
Performs one iteration of traversal in reverse direction
Returns an index object of the new location
*/
function reverse(cm, ln, pos, dir) {
var line = cm.getLine(ln);
var curr = {
line: line,
ln: ln,
pos: pos,
dir: dir,
}
var last_valid = {
ln: curr.ln,
pos: null,
};
var skip_empty_lines = (curr.line === "");
// Move one step to skip character we start on
nextChar(cm, curr);
while (curr.line !== null) {
if (curr.line === "" && !skip_empty_lines) {
if (last_valid.pos !== null) {
return last_valid;
}
else {
return { ln: curr.ln, pos: curr.pos };
}
}
else if (isEndOfSentenceSymbol(curr.line[curr.pos])
&& last_valid.pos !== null
&& !(curr.ln === last_valid.ln && curr.pos + 1 === last_valid.pos)) {
return last_valid;
}
else if (curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) {
skip_empty_lines = false;
last_valid = { ln: curr.ln, pos: curr.pos }
}
nextChar(cm, curr);
}
/*
Set the position to the first non whitespace character on the last
valid line in the case that we reach the beginning of the document.
*/
var line = cm.getLine(last_valid.ln);
last_valid.pos = 0;
for(var i = 0; i < line.length; ++i) {
if (!isWhiteSpaceString(line[i])) {
last_valid.pos = i;
break;
}
}
return last_valid;
}
var curr_index = {
ln: cur.line,
pos: cur.ch,
};
while (repeat > 0) {
if (dir < 0) {
curr_index = reverse(cm, curr_index.ln, curr_index.pos, dir);
}
else {
curr_index = forward(cm, curr_index.ln, curr_index.pos, dir);
}
repeat--;
}
return Pos(curr_index.ln, curr_index.pos);
}
// TODO: perhaps this finagling of start and end positions belonds
// in codemirror/replaceRange?
function selectCompanionObject(cm, head, symb, inclusive) {
@ -3552,8 +3734,8 @@
// cursor is on a matching open bracket.
var offset = curChar === openSym ? 1 : 0;
start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, null, {'bracketRegex': bracketRegexp});
end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, null, {'bracketRegex': bracketRegexp});
start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, undefined, {'bracketRegex': bracketRegexp});
end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, undefined, {'bracketRegex': bracketRegexp});
if (!start || !end) {
return { start: cur, end: cur };

View File

@ -9005,7 +9005,7 @@ ContentEditableInput.prototype.setUneditable = function (node) {
};
ContentEditableInput.prototype.onKeyPress = function (e) {
if (e.charCode == 0) { return }
if (e.charCode == 0 || this.composing) { return }
e.preventDefault()
if (!this.cm.isReadOnly())
{ operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) }
@ -9658,7 +9658,7 @@ CodeMirror.fromTextArea = fromTextArea
addLegacyProps(CodeMirror)
CodeMirror.version = "5.36.0"
CodeMirror.version = "5.37.0"
return CodeMirror;

View File

@ -624,6 +624,10 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
defKeywords: words("class val var object interface fun"),
atoms: words("true false null this"),
hooks: {
"@": function(stream) {
stream.eatWhile(/[\w\$_]/);
return "meta";
},
'"': function(stream, state) {
state.tokenize = tokenKotlinString(stream.match('""'));
return state.tokenize(stream, state);

View File

@ -126,7 +126,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
var kw = keywords[word]
return ret(kw.type, kw.style, word)
}
if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\(\w]/, false))
if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false))
return ret("async", "keyword", word)
}
return ret("variable", "variable", word)
@ -356,6 +356,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
} else if (isTS && value == "namespace") {
cx.marked = "keyword"
return cont(pushlex("form"), expression, block, poplex)
} else if (isTS && value == "abstract") {
cx.marked = "keyword"
return cont(statement)
} else {
return cont(pushlex("stat"), maybelabel);
}
@ -562,7 +565,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
function typeexpr(type, value) {
if (value == "keyof" || value == "typeof") {
cx.marked = "keyword"
return cont(value == "keyof" ? typeexpr : expression)
return cont(value == "keyof" ? typeexpr : expressionNoComma)
}
if (type == "variable" || value == "void") {
cx.marked = "type"
@ -572,6 +575,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr)
}
function maybeReturnType(type) {
if (type == "=>") return cont(typeexpr)
@ -588,9 +592,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
return cont(expression, maybetype, expect("]"), typeprop)
}
}
function typearg(type) {
if (type == "variable") return cont(typearg)
else if (type == ":") return cont(typeexpr)
function typearg(type, value) {
if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg)
if (type == ":") return cont(typeexpr)
return pass(typeexpr)
}
function afterType(type, value) {
if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)

View File

@ -402,6 +402,15 @@
" [def META],",
"}")
TS("parenthesized type",
"[keyword class] [def Foo] {",
" [property x] [operator =] [keyword new] [variable A][operator <][type B], [type string][operator |](() [operator =>] [type void])[operator >]();",
" [keyword private] [property bar]();",
"}")
TS("abstract class",
"[keyword export] [keyword abstract] [keyword class] [def Foo] {}")
var jsonld_mode = CodeMirror.getMode(
{indentUnit: 2},
{name: "javascript", jsonld: true}

View File

@ -509,6 +509,40 @@ testVim('{', function(cm, vim, helpers) {
helpers.doKeys('6', '{');
helpers.assertCursorAt(0, 0);
}, { value: 'a\n\nb\nc\n\nd' });
testVim('(', function(cm, vim, helpers) {
cm.setCursor(6, 23);
helpers.doKeys('(');
helpers.assertCursorAt(6, 14);
helpers.doKeys('2', '(');
helpers.assertCursorAt(5, 0);
helpers.doKeys('(');
helpers.assertCursorAt(4, 0);
helpers.doKeys('(');
helpers.assertCursorAt(3, 0);
helpers.doKeys('(');
helpers.assertCursorAt(2, 0);
helpers.doKeys('(');
helpers.assertCursorAt(0, 0);
helpers.doKeys('(');
helpers.assertCursorAt(0, 0);
}, { value: 'sentence1.\n\n\nsentence2\n\nsentence3. sentence4\n sentence5? sentence6!' });
testVim(')', function(cm, vim, helpers) {
cm.setCursor(0, 0);
helpers.doKeys('2', ')');
helpers.assertCursorAt(3, 0);
helpers.doKeys(')');
helpers.assertCursorAt(4, 0);
helpers.doKeys(')');
helpers.assertCursorAt(5, 0);
helpers.doKeys(')');
helpers.assertCursorAt(5, 11);
helpers.doKeys(')');
helpers.assertCursorAt(6, 14);
helpers.doKeys(')');
helpers.assertCursorAt(6, 23);
helpers.doKeys(')');
helpers.assertCursorAt(6, 23);
}, { value: 'sentence1.\n\n\nsentence2\n\nsentence3. sentence4\n sentence5? sentence6!' });
testVim('paragraph_motions', function(cm, vim, helpers) {
cm.setCursor(10, 0);
helpers.doKeys('{');

View File

@ -30,6 +30,7 @@
#include "mozilla/Services.h"
#include "nsAttrValueInlines.h"
#include "HTMLLinkElement.h"
namespace mozilla {
namespace dom {
@ -162,8 +163,8 @@ Link::TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender()
return;
}
if (!nsStyleLinkElement::CheckPreloadAttrs(asAttr, mimeType, media,
mElement->OwnerDoc())) {
if (!HTMLLinkElement::CheckPreloadAttrs(asAttr, mimeType, media,
mElement->OwnerDoc())) {
policyType = nsIContentPolicy::TYPE_INVALID;
}
@ -247,8 +248,8 @@ Link::UpdatePreload(nsAtom* aName, const nsAttrValue* aValue,
}
nsContentPolicyType policyType = asPolicyType;
if (!nsStyleLinkElement::CheckPreloadAttrs(asAttr, mimeType, media,
mElement->OwnerDoc())) {
if (!HTMLLinkElement::CheckPreloadAttrs(asAttr, mimeType, media,
mElement->OwnerDoc())) {
policyType = nsIContentPolicy::TYPE_INVALID;
}
@ -268,8 +269,8 @@ Link::UpdatePreload(nsAtom* aName, const nsAttrValue* aValue,
if (aName == nsGkAtoms::as) {
if (aOldValue) {
oldPolicyType = AsValueToContentPolicy(*aOldValue);
if (!nsStyleLinkElement::CheckPreloadAttrs(*aOldValue, mimeType, media,
mElement->OwnerDoc())) {
if (!HTMLLinkElement::CheckPreloadAttrs(*aOldValue, mimeType, media,
mElement->OwnerDoc())) {
oldPolicyType = nsIContentPolicy::TYPE_INVALID;
}
} else {
@ -285,8 +286,8 @@ Link::UpdatePreload(nsAtom* aName, const nsAttrValue* aValue,
}
nsAutoString oldMimeType;
nsContentUtils::SplitMimeType(oldType, oldMimeType, notUsed);
if (nsStyleLinkElement::CheckPreloadAttrs(asAttr, oldMimeType, media,
mElement->OwnerDoc())) {
if (HTMLLinkElement::CheckPreloadAttrs(asAttr, oldMimeType, media,
mElement->OwnerDoc())) {
oldPolicyType = asPolicyType;
} else {
oldPolicyType = nsIContentPolicy::TYPE_INVALID;
@ -299,8 +300,8 @@ Link::UpdatePreload(nsAtom* aName, const nsAttrValue* aValue,
} else {
oldMedia = EmptyString();
}
if (nsStyleLinkElement::CheckPreloadAttrs(asAttr, mimeType, oldMedia,
mElement->OwnerDoc())) {
if (HTMLLinkElement::CheckPreloadAttrs(asAttr, mimeType, oldMedia,
mElement->OwnerDoc())) {
oldPolicyType = asPolicyType;
} else {
oldPolicyType = nsIContentPolicy::TYPE_INVALID;

View File

@ -53,6 +53,7 @@
#include "nsParserConstants.h"
#include "nsSandboxFlags.h"
#include "Link.h"
#include "HTMLLinkElement.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -886,8 +887,8 @@ nsContentSink::PrefetchPreloadHref(const nsAString &aHref,
nsAutoString mimeType;
nsAutoString notUsed;
nsContentUtils::SplitMimeType(aType, mimeType, notUsed);
if (!nsStyleLinkElement::CheckPreloadAttrs(asAttr, mimeType,
aMedia,mDocument)) {
if (!HTMLLinkElement::CheckPreloadAttrs(asAttr, mimeType,
aMedia,mDocument)) {
policyType = nsIContentPolicy::TYPE_INVALID;
}

View File

@ -434,7 +434,7 @@ public:
bool IsContainerNode() const
{
return IsElement() || !IsCharacterData();
return IsElement() || IsDocument() || IsDocumentFragment();
}
bool IsSlotable() const

View File

@ -31,14 +31,6 @@
#include "nsContentUtils.h"
#include "nsStyleUtil.h"
#include "nsQueryObject.h"
#include "nsIContentPolicy.h"
#include "nsMimeTypes.h"
#include "imgLoader.h"
#include "MediaContainerType.h"
#include "DecoderDoctorDiagnostics.h"
#include "DecoderTraits.h"
#include "MediaList.h"
#include "nsAttrValueInlines.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -184,120 +176,6 @@ uint32_t nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes)
return linkMask;
}
// We will use official mime-types from:
// https://www.iana.org/assignments/media-types/media-types.xhtml#font
// We do not support old deprecated mime-types for preload feature.
// (We currectly do not support font/collection)
static uint32_t StyleLinkElementFontMimeTypesNum = 5;
static const char* StyleLinkElementFontMimeTypes[] = {
"font/otf",
"font/sfnt",
"font/ttf",
"font/woff",
"font/woff2"
};
bool
IsFontMimeType(const nsAString& aType)
{
if (aType.IsEmpty()) {
return true;
}
for (uint32_t i = 0; i < StyleLinkElementFontMimeTypesNum; i++) {
if (aType.EqualsASCII(StyleLinkElementFontMimeTypes[i])) {
return true;
}
}
return false;
}
bool
nsStyleLinkElement::CheckPreloadAttrs(const nsAttrValue& aAs,
const nsAString& aType,
const nsAString& aMedia,
nsIDocument* aDocument)
{
nsContentPolicyType policyType = Link::AsValueToContentPolicy(aAs);
if (policyType == nsIContentPolicy::TYPE_INVALID) {
return false;
}
// Check if media attribute is valid.
if (!aMedia.IsEmpty()) {
RefPtr<MediaList> mediaList = MediaList::Create(aMedia);
nsPresContext* presContext = aDocument->GetPresContext();
if (!presContext) {
return false;
}
if (!mediaList->Matches(presContext)) {
return false;
}
}
if (aType.IsEmpty()) {
return true;
}
nsString type = nsString(aType);
ToLowerCase(type);
if (policyType == nsIContentPolicy::TYPE_OTHER) {
return true;
} else if (policyType == nsIContentPolicy::TYPE_MEDIA) {
if (aAs.GetEnumValue() == DESTINATION_TRACK) {
if (type.EqualsASCII("text/vtt")) {
return true;
} else {
return false;
}
}
Maybe<MediaContainerType> mimeType = MakeMediaContainerType(aType);
if (!mimeType) {
return false;
}
DecoderDoctorDiagnostics diagnostics;
CanPlayStatus status = DecoderTraits::CanHandleContainerType(*mimeType,
&diagnostics);
// Preload if this return CANPLAY_YES and CANPLAY_MAYBE.
if (status == CANPLAY_NO) {
return false;
} else {
return true;
}
} else if (policyType == nsIContentPolicy::TYPE_FONT) {
if (IsFontMimeType(type)) {
return true;
} else {
return false;
}
} else if (policyType == nsIContentPolicy::TYPE_IMAGE) {
if (imgLoader::SupportImageWithMimeType(NS_ConvertUTF16toUTF8(type).get(),
AcceptedMimeTypes::IMAGES_AND_DOCUMENTS)) {
return true;
} else {
return false;
}
} else if (policyType == nsIContentPolicy::TYPE_SCRIPT) {
if (nsContentUtils::IsJavascriptMIMEType(type)) {
return true;
} else {
return false;
}
} else if (policyType == nsIContentPolicy::TYPE_STYLESHEET) {
if (type.EqualsASCII("text/css")) {
return true;
} else {
return false;
}
}
return false;
}
nsresult
nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
bool* aWillNotify,

View File

@ -20,7 +20,6 @@
#include "nsCOMPtr.h"
#include "nsIStyleSheetLinkingElement.h"
#include "nsTArray.h"
#include "nsAttrValue.h"
class nsIDocument;
class nsIURI;
@ -71,9 +70,6 @@ public:
// The return value is a bitwise or of 0 or more RelValues.
static uint32_t ParseLinkTypes(const nsAString& aTypes);
static bool CheckPreloadAttrs(const nsAttrValue& aAs, const nsAString& aType,
const nsAString& aMedia, nsIDocument* aDocument);
void UpdateStyleSheetInternal()
{
UpdateStyleSheetInternal(nullptr, nullptr);

View File

@ -66,6 +66,23 @@ public:
}
};
template<typename T>
inline typename EnableIf<IsBaseOf<DictionaryBase, T>::value, void>::Type
ImplCycleCollectionUnlink(T& aDictionary)
{
aDictionary.UnlinkForCC();
}
template<typename T>
inline typename EnableIf<IsBaseOf<DictionaryBase, T>::value, void>::Type
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
T& aDictionary,
const char* aName,
uint32_t aFlags = 0)
{
aDictionary.TraverseForCC(aCallback, aFlags);
}
// Struct that serves as a base class for all typed arrays and array buffers and
// array buffer views. Particularly useful so we can use IsBaseOf to detect
// typed array/buffer/view template arguments.
@ -382,6 +399,27 @@ private:
const nsAString* mStr;
};
template<typename T>
inline void
ImplCycleCollectionUnlink(Optional<T>& aField)
{
if (aField.WasPassed()) {
ImplCycleCollectionUnlink(aField.Value());
}
}
template<typename T>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
Optional<T>& aField,
const char* aName,
uint32_t aFlags = 0)
{
if (aField.WasPassed()) {
ImplCycleCollectionTraverse(aCallback, aField.Value(), aName, aFlags);
}
}
template<class T>
class NonNull
{

View File

@ -73,6 +73,11 @@ def isTypeCopyConstructible(type):
(type.isInterface() and type.isGeckoInterface()))
class CycleCollectionUnsupported(TypeError):
def __init__(self, message):
TypeError.__init__(self, message)
def idlTypeNeedsCycleCollection(type):
type = type.unroll() # Takes care of sequences and nullables
if ((type.isPrimitive() and type.tag() in builtinNames) or
@ -88,14 +93,13 @@ def idlTypeNeedsCycleCollection(type):
return any(idlTypeNeedsCycleCollection(t) for t in type.flatMemberTypes)
elif type.isRecord():
if idlTypeNeedsCycleCollection(type.inner):
raise TypeError("Cycle collection for type %s is not supported" % type)
raise CycleCollectionUnsupported("Cycle collection for type %s is not supported" %
type)
return False
elif type.isDictionary():
if any(idlTypeNeedsCycleCollection(m.type) for m in type.inner.members):
raise TypeError("Cycle collection for type %s is not supported" % type)
return False
return CGDictionary.dictionaryNeedsCycleCollection(type.inner)
else:
raise TypeError("Don't know whether to cycle-collect type %s" % type)
raise CycleCollectionUnsupported("Don't know whether to cycle-collect type %s" % type)
def wantsAddProperty(desc):
@ -12828,6 +12832,56 @@ class CGDictionary(CGThing):
Argument("JSTracer*", "trc"),
], body=body)
@staticmethod
def dictionaryNeedsCycleCollection(dictionary):
return (any(idlTypeNeedsCycleCollection(m.type) for m in dictionary.members) or
(dictionary.parent and
CGDictionary.dictionaryNeedsCycleCollection(dictionary.parent)))
def traverseForCCMethod(self):
body = ""
if (self.dictionary.parent and
self.dictionaryNeedsCycleCollection(self.dictionary.parent)):
cls = self.makeClassName(self.dictionary.parent)
body += "%s::TraverseForCC(aCallback, aFlags);\n" % cls
for m, _ in self.memberInfo:
if idlTypeNeedsCycleCollection(m.type):
memberName = self.makeMemberName(m.identifier.name);
body += ('ImplCycleCollectionTraverse(aCallback, %s, "%s", aFlags);\n' %
(memberName, memberName))
return ClassMethod(
"TraverseForCC", "void",
[
Argument("nsCycleCollectionTraversalCallback&", "aCallback"),
Argument("uint32_t", "aFlags"),
],
body=body,
# Inline so we don't pay a codesize hit unless someone actually uses
# this traverse method.
inline=True,
bodyInHeader=True)
def unlinkForCCMethod(self):
body = ""
if (self.dictionary.parent and
self.dictionaryNeedsCycleCollection(self.dictionary.parent)):
cls = self.makeClassName(self.dictionary.parent)
body += "%s::UnlinkForCC();\n" % cls
for m, _ in self.memberInfo:
if idlTypeNeedsCycleCollection(m.type):
memberName = self.makeMemberName(m.identifier.name);
body += ('ImplCycleCollectionUnlink(%s);\n' % memberName)
return ClassMethod(
"UnlinkForCC", "void", [], body=body,
# Inline so we don't pay a codesize hit unless someone actually uses
# this unlink method.
inline=True,
bodyInHeader=True)
def assignmentOperator(self):
body = CGList([])
if self.dictionary.parent:
@ -12912,6 +12966,16 @@ class CGDictionary(CGThing):
pass
methods.append(self.traceDictionaryMethod())
try:
if self.dictionaryNeedsCycleCollection(d):
methods.append(self.traverseForCCMethod())
methods.append(self.unlinkForCCMethod())
except CycleCollectionUnsupported:
# We have some member that we don't know how to CC. Don't output
# our cycle collection overloads, so attempts to CC us will fail to
# compile instead of misbehaving.
pass
if CGDictionary.isDictionaryCopyConstructible(d):
disallowCopyConstruction = False
# Note: no base constructors because our operator= will

View File

@ -1401,7 +1401,9 @@ template <class Derived>
void
FetchBody<Derived>::Abort()
{
MOZ_ASSERT(mReadableStreamBody);
if (!mReadableStreamBody) {
return;
}
AutoJSAPI jsapi;
if (!jsapi.Init(mOwner)) {

View File

@ -266,6 +266,13 @@ FetchStream::CancelCallback(JSContext* aCx, JS::HandleObject aStream,
stream->mInputStream->CloseWithStatus(NS_BASE_STREAM_CLOSED);
}
// It could be that we don't have mInputStream yet, but we still have the
// original stream. We need to close that too.
if (stream->mOriginalInputStream) {
MOZ_ASSERT(!stream->mInputStream);
stream->mOriginalInputStream->Close();
}
stream->ReleaseObjects();
return JS::UndefinedValue();
}

View File

@ -6,7 +6,6 @@
#include "nsHostObjectProtocolHandler.h"
#include "DOMMediaStream.h"
#include "mozilla/dom/ChromeUtils.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
@ -42,7 +41,6 @@ struct DataInfo
{
enum ObjectType {
eBlobImpl,
eMediaStream,
eMediaSource
};
@ -53,13 +51,6 @@ struct DataInfo
, mRevoked(false)
{}
DataInfo(DOMMediaStream* aMediaStream, nsIPrincipal* aPrincipal)
: mObjectType(eMediaStream)
, mMediaStream(aMediaStream)
, mPrincipal(aPrincipal)
, mRevoked(false)
{}
DataInfo(MediaSource* aMediaSource, nsIPrincipal* aPrincipal)
: mObjectType(eMediaSource)
, mMediaSource(aMediaSource)
@ -70,7 +61,6 @@ struct DataInfo
ObjectType mObjectType;
RefPtr<BlobImpl> mBlobImpl;
RefPtr<DOMMediaStream> mMediaStream;
RefPtr<MediaSource> mMediaSource;
nsCOMPtr<nsIPrincipal> mPrincipal;
@ -308,10 +298,9 @@ class BlobURLsReporter final : public nsIMemoryReporter
continue;
}
// Just report the path for the DOMMediaStream or MediaSource.
// Just report the path for the MediaSource.
nsAutoCString path;
path = iter.UserData()->mObjectType == DataInfo::eMediaSource
? "media-source-urls/" : "dom-media-stream-urls/";
path = "media-source-urls/";
BuildPath(path, key, info, aAnonymize);
NS_NAMED_LITERAL_CSTRING(desc,
@ -629,22 +618,6 @@ nsHostObjectProtocolHandler::AddDataEntry(BlobImpl* aBlobImpl,
return NS_OK;
}
/* static */ nsresult
nsHostObjectProtocolHandler::AddDataEntry(DOMMediaStream* aMediaStream,
nsIPrincipal* aPrincipal,
nsACString& aUri)
{
Init();
nsresult rv = GenerateURIStringForBlobURL(aPrincipal, aUri);
NS_ENSURE_SUCCESS(rv, rv);
rv = AddDataEntryInternal(aUri, aMediaStream, aPrincipal);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/* static */ nsresult
nsHostObjectProtocolHandler::AddDataEntry(MediaSource* aMediaSource,
nsIPrincipal* aPrincipal,
@ -824,9 +797,6 @@ nsHostObjectProtocolHandler::Traverse(const nsACString& aUri,
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "HostObjectProtocolHandler DataInfo.mMediaSource");
aCallback.NoteXPCOMChild(res->mMediaSource);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "HostObjectProtocolHandler DataInfo.mMediaStream");
aCallback.NoteXPCOMChild(res->mMediaStream);
}
// -----------------------------------------------------------------------
@ -1074,19 +1044,6 @@ NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream)
return NS_OK;
}
nsresult
NS_GetStreamForMediaStreamURI(nsIURI* aURI, DOMMediaStream** aStream)
{
DataInfo* info = GetDataInfoFromURI(aURI);
if (!info || info->mObjectType != DataInfo::eMediaStream) {
return NS_ERROR_DOM_BAD_URI;
}
RefPtr<DOMMediaStream> mediaStream = info->mMediaStream;
mediaStream.forget(aStream);
return NS_OK;
}
NS_IMETHODIMP
nsFontTableProtocolHandler::NewURI(const nsACString& aSpec,
const char *aCharset,
@ -1187,11 +1144,6 @@ bool IsBlobURI(nsIURI* aUri)
return IsType(aUri, DataInfo::eBlobImpl);
}
bool IsMediaStreamURI(nsIURI* aUri)
{
return IsType(aUri, DataInfo::eMediaStream);
}
bool IsMediaSourceURI(nsIURI* aUri)
{
return IsType(aUri, DataInfo::eMediaSource);

View File

@ -23,7 +23,6 @@ class nsIPrincipal;
namespace mozilla {
class BlobURLsReporter;
class DOMMediaStream;
namespace dom {
class BlobImpl;
@ -65,9 +64,6 @@ public:
static nsresult AddDataEntry(mozilla::dom::BlobImpl* aBlobImpl,
nsIPrincipal* aPrincipal,
nsACString& aUri);
static nsresult AddDataEntry(mozilla::DOMMediaStream* aMediaStream,
nsIPrincipal* aPrincipal,
nsACString& aUri);
static nsresult AddDataEntry(mozilla::dom::MediaSource* aMediaSource,
nsIPrincipal* aPrincipal,
nsACString& aUri);
@ -116,7 +112,6 @@ public:
};
bool IsBlobURI(nsIURI* aUri);
bool IsMediaStreamURI(nsIURI* aUri);
bool IsMediaSourceURI(nsIURI* aUri);
inline bool IsRtspURI(nsIURI* aUri)
@ -140,9 +135,6 @@ NS_GetBlobForBlobURISpec(const nsACString& aSpec, mozilla::dom::BlobImpl** aBlob
extern nsresult
NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
extern nsresult
NS_GetStreamForMediaStreamURI(nsIURI* aURI, mozilla::DOMMediaStream** aStream);
extern nsresult
NS_GetSourceForMediaSourceURI(nsIURI* aURI, mozilla::dom::MediaSource** aSource);

View File

@ -19,9 +19,8 @@
#include "nsProxyRelease.h"
/**
* These URIs refer to host objects: Blobs, with scheme "blob",
* MediaStreams, with scheme "mediastream", and MediaSources, with scheme
* "mediasource".
* These URIs refer to host objects with "blob" scheme. The underlying objects
* can be Blobs or MediaSources.
*/
class nsHostObjectURI final
: public mozilla::net::nsSimpleURI

View File

@ -28,6 +28,14 @@
#include "nsStyleLinkElement.h"
#include "nsUnicharUtils.h"
#include "nsWindowSizes.h"
#include "nsIContentPolicy.h"
#include "nsMimeTypes.h"
#include "imgLoader.h"
#include "MediaContainerType.h"
#include "DecoderDoctorDiagnostics.h"
#include "DecoderTraits.h"
#include "MediaList.h"
#include "nsAttrValueInlines.h"
#define LINK_ELEMENT_FLAG_BIT(n_) \
NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
@ -512,5 +520,119 @@ HTMLLinkElement::GetAs(nsAString& aResult)
GetEnumAttr(nsGkAtoms::as, EmptyCString().get(), aResult);
}
// We will use official mime-types from:
// https://www.iana.org/assignments/media-types/media-types.xhtml#font
// We do not support old deprecated mime-types for preload feature.
// (We currectly do not support font/collection)
static uint32_t StyleLinkElementFontMimeTypesNum = 5;
static const char* StyleLinkElementFontMimeTypes[] = {
"font/otf",
"font/sfnt",
"font/ttf",
"font/woff",
"font/woff2"
};
bool
IsFontMimeType(const nsAString& aType)
{
if (aType.IsEmpty()) {
return true;
}
for (uint32_t i = 0; i < StyleLinkElementFontMimeTypesNum; i++) {
if (aType.EqualsASCII(StyleLinkElementFontMimeTypes[i])) {
return true;
}
}
return false;
}
bool
HTMLLinkElement::CheckPreloadAttrs(const nsAttrValue& aAs,
const nsAString& aType,
const nsAString& aMedia,
nsIDocument* aDocument)
{
nsContentPolicyType policyType = Link::AsValueToContentPolicy(aAs);
if (policyType == nsIContentPolicy::TYPE_INVALID) {
return false;
}
// Check if media attribute is valid.
if (!aMedia.IsEmpty()) {
RefPtr<MediaList> mediaList = MediaList::Create(aMedia);
nsPresContext* presContext = aDocument->GetPresContext();
if (!presContext) {
return false;
}
if (!mediaList->Matches(presContext)) {
return false;
}
}
if (aType.IsEmpty()) {
return true;
}
nsString type = nsString(aType);
ToLowerCase(type);
if (policyType == nsIContentPolicy::TYPE_OTHER) {
return true;
} else if (policyType == nsIContentPolicy::TYPE_MEDIA) {
if (aAs.GetEnumValue() == DESTINATION_TRACK) {
if (type.EqualsASCII("text/vtt")) {
return true;
} else {
return false;
}
}
Maybe<MediaContainerType> mimeType = MakeMediaContainerType(aType);
if (!mimeType) {
return false;
}
DecoderDoctorDiagnostics diagnostics;
CanPlayStatus status = DecoderTraits::CanHandleContainerType(*mimeType,
&diagnostics);
// Preload if this return CANPLAY_YES and CANPLAY_MAYBE.
if (status == CANPLAY_NO) {
return false;
} else {
return true;
}
} else if (policyType == nsIContentPolicy::TYPE_FONT) {
if (IsFontMimeType(type)) {
return true;
} else {
return false;
}
} else if (policyType == nsIContentPolicy::TYPE_IMAGE) {
if (imgLoader::SupportImageWithMimeType(NS_ConvertUTF16toUTF8(type).get(),
AcceptedMimeTypes::IMAGES_AND_DOCUMENTS)) {
return true;
} else {
return false;
}
} else if (policyType == nsIContentPolicy::TYPE_SCRIPT) {
if (nsContentUtils::IsJavascriptMIMEType(type)) {
return true;
} else {
return false;
}
} else if (policyType == nsIContentPolicy::TYPE_STYLESHEET) {
if (type.EqualsASCII("text/css")) {
return true;
} else {
return false;
}
}
return false;
}
} // namespace dom
} // namespace mozilla

View File

@ -202,6 +202,8 @@ public:
nsGenericHTMLElement::NodeInfoChanged(aOldDoc);
}
static bool CheckPreloadAttrs(const nsAttrValue& aAs, const nsAString& aType,
const nsAString& aMedia, nsIDocument* aDocument);
protected:
virtual ~HTMLLinkElement();

View File

@ -2097,8 +2097,7 @@ void HTMLMediaElement::SelectResource()
mMediaSource = mSrcMediaSource;
DDLINKCHILD("mediasource", mMediaSource.get());
UpdatePreloadAction();
if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE &&
!IsMediaStreamURI(mLoadingSrc) && !mMediaSource) {
if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE && !mMediaSource) {
// preload:none media, suspend the load here before we make any
// network requests.
SuspendLoad();
@ -2427,8 +2426,7 @@ void HTMLMediaElement::LoadFromSourceChildren()
NS_ASSERTION(mNetworkState == NETWORK_LOADING,
"Network state should be loading");
if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE &&
!IsMediaStreamURI(mLoadingSrc) && !mMediaSource) {
if (mPreloadAction == HTMLMediaElement::PRELOAD_NONE && !mMediaSource) {
// preload:none media, suspend the load here before we make any
// network requests.
SuspendLoad();
@ -2577,20 +2575,6 @@ HTMLMediaElement::LoadResource()
return rv;
}
if (IsMediaStreamURI(mLoadingSrc)) {
RefPtr<DOMMediaStream> stream;
nsresult rv = NS_GetStreamForMediaStreamURI(mLoadingSrc, getter_AddRefs(stream));
if (NS_FAILED(rv)) {
nsAutoString spec;
GetCurrentSrc(spec);
const char16_t* params[] = { spec.get() };
ReportLoadError("MediaLoadInvalidURI", params, ArrayLength(params));
return MediaResult(rv, "MediaLoadInvalidURI");
}
SetupSrcMediaStreamPlayback(stream);
return NS_OK;
}
if (mMediaSource) {
MediaDecoderInit decoderInit(
this,

View File

@ -1130,9 +1130,6 @@ tags=msg capturestream
[test_streams_element_capture.html]
skip-if = toolkit == 'android' # bug 1372457
tags=msg capturestream
[test_streams_element_capture_createObjectURL.html]
skip-if = android_version == '15' || android_version == '17' || (android_version == '19' && debug) # android(bug 1232305)
tags=msg capturestream
[test_streams_element_capture_playback.html]
skip-if = toolkit == 'android' # android(bug 1232305)
tags=msg capturestream

View File

@ -1,75 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test that a MediaStream captured from one element plays back in another</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var manager = new MediaTestManager;
function checkDrawImage(vout) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.drawImage(vout, 0, 0);
var imgData = ctx.getImageData(0, 0, 1, 1);
is(imgData.data[3], 255, "Check video frame pixel has been drawn");
}
function isGreaterThanOrEqualEps(a, b, msg) {
ok(a >= b - 0.01,
"Got " + a + ", expected at least " + b + "; " + msg);
}
function startTest(test, token) {
manager.started(token);
var v = document.createElement('video');
var vout = document.createElement('video');
vout.token = token;
v.src = test.name;
v.preload = "metadata"
var stream;
var checkEnded = function() {
is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
if (test.duration) {
isGreaterThanOrEqualEps(vout.currentTime, test.duration,
test.name + " current time at end");
}
is(vout.readyState, vout.HAVE_CURRENT_DATA, test.name + " checking readyState");
ok(vout.ended, test.name + " checking playback has ended");
if (test.type.match(/^video/)) {
checkDrawImage(vout);
}
vout.remove();
URL.revokeObjectURL(vout.src);
manager.finished(vout.token);
};
vout.addEventListener("ended", checkEnded);
document.body.appendChild(vout);
v.onloadedmetadata = function () {
stream = v.mozCaptureStreamUntilEnded();
is(stream.currentTime, 0, test.name + " stream initial currentTime");
vout.src = URL.createObjectURL(stream);
v.play();
vout.play();
};
}
SpecialPowers.pushPrefEnv(
{ "set": [["privacy.reduceTimerPrecision", false]]},
function() {
manager.runTests([getPlayableVideo(gSmallTests)], startTest);
});
</script>
</pre>
</body>
</html>

View File

@ -31,9 +31,8 @@ async function startTest() {
let video1 = document.getElementById('video1');
let video2 = document.getElementById('video2');
let src = URL.createObjectURL(stream);
video1.src = src;
video2.src = src;
video1.srcObject = stream;
video2.srcObject = stream;
video1.onplaying = () => video1.pause();

View File

@ -54,7 +54,7 @@ var startTest = function(test, token) {
}
if (v === v2) {
vout.src = URL.createObjectURL(v2.mozCaptureStreamUntilEnded());
vout.srcObject = v2.mozCaptureStreamUntilEnded();
v2.play();
vout.play();
}

View File

@ -668,17 +668,22 @@ AudioContext::CurrentTime()
{
MediaStream* stream = Destination()->Stream();
if (!mIsStarted &&
stream->StreamTimeToSeconds(stream->GetCurrentTime()) == 0) {
return 0;
double rawTime = stream->StreamTimeToSeconds(stream->GetCurrentTime());
// CurrentTime increments in intervals of 128/sampleRate. If the Timer
// Precision Reduction is smaller than this interval, the jittered time
// can always be reversed to the raw step of the interval. In that case
// we can simply return the un-reduced time; and avoid breaking tests.
// We have to convert each variable into a common magnitude, we choose ms.
if ((128/mSampleRate) * 1000.0 > nsRFPService::TimerResolution() / 1000.0) {
return rawTime;
}
// The value of a MediaStream's CurrentTime will always advance forward; it will never
// reset (even if one rewinds a video.) Therefore we can use a single Random Seed
// initialized at the same time as the object.
return nsRFPService::ReduceTimePrecisionAsSecs(
stream->StreamTimeToSeconds(stream->GetCurrentTime()),
GetRandomTimelineSeed());
rawTime, GetRandomTimelineSeed());
}
void AudioContext::DisconnectFromOwner()

View File

@ -25,6 +25,18 @@ const SAME_ORIGIN = "http://mochi.test:8888/"
const CROSS_ORIGIN = "http://example.com/";
const PATH = "tests/dom/security/test/general/file_same_site_cookies_redirect.sjs";
const FRAME_META_REFRESH_SAME = `
<html><head>
<meta http-equiv="refresh" content="0;
url='` + SAME_ORIGIN + PATH + `?loadFrame'">
</head></html>`;
const FRAME_META_REFRESH_CROSS = `
<html><head>
<meta http-equiv="refresh" content="0;
url='` + CROSS_ORIGIN + PATH + `?loadFrame'">
</head></html>`;
function handleRequest(request, response)
{
// avoid confusing cache behaviors
@ -37,6 +49,13 @@ function handleRequest(request, response)
return;
}
if (request.queryString === "sameToSameRedirect") {
let URL = SAME_ORIGIN + PATH + "?loadFrame";
response.setStatusLine("1.1", 302, "Found");
response.setHeader("Location", URL, false);
return;
}
if (request.queryString === "sameToCrossRedirect") {
let URL = CROSS_ORIGIN + PATH + "?loadFrame";
response.setStatusLine("1.1", 302, "Found");
@ -51,6 +70,16 @@ function handleRequest(request, response)
return;
}
if (request.queryString === "sameToCrossRedirectMeta") {
response.write(FRAME_META_REFRESH_CROSS);
return;
}
if (request.queryString === "crossToSameRedirectMeta") {
response.write(FRAME_META_REFRESH_SAME);
return;
}
if (request.queryString === "loadFrame") {
response.write(FRAME);
return;

View File

@ -29,6 +29,12 @@ const PATH = "tests/dom/security/test/general/file_same_site_cookies_redirect.sj
let curTest = 0;
var tests = [
{
description: "baseline: same-site cookie, redirect same-site to same-site",
imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
frameSRC: SAME_ORIGIN + PATH + "?sameToSameRedirect",
result: "myKey=strictSameSiteCookie",
},
{
description: "same-site cookie, redirect same-site to cross-site",
imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
@ -41,6 +47,18 @@ var tests = [
frameSRC: CROSS_ORIGIN + PATH + "?crossToSameRedirect",
result: "", // no cookie should be set
},
{
description: "same-site cookie, meta redirect same-site to cross-site",
imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
frameSRC: SAME_ORIGIN + PATH + "?sameToCrossRedirectMeta",
result: "", // no cookie should be set
},
{
description: "same-site cookie, meta redirect cross-site to same-site",
imgSRC: SAME_ORIGIN + PATH + "?setSameSiteCookie",
frameSRC: CROSS_ORIGIN + PATH + "?crossToSameRedirectMeta",
result: "", // no cookie should be set
},
];
window.addEventListener("message", receiveMessage);

View File

@ -11,7 +11,9 @@
#include "MainThreadUtils.h"
#include "mozilla/dom/URLBinding.h"
#include "mozilla/dom/BindingUtils.h"
#include "nsContentUtils.h"
#include "nsIDocument.h"
#include "nsIURIMutator.h"
namespace mozilla {
namespace dom {
@ -61,17 +63,6 @@ URL::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
}
}
void
URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
nsAString& aResult, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
DeprecationWarning(aGlobal, nsIDocument::eURLCreateObjectURL_MediaStream);
URLMainThread::CreateObjectURL(aGlobal, aStream, aResult, aRv);
}
void
URL::CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
nsAString& aResult, ErrorResult& aRv)
@ -144,5 +135,248 @@ URL::URLSearchParamsUpdated(URLSearchParams* aSearchParams)
SetSearchInternal(search);
}
#define URL_GETTER( value, func ) \
MOZ_ASSERT(mURI); \
value.Truncate(); \
nsAutoCString tmp; \
nsresult rv = mURI->func(tmp); \
if (NS_SUCCEEDED(rv)) { \
CopyUTF8toUTF16(tmp, value); \
}
void
URL::GetHref(nsAString& aHref) const
{
URL_GETTER(aHref, GetSpec);
}
void
URL::GetProtocol(nsAString& aProtocol) const
{
URL_GETTER(aProtocol, GetScheme);
aProtocol.Append(char16_t(':'));
}
void
URL::GetUsername(nsAString& aUsername) const
{
URL_GETTER(aUsername, GetUsername);
}
void
URL::SetUsername(const nsAString& aUsername)
{
MOZ_ASSERT(mURI);
Unused << NS_MutateURI(mURI)
.SetUsername(NS_ConvertUTF16toUTF8(aUsername))
.Finalize(mURI);
}
void
URL::GetPassword(nsAString& aPassword) const
{
URL_GETTER(aPassword, GetPassword);
}
void
URL::SetPassword(const nsAString& aPassword)
{
MOZ_ASSERT(mURI);
Unused << NS_MutateURI(mURI)
.SetPassword(NS_ConvertUTF16toUTF8(aPassword))
.Finalize(mURI);
}
void
URL::GetHost(nsAString& aHost) const
{
URL_GETTER(aHost, GetHostPort);
}
void
URL::SetHost(const nsAString& aHost)
{
MOZ_ASSERT(mURI);
Unused << NS_MutateURI(mURI)
.SetHostPort(NS_ConvertUTF16toUTF8(aHost))
.Finalize(mURI);
}
void
URL::GetHostname(nsAString& aHostname) const
{
MOZ_ASSERT(mURI);
aHostname.Truncate();
nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname);
}
void
URL::SetHostname(const nsAString& aHostname)
{
MOZ_ASSERT(mURI);
// nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
// The return code is silently ignored
mozilla::Unused << NS_MutateURI(mURI)
.SetHost(NS_ConvertUTF16toUTF8(aHostname))
.Finalize(mURI);
}
void
URL::GetPort(nsAString& aPort) const
{
MOZ_ASSERT(mURI);
aPort.Truncate();
int32_t port;
nsresult rv = mURI->GetPort(&port);
if (NS_SUCCEEDED(rv) && port != -1) {
nsAutoString portStr;
portStr.AppendInt(port, 10);
aPort.Assign(portStr);
}
}
void
URL::SetPort(const nsAString& aPort)
{
nsresult rv;
nsAutoString portStr(aPort);
int32_t port = -1;
// nsIURI uses -1 as default value.
if (!portStr.IsEmpty()) {
port = portStr.ToInteger(&rv);
if (NS_FAILED(rv)) {
return;
}
}
Unused << NS_MutateURI(mURI)
.SetPort(port)
.Finalize(mURI);
}
void
URL::GetPathname(nsAString& aPathname) const
{
MOZ_ASSERT(mURI);
aPathname.Truncate();
// Do not throw! Not having a valid URI or URL should result in an empty
// string.
nsAutoCString file;
nsresult rv = mURI->GetFilePath(file);
if (NS_SUCCEEDED(rv)) {
CopyUTF8toUTF16(file, aPathname);
}
}
void
URL::SetPathname(const nsAString& aPathname)
{
MOZ_ASSERT(mURI);
// Do not throw!
Unused << NS_MutateURI(mURI)
.SetFilePath(NS_ConvertUTF16toUTF8(aPathname))
.Finalize(mURI);
}
void
URL::GetSearch(nsAString& aSearch) const
{
MOZ_ASSERT(mURI);
aSearch.Truncate();
// Do not throw! Not having a valid URI or URL should result in an empty
// string.
nsAutoCString search;
nsresult rv;
rv = mURI->GetQuery(search);
if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
aSearch.Assign(u'?');
AppendUTF8toUTF16(search, aSearch);
}
}
void
URL::GetHash(nsAString& aHash) const
{
MOZ_ASSERT(mURI);
aHash.Truncate();
nsAutoCString ref;
nsresult rv = mURI->GetRef(ref);
if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
aHash.Assign(char16_t('#'));
AppendUTF8toUTF16(ref, aHash);
}
}
void
URL::SetHash(const nsAString& aHash)
{
MOZ_ASSERT(mURI);
Unused << NS_MutateURI(mURI)
.SetRef(NS_ConvertUTF16toUTF8(aHash))
.Finalize(mURI);
}
void
URL::SetSearchInternal(const nsAString& aSearch)
{
MOZ_ASSERT(mURI);
// Ignore failures to be compatible with NS4.
Unused << NS_MutateURI(mURI)
.SetQuery(NS_ConvertUTF16toUTF8(aSearch))
.Finalize(mURI);
}
void
URL::UpdateURLSearchParams()
{
if (!mSearchParams) {
return;
}
nsAutoCString search;
nsresult rv = GetURI()->GetQuery(search);
if (NS_WARN_IF(NS_FAILED(rv))) {
search.Truncate();
}
mSearchParams->ParseInput(search);
}
void
URL::SetURI(already_AddRefed<nsIURI> aURI)
{
mURI = Move(aURI);
MOZ_ASSERT(mURI);
}
nsIURI*
URL::GetURI() const
{
MOZ_ASSERT(mURI);
return mURI;
}
} // namespace dom
} // namespace mozilla

View File

@ -19,7 +19,6 @@ class nsIURI;
namespace mozilla {
class ErrorResult;
class DOMMediaStream;
namespace dom {
@ -61,10 +60,6 @@ public:
CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
nsAString& aResult, ErrorResult& aRv);
static void
CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
nsAString& aResult, ErrorResult& aRv);
static void
CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
nsAString& aResult, ErrorResult& aRv);
@ -77,8 +72,8 @@ public:
IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
ErrorResult& aRv);
virtual void
GetHref(nsAString& aHref) const = 0;
void
GetHref(nsAString& aHref) const;
virtual void
SetHref(const nsAString& aHref, ErrorResult& aRv) = 0;
@ -86,61 +81,61 @@ public:
virtual void
GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const = 0;
virtual void
GetProtocol(nsAString& aProtocol) const = 0;
void
GetProtocol(nsAString& aProtocol) const;
virtual void
SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) = 0;
virtual void
GetUsername(nsAString& aUsername) const = 0;
void
GetUsername(nsAString& aUsername) const;
virtual void
SetUsername(const nsAString& aUsername) = 0;
void
SetUsername(const nsAString& aUsername);
virtual void
GetPassword(nsAString& aPassword) const = 0;
void
GetPassword(nsAString& aPassword) const;
virtual void
SetPassword(const nsAString& aPassword) = 0;
void
SetPassword(const nsAString& aPassword);
virtual void
GetHost(nsAString& aHost) const = 0;
void
GetHost(nsAString& aHost) const;
virtual void
SetHost(const nsAString& aHost) = 0;
void
SetHost(const nsAString& aHost);
virtual void
GetHostname(nsAString& aHostname) const = 0;
void
GetHostname(nsAString& aHostname) const;
virtual void
SetHostname(const nsAString& aHostname) = 0;
void
SetHostname(const nsAString& aHostname);
virtual void
GetPort(nsAString& aPort) const = 0;
void
GetPort(nsAString& aPort) const;
virtual void
SetPort(const nsAString& aPort) = 0;
void
SetPort(const nsAString& aPort);
virtual void
GetPathname(nsAString& aPathname) const = 0;
void
GetPathname(nsAString& aPathname) const;
virtual void
SetPathname(const nsAString& aPathname) = 0;
void
SetPathname(const nsAString& aPathname);
virtual void
GetSearch(nsAString& aSearch) const = 0;
void
GetSearch(nsAString& aSearch) const;
virtual void
SetSearch(const nsAString& aSearch);
URLSearchParams* SearchParams();
virtual void
GetHash(nsAString& aHost) const = 0;
void
GetHash(nsAString& aHost) const;
virtual void
SetHash(const nsAString& aHash) = 0;
void
SetHash(const nsAString& aHash);
void Stringify(nsAString& aRetval) const
{
@ -158,19 +153,26 @@ public:
URLSearchParamsUpdated(URLSearchParams* aSearchParams) override;
protected:
virtual ~URL()
{}
virtual ~URL() = default;
virtual void
UpdateURLSearchParams() = 0;
void
SetURI(already_AddRefed<nsIURI> aURI);
virtual void
SetSearchInternal(const nsAString& aSearch) = 0;
nsIURI*
GetURI() const;
void
UpdateURLSearchParams();
private:
void
SetSearchInternal(const nsAString& aSearch);
void CreateSearchParamsIfNeeded();
nsCOMPtr<nsISupports> mParent;
RefPtr<URLSearchParams> mSearchParams;
nsCOMPtr<nsIURI> mURI;
};
bool IsChromeURI(nsIURI* aURI);

View File

@ -18,34 +18,6 @@
namespace mozilla {
namespace dom {
namespace {
template<typename T>
void
CreateObjectURLInternal(const GlobalObject& aGlobal, T aObject,
nsAString& aResult, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (NS_WARN_IF(!global)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIPrincipal> principal =
nsContentUtils::ObjectPrincipal(aGlobal.Get());
nsAutoCString url;
aRv = nsHostObjectProtocolHandler::AddDataEntry(aObject, principal, url);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
global->RegisterHostObjectURI(url);
CopyASCIItoUTF16(url, aResult);
}
} // anonymous namespace
/* static */ already_AddRefed<URLMainThread>
URLMainThread::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
const Optional<nsAString>& aBase, ErrorResult& aRv)
@ -90,7 +62,8 @@ URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL,
return nullptr;
}
RefPtr<URLMainThread> url = new URLMainThread(aParent, uri.forget());
RefPtr<URLMainThread> url = new URLMainThread(aParent);
url->SetURI(uri.forget());
return url.forget();
}
@ -99,16 +72,24 @@ URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
nsAString& aResult, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
CreateObjectURLInternal(aGlobal, aBlob.Impl(), aResult, aRv);
}
/* static */ void
URLMainThread::CreateObjectURL(const GlobalObject& aGlobal,
DOMMediaStream& aStream,
nsAString& aResult, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
CreateObjectURLInternal(aGlobal, &aStream, aResult, aRv);
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (NS_WARN_IF(!global)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsCOMPtr<nsIPrincipal> principal =
nsContentUtils::ObjectPrincipal(aGlobal.Get());
nsAutoCString url;
aRv = nsHostObjectProtocolHandler::AddDataEntry(aBlob.Impl(), principal, url);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
global->RegisterHostObjectURI(url);
CopyASCIItoUTF16(url, aResult);
}
/* static */ void
@ -161,10 +142,8 @@ URLMainThread::RevokeObjectURL(const GlobalObject& aGlobal,
}
}
URLMainThread::URLMainThread(nsISupports* aParent,
already_AddRefed<nsIURI> aURI)
URLMainThread::URLMainThread(nsISupports* aParent)
: URL(aParent)
, mURI(aURI)
{
MOZ_ASSERT(NS_IsMainThread());
}
@ -183,18 +162,6 @@ URLMainThread::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
return nsHostObjectProtocolHandler::HasDataEntry(asciiurl);
}
void
URLMainThread::GetHref(nsAString& aHref) const
{
aHref.Truncate();
nsAutoCString href;
nsresult rv = mURI->GetSpec(href);
if (NS_SUCCEEDED(rv)) {
CopyUTF8toUTF16(href, aHref);
}
}
void
URLMainThread::SetHref(const nsAString& aHref, ErrorResult& aRv)
{
@ -214,26 +181,14 @@ URLMainThread::SetHref(const nsAString& aHref, ErrorResult& aRv)
return;
}
mURI = uri;
SetURI(uri.forget());
UpdateURLSearchParams();
}
void
URLMainThread::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const
{
nsContentUtils::GetUTFOrigin(mURI, aOrigin);
}
void
URLMainThread::GetProtocol(nsAString& aProtocol) const
{
nsAutoCString protocol;
if (NS_SUCCEEDED(mURI->GetScheme(protocol))) {
aProtocol.Truncate();
}
CopyASCIItoUTF16(protocol, aProtocol);
aProtocol.Append(char16_t(':'));
nsContentUtils::GetUTFOrigin(GetURI(), aOrigin);
}
void
@ -250,7 +205,7 @@ URLMainThread::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv)
// implementation. In order to do this properly, we have to serialize the
// existing URL and reparse it in a new object.
nsCOMPtr<nsIURI> clone;
nsresult rv = NS_MutateURI(mURI)
nsresult rv = NS_MutateURI(GetURI())
.SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)))
.Finalize(clone);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -269,205 +224,7 @@ URLMainThread::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv)
return;
}
mURI = uri;
}
#define URL_GETTER( value, func ) \
value.Truncate(); \
nsAutoCString tmp; \
nsresult rv = mURI->func(tmp); \
if (NS_SUCCEEDED(rv)) { \
CopyUTF8toUTF16(tmp, value); \
}
void
URLMainThread::GetUsername(nsAString& aUsername) const
{
URL_GETTER(aUsername, GetUsername);
}
void
URLMainThread::SetUsername(const nsAString& aUsername)
{
Unused << NS_MutateURI(mURI)
.SetUsername(NS_ConvertUTF16toUTF8(aUsername))
.Finalize(mURI);
}
void
URLMainThread::GetPassword(nsAString& aPassword) const
{
URL_GETTER(aPassword, GetPassword);
}
void
URLMainThread::SetPassword(const nsAString& aPassword)
{
Unused << NS_MutateURI(mURI)
.SetPassword(NS_ConvertUTF16toUTF8(aPassword))
.Finalize(mURI);
}
void
URLMainThread::GetHost(nsAString& aHost) const
{
URL_GETTER(aHost, GetHostPort);
}
void
URLMainThread::SetHost(const nsAString& aHost)
{
Unused << NS_MutateURI(mURI)
.SetHostPort(NS_ConvertUTF16toUTF8(aHost))
.Finalize(mURI);
}
void
URLMainThread::UpdateURLSearchParams()
{
if (!mSearchParams) {
return;
}
nsAutoCString search;
nsresult rv = mURI->GetQuery(search);
if (NS_WARN_IF(NS_FAILED(rv))) {
search.Truncate();
}
mSearchParams->ParseInput(search);
}
void
URLMainThread::GetHostname(nsAString& aHostname) const
{
aHostname.Truncate();
nsContentUtils::GetHostOrIPv6WithBrackets(mURI, aHostname);
}
void
URLMainThread::SetHostname(const nsAString& aHostname)
{
// nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
// The return code is silently ignored
mozilla::Unused << NS_MutateURI(mURI)
.SetHost(NS_ConvertUTF16toUTF8(aHostname))
.Finalize(mURI);
}
void
URLMainThread::GetPort(nsAString& aPort) const
{
aPort.Truncate();
int32_t port;
nsresult rv = mURI->GetPort(&port);
if (NS_SUCCEEDED(rv) && port != -1) {
nsAutoString portStr;
portStr.AppendInt(port, 10);
aPort.Assign(portStr);
}
}
void
URLMainThread::SetPort(const nsAString& aPort)
{
nsresult rv;
nsAutoString portStr(aPort);
int32_t port = -1;
// nsIURI uses -1 as default value.
if (!portStr.IsEmpty()) {
port = portStr.ToInteger(&rv);
if (NS_FAILED(rv)) {
return;
}
}
Unused << NS_MutateURI(mURI)
.SetPort(port)
.Finalize(mURI);
}
void
URLMainThread::GetPathname(nsAString& aPathname) const
{
aPathname.Truncate();
// Do not throw! Not having a valid URI or URL should result in an empty
// string.
nsAutoCString file;
nsresult rv = mURI->GetFilePath(file);
if (NS_SUCCEEDED(rv)) {
CopyUTF8toUTF16(file, aPathname);
}
}
void
URLMainThread::SetPathname(const nsAString& aPathname)
{
// Do not throw!
Unused << NS_MutateURI(mURI)
.SetFilePath(NS_ConvertUTF16toUTF8(aPathname))
.Finalize(mURI);
}
void
URLMainThread::GetSearch(nsAString& aSearch) const
{
aSearch.Truncate();
// Do not throw! Not having a valid URI or URL should result in an empty
// string.
nsAutoCString search;
nsresult rv;
rv = mURI->GetQuery(search);
if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
aSearch.Assign(u'?');
AppendUTF8toUTF16(search, aSearch);
}
}
void
URLMainThread::GetHash(nsAString& aHash) const
{
aHash.Truncate();
nsAutoCString ref;
nsresult rv = mURI->GetRef(ref);
if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
aHash.Assign(char16_t('#'));
AppendUTF8toUTF16(ref, aHash);
}
}
void
URLMainThread::SetHash(const nsAString& aHash)
{
Unused << NS_MutateURI(mURI)
.SetRef(NS_ConvertUTF16toUTF8(aHash))
.Finalize(mURI);
}
void
URLMainThread::SetSearchInternal(const nsAString& aSearch)
{
// Ignore failures to be compatible with NS4.
Unused << NS_MutateURI(mURI)
.SetQuery(NS_ConvertUTF16toUTF8(aSearch))
.Finalize(mURI);
}
nsIURI*
URLMainThread::GetURI() const
{
MOZ_ASSERT(NS_IsMainThread());
return mURI;
SetURI(uri.forget());
}
} // namespace dom

View File

@ -32,10 +32,6 @@ public:
CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
nsAString& aResult, ErrorResult& aRv);
static void
CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
nsAString& aResult, ErrorResult& aRv);
static void
CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
nsAString& aResult, ErrorResult& aRv);
@ -48,10 +44,7 @@ public:
IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
ErrorResult& aRv);
URLMainThread(nsISupports* aParent, already_AddRefed<nsIURI> aURI);
virtual void
GetHref(nsAString& aHref) const override;
explicit URLMainThread(nsISupports* aParent);
virtual void
SetHref(const nsAString& aHref, ErrorResult& aRv) override;
@ -59,69 +52,11 @@ public:
virtual void
GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override;
virtual void
GetProtocol(nsAString& aProtocol) const override;
virtual void
SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override;
virtual void
GetUsername(nsAString& aUsername) const override;
virtual void
SetUsername(const nsAString& aUsername) override;
virtual void
GetPassword(nsAString& aPassword) const override;
virtual void
SetPassword(const nsAString& aPassword) override;
virtual void
GetHost(nsAString& aHost) const override;
virtual void
SetHost(const nsAString& aHost) override;
virtual void
GetHostname(nsAString& aHostname) const override;
virtual void
SetHostname(const nsAString& aHostname) override;
virtual void
GetPort(nsAString& aPort) const override;
virtual void
SetPort(const nsAString& aPort) override;
virtual void
GetPathname(nsAString& aPathname) const override;
virtual void
SetPathname(const nsAString& aPathname) override;
virtual void
GetSearch(nsAString& aSearch) const override;
virtual void
GetHash(nsAString& aHost) const override;
virtual void
SetHash(const nsAString& aHash) override;
virtual void UpdateURLSearchParams() override;
virtual void
SetSearchInternal(const nsAString& aSearch) override;
nsIURI*
GetURI() const;
private:
~URLMainThread();
nsCOMPtr<nsIURI> mURI;
};
} // namespace dom

View File

@ -22,32 +22,6 @@ using net::nsStandardURL;
namespace dom {
// Proxy class to forward all the requests to a URLMainThread object.
class URLWorker::URLProxy final
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLProxy)
explicit URLProxy(already_AddRefed<URLMainThread> aURL)
: mURL(aURL)
{
MOZ_ASSERT(NS_IsMainThread());
}
URLMainThread* URL()
{
return mURL;
}
private:
~URLProxy()
{
NS_ReleaseOnMainThreadSystemGroup("URLMainThread", mURL.forget());
}
RefPtr<URLMainThread> mURL;
};
// This class creates an URL from a DOM Blob on the main thread.
class CreateURLRunnable : public WorkerMainThreadRunnable
{
@ -213,7 +187,7 @@ private:
nsString mBase; // IsVoid() if we have no base URI string.
RefPtr<URLWorker::URLProxy> mRetval;
nsCOMPtr<nsIURI> mRetval;
public:
ConstructorRunnable(WorkerPrivate* aWorkerPrivate,
@ -235,25 +209,28 @@ public:
{
AssertIsOnMainThread();
ErrorResult rv;
RefPtr<URLMainThread> url;
nsCOMPtr<nsIURI> baseUri;
if (!mBase.IsVoid()) {
url = URLMainThread::Constructor(nullptr, mURL, mBase, rv);
} else {
url = URLMainThread::Constructor(nullptr, mURL, nullptr, rv);
nsresult rv = NS_NewURI(getter_AddRefs(baseUri), mBase, nullptr, nullptr,
nsContentUtils::GetIOService());
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
}
if (rv.Failed()) {
rv.SuppressException();
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), mURL, nullptr, baseUri,
nsContentUtils::GetIOService());
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
mRetval = new URLWorker::URLProxy(url.forget());
mRetval = Move(uri);
return true;
}
URLWorker::URLProxy*
GetURLProxy(ErrorResult& aRv) const
nsIURI*
GetURI(ErrorResult& aRv) const
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
@ -271,13 +248,13 @@ class OriginGetterRunnable : public WorkerMainThreadRunnable
public:
OriginGetterRunnable(WorkerPrivate* aWorkerPrivate,
nsAString& aValue,
URLWorker::URLProxy* aURLProxy)
nsIURI* aURI)
: WorkerMainThreadRunnable(aWorkerPrivate,
// We can have telemetry keys for each getter when
// needed.
NS_LITERAL_CSTRING("URL :: getter"))
, mValue(aValue)
, mURLProxy(aURLProxy)
, mURI(aURI)
{
mWorkerPrivate->AssertIsOnWorkerThread();
}
@ -287,8 +264,7 @@ public:
{
AssertIsOnMainThread();
ErrorResult rv;
mURLProxy->URL()->GetOrigin(mValue, rv);
MOZ_ASSERT(!rv.Failed(), "Main-thread getters do not fail.");
nsContentUtils::GetUTFOrigin(mURI, mValue);
return true;
}
@ -300,28 +276,19 @@ public:
private:
nsAString& mValue;
RefPtr<URLWorker::URLProxy> mURLProxy;
nsCOMPtr<nsIURI> mURI;
};
class SetterRunnable : public WorkerMainThreadRunnable
class ProtocolSetterRunnable : public WorkerMainThreadRunnable
{
public:
enum SetterType {
SetterHref,
SetterProtocol,
};
SetterRunnable(WorkerPrivate* aWorkerPrivate,
SetterType aType, const nsAString& aValue,
URLWorker::URLProxy* aURLProxy)
ProtocolSetterRunnable(WorkerPrivate* aWorkerPrivate,
const nsACString& aValue,
nsIURI* aURI)
: WorkerMainThreadRunnable(aWorkerPrivate,
// We can have telemetry keys for each setter when
// needed.
NS_LITERAL_CSTRING("URL :: setter"))
NS_LITERAL_CSTRING("ProtocolSetterRunnable"))
, mValue(aValue)
, mType(aType)
, mURLProxy(aURLProxy)
, mFailed(false)
, mURI(aURI)
{
mWorkerPrivate->AssertIsOnWorkerThread();
}
@ -330,43 +297,47 @@ public:
MainThreadRun() override
{
AssertIsOnMainThread();
ErrorResult rv;
switch (mType) {
case SetterHref: {
mURLProxy->URL()->SetHref(mValue, rv);
break;
}
case SetterProtocol:
mURLProxy->URL()->SetProtocol(mValue, rv);
break;
nsCOMPtr<nsIURI> clone;
nsresult rv = NS_MutateURI(mURI)
.SetScheme(mValue)
.Finalize(clone);
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
mFailed = true;
nsAutoCString href;
rv = clone->GetSpec(href);
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), href);
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
mRetval = Move(uri);
return true;
}
bool Failed() const
{
return mFailed;
}
void
Dispatch(ErrorResult& aRv)
{
WorkerMainThreadRunnable::Dispatch(Terminating, aRv);
}
nsIURI*
GetRetval() const
{
return mRetval;
}
private:
const nsString mValue;
SetterType mType;
RefPtr<URLWorker::URLProxy> mURLProxy;
bool mFailed;
const nsCString mValue;
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mRetval;
};
/* static */ already_AddRefed<URLWorker>
@ -488,34 +459,6 @@ URLWorker::Init(const nsAString& aURL, const Optional<nsAString>& aBase,
}
}
if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https")) {
nsCOMPtr<nsIURI> baseURL;
if (aBase.WasPassed()) {
// XXXcatalinb: SetSpec only writes a warning to the console on urls
// without a valid scheme. I can't fix that because we've come to rely
// on that behaviour in a bunch of different places.
nsresult rv = NS_MutateURI(new nsStandardURL::Mutator())
.SetSpec(NS_ConvertUTF16toUTF8(aBase.Value()))
.Finalize(baseURL);
nsAutoCString baseScheme;
if (baseURL) {
baseURL->GetScheme(baseScheme);
}
if (NS_WARN_IF(NS_FAILED(rv)) || baseScheme.IsEmpty()) {
aRv.ThrowTypeError<MSG_INVALID_URL>(aBase.Value());
return;
}
}
nsCOMPtr<nsIURI> uri;
aRv = NS_MutateURI(new nsStandardURL::Mutator())
.Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
nsIStandardURL::URLTYPE_STANDARD,
-1, NS_ConvertUTF16toUTF8(aURL),
nullptr, baseURL, nullptr))
.Finalize(mStdURL);
return;
}
// create url proxy
RefPtr<ConstructorRunnable> runnable =
new ConstructorRunnable(mWorkerPrivate, aURL, aBase);
@ -523,37 +466,19 @@ URLWorker::Init(const nsAString& aURL, const Optional<nsAString>& aBase,
if (NS_WARN_IF(aRv.Failed())) {
return;
}
mURLProxy = runnable->GetURLProxy(aRv);
nsCOMPtr<nsIURI> uri = runnable->GetURI(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
SetURI(uri.forget());
}
URLWorker::~URLWorker() = default;
void
URLWorker::GetHref(nsAString& aHref) const
{
aHref.Truncate();
if (mStdURL) {
nsAutoCString href;
nsresult rv = mStdURL->GetSpec(href);
if (NS_SUCCEEDED(rv)) {
CopyUTF8toUTF16(href, aHref);
}
return;
}
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetHref(aHref);
}
void
URLWorker::SetHref(const nsAString& aHref, ErrorResult& aRv)
{
SetHrefInternal(aHref, eUseProxyIfNeeded, aRv);
}
void
URLWorker::SetHrefInternal(const nsAString& aHref, Strategy aStrategy,
ErrorResult& aRv)
{
nsAutoCString scheme;
nsresult rv = net_ExtractURLScheme(NS_ConvertUTF16toUTF8(aHref), scheme);
@ -562,78 +487,31 @@ URLWorker::SetHrefInternal(const nsAString& aHref, Strategy aStrategy,
return;
}
if (aStrategy == eUseProxyIfNeeded &&
(scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https"))) {
nsCOMPtr<nsIURI> uri;
aRv = NS_MutateURI(new nsStandardURL::Mutator())
.SetSpec(NS_ConvertUTF16toUTF8(aHref))
.Finalize(mStdURL);
mURLProxy = nullptr;
UpdateURLSearchParams();
return;
}
mStdURL = nullptr;
// fallback to using a main thread url proxy
if (mURLProxy) {
RefPtr<SetterRunnable> runnable =
new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterHref, aHref,
mURLProxy);
runnable->Dispatch(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
UpdateURLSearchParams();
return;
}
// create the proxy now
RefPtr<ConstructorRunnable> runnable =
new ConstructorRunnable(mWorkerPrivate, aHref, Optional<nsAString>());
runnable->Dispatch(Terminating, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
mURLProxy = runnable->GetURLProxy(aRv);
nsCOMPtr<nsIURI> uri = runnable->GetURI(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
SetURI(uri.forget());
UpdateURLSearchParams();
}
void
URLWorker::GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const
{
if (mStdURL) {
nsContentUtils::GetUTFOrigin(mStdURL, aOrigin);
return;
}
MOZ_ASSERT(mURLProxy);
RefPtr<OriginGetterRunnable> runnable =
new OriginGetterRunnable(mWorkerPrivate, aOrigin, mURLProxy);
new OriginGetterRunnable(mWorkerPrivate, aOrigin, GetURI());
runnable->Dispatch(aRv);
}
void
URLWorker::GetProtocol(nsAString& aProtocol) const
{
aProtocol.Truncate();
nsAutoCString protocol;
if (mStdURL) {
if (NS_SUCCEEDED(mStdURL->GetScheme(protocol))) {
CopyASCIItoUTF16(protocol, aProtocol);
aProtocol.Append(char16_t(':'));
}
return;
}
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetProtocol(aProtocol);
}
void
URLWorker::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv)
{
@ -645,289 +523,19 @@ URLWorker::SetProtocol(const nsAString& aProtocol, ErrorResult& aRv)
FindCharInReadable(':', iter, end);
NS_ConvertUTF16toUTF8 scheme(Substring(start, iter));
// If we are using nsStandardURL on the owning thread, we can continue only if
// the scheme is http or https.
if (mStdURL &&
(scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https"))) {
Unused << NS_MutateURI(mStdURL)
.SetScheme(scheme)
.Finalize(mStdURL);
return;
}
// If we are using mStandardURL but the new scheme is not http nor https, we
// have to migrate to the URL proxy.
if (mStdURL) {
nsAutoCString href;
nsresult rv = mStdURL->GetSpec(href);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
SetHrefInternal(NS_ConvertUTF8toUTF16(href), eAlwaysUseProxy, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
// We want a proxy here.
MOZ_ASSERT(!mStdURL);
MOZ_ASSERT(mURLProxy);
// Now we can restart setting the protocol.
}
MOZ_ASSERT(mURLProxy);
RefPtr<SetterRunnable> runnable =
new SetterRunnable(mWorkerPrivate, SetterRunnable::SetterProtocol,
aProtocol, mURLProxy);
RefPtr<ProtocolSetterRunnable> runnable =
new ProtocolSetterRunnable(mWorkerPrivate, scheme, GetURI());
runnable->Dispatch(aRv);
MOZ_ASSERT(!runnable->Failed());
}
#define STDURL_GETTER(value, method) \
if (mStdURL) { \
value.Truncate(); \
nsAutoCString tmp; \
nsresult rv = mStdURL->method(tmp); \
if (NS_SUCCEEDED(rv)) { \
CopyUTF8toUTF16(tmp, value); \
} \
return; \
}
#define STDURL_SETTER(value, method) \
if (mStdURL) { \
Unused << NS_MutateURI(mStdURL) \
.method(NS_ConvertUTF16toUTF8(value)) \
.Finalize(mStdURL); \
return; \
}
void
URLWorker::GetUsername(nsAString& aUsername) const
{
STDURL_GETTER(aUsername, GetUsername);
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetUsername(aUsername);
}
void
URLWorker::SetUsername(const nsAString& aUsername)
{
STDURL_SETTER(aUsername, SetUsername);
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->SetUsername(aUsername);
}
void
URLWorker::GetPassword(nsAString& aPassword) const
{
STDURL_GETTER(aPassword, GetPassword);
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetPassword(aPassword);
}
void
URLWorker::SetPassword(const nsAString& aPassword)
{
STDURL_SETTER(aPassword, SetPassword);
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->SetPassword(aPassword);
}
void
URLWorker::GetHost(nsAString& aHost) const
{
STDURL_GETTER(aHost, GetHostPort);
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetHost(aHost);
}
void
URLWorker::SetHost(const nsAString& aHost)
{
STDURL_SETTER(aHost, SetHostPort);
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->SetHost(aHost);
}
void
URLWorker::GetHostname(nsAString& aHostname) const
{
aHostname.Truncate();
if (mStdURL) {
nsresult rv = nsContentUtils::GetHostOrIPv6WithBrackets(mStdURL, aHostname);
if (NS_FAILED(rv)) {
aHostname.Truncate();
}
if (NS_WARN_IF(aRv.Failed())) {
return;
}
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetHostname(aHostname);
}
void
URLWorker::SetHostname(const nsAString& aHostname)
{
STDURL_SETTER(aHostname, SetHost);
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->SetHostname(aHostname);
}
void
URLWorker::GetPort(nsAString& aPort) const
{
aPort.Truncate();
if (mStdURL) {
int32_t port;
nsresult rv = mStdURL->GetPort(&port);
if (NS_SUCCEEDED(rv) && port != -1) {
nsAutoString portStr;
portStr.AppendInt(port, 10);
aPort.Assign(portStr);
}
nsCOMPtr<nsIURI> uri = runnable->GetRetval();
if (NS_WARN_IF(!uri)) {
return;
}
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetPort(aPort);
}
void
URLWorker::SetPort(const nsAString& aPort)
{
if (mStdURL) {
nsresult rv;
nsAutoString portStr(aPort);
int32_t port = -1;
// nsIURI uses -1 as default value.
if (!portStr.IsEmpty()) {
port = portStr.ToInteger(&rv);
if (NS_FAILED(rv)) {
return;
}
}
Unused << NS_MutateURI(mStdURL)
.SetPort(port)
.Finalize(mStdURL);
return;
}
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->SetPort(aPort);
}
void
URLWorker::GetPathname(nsAString& aPathname) const
{
aPathname.Truncate();
if (mStdURL) {
nsAutoCString file;
nsresult rv = mStdURL->GetFilePath(file);
if (NS_SUCCEEDED(rv)) {
CopyUTF8toUTF16(file, aPathname);
}
return;
}
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetPathname(aPathname);
}
void
URLWorker::SetPathname(const nsAString& aPathname)
{
STDURL_SETTER(aPathname, SetFilePath);
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->SetPathname(aPathname);
}
void
URLWorker::GetSearch(nsAString& aSearch) const
{
aSearch.Truncate();
if (mStdURL) {
nsAutoCString search;
nsresult rv;
rv = mStdURL->GetQuery(search);
if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
aSearch.Assign(u'?');
AppendUTF8toUTF16(search, aSearch);
}
return;
}
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetSearch(aSearch);
}
void
URLWorker::GetHash(nsAString& aHash) const
{
aHash.Truncate();
if (mStdURL) {
nsAutoCString ref;
nsresult rv = mStdURL->GetRef(ref);
if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
aHash.Assign(char16_t('#'));
AppendUTF8toUTF16(ref, aHash);
}
return;
}
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->GetHash(aHash);
}
void
URLWorker::SetHash(const nsAString& aHash)
{
STDURL_SETTER(aHash, SetRef);
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->SetHash(aHash);
}
void
URLWorker::SetSearchInternal(const nsAString& aSearch)
{
if (mStdURL) {
// URLMainThread ignores failures here.
Unused << NS_MutateURI(mStdURL)
.SetQuery(NS_ConvertUTF16toUTF8(aSearch))
.Finalize(mStdURL);
return;
}
MOZ_ASSERT(mURLProxy);
mURLProxy->URL()->SetSearch(aSearch);
}
void
URLWorker::UpdateURLSearchParams()
{
if (mSearchParams) {
nsAutoString search;
GetSearch(search);
mSearchParams->ParseInput(NS_ConvertUTF16toUTF8(Substring(search, 1)));
}
SetURI(uri.forget());
}
} // namespace dom

View File

@ -24,8 +24,6 @@ class WorkerPrivate;
class URLWorker final : public URL
{
public:
class URLProxy;
static already_AddRefed<URLWorker>
Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
const Optional<nsAString>& aBase, ErrorResult& aRv);
@ -52,87 +50,19 @@ public:
Init(const nsAString& aURL, const Optional<nsAString>& aBase,
ErrorResult& aRv);
virtual void
GetHref(nsAString& aHref) const override;
virtual void
SetHref(const nsAString& aHref, ErrorResult& aRv) override;
virtual void
GetOrigin(nsAString& aOrigin, ErrorResult& aRv) const override;
virtual void
GetProtocol(nsAString& aProtocol) const override;
virtual void
SetProtocol(const nsAString& aProtocol, ErrorResult& aRv) override;
virtual void
GetUsername(nsAString& aUsername) const override;
virtual void
SetUsername(const nsAString& aUsername) override;
virtual void
GetPassword(nsAString& aPassword) const override;
virtual void
SetPassword(const nsAString& aPassword) override;
virtual void
GetHost(nsAString& aHost) const override;
virtual void
SetHost(const nsAString& aHost) override;
virtual void
GetHostname(nsAString& aHostname) const override;
virtual void
SetHostname(const nsAString& aHostname) override;
virtual void
GetPort(nsAString& aPort) const override;
virtual void
SetPort(const nsAString& aPort) override;
virtual void
GetPathname(nsAString& aPathname) const override;
virtual void
SetPathname(const nsAString& aPathname) override;
virtual void
GetSearch(nsAString& aSearch) const override;
virtual void
GetHash(nsAString& aHost) const override;
virtual void
SetHash(const nsAString& aHash) override;
virtual void UpdateURLSearchParams() override;
virtual void
SetSearchInternal(const nsAString& aSearch) override;
private:
~URLWorker();
enum Strategy {
eAlwaysUseProxy,
eUseProxyIfNeeded,
};
void
SetHrefInternal(const nsAString& aHref,
Strategy aStrategy,
ErrorResult& aRv);
WorkerPrivate* mWorkerPrivate;
RefPtr<URLProxy> mURLProxy;
nsCOMPtr<nsIURI> mStdURL;
};
} // namespace dom

View File

@ -6,7 +6,6 @@
* The origins of this IDL file are
* http://url.spec.whatwg.org/#api
* http://dev.w3.org/2006/webapi/FileAPI/#creating-revoking
* http://dev.w3.org/2011/webrtc/editor/getusermedia.html#url
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
@ -45,8 +44,6 @@ partial interface URL {
[Throws]
static DOMString createObjectURL(Blob blob);
[Throws]
static DOMString createObjectURL(MediaStream stream);
[Throws]
static void revokeObjectURL(DOMString url);
[ChromeOnly, Throws]
static boolean isValidURL(DOMString url);

View File

@ -1553,6 +1553,7 @@ public:
static void ShutDown();
static bool HasSSE2();
static bool HasSSE4();
/**
* Returns false if any of the following are true:

View File

@ -124,7 +124,7 @@ struct BaseRect {
result.y = std::max<T>(y, aRect.y);
result.width = std::min<T>(x - result.x + width, aRect.x - result.x + aRect.width);
result.height = std::min<T>(y - result.y + height, aRect.y - result.y + aRect.height);
if (result.width < 0 || result.height < 0) {
if (result.width <= 0 || result.height <= 0) {
result.SizeTo(0, 0);
}
return result;

View File

@ -87,7 +87,8 @@ enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
#ifdef HAVE_CPUID_H
#if !(defined(__SSE2__) || defined(_M_X64) || \
(defined(_M_IX86_FP) && _M_IX86_FP >= 2))
(defined(_M_IX86_FP) && _M_IX86_FP >= 2)) || \
!defined(__SSE4__)
// cpuid.h is available on gcc 4.3 and higher on i386 and x86_64
#include <cpuid.h>
@ -282,6 +283,29 @@ Factory::HasSSE2()
#endif
}
bool
Factory::HasSSE4()
{
#if defined(__SSE4__)
// gcc with -msse2 (default on OSX and x86-64)
// cl.exe with -arch:SSE2 (default on x64 compiler)
return true;
#elif defined(HAVE_CPU_DETECTION)
static enum {
UNINITIALIZED,
NO_SSE4,
HAS_SSE4
} sDetectionState = UNINITIALIZED;
if (sDetectionState == UNINITIALIZED) {
sDetectionState = HasCPUIDBit(1u, ecx, (1u << 19)) ? HAS_SSE4 : NO_SSE4;
}
return sDetectionState == HAS_SSE4;
#else
return false;
#endif
}
// If the size is "reasonable", we want gfxCriticalError to assert, so
// this is the option set up for it.
inline int LoggerOptionsBasedOnSize(const IntSize& aSize)

View File

@ -8,6 +8,7 @@
#include "APZCTreeManager.h"
#include "AsyncPanZoomController.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/layers/APZThreadUtils.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/LayerMetricsWrapper.h"
@ -52,6 +53,11 @@ APZSampler::SetWebRenderWindowId(const wr::WindowId& aWindowId)
mWindowId = Some(aWindowId);
if (!sWindowIdMap) {
sWindowIdMap = new std::unordered_map<uint64_t, APZSampler*>();
NS_DispatchToMainThread(
NS_NewRunnableFunction("APZUpdater::ClearOnShutdown", [] {
ClearOnShutdown(&sWindowIdMap);
}
));
}
(*sWindowIdMap)[wr::AsUint64(aWindowId)] = this;
}

View File

@ -9,6 +9,7 @@
#include "APZCTreeManager.h"
#include "AsyncPanZoomController.h"
#include "base/task.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/layers/APZThreadUtils.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/SynchronousTask.h"
@ -59,6 +60,11 @@ APZUpdater::SetWebRenderWindowId(const wr::WindowId& aWindowId)
mWindowId = Some(aWindowId);
if (!sWindowIdMap) {
sWindowIdMap = new std::unordered_map<uint64_t, APZUpdater*>();
NS_DispatchToMainThread(
NS_NewRunnableFunction("APZUpdater::ClearOnShutdown", [] {
ClearOnShutdown(&sWindowIdMap);
}
));
}
(*sWindowIdMap)[wr::AsUint64(aWindowId)] = this;
}

View File

@ -13,12 +13,17 @@
#include <algorithm> // for min/max
#include "mozilla/Likely.h" // for MOZ_UNLIKELY
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "nsCoord.h" // for nscoord, etc
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsPoint.h" // for nsIntPoint, nsPoint
#include "nsMargin.h" // for nsIntMargin, nsMargin
#include "nsSize.h" // for IntSize, nsSize
#include "nscore.h" // for NS_BUILD_REFCNT_LOGGING
#if !defined(ANDROID) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
#include "smmintrin.h"
#endif
typedef mozilla::gfx::IntRect nsIntRect;
@ -120,6 +125,79 @@ struct nsRect :
{
*this = aRect1.Union(aRect2);
}
#if defined(_MSC_VER) && !defined(__clang__)
// Only MSVC supports inlining intrinsics for archs you're not compiling for.
MOZ_MUST_USE nsRect Intersect(const nsRect& aRect) const
{
nsRect result;
if (mozilla::gfx::Factory::HasSSE4()) {
__m128i rect1 = _mm_loadu_si128((__m128i*)&aRect); // x1, y1, w1, h1
__m128i rect2 = _mm_loadu_si128((__m128i*)this); // x2, y2, w2, h2
__m128i resultRect = _mm_max_epi32(rect1, rect2); // xr, yr, zz, zz
// result.width = std::min<int32_t>(x - result.x + width, aRect.x - result.x + aRect.width);
// result.height = std::min<int32_t>(y - result.y + height, aRect.y - result.y + aRect.height);
__m128i widthheight = _mm_min_epi32(_mm_add_epi32(_mm_sub_epi32(rect1, resultRect), _mm_srli_si128(rect1, 8)),
_mm_add_epi32(_mm_sub_epi32(rect2, resultRect), _mm_srli_si128(rect2, 8))); // w, h, zz, zz
widthheight = _mm_slli_si128(widthheight, 8); // 00, 00, wr, hr
resultRect = _mm_blend_epi16(resultRect, widthheight, 0xF0); // xr, yr, wr, hr
if ((_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpgt_epi32(resultRect, _mm_setzero_si128()))) & 0xC) != 0xC) {
// It's potentially more efficient to store all 0s. But the non SSE4 code leaves x/y intact
// so let's do the same here.
resultRect = _mm_and_si128(resultRect, _mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF));
}
_mm_storeu_si128((__m128i*)&result, resultRect);
return result;
}
result.x = std::max<int32_t>(x, aRect.x);
result.y = std::max<int32_t>(y, aRect.y);
result.width = std::min<int32_t>(x - result.x + width, aRect.x - result.x + aRect.width);
result.height = std::min<int32_t>(y - result.y + height, aRect.y - result.y + aRect.height);
if (result.width <= 0 || result.height <= 0) {
result.SizeTo(0, 0);
}
return result;
}
bool IntersectRect(const nsRect& aRect1, const nsRect& aRect2)
{
if (mozilla::gfx::Factory::HasSSE4()) {
__m128i rect1 = _mm_loadu_si128((__m128i*)&aRect1); // x1, y1, w1, h1
__m128i rect2 = _mm_loadu_si128((__m128i*)&aRect2); // x2, y2, w2, h2
__m128i resultRect = _mm_max_epi32(rect1, rect2); // xr, yr, zz, zz
// result.width = std::min<int32_t>(x - result.x + width, aRect.x - result.x + aRect.width);
// result.height = std::min<int32_t>(y - result.y + height, aRect.y - result.y + aRect.height);
__m128i widthheight = _mm_min_epi32(_mm_add_epi32(_mm_sub_epi32(rect1, resultRect), _mm_srli_si128(rect1, 8)),
_mm_add_epi32(_mm_sub_epi32(rect2, resultRect), _mm_srli_si128(rect2, 8))); // w, h, zz, zz
widthheight = _mm_slli_si128(widthheight, 8); // 00, 00, wr, hr
resultRect = _mm_blend_epi16(resultRect, widthheight, 0xF0); // xr, yr, wr, hr
if ((_mm_movemask_ps(_mm_castsi128_ps(_mm_cmpgt_epi32(resultRect, _mm_setzero_si128()))) & 0xC) != 0xC) {
// It's potentially more efficient to store all 0s. But the non SSE4 code leaves x/y intact
// so let's do the same here.
resultRect = _mm_and_si128(resultRect, _mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF));
_mm_storeu_si128((__m128i*)this, resultRect);
return false;
}
_mm_storeu_si128((__m128i*)this, resultRect);
return true;
}
*static_cast<nsRect*>(this) = aRect1.Intersect(aRect2);
return !IsEmpty();
}
#endif
#endif
void SaturatingUnionRect(const nsRect& aRect1, const nsRect& aRect2)
@ -214,20 +292,74 @@ nsRect::ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const
return rect;
}
#if !defined(ANDROID) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
// Life would be so much better if we had SSE4 here.
static MOZ_ALWAYS_INLINE __m128i floor_ps2epi32(__m128 x)
{
__m128 one = _mm_set_ps(1.0f, 1.0f, 1.0f, 1.0f);
__m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(x));
__m128 r = _mm_sub_ps(t, _mm_and_ps(_mm_cmplt_ps(x, t), one));
return _mm_cvttps_epi32(r);
}
static MOZ_ALWAYS_INLINE __m128i ceil_ps2epi32(__m128 x)
{
__m128 t = _mm_sub_ps(_mm_setzero_ps(), x);
__m128i r = _mm_sub_epi32(_mm_setzero_si128(), floor_ps2epi32(t));
return r;
}
#endif
// scale the rect but round to preserve centers
inline mozilla::gfx::IntRect
nsRect::ScaleToNearestPixels(float aXScale, float aYScale,
nscoord aAppUnitsPerPixel) const
{
mozilla::gfx::IntRect rect;
rect.SetNonEmptyBox(NSToIntRoundUp(NSAppUnitsToDoublePixels(x,
// Android x86 builds have bindgen issues.
#if !defined(ANDROID) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
__m128 appUnitsPacked = _mm_set_ps(aAppUnitsPerPixel, aAppUnitsPerPixel, aAppUnitsPerPixel, aAppUnitsPerPixel);
__m128 scalesPacked = _mm_set_ps(aYScale, aXScale, aYScale, aXScale);
__m128 biasesPacked = _mm_set_ps(0.5f, 0.5f, 0.5f, 0.5f);
__m128i rectPacked = _mm_loadu_si128((__m128i*)this);
__m128i topLeft = _mm_slli_si128(rectPacked, 8);
rectPacked = _mm_add_epi32(rectPacked, topLeft); // X, Y, XMost(), YMost()
__m128 rectFloat = _mm_cvtepi32_ps(rectPacked);
// Scale, i.e. ([ x y xmost ymost ] / aAppUnitsPerPixel) * [ aXScale aYScale aXScale aYScale ]
rectFloat = _mm_mul_ps(_mm_div_ps(rectFloat, appUnitsPacked), scalesPacked);
// Floor
// Executed with bias and roundmode down, since round-nearest rounds 0.5 downward half the time.
rectFloat = _mm_add_ps(rectFloat, biasesPacked);
rectPacked = floor_ps2epi32(rectFloat);
topLeft = _mm_slli_si128(rectPacked, 8);
rectPacked = _mm_sub_epi32(rectPacked, topLeft); // X, Y, Width, Height
// Avoid negative width/height due to overflow.
__m128i mask = _mm_or_si128(_mm_cmpgt_epi32(rectPacked, _mm_setzero_si128()),
_mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF));
// Mask will now contain [ 0xFFFFFFFF 0xFFFFFFFF (width <= 0 ? 0 : 0xFFFFFFFF) (height <= 0 ? 0 : 0xFFFFFFFF) ]
rectPacked = _mm_and_si128(rectPacked, mask);
_mm_storeu_si128((__m128i*)&rect, rectPacked);
#else
rect.SetNonEmptyBox(NSToIntRoundUp(NSAppUnitsToFloatPixels(x,
aAppUnitsPerPixel) * aXScale),
NSToIntRoundUp(NSAppUnitsToDoublePixels(y,
NSToIntRoundUp(NSAppUnitsToFloatPixels(y,
aAppUnitsPerPixel) * aYScale),
NSToIntRoundUp(NSAppUnitsToDoublePixels(XMost(),
NSToIntRoundUp(NSAppUnitsToFloatPixels(XMost(),
aAppUnitsPerPixel) * aXScale),
NSToIntRoundUp(NSAppUnitsToDoublePixels(YMost(),
NSToIntRoundUp(NSAppUnitsToFloatPixels(YMost(),
aAppUnitsPerPixel) * aYScale));
#endif
return rect;
}
@ -237,6 +369,37 @@ nsRect::ScaleToOutsidePixels(float aXScale, float aYScale,
nscoord aAppUnitsPerPixel) const
{
mozilla::gfx::IntRect rect;
// Android x86 builds have bindgen issues.
#if !defined(ANDROID) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
__m128 appUnitsPacked = _mm_set_ps(aAppUnitsPerPixel, aAppUnitsPerPixel, aAppUnitsPerPixel, aAppUnitsPerPixel);
__m128 scalesPacked = _mm_set_ps(aYScale, aXScale, aYScale, aXScale);
__m128i rectPacked = _mm_loadu_si128((__m128i*)this); // x, y, w, h
__m128i topLeft = _mm_slli_si128(rectPacked, 8); // 0, 0, x, y
rectPacked = _mm_add_epi32(rectPacked, topLeft); // X, Y, XMost(), YMost()
__m128 rectFloat = _mm_cvtepi32_ps(rectPacked);
// Scale i.e. ([ x y xmost ymost ] / aAppUnitsPerPixel) * [ aXScale aYScale aXScale aYScale ]
rectFloat = _mm_mul_ps(_mm_div_ps(rectFloat, appUnitsPacked), scalesPacked);
rectPacked = ceil_ps2epi32(rectFloat); // xx, xx, XMost(), YMost()
__m128i tmp = floor_ps2epi32(rectFloat); // x, y, xx, xx
// _mm_move_sd is 1 cycle method of getting the blending we want.
rectPacked = _mm_castpd_si128(_mm_move_sd(_mm_castsi128_pd(rectPacked), _mm_castsi128_pd(tmp))); // x, y, XMost(), YMost()
topLeft = _mm_slli_si128(rectPacked, 8); // 0, 0, r.x, r.y
rectPacked = _mm_sub_epi32(rectPacked, topLeft); // r.x, r.y, r.w, r.h
// Avoid negative width/height due to overflow.
__m128i mask = _mm_or_si128(_mm_cmpgt_epi32(rectPacked, _mm_setzero_si128()),
_mm_set_epi32(0, 0, 0xFFFFFFFF, 0xFFFFFFFF));
// Mask will now contain [ 0xFFFFFFFF 0xFFFFFFFF (width <= 0 ? 0 : 0xFFFFFFFF) (height <= 0 ? 0 : 0xFFFFFFFF) ]
rectPacked = _mm_and_si128(rectPacked, mask);
_mm_storeu_si128((__m128i*)&rect, rectPacked);
#else
rect.SetNonEmptyBox(NSToIntFloor(NSAppUnitsToFloatPixels(x,
float(aAppUnitsPerPixel)) * aXScale),
NSToIntFloor(NSAppUnitsToFloatPixels(y,
@ -245,6 +408,7 @@ nsRect::ScaleToOutsidePixels(float aXScale, float aYScale,
float(aAppUnitsPerPixel)) * aXScale),
NSToIntCeil(NSAppUnitsToFloatPixels(YMost(),
float(aAppUnitsPerPixel)) * aYScale));
#endif
return rect;
}

View File

@ -17,6 +17,7 @@ AnimationFrameBuffer::AnimationFrameBuffer()
, mInsertIndex(0)
, mGetIndex(0)
, mSizeKnown(false)
, mRedecodeError(false)
{ }
void
@ -71,7 +72,16 @@ AnimationFrameBuffer::Insert(RawAccessFrameRef&& aFrame)
// and we did not keep all of the frames. Replace whatever is there
// (probably an empty frame) with the new frame.
MOZ_ASSERT(MayDiscard());
MOZ_ASSERT(mInsertIndex < mFrames.Length());
// The first decode produced fewer frames than the redecodes, presumably
// because it hit an out-of-memory error which later attempts avoided. Just
// stop the animation because we can't tell the image that we have more
// frames now.
if (mInsertIndex >= mFrames.Length()) {
mRedecodeError = true;
mPending = 0;
return false;
}
if (mInsertIndex > 0) {
MOZ_ASSERT(!mFrames[mInsertIndex]);
@ -127,9 +137,23 @@ AnimationFrameBuffer::Insert(RawAccessFrameRef&& aFrame)
bool
AnimationFrameBuffer::MarkComplete()
{
// We may have stopped decoding at a different point in the animation than we
// did previously. That means the decoder likely hit a new error, e.g. OOM.
// This will prevent us from advancing as well, because we are missing the
// required frames to blend.
//
// XXX(aosmond): In an ideal world, we would be generating full frames, and
// the consumer of our data doesn't care about our internal state. It simply
// knows about the first frame, the current frame, and how long to display the
// current frame.
if (NS_WARN_IF(mInsertIndex != mFrames.Length())) {
MOZ_ASSERT(mSizeKnown);
mRedecodeError = true;
mPending = 0;
}
// We reached the end of the animation, the next frame we get, if we get
// another, will be the first frame again.
MOZ_ASSERT(mInsertIndex == mFrames.Length());
mInsertIndex = 0;
// Since we only request advancing when we want to resume at a certain point
@ -231,7 +255,7 @@ AnimationFrameBuffer::AdvanceInternal()
}
}
if (!mSizeKnown || MayDiscard()) {
if (!mRedecodeError && (!mSizeKnown || MayDiscard())) {
// Calculate how many frames we have requested ahead of the current frame.
size_t buffered = mPending;
if (mGetIndex > mInsertIndex) {
@ -276,13 +300,6 @@ AnimationFrameBuffer::Reset()
return false;
}
// If we are over the threshold, then we know we will have missing frames in
// our buffer. The easiest thing to do is to drop everything but the first
// frame and go back to the initial state.
bool restartDecoder = mPending == 0;
mInsertIndex = 0;
mPending = 2 * mBatch;
// Discard all frames besides the first, because the decoder always expects
// that when it re-inserts a frame, it is not present. (It doesn't re-insert
// the first frame.)
@ -290,6 +307,16 @@ AnimationFrameBuffer::Reset()
RawAccessFrameRef discard = Move(mFrames[i]);
}
mInsertIndex = 0;
// If we hit an error after redecoding, we never want to restart decoding.
if (mRedecodeError) {
MOZ_ASSERT(mPending == 0);
return false;
}
bool restartDecoder = mPending == 0;
mPending = 2 * mBatch;
return restartDecoder;
}

View File

@ -129,6 +129,12 @@ public:
*/
bool SizeKnown() const { return mSizeKnown; }
/**
* @returns True if encountered an error during redecode which should cause
* the caller to stop inserting frames.
*/
bool HasRedecodeError() const { return mRedecodeError; }
/**
* @returns The current frame index we have advanced to.
*/
@ -187,6 +193,9 @@ private:
// True if the total number of frames is known.
bool mSizeKnown;
// True if we encountered an error while redecoding.
bool mRedecodeError;
};
} // namespace image

View File

@ -224,13 +224,17 @@ AnimationSurfaceProvider::Run()
FinishDecoding();
// Even if it is the last frame, we may not have enough frames buffered
// ahead of the current.
if (continueDecoding) {
MOZ_ASSERT(mDecoder);
continue;
// ahead of the current. If we are shutting down, we want to ensure we
// release the thread as soon as possible. The animation may advance even
// during shutdown, which keeps us decoding, and thus blocking the decode
// pool during teardown.
if (!mDecoder || !continueDecoding ||
DecodePool::Singleton()->IsShuttingDown()) {
return;
}
return;
// Restart from the very beginning because the decoder was recreated.
continue;
}
// Notify for the progress we've made so far.
@ -245,9 +249,13 @@ AnimationSurfaceProvider::Run()
}
// There's new output available - a new frame! Grab it. If we don't need any
// more for the moment we can break out of the loop.
// more for the moment we can break out of the loop. If we are shutting
// down, we want to ensure we release the thread as soon as possible. The
// animation may advance even during shutdown, which keeps us decoding, and
// thus blocking the decode pool during teardown.
MOZ_ASSERT(result == LexerResult(Yield::OUTPUT_AVAILABLE));
if (!CheckForNewFrameAtYield()) {
if (!CheckForNewFrameAtYield() ||
DecodePool::Singleton()->IsShuttingDown()) {
return;
}
}
@ -294,10 +302,7 @@ AnimationSurfaceProvider::CheckForNewFrameAtYield()
AnnounceSurfaceAvailable();
}
// If we are shutting down, we want to ensure we release the thread as soon
// as possible. The animation may advance even during shutdown, which keeps
// us decoding, and thus blocking the decode pool during teardown.
return continueDecoding && !DecodePool::Singleton()->IsShuttingDown();
return continueDecoding;
}
bool
@ -347,10 +352,7 @@ AnimationSurfaceProvider::CheckForNewFrameAtTerminalState()
AnnounceSurfaceAvailable();
}
// If we are shutting down, we want to ensure we release the thread as soon
// as possible. The animation may advance even during shutdown, which keeps
// us decoding, and thus blocking the decode pool during teardown.
return continueDecoding && !DecodePool::Singleton()->IsShuttingDown();
return continueDecoding;
}
void
@ -378,15 +380,15 @@ AnimationSurfaceProvider::FinishDecoding()
NotifyDecodeComplete(WrapNotNull(mImage), WrapNotNull(mDecoder));
}
// Destroy our decoder; we don't need it anymore.
bool mayDiscard;
// Determine if we need to recreate the decoder, in case we are discarding
// frames and need to loop back to the beginning.
bool recreateDecoder;
{
MutexAutoLock lock(mFramesMutex);
mayDiscard = mFrames.MayDiscard();
recreateDecoder = !mFrames.HasRedecodeError() && mFrames.MayDiscard();
}
if (mayDiscard) {
// Recreate the decoder so we can regenerate the frames again.
if (recreateDecoder) {
mDecoder = DecoderFactory::CloneAnimationDecoder(mDecoder);
MOZ_ASSERT(mDecoder);
} else {

View File

@ -143,6 +143,7 @@ TEST_F(ImageAnimationFrameBuffer, FinishUnderBatchAndThreshold)
EXPECT_FALSE(keepDecoding);
EXPECT_TRUE(buffer.SizeKnown());
EXPECT_EQ(size_t(0), buffer.PendingDecode());
EXPECT_FALSE(buffer.HasRedecodeError());
}
EXPECT_FALSE(buffer.MayDiscard());
@ -220,6 +221,7 @@ TEST_F(ImageAnimationFrameBuffer, FinishMultipleBatchesUnderThreshold)
EXPECT_TRUE(buffer.SizeKnown());
EXPECT_EQ(size_t(0), buffer.PendingDecode());
EXPECT_EQ(size_t(5), frames.Length());
EXPECT_FALSE(buffer.HasRedecodeError());
// Finish progressing through the animation.
for ( ; i < frames.Length(); ++i) {
@ -330,6 +332,7 @@ TEST_F(ImageAnimationFrameBuffer, MayDiscard)
EXPECT_TRUE(buffer.SizeKnown());
EXPECT_EQ(size_t(2), buffer.PendingDecode());
EXPECT_EQ(size_t(10), frames.Length());
EXPECT_FALSE(buffer.HasRedecodeError());
// Use remaining pending room. It shouldn't add new frames, only replace.
do {
@ -513,3 +516,159 @@ TEST_F(ImageAnimationFrameBuffer, StartAfterBeginningAndReset)
EXPECT_EQ(size_t(0), buffer.PendingAdvance());
}
TEST_F(ImageAnimationFrameBuffer, RedecodeMoreFrames)
{
const size_t kThreshold = 5;
const size_t kBatch = 2;
AnimationFrameBuffer buffer;
buffer.Initialize(kThreshold, kBatch, 0);
const auto& frames = buffer.Frames();
// Add frames until we exceed the threshold.
bool keepDecoding;
bool restartDecoder;
size_t i = 0;
do {
keepDecoding = buffer.Insert(CreateEmptyFrame());
EXPECT_TRUE(keepDecoding);
if (i > 0) {
restartDecoder = buffer.AdvanceTo(i);
EXPECT_FALSE(restartDecoder);
}
++i;
} while (!buffer.MayDiscard());
// Should have threshold + 1 frames, and still not complete.
EXPECT_EQ(size_t(6), frames.Length());
EXPECT_FALSE(buffer.SizeKnown());
// Now we lock in at 6 frames.
keepDecoding = buffer.MarkComplete();
EXPECT_TRUE(keepDecoding);
EXPECT_TRUE(buffer.SizeKnown());
EXPECT_FALSE(buffer.HasRedecodeError());
// Reinsert 6 frames first.
i = 0;
do {
keepDecoding = buffer.Insert(CreateEmptyFrame());
EXPECT_TRUE(keepDecoding);
restartDecoder = buffer.AdvanceTo(i);
EXPECT_FALSE(restartDecoder);
++i;
} while (i < 6);
// We should now encounter an error and shutdown further decodes.
keepDecoding = buffer.Insert(CreateEmptyFrame());
EXPECT_FALSE(keepDecoding);
EXPECT_EQ(size_t(0), buffer.PendingDecode());
EXPECT_TRUE(buffer.HasRedecodeError());
}
TEST_F(ImageAnimationFrameBuffer, RedecodeFewerFrames)
{
const size_t kThreshold = 5;
const size_t kBatch = 2;
AnimationFrameBuffer buffer;
buffer.Initialize(kThreshold, kBatch, 0);
const auto& frames = buffer.Frames();
// Add frames until we exceed the threshold.
bool keepDecoding;
bool restartDecoder;
size_t i = 0;
do {
keepDecoding = buffer.Insert(CreateEmptyFrame());
EXPECT_TRUE(keepDecoding);
if (i > 0) {
restartDecoder = buffer.AdvanceTo(i);
EXPECT_FALSE(restartDecoder);
}
++i;
} while (!buffer.MayDiscard());
// Should have threshold + 1 frames, and still not complete.
EXPECT_EQ(size_t(6), frames.Length());
EXPECT_FALSE(buffer.SizeKnown());
// Now we lock in at 6 frames.
keepDecoding = buffer.MarkComplete();
EXPECT_TRUE(keepDecoding);
EXPECT_TRUE(buffer.SizeKnown());
EXPECT_FALSE(buffer.HasRedecodeError());
// Reinsert 5 frames before marking complete.
i = 0;
do {
keepDecoding = buffer.Insert(CreateEmptyFrame());
EXPECT_TRUE(keepDecoding);
restartDecoder = buffer.AdvanceTo(i);
EXPECT_FALSE(restartDecoder);
++i;
} while (i < 5);
// We should now encounter an error and shutdown further decodes.
keepDecoding = buffer.MarkComplete();
EXPECT_FALSE(keepDecoding);
EXPECT_EQ(size_t(0), buffer.PendingDecode());
EXPECT_TRUE(buffer.HasRedecodeError());
}
TEST_F(ImageAnimationFrameBuffer, RedecodeFewerFramesAndBehindAdvancing)
{
const size_t kThreshold = 5;
const size_t kBatch = 2;
AnimationFrameBuffer buffer;
buffer.Initialize(kThreshold, kBatch, 0);
const auto& frames = buffer.Frames();
// Add frames until we exceed the threshold.
bool keepDecoding;
bool restartDecoder;
size_t i = 0;
do {
keepDecoding = buffer.Insert(CreateEmptyFrame());
EXPECT_TRUE(keepDecoding);
if (i > 0) {
restartDecoder = buffer.AdvanceTo(i);
EXPECT_FALSE(restartDecoder);
}
++i;
} while (!buffer.MayDiscard());
// Should have threshold + 1 frames, and still not complete.
EXPECT_EQ(size_t(6), frames.Length());
EXPECT_FALSE(buffer.SizeKnown());
// Now we lock in at 6 frames.
keepDecoding = buffer.MarkComplete();
EXPECT_TRUE(keepDecoding);
EXPECT_TRUE(buffer.SizeKnown());
EXPECT_FALSE(buffer.HasRedecodeError());
// Reinsert frames without advancing until we exhaust our pending space. This
// should be less than the current buffer length by definition.
i = 0;
do {
keepDecoding = buffer.Insert(CreateEmptyFrame());
++i;
} while (keepDecoding);
EXPECT_EQ(size_t(2), i);
// We should now encounter an error and shutdown further decodes.
keepDecoding = buffer.MarkComplete();
EXPECT_FALSE(keepDecoding);
EXPECT_EQ(size_t(0), buffer.PendingDecode());
EXPECT_TRUE(buffer.HasRedecodeError());
// We should however be able to continue advancing to the last decoded frame
// without it requesting the decoder to restart.
i = 0;
do {
restartDecoder = buffer.AdvanceTo(i);
EXPECT_FALSE(restartDecoder);
++i;
} while (i < 2);
}

View File

@ -4483,7 +4483,6 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
if (caseCount == 0 ||
(caseCount == 1 && (hasDefault = firstCase->isDefault())))
{
caseCount = 0;
low = 0;
high = -1;
} else {

View File

@ -247,6 +247,7 @@ PropertyDescriptor::trace(JSTracer* trc)
void
js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc, AutoTraceSession& session)
{
MOZ_ASSERT(!TlsContext.get()->suppressGC);
MOZ_ASSERT_IF(atomsZone->isCollecting(), session.maybeLock.isSome());
// FinishRoots will have asserted that every root that we do not expect
@ -264,6 +265,8 @@ js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc, AutoTraceSession& sessi
void
js::gc::GCRuntime::traceRuntimeForMinorGC(JSTracer* trc, AutoTraceSession& session)
{
MOZ_ASSERT(!TlsContext.get()->suppressGC);
// Note that we *must* trace the runtime during the SHUTDOWN_GC's minor GC
// despite having called FinishRoots already. This is because FinishRoots
// does not clear the crossCompartmentWrapper map. It cannot do this
@ -314,8 +317,6 @@ void
js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark,
AutoTraceSession& session)
{
MOZ_ASSERT(!TlsContext.get()->suppressGC);
{
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_STACK);

View File

@ -1189,11 +1189,8 @@ class IonBuilder
public:
// These are only valid for IonBuilders that have moved to background
// This is only valid for IonBuilders that have moved to background
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
}
};
class CallInfo

View File

@ -1051,21 +1051,26 @@ FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int n
static JS::UniqueChars
FormatWasmFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int num)
{
JSAtom* functionDisplayAtom = iter.functionDisplayAtom();
UniqueChars nameStr;
if (functionDisplayAtom)
if (JSAtom* functionDisplayAtom = iter.functionDisplayAtom()) {
nameStr = StringToNewUTF8CharsZ(cx, *functionDisplayAtom);
if (!nameStr)
return nullptr;
}
JS::UniqueChars buf = sprintf_append(cx, Move(inBuf), "%d %s()",
num,
nameStr ? nameStr.get() : "<wasm-function>");
if (!buf)
return nullptr;
const char* filename = iter.filename();
uint32_t lineno = iter.computeLine();
buf = sprintf_append(cx, Move(buf), " [\"%s\":%d]\n",
filename ? filename : "<unknown>",
lineno);
if (!buf)
return nullptr;
MOZ_ASSERT(!cx->isExceptionPending());
return buf;

View File

@ -1171,11 +1171,11 @@ GlobalHelperThreadState::addSizeOfIncludingThis(JS::GlobalStats* stats,
// Report IonBuilders on wait lists
for (auto builder : ionWorklist_)
htStats.ionBuilder += builder->sizeOfIncludingThis(mallocSizeOf);
htStats.ionBuilder += builder->sizeOfExcludingThis(mallocSizeOf);
for (auto builder : ionFinishedList_)
htStats.ionBuilder += builder->sizeOfIncludingThis(mallocSizeOf);
htStats.ionBuilder += builder->sizeOfExcludingThis(mallocSizeOf);
for (auto builder : ionFreeList_)
htStats.ionBuilder += builder->sizeOfIncludingThis(mallocSizeOf);
htStats.ionBuilder += builder->sizeOfExcludingThis(mallocSizeOf);
// Report wasm::CompileTasks on wait lists
for (auto task : wasmWorklist_tier1_)

View File

@ -2244,8 +2244,11 @@ AstDecodeModuleTail(AstDecodeContext& c)
return false;
for (DataSegment& s : c.env().dataSegments) {
const uint8_t* src = c.d.begin() + s.bytecodeOffset;
char16_t* buffer = static_cast<char16_t*>(c.lifo.alloc(s.length * sizeof(char16_t)));
if (!buffer)
return false;
const uint8_t* src = c.d.begin() + s.bytecodeOffset;
for (size_t i = 0; i < s.length; i++)
buffer[i] = src[i];

View File

@ -1971,6 +1971,9 @@ ParseCallIndirect(WasmParseContext& c, bool inParens)
index = new(c.lifo) AstPop();
}
if (!index)
return nullptr;
return new(c.lifo) AstCallIndirect(sig, ExprType::Void, Move(args), index);
}

View File

@ -1930,7 +1930,7 @@ public:
mBSize = 0;
}
MOZ_ASSERT(rectDebug.IsEqualEdges(nsRect(mIStart, mBStart, mISize, mBSize)));
MOZ_ASSERT((rectDebug.IsEmpty() && (mISize == 0 || mBSize == 0)) || rectDebug.IsEqualEdges(nsRect(mIStart, mBStart, mISize, mBSize)));
return mISize > 0 && mBSize > 0;
}

View File

@ -23,6 +23,9 @@ if CONFIG['CPU_ARCH'] == 'x86_64':
ASFLAGS += [ '-I%s/media/libaom/config/win/x64/' % TOPSRCDIR ]
LOCAL_INCLUDES += [ '/media/libaom/config/win/x64/' ]
EXPORTS.aom += [ 'config/win/x64/aom_config.h' ]
# This code is not included in our PGO profile, and pointlessly
# PGO-optimizing it slows down our builds a lot.
NO_PGO = True
elif CONFIG['OS_TARGET'] == 'Darwin':
ASFLAGS += [ '-I%s/media/libaom/config/mac/x64/' % TOPSRCDIR ]
LOCAL_INCLUDES += [ '/media/libaom/config/mac/x64/' ]

View File

@ -199,7 +199,6 @@ pref("extensions.dss.enabled", false);
pref("extensions.ignoreMTimeChanges", false);
pref("extensions.logging.enabled", false);
pref("extensions.hideInstallButton", true);
pref("extensions.showMismatchUI", false);
pref("extensions.hideUpdateButton", false);
pref("extensions.strictCompatibility", false);
pref("extensions.minCompatibleAppVersion", "11.0");

View File

@ -57,6 +57,7 @@ import org.mozilla.gecko.util.PackageUtil;
import org.mozilla.gecko.webapps.WebApps;
import org.mozilla.gecko.widget.ActionModePresenter;
import org.mozilla.gecko.widget.GeckoPopupMenu;
import org.mozilla.geckoview.GeckoResponse;
import org.mozilla.geckoview.GeckoRuntime;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoSessionSettings;
@ -600,7 +601,7 @@ public class CustomTabsActivity extends AppCompatActivity
@Override
public void onLoadRequest(final GeckoSession session, final String urlStr,
final int target,
final GeckoSession.Response<Boolean> response) {
final GeckoResponse<Boolean> response) {
if (target != GeckoSession.NavigationDelegate.TARGET_WINDOW_NEW) {
response.respond(false);
return;
@ -641,7 +642,7 @@ public class CustomTabsActivity extends AppCompatActivity
@Override
public void onNewSession(final GeckoSession session, final String uri,
final GeckoSession.Response<GeckoSession> response) {
final GeckoResponse<GeckoSession> response) {
// We should never get here because we abort loads that need a new session in onLoadRequest()
throw new IllegalStateException("Unexpected new session");
}

View File

@ -37,6 +37,7 @@ import org.mozilla.gecko.text.TextSelection;
import org.mozilla.gecko.util.ActivityUtils;
import org.mozilla.gecko.util.ColorUtil;
import org.mozilla.gecko.widget.ActionModePresenter;
import org.mozilla.geckoview.GeckoResponse;
import org.mozilla.geckoview.GeckoRuntime;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoSessionSettings;
@ -369,7 +370,7 @@ public class WebAppActivity extends AppCompatActivity
@Override
public void onLoadRequest(final GeckoSession session, final String urlStr,
final int target,
final GeckoSession.Response<Boolean> response) {
final GeckoResponse<Boolean> response) {
final Uri uri = Uri.parse(urlStr);
if (uri == null) {
// We can't really handle this, so deny it?
@ -421,7 +422,7 @@ public class WebAppActivity extends AppCompatActivity
@Override
public void onNewSession(final GeckoSession session, final String uri,
final GeckoSession.Response<GeckoSession> response) {
final GeckoResponse<GeckoSession> response) {
// We should never get here because we abort loads that need a new session in onLoadRequest()
throw new IllegalStateException("Unexpected new session");
}

View File

@ -4,6 +4,7 @@
package org.mozilla.geckoview.test
import org.mozilla.geckoview.GeckoResponse
import org.mozilla.geckoview.GeckoSession
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
import org.mozilla.geckoview.test.util.Callbacks
@ -36,12 +37,12 @@ class ContentDelegateTest : BaseSessionTest() {
sessionRule.waitUntilCalled(object : Callbacks.NavigationDelegate, Callbacks.ContentDelegate {
@AssertCalled(count = 2)
override fun onLoadRequest(session: GeckoSession, uri: String, where: Int, response: GeckoSession.Response<Boolean>) {
override fun onLoadRequest(session: GeckoSession, uri: String, where: Int, response: GeckoResponse<Boolean>) {
response.respond(false)
}
@AssertCalled(false)
override fun onNewSession(session: GeckoSession, uri: String, response: GeckoSession.Response<GeckoSession>) {
override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
}
@AssertCalled(count = 1)
@ -54,4 +55,4 @@ class ContentDelegateTest : BaseSessionTest() {
})
}
}
}

View File

@ -5,6 +5,7 @@
package org.mozilla.geckoview.test
import android.support.test.InstrumentationRegistry
import org.mozilla.geckoview.GeckoResponse
import org.mozilla.geckoview.GeckoSession
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
@ -28,7 +29,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(count = 1, order = intArrayOf(1))
override fun onLoadRequest(session: GeckoSession, uri: String,
where: Int,
response: GeckoSession.Response<Boolean>) {
response: GeckoResponse<Boolean>) {
assertThat("Session should not be null", session, notNullValue())
assertThat("URI should not be null", uri, notNullValue())
assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH))
@ -59,7 +60,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(false)
override fun onNewSession(session: GeckoSession, uri: String,
response: GeckoSession.Response<GeckoSession>) {
response: GeckoResponse<GeckoSession>) {
}
})
}
@ -189,7 +190,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(count = 1, order = intArrayOf(1))
override fun onLoadRequest(session: GeckoSession, uri: String,
where: Int,
response: GeckoSession.Response<Boolean>) {
response: GeckoResponse<Boolean>) {
assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH))
assertThat("Where should match", where,
equalTo(GeckoSession.NavigationDelegate.TARGET_WINDOW_CURRENT))
@ -213,7 +214,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(false)
override fun onNewSession(session: GeckoSession, uri: String,
response: GeckoSession.Response<GeckoSession>) {
response: GeckoResponse<GeckoSession>) {
}
})
}
@ -239,7 +240,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(count = 1, order = intArrayOf(1))
override fun onLoadRequest(session: GeckoSession, uri: String,
where: Int,
response: GeckoSession.Response<Boolean>) {
response: GeckoResponse<Boolean>) {
assertThat("URI should match", uri, endsWith(HELLO_HTML_PATH))
assertThat("Where should match", where,
equalTo(GeckoSession.NavigationDelegate.TARGET_WINDOW_CURRENT))
@ -263,7 +264,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(false)
override fun onNewSession(session: GeckoSession, uri: String,
response: GeckoSession.Response<GeckoSession>) {
response: GeckoResponse<GeckoSession>) {
}
})
@ -274,7 +275,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(count = 1, order = intArrayOf(1))
override fun onLoadRequest(session: GeckoSession, uri: String,
where: Int,
response: GeckoSession.Response<Boolean>) {
response: GeckoResponse<Boolean>) {
assertThat("URI should match", uri, endsWith(HELLO2_HTML_PATH))
assertThat("Where should match", where,
equalTo(GeckoSession.NavigationDelegate.TARGET_WINDOW_CURRENT))
@ -298,7 +299,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(false)
override fun onNewSession(session: GeckoSession, uri: String,
response: GeckoSession.Response<GeckoSession>) {
response: GeckoResponse<GeckoSession>) {
}
})
}
@ -308,7 +309,7 @@ class NavigationDelegateTest : BaseSessionTest() {
@AssertCalled(count = 2)
override fun onLoadRequest(session: GeckoSession, uri: String,
where: Int,
response: GeckoSession.Response<Boolean>) {
response: GeckoResponse<Boolean>) {
response.respond(uri.endsWith(HELLO_HTML_PATH))
}
})
@ -337,7 +338,7 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1)
override fun onNewSession(session: GeckoSession, uri: String, response: GeckoSession.Response<GeckoSession>) {
override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
response.respond(null)
}
})
@ -354,7 +355,7 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1)
override fun onNewSession(session: GeckoSession, uri: String, response: GeckoSession.Response<GeckoSession>) {
override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
val newSession = sessionRule.createClosedSession(session.settings)
newSession.open()
response.respond(newSession)

View File

@ -4,6 +4,7 @@
package org.mozilla.geckoview.test
import org.mozilla.geckoview.GeckoResponse
import org.mozilla.geckoview.GeckoSession
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
import org.mozilla.geckoview.test.util.Callbacks
@ -60,7 +61,7 @@ class ProgressDelegateTest : BaseSessionTest() {
@AssertCalled(count = 2)
override fun onLoadRequest(session: GeckoSession, uri: String,
where: Int,
response: GeckoSession.Response<Boolean>) {
response: GeckoResponse<Boolean>) {
if (sessionRule.currentCall.counter == 1) {
assertThat("URI should be " + testUri, uri, equalTo(testUri));
} else {

View File

@ -5,6 +5,7 @@
package org.mozilla.geckoview.test;
import org.mozilla.geckoview.GeckoResponse;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoSessionSettings;
import org.mozilla.geckoview.GeckoView;
@ -43,13 +44,13 @@ public class TestRunnerActivity extends Activity {
@Override
public void onLoadRequest(GeckoSession session, String uri, int target,
GeckoSession.Response<Boolean> response) {
GeckoResponse<Boolean> response) {
// Allow Gecko to load all URIs
response.respond(false);
}
@Override
public void onNewSession(GeckoSession session, String uri, GeckoSession.Response<GeckoSession> response) {
public void onNewSession(GeckoSession session, String uri, GeckoResponse<GeckoSession> response) {
response.respond(createSession(session.getSettings()));
}
};

View File

@ -5,6 +5,7 @@
package org.mozilla.geckoview.test.util
import org.mozilla.geckoview.GeckoResponse
import org.mozilla.geckoview.GeckoSession
class Callbacks private constructor() {
@ -47,11 +48,11 @@ class Callbacks private constructor() {
}
override fun onLoadRequest(session: GeckoSession, uri: String, where: Int,
response: GeckoSession.Response<Boolean>) {
response: GeckoResponse<Boolean>) {
response.respond(false)
}
override fun onNewSession(session: GeckoSession, uri: String, response: GeckoSession.Response<GeckoSession>) {
override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
response.respond(null)
}
}
@ -126,7 +127,7 @@ class Callbacks private constructor() {
}
interface SelectionActionDelegate : GeckoSession.SelectionActionDelegate {
override fun onShowActionRequest(session: GeckoSession, selection: GeckoSession.SelectionActionDelegate.Selection, actions: Array<out String>, response: GeckoSession.Response<String>) {
override fun onShowActionRequest(session: GeckoSession, selection: GeckoSession.SelectionActionDelegate.Selection, actions: Array<out String>, response: GeckoResponse<String>) {
}
override fun onHideAction(session: GeckoSession, reason: Int) {

View File

@ -64,7 +64,7 @@ public class BasicSelectionActionDelegate implements ActionMode.Callback,
protected GeckoSession mSession;
protected Selection mSelection;
protected List<String> mActions;
protected GeckoSession.Response<String> mResponse;
protected GeckoResponse<String> mResponse;
protected boolean mRepopulatedMenu;
@TargetApi(Build.VERSION_CODES.M)
@ -350,7 +350,7 @@ public class BasicSelectionActionDelegate implements ActionMode.Callback,
@Override
public void onShowActionRequest(final GeckoSession session, final Selection selection,
final String[] actions,
final GeckoSession.Response<String> response) {
final GeckoResponse<String> response) {
mSession = session;
mSelection = selection;
mActions = Arrays.asList(actions);

View File

@ -0,0 +1,19 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* vim: ts=4 sw=4 expandtab:
* 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/. */
package org.mozilla.geckoview;
/**
* This is used to receive async responses from delegate methods.
*/
public interface GeckoResponse<T> {
/**
* Called when async processing has finished.
*
* @param value The value contained in the response.
*/
void respond(T value);
}

View File

@ -20,6 +20,7 @@ import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
public final class GeckoRuntime implements Parcelable {
private static final String LOGTAG = "GeckoRuntime";
@ -32,7 +33,7 @@ public final class GeckoRuntime implements Parcelable {
* This will create and initialize the runtime with the default settings.
*
* Note: Only use this for session-less apps.
* For regular apps, use create() and createSession() instead.
* For regular apps, use create() instead.
*
* @param context An application context for the default runtime.
* @return The (static) default runtime for the context.
@ -51,6 +52,7 @@ public final class GeckoRuntime implements Parcelable {
private GeckoRuntimeSettings mSettings;
private Delegate mDelegate;
private RuntimeTelemetry mTelemetry;
/**
* Attach the runtime to the given context.
@ -195,6 +197,21 @@ public final class GeckoRuntime implements Parcelable {
PrefsHelper.setPref(name, value, /* flush */ false);
}
/**
* Return the telemetry object for this runtime.
*
* @return The telemetry object.
*/
public RuntimeTelemetry getTelemetry() {
ThreadUtils.assertOnUiThread();
if (mTelemetry == null) {
mTelemetry = new RuntimeTelemetry(this);
}
return mTelemetry;
}
@Override // Parcelable
public int describeContents() {
return 0;

View File

@ -181,7 +181,7 @@ public class GeckoSession extends LayerSession
final String uri = message.getString("uri");
final int where = convertGeckoTarget(message.getInt("where"));
delegate.onLoadRequest(GeckoSession.this, uri, where,
new Response<Boolean>() {
new GeckoResponse<Boolean>() {
@Override
public void respond(Boolean handled) {
callback.sendSuccess(handled);
@ -190,7 +190,7 @@ public class GeckoSession extends LayerSession
} else if ("GeckoView:OnNewSession".equals(event)) {
final String uri = message.getString("uri");
delegate.onNewSession(GeckoSession.this, uri,
new Response<GeckoSession>() {
new GeckoResponse<GeckoSession>() {
@Override
public void respond(GeckoSession session) {
if (session == null) {
@ -363,7 +363,7 @@ public class GeckoSession extends LayerSession
final String[] actions = message.getStringArray("actions");
final int seqNo = message.getInt("seqNo");
final Response<String> response = new Response<String>() {
final GeckoResponse<String> response = new GeckoResponse<String>() {
@Override
public void respond(final String action) {
final GeckoBundle response = new GeckoBundle(2);
@ -1124,7 +1124,7 @@ public class GeckoSession extends LayerSession
* @param response This is a response which will be called with the state once it has been
* saved. Can be null if we fail to save the state for any reason.
*/
public void saveState(final Response<SessionState> response) {
public void saveState(final GeckoResponse<SessionState> response) {
mEventDispatcher.dispatch("GeckoView:SaveState", null, new EventCallback() {
@Override
public void sendSuccess(final Object result) {
@ -2005,7 +2005,7 @@ public class GeckoSession extends LayerSession
* multiple times to perform multiple actions at once.
*/
void onShowActionRequest(GeckoSession session, Selection selection,
@Action String[] actions, Response<String> response);
@Action String[] actions, GeckoResponse<String> response);
@IntDef({HIDE_REASON_NO_SELECTION,
HIDE_REASON_INVISIBLE_SELECTION,
@ -2048,16 +2048,6 @@ public class GeckoSession extends LayerSession
void onHideAction(GeckoSession session, @HideReason int reason);
}
/**
* This is used to send responses in delegate methods that have asynchronous responses.
*/
public interface Response<T> {
/**
* @param val The value contained in the response
*/
void respond(T val);
}
public interface NavigationDelegate {
/**
* A view has started loading content from the network.
@ -2103,7 +2093,7 @@ public class GeckoSession extends LayerSession
*/
void onLoadRequest(GeckoSession session, String uri,
@TargetWindow int target,
Response<Boolean> response);
GeckoResponse<Boolean> response);
/**
* A request has been made to open a new session. The URI is provided only for
@ -2115,7 +2105,7 @@ public class GeckoSession extends LayerSession
*
* @param response A Response which will hold the returned GeckoSession
*/
void onNewSession(GeckoSession session, String uri, Response<GeckoSession> response);
void onNewSession(GeckoSession session, String uri, GeckoResponse<GeckoSession> response);
}
/**

View File

@ -0,0 +1,130 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* vim: ts=4 sw=4 expandtab:
* 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/. */
package org.mozilla.geckoview;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.json.JSONException;
import org.json.JSONObject;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.EventCallback;
/**
* The telemetry API gives access to telemetry data of the Gecko runtime.
*/
public final class RuntimeTelemetry {
private final static String LOGTAG = "GeckoViewTelemetry";
private final static boolean DEBUG = false;
private final GeckoRuntime mRuntime;
private final EventDispatcher mEventDispatcher;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ DATASET_BASE, DATASET_EXTENDED })
public @interface DatasetType {}
// Match with nsITelemetry.
/**
* The base dataset suitable for release builds.
*/
public static final int DATASET_BASE = 0;
/**
* The extended dataset suitable for pre-release builds.
*/
public static final int DATASET_EXTENDED = 1;
@IntDef(flag = true,
value = { SNAPSHOT_HISTOGRAMS, SNAPSHOT_KEYED_HISTOGRAMS,
SNAPSHOT_SCALARS, SNAPSHOT_KEYED_SCALARS,
SNAPSHOT_ALL })
public @interface SnapshotType {}
// Match with GeckoViewTelemetryController.
/**
* Adds a "histogram" object entry to the snapshot response.
*/
public static final int SNAPSHOT_HISTOGRAMS = 1 << 0;
/**
* Adds a "keyedHistogram" object entry to the snapshot response.
*/
public static final int SNAPSHOT_KEYED_HISTOGRAMS = 1 << 1;
/**
* Adds a "scalars" object entry to the snapshot response.
*/
public static final int SNAPSHOT_SCALARS = 1 << 2;
/**
* Adds a "keyedScalars" object entry to the snapshot response.
*/
public static final int SNAPSHOT_KEYED_SCALARS = 1 << 3;
/**
* Adds all snapshot types to the response.
*/
public static final int SNAPSHOT_ALL = (1 << 4) - 1;
/* package */ RuntimeTelemetry(final @NonNull GeckoRuntime runtime) {
mRuntime = runtime;
mEventDispatcher = EventDispatcher.getInstance();
}
/**
* Retrieve all telemetry snapshots.
*
* @param dataset The dataset type to retreive.
* One of {@link #RuntimeTelemetry.DATASET_BASE DATASET_*} flags.
* @param clear Whether the retrieved snapshots should be cleared.
* @param response Used to return the async response.
*/
public void getSnapshots(
final @DatasetType int dataset,
final boolean clear,
final @NonNull GeckoResponse<GeckoBundle> response) {
getSnapshots(SNAPSHOT_ALL, dataset, clear, response);
}
/**
* Retrieve the requested telemetry snapshots.
*
* @param types The requested snapshot types.
* One or more of {@link #RuntimeTelemetry.SNAPSHOT_HISTOGRAMS SNAPSHOT_*} flags.
* @param dataset The dataset type to retreive.
* One of {@link #RuntimeTelemetry.DATASET_BASE DATASET_*} flags.
* @param clear Whether the retrieved snapshots should be cleared.
* @param response Used to return the async response.
*/
public void getSnapshots(
final @SnapshotType int types,
final @DatasetType int dataset,
final boolean clear,
final @NonNull GeckoResponse<GeckoBundle> response) {
final GeckoBundle msg = new GeckoBundle(3);
msg.putInt("types", types);
msg.putInt("dataset", dataset);
msg.putBoolean("clear", clear);
mEventDispatcher.dispatch("GeckoView:TelemetrySnapshots", msg,
new EventCallback() {
@Override
public void sendSuccess(final Object result) {
response.respond((GeckoBundle) result);
}
@Override
public void sendError(final Object error) {
Log.e(LOGTAG, "getSnapshots failed: " + error);
response.respond(null);
}
});
}
}

View File

@ -17,9 +17,9 @@ import android.view.WindowManager;
import java.util.Locale;
import org.mozilla.geckoview.GeckoResponse;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoSessionSettings;
import org.mozilla.geckoview.GeckoSession.Response;
import org.mozilla.geckoview.GeckoSession.TrackingProtectionDelegate;
import org.mozilla.geckoview.GeckoView;
import org.mozilla.geckoview.GeckoRuntime;
@ -360,13 +360,13 @@ public class GeckoViewActivity extends Activity {
@Override
public void onLoadRequest(final GeckoSession session, final String uri,
final int target, Response<Boolean> response) {
final int target, GeckoResponse<Boolean> response) {
Log.d(LOGTAG, "onLoadRequest=" + uri + " where=" + target);
response.respond(false);
}
@Override
public void onNewSession(final GeckoSession session, final String uri, Response<GeckoSession> response) {
public void onNewSession(final GeckoSession session, final String uri, GeckoResponse<GeckoSession> response) {
response.respond(null);
}
}

View File

@ -59,7 +59,7 @@ with Files('**/Makefile.in'):
FINAL = True
with Files("**/*.js"):
SCHEDULES.inclusive += ['test-verify', 'docs']
SCHEDULES.inclusive += ['test-verify', 'test-verify-gpu', 'docs']
with Files("**/*.jsm"):
SCHEDULES.inclusive += ['docs']
@ -71,13 +71,13 @@ with Files("**/*.md"):
SCHEDULES.inclusive += ['docs']
with Files("**/*.html"):
SCHEDULES.inclusive += ['test-verify']
SCHEDULES.inclusive += ['test-verify', 'test-verify-gpu']
with Files("**/*.xhtml"):
SCHEDULES.inclusive += ['test-verify']
SCHEDULES.inclusive += ['test-verify', 'test-verify-gpu']
with Files("**/*.xul"):
SCHEDULES.inclusive += ['test-verify']
SCHEDULES.inclusive += ['test-verify', 'test-verify-gpu']
CONFIGURE_SUBST_FILES += [
'config/autoconf.mk',

View File

@ -54,8 +54,8 @@ mozilla::detail::ConditionVariableImpl::notify_all()
void
mozilla::detail::ConditionVariableImpl::wait(MutexImpl& lock)
{
CRITICAL_SECTION* cs = &lock.platformData()->criticalSection;
bool r = SleepConditionVariableCS(&platformData()->cv_, cs, INFINITE);
SRWLOCK* srwlock = &lock.platformData()->lock;
bool r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, INFINITE, 0);
MOZ_RELEASE_ASSERT(r);
}
@ -68,7 +68,7 @@ mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock,
return CVStatus::NoTimeout;
}
CRITICAL_SECTION* cs = &lock.platformData()->criticalSection;
SRWLOCK* srwlock = &lock.platformData()->lock;
// Note that DWORD is unsigned, so we have to be careful to clamp at 0. If
// rel_time is Forever, then ToMilliseconds is +inf, which evaluates as
@ -89,7 +89,7 @@ mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock,
}
}
BOOL r = SleepConditionVariableCS(&platformData()->cv_, cs, msec);
BOOL r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, msec, 0);
if (r)
return CVStatus::NoTimeout;
MOZ_RELEASE_ASSERT(GetLastError() == ERROR_TIMEOUT);

View File

@ -13,7 +13,7 @@
struct mozilla::detail::MutexImpl::PlatformData
{
CRITICAL_SECTION criticalSection;
SRWLOCK lock;
};
#endif // MutexPlatformData_windows_h

View File

@ -14,38 +14,23 @@
mozilla::detail::MutexImpl::MutexImpl()
{
// This number was adopted from NSPR.
const static DWORD LockSpinCount = 1500;
#if defined(RELEASE_OR_BETA)
// Vista and later automatically allocate and subsequently leak a debug info
// object for each critical section that we allocate unless we tell the
// system not to do that.
DWORD flags = CRITICAL_SECTION_NO_DEBUG_INFO;
#else
DWORD flags = 0;
#endif // defined(RELEASE_OR_BETA)
BOOL r = InitializeCriticalSectionEx(&platformData()->criticalSection,
LockSpinCount, flags);
MOZ_RELEASE_ASSERT(r);
InitializeSRWLock(&platformData()->lock);
}
mozilla::detail::MutexImpl::~MutexImpl()
{
DeleteCriticalSection(&platformData()->criticalSection);
}
void
mozilla::detail::MutexImpl::lock()
{
EnterCriticalSection(&platformData()->criticalSection);
AcquireSRWLockExclusive(&platformData()->lock);
}
void
mozilla::detail::MutexImpl::unlock()
{
LeaveCriticalSection(&platformData()->criticalSection);
ReleaseSRWLockExclusive(&platformData()->lock);
}
mozilla::detail::MutexImpl::PlatformData*

View File

@ -139,8 +139,8 @@ public:
MEMORY_BASIC_INFORMATION mbi;
SIZE_T result = ::VirtualQuery(aVAddress, &mbi, sizeof(mbi));
return result && mbi.AllocationProtect && mbi.State == MEM_COMMIT &&
mbi.Protect != PAGE_NOACCESS;
return result && mbi.AllocationProtect && (mbi.Type & MEM_IMAGE) &&
mbi.State == MEM_COMMIT && mbi.Protect != PAGE_NOACCESS;
}
bool FlushInstructionCache() const

View File

@ -45,35 +45,47 @@ protected:
}
}
origFn += 2 + offset;
return ReadOnlyTargetFunction<MMPolicyT>(mVMPolicy, origFn.GetAddress());
uintptr_t abstarget = (origFn + 2 + offset).GetAddress();
return EnsureTargetIsAccessible(Move(origFn), abstarget);
}
#if defined(_M_IX86)
// If function entry is jmp [disp32] such as used by kernel32,
// we resolve redirected address from import table.
if (origFn[0] == 0xff && origFn[1] == 0x25) {
return ReadOnlyTargetFunction<MMPolicyT>(mVMPolicy,
reinterpret_cast<const void*>((origFn + 2).template ChasePointer<uintptr_t*>()));
uintptr_t abstarget = (origFn + 2).template ChasePointer<uintptr_t*>();
return EnsureTargetIsAccessible(Move(origFn), abstarget);
}
#elif defined(_M_X64)
// If function entry is jmp [disp32] such as used by kernel32,
// we resolve redirected address from import table.
if (origFn[0] == 0x48 && origFn[1] == 0xff && origFn[2] == 0x25) {
return ReadOnlyTargetFunction<MMPolicyT>(mVMPolicy,
reinterpret_cast<const void*>((origFn + 3).ChasePointerFromDisp()));
uintptr_t abstarget = (origFn + 3).ChasePointerFromDisp();
return EnsureTargetIsAccessible(Move(origFn), abstarget);
}
if (origFn[0] == 0xe9) {
// require for TestDllInterceptor with --disable-optimize
uintptr_t abstarget = (origFn + 1).ReadDisp32AsAbsolute();
return ReadOnlyTargetFunction<MMPolicyT>(mVMPolicy, abstarget);
return EnsureTargetIsAccessible(Move(origFn), abstarget);
}
#endif
return Move(origFn);
}
private:
ReadOnlyTargetFunction<MMPolicyT>
EnsureTargetIsAccessible(ReadOnlyTargetFunction<MMPolicyT> aOrigFn,
uintptr_t aRedirAddress)
{
if (!mVMPolicy.IsPageAccessible(reinterpret_cast<void*>(aRedirAddress))) {
return Move(aOrigFn);
}
return ReadOnlyTargetFunction<MMPolicyT>(mVMPolicy, aRedirAddress);
}
protected:
VMPolicy mVMPolicy;
};

View File

@ -291,6 +291,7 @@ public:
, mTrampSize(0)
, mNumTramps(0)
, mPrevProt(0)
, mCS(nullptr)
{
}
@ -303,6 +304,7 @@ public:
, mTrampSize(aTrampSize)
, mNumTramps(aNumTramps)
, mPrevProt(0)
, mCS(nullptr)
{
if (!aNumTramps) {
return;
@ -321,6 +323,20 @@ public:
mMMPolicy.Protect(mLocalBase, mNumTramps * mTrampSize,
mPrevProt, &mPrevProt);
if (mCS) {
::LeaveCriticalSection(mCS);
}
}
void Lock(CRITICAL_SECTION& aCS)
{
if (!mPrevProt || mCS) {
return;
}
mCS = &aCS;
::EnterCriticalSection(&aCS);
}
TrampolineIterator begin() const
@ -348,17 +364,20 @@ public:
, mTrampSize(aOther.mTrampSize)
, mNumTramps(aOther.mNumTramps)
, mPrevProt(aOther.mPrevProt)
, mCS(aOther.mCS)
{
aOther.mPrevProt = 0;
aOther.mCS = nullptr;
}
private:
const MMPolicy& mMMPolicy;
uint8_t* const mLocalBase;
const uintptr_t mRemoteBase;
const uint32_t mTrampSize;
const uint32_t mNumTramps;
uint32_t mPrevProt;
const MMPolicy& mMMPolicy;
uint8_t* const mLocalBase;
const uintptr_t mRemoteBase;
const uint32_t mTrampSize;
const uint32_t mNumTramps;
uint32_t mPrevProt;
CRITICAL_SECTION* mCS;
friend class TrampolineIterator;
};

View File

@ -9,6 +9,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Types.h"
#include "mozilla/StaticPtr.h"
namespace mozilla {
namespace interceptor {
@ -83,6 +84,213 @@ private:
uint32_t mNextChunkIndex;
};
template <typename MMPolicy, uint32_t kChunkSize>
class VMSharingPolicyShared : public MMPolicyBase
{
typedef VMSharingPolicyUnique<MMPolicy, kChunkSize> ValueT;
// We use pid instead of HANDLE for mapping, since more than one handle may
// map to the same pid. We don't worry about pid reuse becuase each mVMPolicy
// holds an open handle to pid, thus keeping the pid reserved at least for the
// lifetime of mVMPolicy.
struct ProcMapEntry
{
ProcMapEntry()
: mPid(::GetCurrentProcessId())
{
}
explicit ProcMapEntry(HANDLE aProc)
: mPid(::GetProcessId(aProc))
, mVMPolicy(aProc)
{
}
ProcMapEntry(ProcMapEntry&& aOther)
: mPid(aOther.mPid)
, mVMPolicy(Move(aOther.mVMPolicy))
{
aOther.mPid = 0;
}
ProcMapEntry(const ProcMapEntry&) = delete;
ProcMapEntry& operator=(const ProcMapEntry&) = delete;
ProcMapEntry& operator=(ProcMapEntry&& aOther)
{
mPid = aOther.mPid;
mVMPolicy = Move(aOther.mVMPolicy);
aOther.mPid = 0;
return *this;
}
bool operator==(DWORD aPid) const
{
return mPid == aPid;
}
DWORD mPid;
ValueT mVMPolicy;
};
// We normally expect to reference only one other process at a time, but this
// is not a requirement.
typedef Vector<ProcMapEntry, 1> MapT;
public:
typedef MMPolicy MMPolicyT;
template <typename... Args>
explicit VMSharingPolicyShared(Args... aArgs)
: mPid(GetPid(aArgs...))
{
static const bool isAlloc = []() -> bool {
sPerProcVM = new MapT();
DWORD flags = 0;
#if defined(RELEASE_OR_BETA)
flags |= CRITICAL_SECTION_NO_DEBUG_INFO;
#endif // defined(RELEASE_OR_BETA)
::InitializeCriticalSectionEx(&sCS, 4000, flags);
return true;
}();
MOZ_ASSERT(mPid);
if (!mPid) {
return;
}
AutoCriticalSection lock(&sCS);
if (find(mPid)) {
return;
}
MOZ_RELEASE_ASSERT(sPerProcVM->append(ProcMapEntry(aArgs...)));
}
explicit operator bool() const
{
AutoCriticalSection lock(&sCS);
ProcMapEntry* entry;
MOZ_RELEASE_ASSERT(find(mPid, &entry));
return !!entry->mVMPolicy;
}
operator const MMPolicy&() const
{
AutoCriticalSection lock(&sCS);
ProcMapEntry* entry;
MOZ_RELEASE_ASSERT(find(mPid, &entry));
return entry->mVMPolicy;
}
bool ShouldUnhookUponDestruction() const
{
AutoCriticalSection lock(&sCS);
ProcMapEntry* entry;
if (!find(mPid, &entry)) {
return 0;
}
return entry->mVMPolicy.ShouldUnhookUponDestruction();
}
bool Reserve(uint32_t aCount)
{
AutoCriticalSection lock(&sCS);
ProcMapEntry* entry;
if (!find(mPid, &entry)) {
return false;
}
return entry->mVMPolicy.Reserve(aCount);
}
Trampoline<MMPolicy> GetNextTrampoline()
{
AutoCriticalSection lock(&sCS);
ProcMapEntry* entry;
if (!find(mPid, &entry)) {
return nullptr;
}
return entry->mVMPolicy.GetNextTrampoline();
}
TrampolineCollection<MMPolicy> Items() const
{
AutoCriticalSection lock(&sCS);
ProcMapEntry* entry;
MOZ_RELEASE_ASSERT(find(mPid, &entry));
TrampolineCollection<MMPolicy> items(Move(entry->mVMPolicy.Items()));
// We need to continue holding the lock until items is destroyed.
items.Lock(sCS);
return Move(items);
}
void Clear()
{
// This must be a no-op for shared VM policy; we can't have one interceptor
// wiping out trampolines for all interceptors in the process.
}
~VMSharingPolicyShared() = default;
VMSharingPolicyShared(const VMSharingPolicyShared&) = delete;
VMSharingPolicyShared(VMSharingPolicyShared&&) = delete;
VMSharingPolicyShared& operator=(const VMSharingPolicyShared&) = delete;
VMSharingPolicyShared& operator=(VMSharingPolicyShared&&) = delete;
private:
static bool find(DWORD aPid, ProcMapEntry** aOutEntry = nullptr)
{
MOZ_ASSERT(sPerProcVM);
if (!sPerProcVM) {
return false;
}
if (aOutEntry) {
*aOutEntry = nullptr;
}
for (auto&& mapping : *sPerProcVM) {
if (mapping == aPid) {
if (aOutEntry) {
*aOutEntry = &mapping;
}
return true;
}
}
return false;
}
static DWORD GetPid() { return ::GetCurrentProcessId(); }
static DWORD GetPid(HANDLE aHandle) { return ::GetProcessId(aHandle); }
DWORD mPid;
static StaticAutoPtr<MapT> sPerProcVM;
static CRITICAL_SECTION sCS;
};
template <typename MMPolicy, uint32_t kChunkSize>
StaticAutoPtr<typename VMSharingPolicyShared<MMPolicy, kChunkSize>::MapT>
VMSharingPolicyShared<MMPolicy, kChunkSize>::sPerProcVM;
template <typename MMPolicy, uint32_t kChunkSize>
CRITICAL_SECTION VMSharingPolicyShared<MMPolicy, kChunkSize>::sCS;
} // namespace interceptor
} // namespace mozilla

View File

@ -150,7 +150,7 @@ MODERN_MERCURIAL_VERSION = LooseVersion('4.2.3')
MODERN_PYTHON_VERSION = LooseVersion('2.7.3')
# Upgrade rust older than this.
MODERN_RUST_VERSION = LooseVersion('1.25.0')
MODERN_RUST_VERSION = LooseVersion('1.24.0')
class BaseBootstrapper(object):

View File

@ -23,6 +23,7 @@ INCLUSIVE_COMPONENTS = [
# inclusive test suites -- these *only* run when certain files have changed
'jittest',
'test-verify',
'test-verify-gpu',
'test-verify-wpt',
'test-coverage',
'test-coverage-wpt',

View File

@ -4,3 +4,4 @@ add_WOW64_flags_to_allowed_registry_read_flags.patch
consult_PermissionsService_for_file_access.patch
allow_flash_temporary_files.patch
use_STARTF_FORCEOFFFEEDBACK_flag.patch
remove_dynamic_GetUserDefaultLocaleName_call.patch

View File

@ -0,0 +1,66 @@
# HG changeset patch
# User Bob Owen <bobowencode@gmail.com>
# Date 1524480221 -3600
# Mon Apr 23 11:43:41 2018 +0100
# Node ID c881904b6139ba0c6f5072f7577a94812021913a
# Parent e96685584bf7d3c1d7a4c1861716da89fd650c51
Bug 1444699: Remove dynamic load and call for GetUserDefaultLocaleName. r=handyman
This was only required because it is not available on Windows XP, which is no
longer supported. Patch already landed upstream in chromium.
diff --git a/security/sandbox/chromium/sandbox/win/src/target_services.cc b/security/sandbox/chromium/sandbox/win/src/target_services.cc
--- a/security/sandbox/chromium/sandbox/win/src/target_services.cc
+++ b/security/sandbox/chromium/sandbox/win/src/target_services.cc
@@ -75,50 +75,30 @@ bool CloseOpenHandles(bool* is_csrss_con
}
}
if (!handle_closer.CloseHandles())
return false;
}
return true;
}
-// GetUserDefaultLocaleName is not available on WIN XP. So we'll
-// load it on-the-fly.
-const wchar_t kKernel32DllName[] = L"kernel32.dll";
-typedef decltype(GetUserDefaultLocaleName)* GetUserDefaultLocaleNameFunction;
-
// Warm up language subsystems before the sandbox is turned on.
// Tested on Win8.1 x64:
// This needs to happen after RevertToSelf() is called, because (at least) in
// the case of GetUserDefaultLCID() it checks the TEB to see if the process is
// impersonating (TEB!IsImpersonating). If it is, the cached locale information
// is not used, nor is it set. Therefore, calls after RevertToSelf() will not
// have warmed-up values to use.
bool WarmupWindowsLocales() {
// NOTE(liamjm): When last checked (Win 8.1 x64) it wasn't necessary to
// warmup all of these functions, but let's not assume that.
::GetUserDefaultLangID();
::GetUserDefaultLCID();
- static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func =
- NULL;
- if (!GetUserDefaultLocaleName_func) {
- HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName);
- if (!kernel32_dll) {
- return false;
- }
- GetUserDefaultLocaleName_func =
- reinterpret_cast<GetUserDefaultLocaleNameFunction>(
- GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName"));
- if (!GetUserDefaultLocaleName_func) {
- return false;
- }
- }
wchar_t localeName[LOCALE_NAME_MAX_LENGTH] = {0};
- return (0 != GetUserDefaultLocaleName_func(
- localeName, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t)));
+ return (0 != ::GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH));
}
// Used as storage for g_target_services, because other allocation facilities
// are not available early. We can't use a regular function static because on
// VS2015, because the CRT tries to acquire a lock to guard initialization, but
// this code runs before the CRT is initialized.
char g_target_services_memory[sizeof(TargetServicesBase)];
TargetServicesBase* g_target_services = nullptr;

View File

@ -80,11 +80,6 @@ bool CloseOpenHandles(bool* is_csrss_connected) {
return true;
}
// GetUserDefaultLocaleName is not available on WIN XP. So we'll
// load it on-the-fly.
const wchar_t kKernel32DllName[] = L"kernel32.dll";
typedef decltype(GetUserDefaultLocaleName)* GetUserDefaultLocaleNameFunction;
// Warm up language subsystems before the sandbox is turned on.
// Tested on Win8.1 x64:
// This needs to happen after RevertToSelf() is called, because (at least) in
@ -97,23 +92,8 @@ bool WarmupWindowsLocales() {
// warmup all of these functions, but let's not assume that.
::GetUserDefaultLangID();
::GetUserDefaultLCID();
static GetUserDefaultLocaleNameFunction GetUserDefaultLocaleName_func =
NULL;
if (!GetUserDefaultLocaleName_func) {
HMODULE kernel32_dll = ::GetModuleHandle(kKernel32DllName);
if (!kernel32_dll) {
return false;
}
GetUserDefaultLocaleName_func =
reinterpret_cast<GetUserDefaultLocaleNameFunction>(
GetProcAddress(kernel32_dll, "GetUserDefaultLocaleName"));
if (!GetUserDefaultLocaleName_func) {
return false;
}
}
wchar_t localeName[LOCALE_NAME_MAX_LENGTH] = {0};
return (0 != GetUserDefaultLocaleName_func(
localeName, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t)));
return (0 != ::GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH));
}
// Used as storage for g_target_services, because other allocation facilities

View File

@ -98,6 +98,51 @@ test-verify:
extra-options:
- --verify
test-verify-gpu:
description: "Extra verification of tests modified on this push on gpu instances"
suite: test-verify
treeherder-symbol: TVg
loopback-video: true
virtualization: virtual-with-gpu
instance-size:
by-test-platform:
android.*: xlarge
default: default
max-run-time: 10800
allow-software-gl-layers: false
run-on-projects:
by-test-platform:
# do not run on ccov; see also the enable_code_coverage transform
linux64-ccov/.*: []
windows10-64-ccov/debug: []
# do not run on beta or release: usually just confirms earlier results
default: ['trunk', 'try']
tier:
by-test-platform:
windows10-64-asan.*: 3
default: 2
mozharness:
script:
by-test-platform:
android.*: android_emulator_unittest.py
default: desktop_unittest.py
config:
by-test-platform:
android.*:
- android/android_common.py
- android/androidarm_4_3.py
linux.*:
- unittests/linux_unittest.py
- remove_executables.py
macosx.*:
- unittests/mac_unittest.py
windows.*:
- unittests/win_taskcluster_unittest.py
no-read-buildbot-config: true
extra-options:
- --verify
- --gpu-required
test-coverage:
description: "Per-test coverage"
suite: test-coverage

View File

@ -40,6 +40,7 @@ common-tests:
- test-coverage
- test-coverage-wpt
- test-verify
- test-verify-gpu
- test-verify-wpt
- xpcshell
@ -190,6 +191,7 @@ windows-tests:
- test-coverage
- test-coverage-wpt
- test-verify
- test-verify-gpu
- test-verify-wpt
- web-platform-tests
- web-platform-tests-reftests
@ -253,6 +255,7 @@ macosx64-tests:
- mochitest-webgl
- reftest
- test-verify
- test-verify-gpu
- test-verify-wpt
- web-platform-tests
- web-platform-tests-reftests

View File

@ -382,7 +382,7 @@ linux64-android-gradle-dependencies:
# Aliases aren't allowed for toolchains depending on toolchains.
- linux64-android-sdk-linux-repack
linux64-rust-1.25:
linux64-rust-1.24:
description: "rust repack"
treeherder:
kind: build
@ -398,7 +398,7 @@ linux64-rust-1.25:
using: toolchain-script
script: repack_rust.py
arguments: [
'--channel', '1.25.0',
'--channel', '1.24.0',
'--host', 'x86_64-unknown-linux-gnu',
'--target', 'x86_64-unknown-linux-gnu',
'--target', 'i686-unknown-linux-gnu',
@ -406,30 +406,7 @@ linux64-rust-1.25:
toolchain-alias: linux64-rust
toolchain-artifact: public/build/rustc.tar.xz
linux64-rust-1.24:
description: "rust repack"
treeherder:
kind: build
platform: toolchains/opt
symbol: TL(rust-1.24)
tier: 1
worker-type: aws-provisioner-v1/gecko-{level}-b-linux
worker:
max-run-time: 7200
env:
UPLOAD_DIR: artifacts
run:
using: toolchain-script
script: repack_rust.py
arguments: [
'--channel', '1.24.0',
'--host', 'x86_64-unknown-linux-gnu',
'--target', 'x86_64-unknown-linux-gnu',
'--target', 'i686-unknown-linux-gnu',
]
toolchain-artifact: public/build/rustc.tar.xz
linux64-rust-macos-1.25:
linux64-rust-macos-1.24:
description: "rust repack with macos-cross support"
treeherder:
kind: build
@ -445,7 +422,7 @@ linux64-rust-macos-1.25:
using: toolchain-script
script: repack_rust.py
arguments: [
'--channel', '1.25.0',
'--channel', '1.24.0',
'--host', 'x86_64-unknown-linux-gnu',
'--target', 'x86_64-unknown-linux-gnu',
'--target', 'x86_64-apple-darwin',
@ -453,7 +430,7 @@ linux64-rust-macos-1.25:
toolchain-alias: linux64-rust-macos
toolchain-artifact: public/build/rustc.tar.xz
linux64-rust-android-1.25:
linux64-rust-android-1.24:
description: "rust repack with android-cross support"
treeherder:
kind: build
@ -469,7 +446,7 @@ linux64-rust-android-1.25:
using: toolchain-script
script: repack_rust.py
arguments: [
'--channel', '1.25.0',
'--channel', '1.24.0',
'--host', 'x86_64-unknown-linux-gnu',
'--target', 'x86_64-unknown-linux-gnu',
'--target', 'armv7-linux-androideabi',
@ -496,7 +473,7 @@ linux64-sccache:
- 'taskcluster/scripts/misc/tooltool-download.sh'
toolchain-artifact: public/build/sccache2.tar.xz
toolchains:
- linux64-rust-1.25
- linux64-rust-1.24
linux64-gn:
description: "gn toolchain build"

View File

@ -118,7 +118,7 @@ win64-clang-tidy:
- 'taskcluster/scripts/misc/build-clang-windows-helper64.sh'
toolchain-artifact: public/build/clang-tidy.tar.bz2
win64-rust-1.25:
win64-rust-1.24:
description: "rust repack"
treeherder:
kind: build
@ -135,7 +135,7 @@ win64-rust-1.25:
using: toolchain-script
script: repack_rust.py
arguments: [
'--channel', '1.25.0',
'--channel', '1.24.0',
'--host', 'x86_64-pc-windows-msvc',
'--target', 'x86_64-pc-windows-msvc',
'--target', 'i686-pc-windows-msvc',
@ -143,7 +143,7 @@ win64-rust-1.25:
toolchain-alias: win64-rust
toolchain-artifact: public/build/rustc.tar.bz2
win32-rust-1.25:
win32-rust-1.24:
description: "rust repack"
treeherder:
kind: build
@ -160,14 +160,14 @@ win32-rust-1.25:
using: toolchain-script
script: repack_rust.py
arguments: [
'--channel', '1.25.0',
'--channel', '1.24.0',
'--host', 'i686-pc-windows-msvc',
'--target', 'i686-pc-windows-msvc',
]
toolchain-alias: win32-rust
toolchain-artifact: public/build/rustc.tar.bz2
mingw32-rust-1.25:
mingw32-rust-1.24:
description: "rust repack"
treeherder:
kind: build
@ -184,7 +184,7 @@ mingw32-rust-1.25:
using: toolchain-script
script: repack_rust.py
arguments: [
'--channel', '1.25.0',
'--channel', '1.24.0',
'--host', 'i686-unknown-linux-gnu',
'--target', 'i686-pc-windows-gnu',
'--target', 'x86_64-unknown-linux-gnu',
@ -212,7 +212,7 @@ win64-sccache:
- 'taskcluster/scripts/misc/tooltool-download.sh'
toolchain-artifact: public/build/sccache2.tar.bz2
toolchains:
- win64-rust-1.25
- win64-rust-1.24
win32-gn:
description: "gn toolchain build"

View File

@ -282,6 +282,9 @@ def target_tasks_mozilla_esr60(full_task_graph, parameters, graph_config):
of builds and signing, but does not include beetmover or balrog jobs."""
def filter(task):
if not filter_beta_release_tasks(task, parameters):
return False
platform = task.attributes.get('build_platform')
# Android is not built on esr.
@ -291,10 +294,7 @@ def target_tasks_mozilla_esr60(full_task_graph, parameters, graph_config):
# All else was already filtered
return True
tasks = [l for l, t in full_task_graph.tasks.iteritems() if
filter_beta_release_tasks(t, parameters)]
return [l for l, t in tasks.iteritems() if filter(t)]
return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
@_target_task('promote_firefox')

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