Merge m-i to m-c, a=merge

This commit is contained in:
Phil Ringnalda 2016-09-05 13:05:52 -07:00
commit 66b3a90750
61 changed files with 661 additions and 490 deletions

View File

@ -76,10 +76,6 @@ leak:processInternalEntity
# Bug 1187421 - With e10s, NSS does not always free the error stack. m1.
leak:nss_ClearErrorStack
# Bug 1189430 - DNS leaks in mochitest-chrome.
leak:nsDNSService::AsyncResolveExtended
leak:_GetAddrInfo_Portable
# Bug 1189568 - Indirect leaks of IMContextWrapper and nsIntRect.
leak:nsWindow::Create
leak:nsBaseWidget::StoreWindowClipRegion

View File

@ -1136,10 +1136,11 @@ public:
NS_LITERAL_CSTRING("explicit/dom/memory-file-data/small"),
KIND_HEAP, UNITS_BYTES, smallObjectsTotal,
nsPrintfCString(
"Memory used to back small memory files (less than %d bytes each).\n\n"
"Memory used to back small memory files (i.e. those taking up less "
"than %zu bytes of memory each).\n\n"
"Note that the allocator may round up a memory file's length -- "
"that is, an N-byte memory file may take up more than N bytes of "
"memory."),
"memory.", LARGE_OBJECT_MIN_SIZE),
aData);
}

View File

@ -461,7 +461,7 @@ nsTextFragment::UpdateBidiFlag(const char16_t* aBuffer, uint32_t aLength)
char16_t ch2 = *cp++;
utf32Char = SURROGATE_TO_UCS4(ch1, ch2);
}
if (UTF32_CHAR_IS_BIDI(utf32Char) || IsBidiControl(utf32Char)) {
if (UTF32_CHAR_IS_BIDI(utf32Char) || IsBidiControlRTL(utf32Char)) {
mState.mIsBidi = true;
break;
}

View File

@ -3805,19 +3805,6 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
}
}
if (aVisitor.mEvent->mMessage == eKeyUp && aVisitor.mEvent->IsTrusted()) {
WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
if (MayFireChangeOnKeyUp(keyEvent->mKeyCode) &&
!(keyEvent->IsShift() || keyEvent->IsControl() || keyEvent->IsAlt() ||
keyEvent->IsMeta() || keyEvent->IsAltGraph() || keyEvent->IsFn() ||
keyEvent->IsOS())) {
// The up/down arrow key events fire 'change' events when released
// so that at the end of a series of up/down arrow key repeat events
// the value is considered to be "commited" by the user.
FireChangeEventIfNeeded();
}
}
nsresult rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
// We do this after calling the base class' PreHandleEvent so that
@ -4303,6 +4290,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
// event to increase/decrease the value of the number control.
if (!aVisitor.mEvent->DefaultPreventedByContent() && IsMutable()) {
StepNumberControlForUserEvent(keyEvent->mKeyCode == NS_VK_UP ? 1 : -1);
FireChangeEventIfNeeded();
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
}
} else if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
@ -4480,6 +4468,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
break;
}
SetValueOfRangeForUserEvent(newValue);
FireChangeEventIfNeeded();
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
}
}
@ -4557,6 +4546,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
do_QueryFrame(GetPrimaryFrame());
if (numberControlFrame && numberControlFrame->IsFocused()) {
StepNumberControlForUserEvent(wheelEvent->mDeltaY > 0 ? -1 : 1);
FireChangeEventIfNeeded();
aVisitor.mEvent->PreventDefault();
}
} else if (mType == NS_FORM_INPUT_RANGE &&
@ -4570,6 +4560,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
MOZ_ASSERT(value.isFinite() && step.isFinite());
SetValueOfRangeForUserEvent(wheelEvent->mDeltaY < 0 ?
value + step : value - step);
FireChangeEventIfNeeded();
aVisitor.mEvent->PreventDefault();
}
}
@ -8344,18 +8335,6 @@ HTMLInputElement::GetWebkitEntries(nsTArray<RefPtr<FileSystemEntry>>& aSequence)
aSequence.AppendElements(mEntries);
}
bool HTMLInputElement::MayFireChangeOnKeyUp(uint32_t aKeyCode) const
{
switch (mType) {
case NS_FORM_INPUT_NUMBER:
return aKeyCode == NS_VK_UP || aKeyCode == NS_VK_DOWN;
case NS_FORM_INPUT_RANGE:
return aKeyCode == NS_VK_UP || aKeyCode == NS_VK_DOWN ||
aKeyCode == NS_VK_LEFT || aKeyCode == NS_VK_RIGHT;
}
return false;
}
} // namespace dom
} // namespace mozilla

View File

@ -1515,12 +1515,6 @@ private:
aType == NS_FORM_INPUT_NUMBER;
}
/**
* Returns true if the key code may induce the input's value changed to fire
* a "change" event accordingly.
*/
bool MayFireChangeOnKeyUp(uint32_t aKeyCode) const;
struct nsFilePickerFilter {
nsFilePickerFilter()
: mFilterMask(0) {}

View File

@ -215,9 +215,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=722599
is(rangeChange, 0, "Change event shouldn't be dispatched on range input element for key changes that don't change its value");
range.focus();
synthesizeKey("VK_HOME", {});
is(rangeChange, 0, "Change event shouldn't be dispatched on range input element for key changes until it loses focus");
is(rangeChange, 1, "Change event should be dispatched on range input element for key changes");
range.blur();
is(rangeChange, 1, "Change event should be dispatched on range input element on blur");
is(rangeChange, 1, "Change event shouldn't be dispatched on range input element on blur");
range.focus();
var bcr = range.getBoundingClientRect();
var centerOfRangeX = bcr.width / 2;
@ -233,6 +233,32 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=722599
synthesizeMouse(range, centerOfRangeX - 10, centerOfRangeY, {});
is(rangeChange, 3, "Change event should be dispatched on range input element for a click that gives the range focus");
if (isDesktop) { // up/down arrow keys not supported on android/b2g
synthesizeKey("VK_UP", {});
is(rangeChange, 4, "Change event should be dispatched on range input element for key changes that change its value (VK_UP)");
synthesizeKey("VK_DOWN", {});
is(rangeChange, 5, "Change event should be dispatched on range input element for key changes that change its value (VK_DOWN)");
synthesizeKey("VK_RIGHT", {});
is(rangeChange, 6, "Change event should be dispatched on range input element for key changes that change its value (VK_RIGHT)");
synthesizeKey("VK_LEFT", {});
is(rangeChange, 7, "Change event should be dispatched on range input element for key changes that change its value (VK_LEFT)");
synthesizeKey("VK_UP", {shiftKey: true});
is(rangeChange, 8, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_UP)");
synthesizeKey("VK_DOWN", {shiftKey: true});
is(rangeChange, 9, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_DOWN)");
synthesizeKey("VK_RIGHT", {shiftKey: true});
is(rangeChange, 10, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_RIGHT)");
synthesizeKey("VK_LEFT", {shiftKey: true});
is(rangeChange, 11, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_LEFT)");
synthesizeKey("VK_PAGE_UP", {});
is(rangeChange, 12, "Change event should be dispatched on range input element for key changes that change its value (VK_PAGE_UP)");
synthesizeKey("VK_PAGE_DOWN", {});
is(rangeChange, 13, "Change event should be dispatched on range input element for key changes that change its value (VK_PAGE_DOWN");
synthesizeKey("VK_RIGHT", {shiftKey: true});
is(rangeChange, 14, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_PAGE_UP)");
synthesizeKey("VK_LEFT", {shiftKey: true});
is(rangeChange, 15, "Change event should be dispatched on range input element for key changes that change its value (Shift+VK_PAGE_DOWN)");
}
//Input type change test.
input = document.getElementById("input_checkbox");
input.type = "text";

View File

@ -631,3 +631,6 @@ skip-if = (os != 'win' && os != 'linux')
[test_bug1260704.html]
[test_allowMedia.html]
[test_bug1292522_same_domain_with_different_port_number.html]
[test_bug1295719_event_sequence_for_arrow_keys.html]
skip-if = os == "android" || appname == "b2g" # up/down arrow keys not supported on android/b2g
[test_bug1295719_event_sequence_for_number_keys.html]

View File

@ -42,10 +42,17 @@ function runTests() {
let testIdx = 0;
let result = parseInt(input.value);
let numberChange = 0;
let expectChange = 0;
input.addEventListener("change", () => {
++numberChange;
}, false);
function runNext() {
let p = params[testIdx];
(p["focus"]) ? input.focus() : input.blur();
expectChange = p["valueChanged"] == 0 ? expectChange : expectChange + 1;
result += parseInt(p["valueChanged"]);
synthesizeWheel(input, 1, 1, { deltaY: p["deltaY"], deltaMode: p["deltaMode"] });
window.postMessage("finished", "http://mochi.test:8888");
@ -57,6 +64,8 @@ function runTests() {
ok(input.value == result,
"Handle wheel in number input test-" + testIdx + " expect " + result +
" get " + input.value);
ok(numberChange == expectChange,
"UA should fire change event when input's value changed, expect " + expectChange + " get " + numberChange);
(testIdx >= params.length) ? SimpleTest.finish() : runNext();
}
});

View File

@ -43,14 +43,23 @@ function runTests() {
let testIdx = 0;
let result = parseInt(input.value);
let rangeChange = 0;
let expectChange = 0;
input.addEventListener("change", () => {
++rangeChange;
}, false);
function runNext() {
let p = params[testIdx];
(p["focus"]) ? input.focus() : input.blur();
expectChange = p["valueChanged"] == 0 ? expectChange : expectChange + 1;
result += parseInt(p["valueChanged"]);
sendWheelAndPaint(input, 1, 1, { deltaY: p["deltaY"], deltaMode: p["deltaMode"] }, () => {
ok(input.value == result,
"Handle wheel in range input test-" + testIdx + " expect " + result + " get " + input.value);
ok(rangeChange == expectChange,
"UA should fire change event when input's value changed, expect " + expectChange + " get " + rangeChange);
(++testIdx >= params.length) ? SimpleTest.finish() : runNext();
});
}

View File

@ -41,6 +41,11 @@ function runTests() {
let testIdx = 0;
let result = parseInt(input.value);
let rangeChange = 0;
input.addEventListener("change", () => {
++rangeChange;
}, false);
function runNext() {
let p = params[testIdx];
@ -48,6 +53,7 @@ function runTests() {
sendWheelAndPaint(input, 1, 1, { deltaY: p["deltaY"], deltaMode: p["deltaMode"] }, () => {
ok(input.value == result,
"Handle wheel in range input test-" + testIdx + " expect " + result + " get " + input.value);
ok(rangeChange == 0, "Wheel event should not trigger change event when max < min");
testIdx++;
(testIdx >= params.length) ? SimpleTest.finish() : runNext();
});

View File

@ -0,0 +1,67 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1295719
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1295719</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1295719">Mozilla Bug 1295719</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<input id="test_number" type="number" value=50>
<input id="test_range" type="range" value=50 max=100 min=0>
<script type="text/javascript">
/** Test for Bug 1295719 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTests);
function runTests() {
let number = window.document.getElementById("test_number");
let range = window.document.getElementById("test_range");
let waiting_event_sequence = ["keydown", "keypress", "input", "change"];
let waiting_event_idx = 0;
waiting_event_sequence.forEach((eventType) => {
number.addEventListener(eventType, (event) => {
let waiting_event = waiting_event_sequence[waiting_event_idx];
is(waiting_event, eventType, "Waiting " + waiting_event + " get " + eventType);
// Input element will fire input and change events when handling keypress
// with keycode=arrows. When user press and hold the keyboard, we expect
// that input element repeatedly fires "keydown", "keypress", "input", and
// "change" events until user release the keyboard. Using
// waiting_event_sequence as a circular buffer and reset waiting_event_idx
// when it point to the end of buffer.
waiting_event_idx = waiting_event_idx == waiting_event_sequence.length -1 ? 0 : waiting_event_idx + 1;
}, false);
range.addEventListener(eventType, (event) => {
let waiting_event = waiting_event_sequence[waiting_event_idx];
is(waiting_event, eventType, "Waiting " + waiting_event + " get " + eventType);
waiting_event_idx = waiting_event_idx == waiting_event_sequence.length - 1 ? 0 : waiting_event_idx + 1;
}, false);
});
number.focus();
synthesizeKey("VK_DOWN", {type: "keydown"});
synthesizeKey("VK_DOWN", {type: "keydown"});
synthesizeKey("VK_DOWN", {type: "keyup"});
number.blur();
range.focus();
waiting_event_idx = 0;
synthesizeKey("VK_DOWN", {type: "keydown"});
synthesizeKey("VK_DOWN", {type: "keydown"});
synthesizeKey("VK_DOWN", {type: "keyup"});
SimpleTest.finish();
}
</script>
</body>
</html>

View File

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1295719
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1295719</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1295719">Mozilla Bug 1295719</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<input id="test_number" type="number" value=50>
<script type="text/javascript">
/** Test for Bug 1295719 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTests);
function runTests() {
let number = window.document.getElementById("test_number");
let waiting_event_sequence = ["keydown", "keypress", "input"];
let change_event_of_number = 0;
let keyup_event_of_number = 0;
let waiting_event_idx = 0;
waiting_event_sequence.forEach((eventType) => {
number.addEventListener(eventType, (event) => {
let waiting_event = waiting_event_sequence[waiting_event_idx];
is(eventType, waiting_event, "Waiting " + waiting_event + " get " + eventType);
// Input element will fire input event when handling keypress with
// keycode=numbers. When user press and hold the keyboard, we expect that
// input element repeatedly fires "keydown", "keypress", and "input" until
// user release the keyboard. Input element will fire change event when
// it's blurred. Using waiting_event_sequence as a circular buffer and
// reset waiting_event_idx when it point to the end of buffer.
waiting_event_idx = waiting_event_idx == waiting_event_sequence.length - 1 ? 0 : waiting_event_idx + 1;
}, false);
});
number.addEventListener("change", (event) => {
is(keyup_event_of_number, 1, "change event should be fired after blurred");
++change_event_of_number;
}, false);
number.addEventListener("keyup", (event) => {
is(keyup_event_of_number, 0, "keyup event should be fired once");
is(change_event_of_number, 0, "keyup event should be fired before change event");
++keyup_event_of_number;
}, false);
number.focus();
synthesizeKey("5", {type: "keydown"});
synthesizeKey("5", {type: "keydown"});
synthesizeKey("5", {type: "keyup"});
is(change_event_of_number, 0, "change event shouldn't be fired when input element is focused");
number.blur();
is(change_event_of_number, 1, "change event should be fired when input element is blurred");
SimpleTest.finish();
}
</script>
</body>
</html>

View File

@ -294,6 +294,12 @@ void VideoFrameContainer::ClearFutureFrames()
}
}
void
VideoFrameContainer::ClearCachedResources()
{
mImageContainer->ClearCachedResources();
}
ImageContainer* VideoFrameContainer::GetImageContainer() {
return mImageContainer;
}

View File

@ -73,6 +73,9 @@ public:
// but was actually painted at t+n, this returns n in seconds. Threadsafe.
double GetFrameDelay();
// Clear any resources that are not immediately necessary.
void ClearCachedResources();
// Returns a new frame ID for SetCurrentFrames(). The client must either
// call this on only one thread or provide barriers. Do not use together
// with SetCurrentFrame().

View File

@ -145,6 +145,9 @@ VideoSink::SetPlaying(bool aPlaying)
mUpdateScheduler.Reset();
// Since playback is paused, tell compositor to render only current frame.
RenderVideoFrames(1);
if (mContainer) {
mContainer->ClearCachedResources();
}
}
mAudioSink->SetPlaying(aPlaying);

View File

@ -72,7 +72,7 @@ AvailabilityCollection::Remove(PresentationAvailability* aAvailability)
}
already_AddRefed<PresentationAvailability>
AvailabilityCollection::Find(const uint64_t aWindowId, const nsAString& aUrl)
AvailabilityCollection::Find(const uint64_t aWindowId, const nsTArray<nsString>& aUrls)
{
MOZ_ASSERT(NS_IsMainThread());
@ -85,7 +85,7 @@ AvailabilityCollection::Find(const uint64_t aWindowId, const nsAString& aUrl)
continue;
}
if (availability->Equals(aWindowId, aUrl)) {
if (availability->Equals(aWindowId, aUrls)) {
RefPtr<PresentationAvailability> matchedAvailability = availability.get();
return matchedAvailability.forget();
}

View File

@ -27,7 +27,7 @@ public:
void Remove(PresentationAvailability* aAvailability);
already_AddRefed<PresentationAvailability>
Find(const uint64_t aWindowId, const nsAString& aUrl);
Find(const uint64_t aWindowId, const nsTArray<nsString>& aUrls);
private:
friend class StaticAutoPtr<AvailabilityCollection>;

View File

@ -37,20 +37,20 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
/* static */ already_AddRefed<PresentationAvailability>
PresentationAvailability::Create(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl,
const nsTArray<nsString>& aUrls,
RefPtr<Promise>& aPromise)
{
RefPtr<PresentationAvailability> availability =
new PresentationAvailability(aWindow, aUrl);
new PresentationAvailability(aWindow, aUrls);
return NS_WARN_IF(!availability->Init(aPromise)) ? nullptr
: availability.forget();
}
PresentationAvailability::PresentationAvailability(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl)
const nsTArray<nsString>& aUrls)
: DOMEventTargetHelper(aWindow)
, mIsAvailable(false)
, mUrl(aUrl)
, mUrls(aUrls)
{
}
@ -120,10 +120,15 @@ PresentationAvailability::WrapObject(JSContext* aCx,
bool
PresentationAvailability::Equals(const uint64_t aWindowID,
const nsAString& aUrl) const
const nsTArray<nsString>& aUrls) const
{
if (GetOwner() && GetOwner()->WindowID() == aWindowID &&
mUrl.Equals(aUrl)) {
mUrls.Length() == aUrls.Length()) {
for (const auto& url : aUrls) {
if (!mUrls.Contains(url)) {
return false;
}
}
return true;
}
@ -162,8 +167,7 @@ PresentationAvailability::NotifyAvailableChange(bool aIsAvailable)
void
PresentationAvailability::UpdateAvailabilityAndDispatchEvent(bool aIsAvailable)
{
PRES_DEBUG("%s:id[%s]\n", __func__,
NS_ConvertUTF16toUTF8(mUrl).get());
PRES_DEBUG("%s\n", __func__);
bool isChanged = (aIsAvailable != mIsAvailable);
mIsAvailable = aIsAvailable;

View File

@ -29,7 +29,7 @@ public:
static already_AddRefed<PresentationAvailability>
Create(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl,
const nsTArray<nsString>& aUrls,
RefPtr<Promise>& aPromise);
virtual void DisconnectFromOwner() override;
@ -37,7 +37,7 @@ public:
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
bool Equals(const uint64_t aWindowID, const nsAString& aUrl) const;
bool Equals(const uint64_t aWindowID, const nsTArray<nsString>& aUrls) const;
bool IsCachedValueReady();
@ -50,7 +50,7 @@ public:
private:
explicit PresentationAvailability(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl);
const nsTArray<nsString>& aUrls);
virtual ~PresentationAvailability();
@ -64,7 +64,7 @@ private:
nsTArray<RefPtr<Promise>> mPromises;
nsString mUrl;
nsTArray<nsString> mUrls;
};
} // namespace dom

View File

@ -25,11 +25,9 @@ using namespace mozilla::dom;
NS_IMPL_ISUPPORTS(PresentationRequesterCallback, nsIPresentationServiceCallback)
PresentationRequesterCallback::PresentationRequesterCallback(PresentationRequest* aRequest,
const nsAString& aUrl,
const nsAString& aSessionId,
Promise* aPromise)
: mRequest(aRequest)
, mUrl(aUrl)
, mSessionId(aSessionId)
, mPromise(aPromise)
{
@ -44,12 +42,16 @@ PresentationRequesterCallback::~PresentationRequesterCallback()
// nsIPresentationServiceCallback
NS_IMETHODIMP
PresentationRequesterCallback::NotifySuccess()
PresentationRequesterCallback::NotifySuccess(const nsAString& aUrl)
{
MOZ_ASSERT(NS_IsMainThread());
if (aUrl.IsEmpty()) {
return NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
RefPtr<PresentationConnection> connection =
PresentationConnection::Create(mRequest->GetOwner(), mSessionId, mUrl,
PresentationConnection::Create(mRequest->GetOwner(), mSessionId, aUrl,
nsIPresentationService::ROLE_CONTROLLER);
if (NS_WARN_IF(!connection)) {
mPromise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
@ -79,11 +81,10 @@ NS_IMPL_ISUPPORTS_INHERITED0(PresentationReconnectCallback,
PresentationReconnectCallback::PresentationReconnectCallback(
PresentationRequest* aRequest,
const nsAString& aUrl,
const nsAString& aSessionId,
Promise* aPromise,
PresentationConnection* aConnection)
: PresentationRequesterCallback(aRequest, aUrl, aSessionId, aPromise)
: PresentationRequesterCallback(aRequest, aSessionId, aPromise)
, mConnection(aConnection)
{
}
@ -93,7 +94,7 @@ PresentationReconnectCallback::~PresentationReconnectCallback()
}
NS_IMETHODIMP
PresentationReconnectCallback::NotifySuccess()
PresentationReconnectCallback::NotifySuccess(const nsAString& aUrl)
{
MOZ_ASSERT(NS_IsMainThread());
@ -116,7 +117,7 @@ PresentationReconnectCallback::NotifySuccess()
} else {
// Use |PresentationRequesterCallback::NotifySuccess| to create a new
// connection since we don't find one that can be reused.
rv = PresentationRequesterCallback::NotifySuccess();
rv = PresentationRequesterCallback::NotifySuccess(aUrl);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

View File

@ -31,7 +31,6 @@ public:
NS_DECL_NSIPRESENTATIONSERVICECALLBACK
PresentationRequesterCallback(PresentationRequest* aRequest,
const nsAString& aUrl,
const nsAString& aSessionId,
Promise* aPromise);
@ -39,7 +38,6 @@ protected:
virtual ~PresentationRequesterCallback();
RefPtr<PresentationRequest> mRequest;
nsString mUrl;
nsString mSessionId;
RefPtr<Promise> mPromise;
};
@ -51,7 +49,6 @@ public:
NS_DECL_NSIPRESENTATIONSERVICECALLBACK
PresentationReconnectCallback(PresentationRequest* aRequest,
const nsAString& aUrl,
const nsAString& aSessionId,
Promise* aPromise,
PresentationConnection* aConnection);

View File

@ -12,6 +12,7 @@
#include "mozilla/dom/PresentationRequestBinding.h"
#include "mozilla/dom/PresentationConnectionAvailableEvent.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/Move.h"
#include "mozIThirdPartyUtil.h"
#include "nsContentSecurityManager.h"
#include "nsCycleCollectionParticipant.h"
@ -64,6 +65,16 @@ GetAbsoluteURL(const nsAString& aUrl,
PresentationRequest::Constructor(const GlobalObject& aGlobal,
const nsAString& aUrl,
ErrorResult& aRv)
{
Sequence<nsString> urls;
urls.AppendElement(aUrl, fallible);
return Constructor(aGlobal, urls, aRv);
}
/* static */ already_AddRefed<PresentationRequest>
PresentationRequest::Constructor(const GlobalObject& aGlobal,
const Sequence<nsString>& aUrls,
ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
@ -71,31 +82,35 @@ PresentationRequest::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
// Ensure the URL is not empty.
if (NS_WARN_IF(aUrl.IsEmpty())) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
if (aUrls.IsEmpty()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
// Resolve relative URL to absolute URL
nsCOMPtr<nsIURI> baseUri = window->GetDocBaseURI();
nsTArray<nsString> urls;
for (const auto& url : aUrls) {
nsAutoString absoluteUrl;
nsresult rv =
GetAbsoluteURL(url, baseUri, window->GetExtantDoc(), absoluteUrl);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return nullptr;
}
nsAutoString absoluteUrl;
nsresult rv = GetAbsoluteURL(aUrl, baseUri, window->GetExtantDoc(), absoluteUrl);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
urls.AppendElement(absoluteUrl);
}
RefPtr<PresentationRequest> request =
new PresentationRequest(window, absoluteUrl);
new PresentationRequest(window, Move(urls));
return NS_WARN_IF(!request->Init()) ? nullptr : request.forget();
}
PresentationRequest::PresentationRequest(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl)
nsTArray<nsString>&& aUrls)
: DOMEventTargetHelper(aWindow)
, mUrl(aUrl)
, mUrls(Move(aUrls))
{
}
@ -152,7 +167,7 @@ PresentationRequest::StartWithDevice(const nsAString& aDeviceId,
}
if (IsProhibitMixedSecurityContexts(doc) &&
!IsPrioriAuthenticatedURL(mUrl)) {
!IsAllURLAuthenticated()) {
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
return promise.forget();
}
@ -185,8 +200,8 @@ PresentationRequest::StartWithDevice(const nsAString& aDeviceId,
}
nsCOMPtr<nsIPresentationServiceCallback> callback =
new PresentationRequesterCallback(this, mUrl, id, promise);
rv = service->StartSession(mUrl, id, origin, aDeviceId, GetOwner()->WindowID(), callback);
new PresentationRequesterCallback(this, id, promise);
rv = service->StartSession(mUrls, id, origin, aDeviceId, GetOwner()->WindowID(), callback);
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
}
@ -216,7 +231,7 @@ PresentationRequest::Reconnect(const nsAString& aPresentationId,
}
if (IsProhibitMixedSecurityContexts(doc) &&
!IsPrioriAuthenticatedURL(mUrl)) {
!IsAllURLAuthenticated()) {
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
return promise.forget();
}
@ -262,7 +277,7 @@ PresentationRequest::FindOrCreatePresentationConnection(
if (connection) {
nsAutoString url;
connection->GetUrl(url);
if (url.Equals(mUrl)) {
if (mUrls.Contains(url)) {
switch (connection->State()) {
case PresentationConnectionState::Closed:
// We found the matched connection.
@ -293,13 +308,12 @@ PresentationRequest::FindOrCreatePresentationConnection(
nsCOMPtr<nsIPresentationServiceCallback> callback =
new PresentationReconnectCallback(this,
mUrl,
aPresentationId,
aPromise,
connection);
nsresult rv =
service->ReconnectSession(mUrl,
service->ReconnectSession(mUrls,
aPresentationId,
nsIPresentationService::ROLE_CONTROLLER,
callback);
@ -311,8 +325,7 @@ PresentationRequest::FindOrCreatePresentationConnection(
already_AddRefed<Promise>
PresentationRequest::GetAvailability(ErrorResult& aRv)
{
PRES_DEBUG("%s:id[%s]\n", __func__,
NS_ConvertUTF16toUTF8(mUrl).get());
PRES_DEBUG("%s\n", __func__);
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
if (NS_WARN_IF(!global)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
@ -331,7 +344,7 @@ PresentationRequest::GetAvailability(ErrorResult& aRv)
}
if (IsProhibitMixedSecurityContexts(doc) &&
!IsPrioriAuthenticatedURL(mUrl)) {
!IsAllURLAuthenticated()) {
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
return promise.forget();
}
@ -363,13 +376,12 @@ PresentationRequest::FindOrCreatePresentationAvailability(RefPtr<Promise>& aProm
}
RefPtr<PresentationAvailability> availability =
collection->Find(GetOwner()->WindowID(), mUrl);
collection->Find(GetOwner()->WindowID(), mUrls);
if (!availability) {
availability = PresentationAvailability::Create(GetOwner(), mUrl, aPromise);
availability = PresentationAvailability::Create(GetOwner(), mUrls, aPromise);
} else {
PRES_DEBUG(">resolve with same object:id[%s]\n",
NS_ConvertUTF16toUTF8(mUrl).get());
PRES_DEBUG(">resolve with same object\n");
// Fetching cached available devices is asynchronous in our implementation,
// we need to ensure the promise is resolved in order.
@ -474,3 +486,15 @@ PresentationRequest::IsPrioriAuthenticatedURL(const nsAString& aUrl)
csm->IsOriginPotentiallyTrustworthy(principal, &isTrustworthyOrigin);
return isTrustworthyOrigin;
}
bool
PresentationRequest::IsAllURLAuthenticated()
{
for (const auto& url : mUrls) {
if (!IsPrioriAuthenticatedURL(url)) {
return false;
}
}
return true;
}

View File

@ -7,6 +7,7 @@
#ifndef mozilla_dom_PresentationRequest_h
#define mozilla_dom_PresentationRequest_h
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/DOMEventTargetHelper.h"
class nsIDocument;
@ -23,9 +24,15 @@ class PresentationRequest final : public DOMEventTargetHelper
public:
NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<PresentationRequest> Constructor(const GlobalObject& aGlobal,
const nsAString& aUrl,
ErrorResult& aRv);
static already_AddRefed<PresentationRequest> Constructor(
const GlobalObject& aGlobal,
const nsAString& aUrl,
ErrorResult& aRv);
static already_AddRefed<PresentationRequest> Constructor(
const GlobalObject& aGlobal,
const Sequence<nsString>& aUrls,
ErrorResult& aRv);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
@ -47,7 +54,7 @@ public:
private:
PresentationRequest(nsPIDOMWindowInner* aWindow,
const nsAString& aUrl);
nsTArray<nsString>&& aUrls);
~PresentationRequest();
@ -64,7 +71,9 @@ private:
// Implement https://w3c.github.io/webappsec-mixed-content/#a-priori-authenticated-url
bool IsPrioriAuthenticatedURL(const nsAString& aUrl);
nsString mUrl;
bool IsAllURLAuthenticated();
nsTArray<nsString> mUrls;
};
} // namespace dom

View File

@ -59,6 +59,44 @@ IsSameDevice(nsIPresentationDevice* aDevice, nsIPresentationDevice* aDeviceAnoth
return true;
}
static nsresult
ConvertURLArrayHelper(const nsTArray<nsString>& aUrls, nsIArray** aResult)
{
if (!aResult) {
return NS_ERROR_INVALID_POINTER;
}
*aResult = nullptr;
nsresult rv;
nsCOMPtr<nsIMutableArray> urls =
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
for (const auto& url : aUrls) {
nsCOMPtr<nsISupportsString> isupportsString =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = isupportsString->SetData(url);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = urls->AppendElement(isupportsString, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
urls.forget(aResult);
return NS_OK;
}
/*
* Implementation of PresentationDeviceRequest
*/
@ -69,7 +107,7 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPRESENTATIONDEVICEREQUEST
PresentationDeviceRequest(const nsAString& aRequestUrl,
PresentationDeviceRequest(const nsTArray<nsString>& aUrls,
const nsAString& aId,
const nsAString& aOrigin,
uint64_t aWindowId,
@ -77,9 +115,10 @@ public:
private:
virtual ~PresentationDeviceRequest() = default;
nsresult CreateSessionInfo(nsIPresentationDevice* aDevice);
nsresult CreateSessionInfo(nsIPresentationDevice* aDevice,
const nsAString& aSelectedRequestUrl);
nsString mRequestUrl;
nsTArray<nsString> mRequestUrls;
nsString mId;
nsString mOrigin;
uint64_t mWindowId;
@ -94,18 +133,18 @@ LazyLogModule gPresentationLog("Presentation");
NS_IMPL_ISUPPORTS(PresentationDeviceRequest, nsIPresentationDeviceRequest)
PresentationDeviceRequest::PresentationDeviceRequest(
const nsAString& aRequestUrl,
const nsTArray<nsString>& aUrls,
const nsAString& aId,
const nsAString& aOrigin,
uint64_t aWindowId,
nsIPresentationServiceCallback* aCallback)
: mRequestUrl(aRequestUrl)
: mRequestUrls(aUrls)
, mId(aId)
, mOrigin(aOrigin)
, mWindowId(aWindowId)
, mCallback(aCallback)
{
MOZ_ASSERT(!mRequestUrl.IsEmpty());
MOZ_ASSERT(!mRequestUrls.IsEmpty());
MOZ_ASSERT(!mId.IsEmpty());
MOZ_ASSERT(!mOrigin.IsEmpty());
MOZ_ASSERT(mCallback);
@ -119,29 +158,47 @@ PresentationDeviceRequest::GetOrigin(nsAString& aOrigin)
}
NS_IMETHODIMP
PresentationDeviceRequest::GetRequestURL(nsAString& aRequestUrl)
PresentationDeviceRequest::GetRequestURLs(nsIArray** aUrls)
{
aRequestUrl = mRequestUrl;
return NS_OK;
return ConvertURLArrayHelper(mRequestUrls, aUrls);
}
NS_IMETHODIMP
PresentationDeviceRequest::Select(nsIPresentationDevice* aDevice)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aDevice);
nsresult rv = CreateSessionInfo(aDevice);
if (NS_WARN_IF(NS_FAILED(rv))) {
mCallback->NotifyError(rv);
return rv;
if (NS_WARN_IF(!aDevice)) {
MOZ_ASSERT(false, "|aDevice| should noe be null.");
mCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
return NS_ERROR_INVALID_ARG;
}
return mCallback->NotifySuccess();
// Select the most suitable URL for starting the presentation.
nsAutoString selectedRequestUrl;
for (const auto& url : mRequestUrls) {
bool isSupported;
if (NS_SUCCEEDED(aDevice->IsRequestedUrlSupported(url, &isSupported)) &&
isSupported) {
selectedRequestUrl.Assign(url);
break;
}
}
if (selectedRequestUrl.IsEmpty()) {
return mCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
}
if (NS_WARN_IF(NS_FAILED(CreateSessionInfo(aDevice, selectedRequestUrl)))) {
return mCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
return mCallback->NotifySuccess(selectedRequestUrl);
}
nsresult
PresentationDeviceRequest::CreateSessionInfo(nsIPresentationDevice* aDevice)
PresentationDeviceRequest::CreateSessionInfo(
nsIPresentationDevice* aDevice,
const nsAString& aSelectedRequestUrl)
{
nsCOMPtr<nsIPresentationService> service =
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
@ -152,7 +209,7 @@ PresentationDeviceRequest::CreateSessionInfo(nsIPresentationDevice* aDevice)
// Create the controlling session info
RefPtr<PresentationSessionInfo> info =
static_cast<PresentationService*>(service.get())->
CreateControllingSessionInfo(mRequestUrl, mId, mWindowId);
CreateControllingSessionInfo(aSelectedRequestUrl, mId, mWindowId);
if (NS_WARN_IF(!info)) {
return NS_ERROR_NOT_AVAILABLE;
}
@ -572,23 +629,22 @@ PresentationService::IsAppInstalled(nsIURI* aUri)
}
NS_IMETHODIMP
PresentationService::StartSession(const nsAString& aUrl,
PresentationService::StartSession(const nsTArray<nsString>& aUrls,
const nsAString& aSessionId,
const nsAString& aOrigin,
const nsAString& aDeviceId,
uint64_t aWindowId,
nsIPresentationServiceCallback* aCallback)
{
PRES_DEBUG("%s:url[%s], id[%s]\n", __func__,
NS_ConvertUTF16toUTF8(aUrl).get(),
NS_ConvertUTF16toUTF8(aSessionId).get());
PRES_DEBUG("%s:id[%s]\n", __func__, NS_ConvertUTF16toUTF8(aSessionId).get());
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aCallback);
MOZ_ASSERT(!aSessionId.IsEmpty());
MOZ_ASSERT(!aUrls.IsEmpty());
nsCOMPtr<nsIPresentationDeviceRequest> request =
new PresentationDeviceRequest(aUrl,
new PresentationDeviceRequest(aUrls,
aSessionId,
aOrigin,
aWindowId,
@ -617,15 +673,11 @@ PresentationService::StartSession(const nsAString& aUrl,
return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
nsCOMPtr<nsIMutableArray> presentationUrls =
do_CreateInstance(NS_ARRAY_CONTRACTID);
if (!presentationUrls) {
nsCOMPtr<nsIArray> presentationUrls;
if (NS_WARN_IF(NS_FAILED(
ConvertURLArrayHelper(aUrls, getter_AddRefs(presentationUrls))))) {
return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
nsCOMPtr<nsISupportsString> supportsStr =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
supportsStr->SetData(aUrl);
presentationUrls->AppendElement(supportsStr, false);
nsCOMPtr<nsIArray> devices;
nsresult rv = deviceManager->GetAvailableDevices(presentationUrls, getter_AddRefs(devices));
@ -747,18 +799,17 @@ PresentationService::TerminateSession(const nsAString& aSessionId,
}
NS_IMETHODIMP
PresentationService::ReconnectSession(const nsAString& aUrl,
PresentationService::ReconnectSession(const nsTArray<nsString>& aUrls,
const nsAString& aSessionId,
uint8_t aRole,
nsIPresentationServiceCallback* aCallback)
{
PRES_DEBUG("%s:url[%s], id[%s]\n", __func__,
NS_ConvertUTF16toUTF8(aUrl).get(),
NS_ConvertUTF16toUTF8(aSessionId).get());
PRES_DEBUG("%s:id[%s]\n", __func__, NS_ConvertUTF16toUTF8(aSessionId).get());
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aSessionId.IsEmpty());
MOZ_ASSERT(aCallback);
MOZ_ASSERT(!aUrls.IsEmpty());
if (aRole != nsIPresentationService::ROLE_CONTROLLER) {
MOZ_ASSERT(false, "Only controller can call ReconnectSession.");
@ -774,7 +825,7 @@ PresentationService::ReconnectSession(const nsAString& aUrl,
return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
}
if (NS_WARN_IF(!info->GetUrl().Equals(aUrl))) {
if (NS_WARN_IF(!aUrls.Contains(info->GetUrl()))) {
return aCallback->NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
}

View File

@ -806,7 +806,7 @@ PresentationControllingInfo::NotifyReconnected()
return NS_ERROR_FAILURE;
}
return mReconnectCallback->NotifySuccess();
return mReconnectCallback->NotifySuccess(GetUrl());
}
nsresult

View File

@ -4,6 +4,7 @@
#include "nsISupports.idl"
interface nsIArray;
interface nsIPresentationDevice;
%{C++
@ -19,8 +20,8 @@ interface nsIPresentationDeviceRequest : nsISupports
// The origin which initiate the request.
readonly attribute DOMString origin;
// The URL to be opened after selection.
readonly attribute DOMString requestURL;
// The array of candidate URLs.
readonly attribute nsIArray requestURLs;
/*
* Callback after selecting a device

View File

@ -15,15 +15,23 @@ interface nsIPresentationSessionListener;
{ 0x9e, 0x4f, 0x40, 0x58, 0xb8, 0x51, 0x98, 0x32 } }
#define PRESENTATION_SERVICE_CONTRACTID \
"@mozilla.org/presentation/presentationservice;1"
#include "nsTArray.h"
class nsString;
%}
[ref] native URLArrayRef(const nsTArray<nsString>);
[scriptable, uuid(12073206-0065-4b10-9488-a6eb9b23e65b)]
interface nsIPresentationServiceCallback : nsISupports
{
/*
* Called when the operation succeeds.
*
* @param url: the selected request url used to start or reconnect a session.
*/
void notifySuccess();
void notifySuccess(in DOMString url);
/*
* Called when the operation fails.
@ -47,7 +55,7 @@ interface nsIPresentationService : nsISupports
* Start a new presentation session and display a prompt box which asks users
* to select a device.
*
* @param url: The url of presenting page.
* @param urls: The candidate Urls of presenting page. Only one url would be used.
* @param sessionId: An ID to identify presentation session.
* @param origin: The url of requesting page.
* @param deviceId: The specified device of handling this request, null string
@ -61,12 +69,12 @@ interface nsIPresentationService : nsISupports
* established successfully with the selected device.
* Otherwise, NotifyError() is called with a error message.
*/
void startSession(in DOMString url,
in DOMString sessionId,
in DOMString origin,
in DOMString deviceId,
in unsigned long long windowId,
in nsIPresentationServiceCallback callback);
[noscript] void startSession(in URLArrayRef urls,
in DOMString sessionId,
in DOMString origin,
in DOMString deviceId,
in unsigned long long windowId,
in nsIPresentationServiceCallback callback);
/*
* Send the message to the session.
@ -101,17 +109,17 @@ interface nsIPresentationService : nsISupports
/*
* Reconnect the session.
*
* @param url: The url of presenting page.
* @param url: The request Urls.
* @param sessionId: An ID to identify presentation session.
* @param role: Identify the function called by controller or receiver.
* @param callback: NotifySuccess() is called when a control channel
* is opened successfully.
* Otherwise, NotifyError() is called with a error message.
*/
void reconnectSession(in DOMString url,
in DOMString sessionId,
in uint8_t role,
in nsIPresentationServiceCallback callback);
[noscript] void reconnectSession(in URLArrayRef urls,
in DOMString sessionId,
in uint8_t role,
in nsIPresentationServiceCallback callback);
/*
* Register an availability listener. Must be called from the main thread.

View File

@ -15,7 +15,7 @@ namespace dom {
struct StartSessionRequest
{
nsString url;
nsString[] urls;
nsString sessionId;
nsString origin;
nsString deviceId;
@ -44,7 +44,7 @@ struct TerminateSessionRequest
struct ReconnectSessionRequest
{
nsString url;
nsString[] urls;
nsString sessionId;
uint8_t role;
};

View File

@ -15,6 +15,7 @@ sync protocol PPresentationRequest
child:
async __delete__(nsresult result);
async NotifyRequestUrlSelected(nsString aUrl);
};
} // namespace dom

View File

@ -163,12 +163,17 @@ PresentationRequestChild::Recv__delete__(const nsresult& aResult)
}
if (mCallback) {
if (NS_SUCCEEDED(aResult)) {
NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess()));
} else {
if (NS_FAILED(aResult)) {
NS_WARN_IF(NS_FAILED(mCallback->NotifyError(aResult)));
}
}
return true;
}
bool
PresentationRequestChild::RecvNotifyRequestUrlSelected(const nsString& aUrl)
{
NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess(aUrl)));
return true;
}

View File

@ -78,6 +78,9 @@ public:
virtual bool
Recv__delete__(const nsresult& aResult) override;
virtual bool
RecvNotifyRequestUrlSelected(const nsString& aUrl) override;
private:
virtual ~PresentationRequestChild();

View File

@ -52,7 +52,7 @@ PresentationIPCService::~PresentationIPCService()
}
NS_IMETHODIMP
PresentationIPCService::StartSession(const nsAString& aUrl,
PresentationIPCService::StartSession(const nsTArray<nsString>& aUrls,
const nsAString& aSessionId,
const nsAString& aOrigin,
const nsAString& aDeviceId,
@ -65,7 +65,7 @@ PresentationIPCService::StartSession(const nsAString& aUrl,
nsIPresentationService::ROLE_CONTROLLER);
}
return SendRequest(aCallback, StartSessionRequest(nsString(aUrl),
return SendRequest(aCallback, StartSessionRequest(aUrls,
nsString(aSessionId),
nsString(aOrigin),
nsString(aDeviceId),
@ -135,7 +135,7 @@ PresentationIPCService::TerminateSession(const nsAString& aSessionId,
}
NS_IMETHODIMP
PresentationIPCService::ReconnectSession(const nsAString& aUrl,
PresentationIPCService::ReconnectSession(const nsTArray<nsString>& aUrls,
const nsAString& aSessionId,
uint8_t aRole,
nsIPresentationServiceCallback* aCallback)
@ -147,7 +147,7 @@ PresentationIPCService::ReconnectSession(const nsAString& aUrl,
return NS_ERROR_INVALID_ARG;
}
return SendRequest(aCallback, ReconnectSessionRequest(nsString(aUrl),
return SendRequest(aCallback, ReconnectSessionRequest(aUrls,
nsString(aSessionId),
aRole));
}

View File

@ -6,6 +6,7 @@
#include "DCPresentationChannelDescription.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/Unused.h"
#include "nsIPresentationDeviceManager.h"
#include "nsServiceManagerUtils.h"
#include "PresentationBuilderParent.h"
@ -333,7 +334,7 @@ PresentationRequestParent::DoRequest(const StartSessionRequest& aRequest)
MOZ_ASSERT(mService);
mNeedRegisterBuilder = true;
mSessionId = aRequest.sessionId();
return mService->StartSession(aRequest.url(), aRequest.sessionId(),
return mService->StartSession(aRequest.urls(), aRequest.sessionId(),
aRequest.origin(), aRequest.deviceId(),
aRequest.windowId(), this);
}
@ -347,16 +348,16 @@ PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest)
// compromised child process can't fake the ID.
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
}
nsresult rv = mService->SendSessionMessage(aRequest.sessionId(),
aRequest.role(),
aRequest.data());
if (NS_WARN_IF(NS_FAILED(rv))) {
return NotifyError(rv);
return SendResponse(rv);
}
return NotifySuccess();
return SendResponse(NS_OK);
}
nsresult
@ -368,16 +369,16 @@ PresentationRequestParent::DoRequest(const CloseSessionRequest& aRequest)
// compromised child process can't fake the ID.
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
}
nsresult rv = mService->CloseSession(aRequest.sessionId(),
aRequest.role(),
aRequest.closedReason());
if (NS_WARN_IF(NS_FAILED(rv))) {
return NotifyError(rv);
return SendResponse(rv);
}
return NotifySuccess();
return SendResponse(NS_OK);
}
nsresult
@ -389,14 +390,14 @@ PresentationRequestParent::DoRequest(const TerminateSessionRequest& aRequest)
// compromised child process can't fake the ID.
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
}
nsresult rv = mService->TerminateSession(aRequest.sessionId(), aRequest.role());
if (NS_WARN_IF(NS_FAILED(rv))) {
return NotifyError(rv);
return SendResponse(rv);
}
return NotifySuccess();
return SendResponse(NS_OK);
}
nsresult
@ -411,12 +412,12 @@ PresentationRequestParent::DoRequest(const ReconnectSessionRequest& aRequest)
// NOTE: Return NS_ERROR_DOM_NOT_FOUND_ERR here to match the spec.
// https://w3c.github.io/presentation-api/#reconnecting-to-a-presentation
return NotifyError(NS_ERROR_DOM_NOT_FOUND_ERR);
return SendResponse(NS_ERROR_DOM_NOT_FOUND_ERR);
}
mNeedRegisterBuilder = true;
mSessionId = aRequest.sessionId();
return mService->ReconnectSession(aRequest.url(),
return mService->ReconnectSession(aRequest.urls(),
aRequest.sessionId(),
aRequest.role(),
this);
@ -431,18 +432,18 @@ PresentationRequestParent::DoRequest(const BuildTransportRequest& aRequest)
// compromised child process can't fake the ID.
if (NS_WARN_IF(!static_cast<PresentationService*>(mService.get())->
IsSessionAccessible(aRequest.sessionId(), aRequest.role(), OtherPid()))) {
return NotifyError(NS_ERROR_DOM_SECURITY_ERR);
return SendResponse(NS_ERROR_DOM_SECURITY_ERR);
}
nsresult rv = mService->BuildTransport(aRequest.sessionId(), aRequest.role());
if (NS_WARN_IF(NS_FAILED(rv))) {
return NotifyError(rv);
return SendResponse(rv);
}
return NotifySuccess();
return SendResponse(NS_OK);
}
NS_IMETHODIMP
PresentationRequestParent::NotifySuccess()
PresentationRequestParent::NotifySuccess(const nsAString& aUrl)
{
if (mNeedRegisterBuilder) {
RefPtr<PresentationParent> parent = static_cast<PresentationParent*>(Manager());
@ -451,6 +452,7 @@ PresentationRequestParent::NotifySuccess()
nsIPresentationService::ROLE_CONTROLLER));
}
Unused << SendNotifyRequestUrlSelected(nsString(aUrl));
return SendResponse(NS_OK);
}

View File

@ -238,6 +238,29 @@ function teardown() {
gScript.sendAsyncMessage('teardown');
}
function testConstructRequestError() {
return Promise.all([
new Promise(function(aResolve, aReject) {
try {
request = new PresentationRequest("\\\\\\");
}
catch(e) {
is(e.name, "SyntaxError", "Expect to get SyntaxError.");
aResolve();
}
}),
new Promise(function(aResolve, aReject) {
try {
request = new PresentationRequest([]);
}
catch(e) {
is(e.name, "NotSupportedError", "Expect to get NotSupportedError.");
aResolve();
}
}),
]);
}
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
@ -248,6 +271,7 @@ function runTests() {
then(testCloseConnection).
then(testReconnect).
then(testCloseConnection).
then(testConstructRequestError).
then(teardown);
}

View File

@ -41,17 +41,6 @@ function setup() {
});
}
function testCreateRequestWithEmptyURL() {
return new Promise(function(aResolve, aReject) {
try {
request = new PresentationRequest("");
} catch (aError) {
is(aError.name, "SyntaxError", "SyntaxError is expected when using an empty URL.");
aResolve();
}
});
}
function testStartConnectionCancelPrompt() {
return new Promise(function(aResolve, aReject) {
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
@ -380,8 +369,7 @@ function teardown() {
function runTests() {
ok(window.PresentationRequest, "PresentationRequest should be available.");
testCreateRequestWithEmptyURL().
then(setup).
setup().
then(testStartConnectionCancelPrompt).
then(testStartConnectionNoDevice).
then(testStartConnectionUnexpectedControlChannelCloseBeforeDataTransportInit).

View File

@ -5,6 +5,7 @@
*/
[Constructor(DOMString url),
Constructor(sequence<DOMString> urls),
Pref="dom.presentation.controller.enabled"]
interface PresentationRequest : EventTarget {
/*

View File

@ -481,28 +481,28 @@ CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName,
nsAutoPrinter autoPrinter(hPrinter);
// Get the buffer size
DWORD dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr,
nullptr, 0);
if (dwNeeded == 0) {
LONG needed = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr,
nullptr, 0);
if (needed < 0) {
return nsReturnRef<nsHGLOBAL>();
}
// Allocate a buffer of the correct size.
nsAutoDevMode newDevMode((LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
dwNeeded));
needed));
if (!newDevMode) {
return nsReturnRef<nsHGLOBAL>();
}
nsHGLOBAL hDevMode = ::GlobalAlloc(GHND, dwNeeded);
nsHGLOBAL hDevMode = ::GlobalAlloc(GHND, needed);
nsAutoGlobalMem globalDevMode(hDevMode);
if (!hDevMode) {
return nsReturnRef<nsHGLOBAL>();
}
DWORD dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, newDevMode,
nullptr, DM_OUT_BUFFER);
if (dwRet != IDOK) {
LONG ret = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, newDevMode,
nullptr, DM_OUT_BUFFER);
if (ret != IDOK) {
return nsReturnRef<nsHGLOBAL>();
}
@ -513,16 +513,16 @@ CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName,
return nsReturnRef<nsHGLOBAL>();
}
memcpy(devMode, newDevMode.get(), dwNeeded);
memcpy(devMode, newDevMode.get(), needed);
// Initialize values from the PrintSettings
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
MOZ_ASSERT(psWin);
psWin->CopyToNative(devMode);
// Sets back the changes we made to the DevMode into the Printer Driver
dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode,
DM_IN_BUFFER | DM_OUT_BUFFER);
if (dwRet != IDOK) {
ret = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode,
DM_IN_BUFFER | DM_OUT_BUFFER);
if (ret != IDOK) {
::GlobalUnlock(hDevMode);
return nsReturnRef<nsHGLOBAL>();
}

View File

@ -1016,7 +1016,12 @@ gfxFontUtils::RenameFont(const nsAString& aName, const uint8_t *aFontData,
uint16_t nameCount = ArrayLength(neededNameIDs);
// leave room for null-terminator
uint16_t nameStrLength = (aName.Length() + 1) * sizeof(char16_t);
uint32_t nameStrLength = (aName.Length() + 1) * sizeof(char16_t);
if (nameStrLength > 65535) {
// The name length _in bytes_ must fit in an unsigned short field;
// therefore, a name longer than this cannot be used.
return NS_ERROR_FAILURE;
}
// round name table size up to 4-byte multiple
uint32_t nameTableSize = (sizeof(NameHeader) +

View File

@ -2515,17 +2515,18 @@ gfxPlatform::InitOpenGLConfig()
openGLFeature.EnableByDefault();
#endif
// When layers acceleration is force-enabled, enable it even for blacklisted
// devices.
if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
openGLFeature.UserForceEnable("Force-enabled by pref");
return;
}
nsCString message;
nsCString failureId;
if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &message, failureId)) {
openGLFeature.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
}
// Ensure that an accelerated compositor backend is available when layers
// acceleration is force-enabled.
if (gfxPrefs::LayersAccelerationForceEnabledDoNotUseDirectly()) {
openGLFeature.UserForceEnable("Force-enabled by pref");
}
}
bool

View File

@ -111,10 +111,19 @@ typedef enum nsCharType nsCharType;
* Return false, otherwise
*/
#define LRM_CHAR 0x200e
#define RLM_CHAR 0x200f
#define LRE_CHAR 0x202a
#define RLE_CHAR 0x202b
#define PDF_CHAR 0x202c
#define LRO_CHAR 0x202d
#define RLO_CHAR 0x202e
#define LRI_CHAR 0x2066
#define RLI_CHAR 0x2067
#define FSI_CHAR 0x2068
#define PDI_CHAR 0x2069
#define ALM_CHAR 0x061C
inline bool IsBidiControl(uint32_t aChar) {
return ((LRE_CHAR <= aChar && aChar <= RLO_CHAR) ||
@ -123,6 +132,20 @@ typedef enum nsCharType nsCharType;
(aChar & 0xfffffe) == LRM_CHAR);
}
/**
* Give a UTF-32 codepoint
* Return true if the codepoint is a Bidi control character that may result
* in RTL directionality and therefore needs to trigger bidi resolution;
* return false otherwise.
*/
inline bool IsBidiControlRTL(uint32_t aChar) {
return aChar == RLM_CHAR ||
aChar == RLE_CHAR ||
aChar == RLO_CHAR ||
aChar == RLI_CHAR ||
aChar == ALM_CHAR;
}
/**
* Give an nsString.
* @return true if the string contains right-to-left characters

View File

@ -54,24 +54,6 @@ namespace {
static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
class XPCShellDirProvider : public nsIDirectoryServiceProvider
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDIRECTORYSERVICEPROVIDER
XPCShellDirProvider() { }
~XPCShellDirProvider() { }
bool SetGREDirs(const char *dir);
void ClearGREDirs() { mGREDir = nullptr;
mGREBinDir = nullptr; }
private:
nsCOMPtr<nsIFile> mGREDir;
nsCOMPtr<nsIFile> mGREBinDir;
};
inline XPCShellEnvironment*
Environment(Handle<JSObject*> global)
{
@ -389,51 +371,6 @@ XPCShellEnvironment::ProcessFile(JSContext *cx,
fprintf(stdout, "\n");
}
NS_IMETHODIMP_(MozExternalRefCountType)
XPCShellDirProvider::AddRef()
{
return 2;
}
NS_IMETHODIMP_(MozExternalRefCountType)
XPCShellDirProvider::Release()
{
return 1;
}
NS_IMPL_QUERY_INTERFACE(XPCShellDirProvider, nsIDirectoryServiceProvider)
bool
XPCShellDirProvider::SetGREDirs(const char *dir)
{
nsresult rv = XRE_GetFileFromPath(dir, getter_AddRefs(mGREDir));
if (NS_SUCCEEDED(rv)) {
mGREDir->Clone(getter_AddRefs(mGREBinDir));
#ifdef XP_MACOSX
mGREBinDir->SetNativeLeafName(NS_LITERAL_CSTRING("MacOS"));
#endif
}
return NS_SUCCEEDED(rv);
}
NS_IMETHODIMP
XPCShellDirProvider::GetFile(const char *prop,
bool *persistent,
nsIFile* *result)
{
if (mGREDir && !strcmp(prop, NS_GRE_DIR)) {
*persistent = true;
NS_ADDREF(*result = mGREDir);
return NS_OK;
} else if (mGREBinDir && !strcmp(prop, NS_GRE_BIN_DIR)) {
*persistent = true;
NS_ADDREF(*result = mGREBinDir);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
// static
XPCShellEnvironment*
XPCShellEnvironment::CreateEnvironment()

View File

@ -169,9 +169,13 @@ FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue v
RootedValue value(cx, value_);
mozilla::Maybe<AutoCompartment> ac;
if (!IsWrapper(promiseObj)) {
if (!IsProxy(promiseObj)) {
promise = &promiseObj->as<PromiseObject>();
} else {
if (JS_IsDeadWrapper(promiseObj)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
ac.emplace(cx, promise);
if (!promise->compartment()->wrap(cx, &value))
@ -190,9 +194,13 @@ RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue re
RootedValue reason(cx, reason_);
mozilla::Maybe<AutoCompartment> ac;
if (!IsWrapper(promiseObj)) {
if (!IsProxy(promiseObj)) {
promise = &promiseObj->as<PromiseObject>();
} else {
if (JS_IsDeadWrapper(promiseObj)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
return false;
}
promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
ac.emplace(cx, promise);

View File

@ -4559,12 +4559,6 @@ Parser<SyntaxParseHandler>::importDeclaration()
return SyntaxParseHandler::NodeFailure;
}
template <>
ParseNode*
Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
ClassContext classContext,
DefaultHandling defaultHandling);
template<>
bool
Parser<FullParseHandler>::checkExportedName(JSAtom* exportName)
@ -6191,11 +6185,11 @@ GeneratorKindFromPropertyType(PropertyType propType)
return propType == PropertyType::GeneratorMethod ? StarGenerator : NotGenerator;
}
template <>
ParseNode*
Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
ClassContext classContext,
DefaultHandling defaultHandling)
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
ClassContext classContext,
DefaultHandling defaultHandling)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS));
@ -6250,7 +6244,7 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
// in order to provide it for the nodes created later.
TokenPos namePos = pos();
ParseNode* classHeritage = null();
Node classHeritage = null();
bool hasHeritage;
if (!tokenStream.matchToken(&hasHeritage, TOK_EXTENDS))
return null();
@ -6264,7 +6258,7 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CLASS);
ParseNode* classMethods = handler.newClassMethodList(pos().begin);
Node classMethods = handler.newClassMethodList(pos().begin);
if (!classMethods)
return null();
@ -6304,7 +6298,7 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
}
PropertyType propType;
ParseNode* propName = propertyName(yieldHandling, classMethods, &propType, &propAtom);
Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom);
if (!propName)
return null();
@ -6356,7 +6350,7 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
if (!tokenStream.isCurrentTokenType(TOK_RB))
funName = propAtom;
}
ParseNode* fn = methodDefinition(yieldHandling, propType, funName);
Node fn = methodDefinition(yieldHandling, propType, funName);
if (!fn)
return null();
@ -6365,18 +6359,18 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
return null();
}
ParseNode* nameNode = null();
ParseNode* methodsOrBlock = classMethods;
Node nameNode = null();
Node methodsOrBlock = classMethods;
if (name) {
// The inner name is immutable.
if (!noteDeclaredName(name, DeclarationKind::Const, namePos))
return null();
ParseNode* innerName = newName(name, namePos);
Node innerName = newName(name, namePos);
if (!innerName)
return null();
ParseNode* classBlock = finishLexicalScope(*classScope, classMethods);
Node classBlock = finishLexicalScope(*classScope, classMethods);
if (!classBlock)
return null();
@ -6386,7 +6380,7 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
classScope.reset();
classStmt.reset();
ParseNode* outerName = null();
Node outerName = null();
if (classContext == ClassStatement) {
// The outer name is mutable.
if (!noteDeclaredName(name, DeclarationKind::Let, namePos))
@ -6407,16 +6401,6 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
return handler.newClass(nameNode, classHeritage, methodsOrBlock);
}
template <>
SyntaxParseHandler::Node
Parser<SyntaxParseHandler>::classDefinition(YieldHandling yieldHandling,
ClassContext classContext,
DefaultHandling defaultHandling)
{
MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
return SyntaxParseHandler::NodeFailure;
}
template <class ParseHandler>
bool
Parser<ParseHandler>::nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling)
@ -6851,8 +6835,6 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
// ClassDeclaration[?Yield, ~Default]
case TOK_CLASS:
if (!abortIfSyntaxParser())
return null();
return classDefinition(yieldHandling, ClassStatement, NameRequired);
// LexicalDeclaration[In, ?Yield]

View File

@ -262,6 +262,8 @@ class SyntaxParseHandler
Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
Node newClassMethodList(uint32_t begin) { return NodeGeneric; }
Node newClassNames(Node outer, Node inner, const TokenPos& pos) { return NodeGeneric; }
Node newClass(Node name, Node heritage, Node methodBlock) { return NodeGeneric; }
Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; }
Node newPosHolder(const TokenPos& pos) { return NodeGeneric; }

View File

@ -0,0 +1,39 @@
/* 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/. */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=1298597 */
function run_test()
{
var sb = Components.utils.Sandbox("http://www.blah.com");
var resolveFun;
var p1 = new sb.Promise((res, rej) => {resolveFun = res});
var rejectFun;
var p2 = new sb.Promise((res, rej) => {rejectFun = rej});
Components.utils.nukeSandbox(sb);
do_check_true(Components.utils.isDeadWrapper(sb), "sb should be dead");
do_check_true(Components.utils.isDeadWrapper(p1), "p1 should be dead");
do_check_true(Components.utils.isDeadWrapper(p2), "p2 should be dead");
var exception;
try{
resolveFun(1);
do_check_true(false);
} catch (e) {
exception = e;
}
do_check_true(exception.toString().includes("can't access dead object"),
"Resolving dead wrapped promise should throw");
exception = undefined;
try{
rejectFun(1);
do_check_true(false);
} catch (e) {
exception = e;
}
do_check_true(exception.toString().includes("can't access dead object"),
"Rejecting dead wrapped promise should throw");
}

View File

@ -133,3 +133,4 @@ head = head_watchdog.js
[test_xrayed_iterator.js]
[test_xray_SavedFrame.js]
[test_xray_SavedFrame-02.js]
[test_resolve_dead_promise.js]

View File

@ -46,17 +46,12 @@ PresentationDevicePrompt.prototype = {
return this.bundle.GetStringFromName(aName);
},
_loadDevices: function(requestURL) {
_loadDevices: function(requestURLs) {
debug("_loadDevices");
let presentationUrls = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
let url = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
url.data = requestURL;
presentationUrls.appendElement(url, false);
let deviceManager = Cc["@mozilla.org/presentation-device/manager;1"]
.getService(Ci.nsIPresentationDeviceManager);
let devices = deviceManager.getAvailableDevices(presentationUrls).QueryInterface(Ci.nsIArray);
let devices = deviceManager.getAvailableDevices(requestURLs).QueryInterface(Ci.nsIArray);
// Re-load the available devices
this._devices = [];
@ -118,7 +113,7 @@ PresentationDevicePrompt.prototype = {
debug("promptDeviceSelection");
// Load available presentation devices into this._devices
this._loadDevices(aRequest.requestURL);
this._loadDevices(aRequest.requestURLs);
if (!this._devices.length) { // Cancel request if no available device
aRequest.cancel(Cr.NS_ERROR_DOM_NOT_FOUND_ERR);

View File

@ -284,9 +284,7 @@ NetAddrElement::~NetAddrElement()
AddrInfo::AddrInfo(const char *host, const PRAddrInfo *prAddrInfo,
bool disableIPv4, bool filterNameCollision, const char *cname)
: mHostName(nullptr)
, mCanonicalName(nullptr)
, ttl(NO_TTL_DATA)
: ttl(NO_TTL_DATA)
{
MOZ_ASSERT(prAddrInfo, "Cannot construct AddrInfo with a null prAddrInfo pointer!");
const uint32_t nameCollisionAddr = htonl(0x7f003535); // 127.0.53.53
@ -307,9 +305,7 @@ AddrInfo::AddrInfo(const char *host, const PRAddrInfo *prAddrInfo,
}
AddrInfo::AddrInfo(const char *host, const char *cname)
: mHostName(nullptr)
, mCanonicalName(nullptr)
, ttl(NO_TTL_DATA)
: ttl(NO_TTL_DATA)
{
Init(host, cname);
}
@ -320,8 +316,6 @@ AddrInfo::~AddrInfo()
while ((addrElement = mAddresses.popLast())) {
delete addrElement;
}
free(mHostName);
free(mCanonicalName);
}
void
@ -331,15 +325,13 @@ AddrInfo::Init(const char *host, const char *cname)
ttl = NO_TTL_DATA;
size_t hostlen = strlen(host);
mHostName = static_cast<char*>(moz_xmalloc(hostlen + 1));
memcpy(mHostName, host, hostlen + 1);
mHostName = mozilla::MakeUnique<char[]>(hostlen + 1);
memcpy(mHostName.get(), host, hostlen + 1);
if (cname) {
size_t cnameLen = strlen(cname);
mCanonicalName = static_cast<char*>(moz_xmalloc(cnameLen + 1));
memcpy(mCanonicalName, cname, cnameLen + 1);
}
else {
mCanonicalName = nullptr;
mCanonicalName = mozilla::MakeUnique<char[]>(cnameLen + 1);
memcpy(mCanonicalName.get(), cname, cnameLen + 1);
}
}
@ -355,8 +347,8 @@ size_t
AddrInfo::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
{
size_t n = mallocSizeOf(this);
n += mallocSizeOf(mHostName);
n += mallocSizeOf(mCanonicalName);
n += mallocSizeOf(mHostName.get());
n += mallocSizeOf(mCanonicalName.get());
n += mAddresses.sizeOfExcludingThis(mallocSizeOf);
return n;
}

View File

@ -13,6 +13,7 @@
#include "plstr.h"
#include "mozilla/LinkedList.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/UniquePtr.h"
#if !defined(XP_WIN)
#include <arpa/inet.h>
@ -141,8 +142,8 @@ public:
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
char *mHostName;
char *mCanonicalName;
UniquePtr<char[]> mHostName;
UniquePtr<char[]> mCanonicalName;
uint16_t ttl;
static const uint16_t NO_TTL_DATA = (uint16_t) -1;

View File

@ -345,7 +345,7 @@ GetAddrInfo(const char* aHost, uint16_t aAddressFamily, uint16_t aFlags,
// we have.
const char *name = nullptr;
if (*aAddrInfo != nullptr && (*aAddrInfo)->mCanonicalName) {
name = (*aAddrInfo)->mCanonicalName;
name = (*aAddrInfo)->mCanonicalName.get();
} else {
name = aHost;
}

View File

@ -93,9 +93,9 @@ nsDNSRecord::GetCanonicalName(nsACString &result)
{
MutexAutoLock lock(mHostRecord->addr_info_lock);
if (mHostRecord->addr_info)
cname = mHostRecord->addr_info->mCanonicalName ?
mHostRecord->addr_info->mCanonicalName :
mHostRecord->addr_info->mHostName;
cname = !mHostRecord->addr_info->mCanonicalName.get() ?
mHostRecord->addr_info->mCanonicalName.get() :
mHostRecord->addr_info->mHostName.get();
else
cname = mHostRecord->host;
result.Assign(cname);
@ -156,7 +156,7 @@ nsDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr)
// attempt to reresolve it failed.
return NS_ERROR_NOT_AVAILABLE;
}
memcpy(addr, mHostRecord->addr, sizeof(NetAddr));
memcpy(addr, mHostRecord->addr.get(), sizeof(NetAddr));
mDone = true;
}
@ -201,7 +201,7 @@ nsDNSRecord::GetAddresses(nsTArray<NetAddr> & aAddressArray)
return NS_ERROR_NOT_AVAILABLE;
}
NetAddr *addr = aAddressArray.AppendElement(NetAddr());
memcpy(addr, mHostRecord->addr, sizeof(NetAddr));
memcpy(addr, mHostRecord->addr.get(), sizeof(NetAddr));
if (addr->raw.family == AF_INET) {
addr->inet.port = 0;
} else if (addr->raw.family == AF_INET6) {

View File

@ -164,8 +164,6 @@ IsLowPriority(uint16_t flags)
nsHostRecord::nsHostRecord(const nsHostKey *key)
: addr_info_lock("nsHostRecord.addr_info_lock")
, addr_info_gencnt(0)
, addr_info(nullptr)
, addr(nullptr)
, negative(false)
, resolving(false)
, onQueue(false)
@ -226,8 +224,6 @@ nsHostRecord::CopyExpirationTimesAndFlagsFrom(const nsHostRecord *aFromHostRecor
nsHostRecord::~nsHostRecord()
{
Telemetry::Accumulate(Telemetry::DNS_BLACKLIST_COUNT, mBlacklistedCount);
delete addr_info;
delete addr;
}
bool
@ -317,7 +313,7 @@ nsHostRecord::HasUsableResult(const mozilla::TimeStamp& now, uint16_t queryFlags
return false;
}
return addr_info || addr || negative;
return addr_info.get() || addr.get() || negative;
}
static size_t
@ -347,7 +343,7 @@ nsHostRecord::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
n += SizeOfResolveHostCallbackListExcludingHead(&callbacks, mallocSizeOf);
n += addr_info ? addr_info->SizeOfIncludingThis(mallocSizeOf) : 0;
n += mallocSizeOf(addr);
n += mallocSizeOf(addr.get());
n += mBlacklistedItems.ShallowSizeOfExcludingThis(mallocSizeOf);
for (size_t i = 0; i < mBlacklistedItems.Length(); i++) {
@ -807,8 +803,8 @@ nsHostResolver::ResolveHost(const char *host,
LOG((" Host is IP Literal [%s].\n", host));
// ok, just copy the result into the host record, and be done
// with it! ;-)
he->rec->addr = new NetAddr();
PRNetAddrToNetAddr(&tempAddr, he->rec->addr);
he->rec->addr.reset(new NetAddr());
PRNetAddrToNetAddr(&tempAddr, he->rec->addr.get());
// put reference to host record on stack...
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_LITERAL);
@ -870,9 +866,9 @@ nsHostResolver::ResolveHost(const char *host,
if ((af == addrIter->mAddress.inet.family) &&
!unspecHe->rec->Blacklisted(&addrIter->mAddress)) {
if (!he->rec->addr_info) {
he->rec->addr_info = new AddrInfo(
unspecHe->rec->addr_info->mHostName,
unspecHe->rec->addr_info->mCanonicalName);
he->rec->addr_info.reset(new AddrInfo(
unspecHe->rec->addr_info->mHostName.get(),
unspecHe->rec->addr_info->mCanonicalName.get()));
he->rec->CopyExpirationTimesAndFlagsFrom(unspecHe->rec);
}
he->rec->addr_info->AddAddress(
@ -1222,7 +1218,7 @@ different_rrset(AddrInfo *rrset1, AddrInfo *rrset2)
return true;
}
LOG(("different_rrset %s\n", rrset1->mHostName));
LOG(("different_rrset %s\n", rrset1->mHostName.get()));
nsTArray<NetAddr> orderedSet1;
nsTArray<NetAddr> orderedSet2;
@ -1289,27 +1285,24 @@ nsHostResolver::OnLookupComplete(nsHostRecord* rec, nsresult status, AddrInfo* n
// update record fields. We might have a rec->addr_info already if a
// previous lookup result expired and we're reresolving it..
AddrInfo *old_addr_info;
{
MutexAutoLock lock(rec->addr_info_lock);
if (different_rrset(rec->addr_info, newRRSet)) {
if (different_rrset(rec->addr_info.get(), newRRSet)) {
LOG(("nsHostResolver record %p new gencnt\n", rec));
old_addr_info = rec->addr_info;
rec->addr_info = newRRSet;
rec->addr_info.reset(newRRSet);
rec->addr_info_gencnt++;
} else {
if (rec->addr_info && newRRSet) {
rec->addr_info->ttl = newRRSet->ttl;
}
old_addr_info = newRRSet;
delete newRRSet;
}
}
delete old_addr_info;
rec->negative = !rec->addr_info;
PrepareRecordExpiration(rec);
rec->resolving = false;
if (rec->usingAnyThread) {
mActiveAnyThreadCount--;
rec->usingAnyThread = false;

View File

@ -21,6 +21,7 @@
#include "mozilla/net/DNS.h"
#include "mozilla/net/DashboardTypes.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
class nsHostResolver;
class nsHostRecord;
@ -73,8 +74,8 @@ public:
*/
Mutex addr_info_lock;
int addr_info_gencnt; /* generation count of |addr_info| */
mozilla::net::AddrInfo *addr_info;
mozilla::net::NetAddr *addr;
mozilla::UniquePtr<mozilla::net::AddrInfo> addr_info;
mozilla::UniquePtr<mozilla::net::NetAddr> addr;
bool negative; /* True if this record is a cache of a failed lookup.
Negative cache entries are valid just like any other
(though never for more than 60 seconds), but a use

View File

@ -139,34 +139,6 @@ nsNSSCertTrust::SetValidCA()
false, false);
}
void
nsNSSCertTrust::SetTrustedServerCA()
{
SetSSLTrust(false, false,
true, true, false,
false, false);
SetEmailTrust(false, false,
true, true, false,
false, false);
SetObjSignTrust(false, false,
true, true, false,
false, false);
}
void
nsNSSCertTrust::SetTrustedCA()
{
SetSSLTrust(false, false,
true, true, true,
false, false);
SetEmailTrust(false, false,
true, true, true,
false, false);
SetObjSignTrust(false, false,
true, true, true,
false, false);
}
void
nsNSSCertTrust::SetValidPeer()
{
@ -181,34 +153,6 @@ nsNSSCertTrust::SetValidPeer()
false, false);
}
void
nsNSSCertTrust::SetTrustedPeer()
{
SetSSLTrust(true, true,
false, false, false,
false, false);
SetEmailTrust(true, true,
false, false, false,
false, false);
SetObjSignTrust(true, true,
false, false, false,
false, false);
}
void
nsNSSCertTrust::SetUser()
{
SetSSLTrust(false, false,
false, false, false,
true, false);
SetEmailTrust(false, false,
false, false, false,
true, false);
SetObjSignTrust(false, false,
false, false, false,
true, false);
}
bool
nsNSSCertTrust::HasAnyCA()
{
@ -219,20 +163,6 @@ nsNSSCertTrust::HasAnyCA()
return false;
}
bool
nsNSSCertTrust::HasCA(bool checkSSL,
bool checkEmail,
bool checkObjSign)
{
if (checkSSL && !hasTrust(mTrust.sslFlags, CERTDB_VALID_CA))
return false;
if (checkEmail && !hasTrust(mTrust.emailFlags, CERTDB_VALID_CA))
return false;
if (checkObjSign && !hasTrust(mTrust.objectSigningFlags, CERTDB_VALID_CA))
return false;
return true;
}
bool
nsNSSCertTrust::HasPeer(bool checkSSL,
bool checkEmail,
@ -257,20 +187,6 @@ nsNSSCertTrust::HasAnyUser()
return false;
}
bool
nsNSSCertTrust::HasUser(bool checkSSL,
bool checkEmail,
bool checkObjSign)
{
if (checkSSL && !hasTrust(mTrust.sslFlags, CERTDB_USER))
return false;
if (checkEmail && !hasTrust(mTrust.emailFlags, CERTDB_USER))
return false;
if (checkObjSign && !hasTrust(mTrust.objectSigningFlags, CERTDB_USER))
return false;
return true;
}
bool
nsNSSCertTrust::HasTrustedCA(bool checkSSL,
bool checkEmail,
@ -315,4 +231,3 @@ nsNSSCertTrust::hasTrust(unsigned int t, unsigned int v)
{
return !!(t & v);
}

View File

@ -2,15 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _NSNSSCERTTRUST_H_
#define _NSNSSCERTTRUST_H_
#ifndef nsNSSCertTrust_h
#define nsNSSCertTrust_h
#include "certt.h"
#include "certdb.h"
#include "certt.h"
/*
* nsNSSCertTrust
*
* Class for maintaining trust flags for an NSS certificate.
*/
class nsNSSCertTrust
@ -24,15 +22,9 @@ public:
/* query */
bool HasAnyCA();
bool HasAnyUser();
bool HasCA(bool checkSSL = true,
bool checkEmail = true,
bool checkObjSign = true);
bool HasPeer(bool checkSSL = true,
bool checkEmail = true,
bool checkObjSign = true);
bool HasUser(bool checkSSL = true,
bool checkEmail = true,
bool checkObjSign = true);
bool HasTrustedCA(bool checkSSL = true,
bool checkEmail = true,
bool checkObjSign = true);
@ -43,16 +35,8 @@ public:
/* common defaults */
/* equivalent to "c,c,c" */
void SetValidCA();
/* equivalent to "C,C,C" */
void SetTrustedServerCA();
/* equivalent to "CT,CT,CT" */
void SetTrustedCA();
/* equivalent to "p,p,p" */
void SetValidPeer();
/* equivalent to "P,P,P" */
void SetTrustedPeer();
/* equivalent to "u,u,u" */
void SetUser();
/* general setters */
/* read: "p, P, c, C, T, u, w" */
@ -83,4 +67,4 @@ private:
CERTCertTrust mTrust;
};
#endif
#endif // nsNSSCertTrust_h

View File

@ -333,7 +333,9 @@ this.FxAccountsWebChannelHelpers.prototype = {
// features (ie, new fields) - forcing the server to track a map of
// versions to supported field names doesn't buy us much.
// So we just remove field names we know aren't handled.
let newCredentials = {};
let newCredentials = {
deviceId: null
};
for (let name of Object.keys(credentials)) {
if (name == "email" || name == "uid" || FxAccountsStorageManagerCanStoreField(name)) {
newCredentials[name] = credentials[name];

View File

@ -414,6 +414,8 @@ add_task(function* test_helpers_change_password() {
do_check_true(credentials.hasOwnProperty("email"));
do_check_true(credentials.hasOwnProperty("uid"));
do_check_true(credentials.hasOwnProperty("kA"));
do_check_true(credentials.hasOwnProperty("deviceId"));
do_check_null(credentials.deviceId);
// "foo" isn't a field known by storage, so should be dropped.
do_check_false(credentials.hasOwnProperty("foo"));
wasCalled.updateUserAccountData = true;

View File

@ -66,6 +66,7 @@ enum VersionComparisonOp {
DRIVER_LESS_THAN, // driver < version
DRIVER_BUILD_ID_LESS_THAN, // driver build id < version
DRIVER_LESS_THAN_OR_EQUAL, // driver <= version
DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL, // driver build id <= version
DRIVER_GREATER_THAN, // driver > version
DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version
DRIVER_EQUAL, // driver == version

View File

@ -375,8 +375,12 @@ BlacklistComparatorToComparisonOp(const nsAString& op)
{
if (op.EqualsLiteral("LESS_THAN"))
return DRIVER_LESS_THAN;
else if (op.EqualsLiteral("BUILD_ID_LESS_THAN"))
return DRIVER_BUILD_ID_LESS_THAN;
else if (op.EqualsLiteral("LESS_THAN_OR_EQUAL"))
return DRIVER_LESS_THAN_OR_EQUAL;
else if (op.EqualsLiteral("BUILD_ID_LESS_THAN_OR_EQUAL"))
return DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL;
else if (op.EqualsLiteral("GREATER_THAN"))
return DRIVER_GREATER_THAN;
else if (op.EqualsLiteral("GREATER_THAN_OR_EQUAL"))
@ -740,6 +744,9 @@ GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& info,
case DRIVER_LESS_THAN_OR_EQUAL:
match = driverVersion <= info[i].mDriverVersion;
break;
case DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL:
match = (driverVersion & 0xFFFF) <= info[i].mDriverVersion;
break;
case DRIVER_GREATER_THAN:
match = driverVersion > info[i].mDriverVersion;
break;

View File

@ -1067,7 +1067,7 @@ GfxInfo::GetGfxDriverInfo()
APPEND_TO_DRIVER_BLOCKLIST(OperatingSystem::Windows,
(nsAString&) GfxDriverInfo::GetDeviceVendor(VendorIntel), (GfxDeviceFamily*) GfxDriverInfo::GetDeviceFamily(IntelHD3000),
GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
DRIVER_LESS_THAN_OR_EQUAL, V(8,15,10,2321), "FEATURE_FAILURE_BUG_1018278", "8.15.10.2342");
DRIVER_BUILD_ID_LESS_THAN_OR_EQUAL, 2321, "FEATURE_FAILURE_BUG_1018278", "X.X.X.2342");
/* Disable D2D on Win7 on Intel HD Graphics on driver <= 8.15.10.2302
* See bug 806786

View File

@ -13,15 +13,12 @@
#include <winspool.h>
#include <tchar.h>
#include "nsIWidget.h"
#include "nsTArray.h"
#include "nsIPrintSettingsWin.h"
#include "nsString.h"
#include "nsCRT.h"
#include "nsIServiceManager.h"
#include "nsReadableUtils.h"
#include "nsStringEnumerator.h"
@ -34,15 +31,6 @@
#include "mozilla/Services.h"
#include "nsWindowsHelpers.h"
// For NS_CopyNativeToUnicode
#include "nsNativeCharsetUtils.h"
// File Picker
#include "nsIFile.h"
#include "nsIFilePicker.h"
#include "nsIStringBundle.h"
#define NS_ERROR_GFX_PRINTER_BUNDLE_URL "chrome://global/locale/printing.properties"
#include "mozilla/gfx/Logging.h"
#include "mozilla/Logging.h"
@ -342,42 +330,50 @@ nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings*
NS_ENSURE_SUCCESS(rv, rv);
}
HANDLE hPrinter = nullptr;
nsHPRINTER hPrinter = nullptr;
wchar_t *name = (wchar_t*)aName; // Windows APIs use non-const name argument
BOOL status = ::OpenPrinterW(name, &hPrinter, nullptr);
if (status) {
nsAutoPrinter autoPrinter(hPrinter);
LPDEVMODEW pDevMode;
DWORD dwNeeded, dwRet;
// Allocate a buffer of the correct size.
dwNeeded = ::DocumentPropertiesW(nullptr, hPrinter, name, nullptr, nullptr, 0);
LONG needed = ::DocumentPropertiesW(nullptr, hPrinter, name, nullptr,
nullptr, 0);
if (needed < 0) {
PR_PL(("**** nsDeviceContextSpecWin::GetDataFromPrinter - Couldn't get "
"size of DEVMODE using DocumentPropertiesW(pDeviceName = \"%s\"). "
"GetLastEror() = %08x\n",
aName ? NS_ConvertUTF16toUTF8(aName).get() : "", GetLastError()));
return NS_ERROR_FAILURE;
}
pDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
pDevMode = (LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
needed);
if (!pDevMode) return NS_ERROR_FAILURE;
// Get the default DevMode for the printer and modify it for our needs.
dwRet = DocumentPropertiesW(nullptr, hPrinter, name,
pDevMode, nullptr, DM_OUT_BUFFER);
LONG ret = ::DocumentPropertiesW(nullptr, hPrinter, name,
pDevMode, nullptr, DM_OUT_BUFFER);
if (dwRet == IDOK && aPS) {
if (ret == IDOK && aPS) {
nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
MOZ_ASSERT(psWin);
psWin->CopyToNative(pDevMode);
// Sets back the changes we made to the DevMode into the Printer Driver
dwRet = ::DocumentPropertiesW(nullptr, hPrinter, name,
pDevMode, pDevMode,
DM_IN_BUFFER | DM_OUT_BUFFER);
ret = ::DocumentPropertiesW(nullptr, hPrinter, name,
pDevMode, pDevMode,
DM_IN_BUFFER | DM_OUT_BUFFER);
// We need to copy the final DEVMODE settings back to our print settings,
// because they may have been set from invalid prefs.
if (dwRet == IDOK) {
if (ret == IDOK) {
// We need to get information from the device as well.
nsAutoHDC printerDC(::CreateICW(kDriverName, aName, nullptr, pDevMode));
if (NS_WARN_IF(!printerDC)) {
::HeapFree(::GetProcessHeap(), 0, pDevMode);
::ClosePrinter(hPrinter);
return NS_ERROR_FAILURE;
}
@ -385,10 +381,9 @@ nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings*
}
}
if (dwRet != IDOK) {
if (ret != IDOK) {
::HeapFree(::GetProcessHeap(), 0, pDevMode);
::ClosePrinter(hPrinter);
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", dwRet, dwRet));
PR_PL(("***** nsDeviceContextSpecWin::GetDataFromPrinter - DocumentProperties call failed code: %d/0x%x\n", ret, ret));
DISPLAY_LAST_ERROR
return NS_ERROR_FAILURE;
}
@ -399,7 +394,6 @@ nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings*
SetDriverName(kDriverName);
::ClosePrinter(hPrinter);
rv = NS_OK;
} else {
rv = NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND;