merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-06-08 11:55:30 +02:00
commit 21dc4a9b86
122 changed files with 2726 additions and 1869 deletions

View File

@ -800,11 +800,12 @@ getParentCB(AtkObject *aAtkObj)
atkParent = parent ? AccessibleWrap::GetAtkObject(parent) : nullptr;
} else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
ProxyAccessible* parent = proxy->Parent();
if (parent)
if (parent) {
atkParent = GetWrapperFor(parent);
// Otherwise this should be the proxy for the tab's top level document.
atkParent = AccessibleWrap::GetAtkObject(proxy->OuterDocOfRemoteBrowser());
} else {
// Otherwise this should be the proxy for the tab's top level document.
atkParent = AccessibleWrap::GetAtkObject(proxy->OuterDocOfRemoteBrowser());
}
}
if (atkParent)

View File

@ -456,7 +456,7 @@ DocAccessible::Shutdown()
// XXX thinking about ordering?
if (IPCAccessibilityActive()) {
DocAccessibleChild::Send__delete__(mIPCDoc);
mIPCDoc->Shutdown();
MOZ_ASSERT(!mIPCDoc);
}

View File

@ -70,6 +70,9 @@ DocAccessibleChild::IdToAccessible(const uint64_t& aID) const
if (!aID)
return mDoc;
if (!mDoc)
return nullptr;
return mDoc->GetAccessibleByUniqueID(reinterpret_cast<void*>(aID));
}
@ -225,7 +228,7 @@ DocAccessibleChild::RecvRelationByType(const uint64_t& aID,
const uint32_t& aType,
nsTArray<uint64_t>* aTargets)
{
Accessible* acc = mDoc->GetAccessibleByUniqueID((void*)aID);
Accessible* acc = IdToAccessible(aID);
if (!acc)
return true;
@ -258,7 +261,7 @@ bool
DocAccessibleChild::RecvRelations(const uint64_t& aID,
nsTArray<RelationTargets>* aRelations)
{
Accessible* acc = mDoc->GetAccessibleByUniqueID((void*)aID);
Accessible* acc = IdToAccessible(aID);
if (!acc)
return true;

View File

@ -32,10 +32,21 @@ public:
{ MOZ_COUNT_CTOR(DocAccessibleChild); }
~DocAccessibleChild()
{
mDoc->SetIPCDoc(nullptr);
// Shutdown() should have been called, but maybe it isn't if the process is
// killed?
MOZ_ASSERT(!mDoc);
if (mDoc)
mDoc->SetIPCDoc(nullptr);
MOZ_COUNT_DTOR(DocAccessibleChild);
}
void Shutdown()
{
mDoc->SetIPCDoc(nullptr);
mDoc = nullptr;
SendShutdown();
}
void ShowEvent(AccShowEvent* aShowEvent);
/*

View File

@ -8,6 +8,7 @@
#include "nsAutoPtr.h"
#include "mozilla/a11y/Platform.h"
#include "ProxyAccessible.h"
#include "mozilla/dom/TabParent.h"
namespace mozilla {
namespace a11y {
@ -186,6 +187,18 @@ DocAccessibleParent::ShutdownAccessibles(ProxyEntry* entry, void*)
return PL_DHASH_REMOVE;
}
bool
DocAccessibleParent::RecvShutdown()
{
Destroy();
if (!static_cast<dom::TabParent*>(Manager())->IsDestroyed()) {
return PDocAccessibleParent::Send__delete__(this);
}
return true;
}
void
DocAccessibleParent::Destroy()
{

View File

@ -59,6 +59,7 @@ public:
mParentDoc = nullptr;
}
virtual bool RecvShutdown() override;
void Destroy();
virtual void ActorDestroy(ActorDestroyReason aWhy) override
{

View File

@ -48,7 +48,7 @@ prio(normal upto high) sync protocol PDocAccessible
manager PBrowser;
parent:
__delete__();
Shutdown();
/*
* Notify the parent process the document in the child process is firing an
@ -67,6 +67,8 @@ parent:
BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
child:
__delete__();
// Accessible
prio(high) sync State(uint64_t aID) returns(uint64_t states);
prio(high) sync Name(uint64_t aID) returns(nsString name);

View File

@ -1924,3 +1924,8 @@ pref("browser.pocket.useLocaleList", true);
pref("browser.pocket.enabledLocales", "en-US de es-ES ja ja-JP-mac ru");
pref("view_source.tab", true);
// Enable Service Workers for desktop on non-release builds
#ifndef RELEASE_BUILD
pref("dom.serviceWorkers.enabled", true);
#endif

Binary file not shown.

Binary file not shown.

View File

@ -96,6 +96,7 @@ http://example.net:80 privileged
http://prefixexample.com:80
https://example.com:443 privileged
https://example.org:443 privileged
https://test1.example.com:443 privileged
https://test2.example.com:443 privileged
https://sub1.test1.example.com:443 privileged

View File

@ -247,6 +247,7 @@ nsString* nsContentUtils::sModifierSeparator = nullptr;
bool nsContentUtils::sInitialized = false;
bool nsContentUtils::sIsFullScreenApiEnabled = false;
bool nsContentUtils::sTrustedFullScreenOnly = true;
bool nsContentUtils::sIsCutCopyAllowed = true;
bool nsContentUtils::sIsPerformanceTimingEnabled = false;
bool nsContentUtils::sIsResourceTimingEnabled = false;
bool nsContentUtils::sIsUserTimingLoggingEnabled = false;
@ -514,6 +515,9 @@ nsContentUtils::Init()
Preferences::AddBoolVarCache(&sTrustedFullScreenOnly,
"full-screen-api.allow-trusted-requests-only");
Preferences::AddBoolVarCache(&sIsCutCopyAllowed,
"dom.allow_cut_copy", true);
Preferences::AddBoolVarCache(&sIsPerformanceTimingEnabled,
"dom.enable_performance", true);
@ -6632,7 +6636,8 @@ nsContentUtils::IsRequestFullScreenAllowed()
bool
nsContentUtils::IsCutCopyAllowed()
{
return EventStateManager::IsHandlingUserInput() ||
return (!IsCutCopyRestricted() &&
EventStateManager::IsHandlingUserInput()) ||
IsCallerChrome();
}

View File

@ -1863,6 +1863,15 @@ public:
*/
static bool IsRequestFullScreenAllowed();
/**
* Returns true if calling execCommand with 'cut' or 'copy' arguments
* is restricted to chrome code.
*/
static bool IsCutCopyRestricted()
{
return !sIsCutCopyAllowed;
}
/**
* Returns true if calling execCommand with 'cut' or 'copy' arguments is
* allowed in the current context. These are only allowed if the user initiated
@ -2434,6 +2443,7 @@ private:
static bool sAllowXULXBL_for_file;
static bool sIsFullScreenApiEnabled;
static bool sTrustedFullScreenOnly;
static bool sIsCutCopyAllowed;
static uint32_t sHandlingInputTimeout;
static bool sIsPerformanceTimingEnabled;
static bool sIsResourceTimingEnabled;

View File

@ -29,11 +29,11 @@ namespace dom {
namespace cache {
namespace db {
const int32_t kMaxWipeSchemaVersion = 10;
const int32_t kMaxWipeSchemaVersion = 11;
namespace {
const int32_t kLatestSchemaVersion = 10;
const int32_t kLatestSchemaVersion = 11;
const int32_t kMaxEntriesPerStatement = 255;
const uint32_t kPageSize = 4 * 1024;
@ -301,6 +301,10 @@ CreateSchema(mozIStorageConnection* aConn)
"response_headers_guard INTEGER NOT NULL, "
"response_body_id TEXT NULL, "
"response_security_info_id INTEGER NULL REFERENCES security_info(id), "
"response_redirected INTEGER NOT NULL, "
// Note that response_redirected_url is either going to be empty, or
// it's going to be a URL different than response_url.
"response_redirected_url TEXT NOT NULL, "
"cache_id INTEGER NOT NULL REFERENCES caches(id) ON DELETE CASCADE"
");"
));
@ -1468,6 +1472,8 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
"response_headers_guard, "
"response_body_id, "
"response_security_info_id, "
"response_redirected, "
"response_redirected_url, "
"cache_id "
") VALUES ("
":request_method, "
@ -1488,6 +1494,8 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
":response_headers_guard, "
":response_body_id, "
":response_security_info_id, "
":response_redirected, "
":response_redirected_url, "
":cache_id "
");"
), getter_AddRefs(state));
@ -1567,6 +1575,14 @@ InsertEntry(mozIStorageConnection* aConn, CacheId aCacheId,
}
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindInt32ByName(NS_LITERAL_CSTRING("response_redirected"),
aResponse.channelInfo().redirected() ? 1 : 0);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("response_redirected_url"),
aResponse.channelInfo().redirectedURI());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->BindInt64ByName(NS_LITERAL_CSTRING("cache_id"), aCacheId);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@ -1658,6 +1674,8 @@ ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
"entries.response_status_text, "
"entries.response_headers_guard, "
"entries.response_body_id, "
"entries.response_redirected, "
"entries.response_redirected_url, "
"security_info.data "
"FROM entries "
"LEFT OUTER JOIN security_info "
@ -1705,7 +1723,15 @@ ReadResponse(mozIStorageConnection* aConn, EntryId aEntryId,
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
}
rv = state->GetBlobAsUTF8String(6, aSavedResponseOut->mValue.channelInfo().securityInfo());
int32_t redirected;
rv = state->GetInt32(6, &redirected);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
aSavedResponseOut->mValue.channelInfo().redirected() = !!redirected;
rv = state->GetUTF8String(7, aSavedResponseOut->mValue.channelInfo().redirectedURI());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = state->GetBlobAsUTF8String(8, aSavedResponseOut->mValue.channelInfo().securityInfo());
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = aConn->CreateStatement(NS_LITERAL_CSTRING(

View File

@ -13,6 +13,7 @@
#include "nsContentUtils.h"
#include "nsCopySupport.h"
#include "nsFocusManager.h"
#include "nsFontMetrics.h"
#include "nsFrameSelection.h"
#include "nsIContentIterator.h"
#include "nsIPresShell.h"
@ -1081,18 +1082,44 @@ ContentEventHandler::OnQueryCaretRect(WidgetQueryContentEvent* aEvent)
rv = frame->GetPointFromOffset(range->StartOffset(), &posInFrame);
NS_ENSURE_SUCCESS(rv, rv);
aEvent->mReply.mWritingMode = frame->GetWritingMode();
bool isVertical = aEvent->mReply.mWritingMode.IsVertical();
nsRect rect;
rect.x = posInFrame.x;
rect.y = posInFrame.y;
rect.width = caretRect.width;
rect.height = frame->GetSize().height;
nscoord fontHeight = 0;
float inflation = nsLayoutUtils::FontSizeInflationFor(frame);
nsRefPtr<nsFontMetrics> fontMetrics;
rv = nsLayoutUtils::GetFontMetricsForFrame(frame, getter_AddRefs(fontMetrics),
inflation);
if (NS_WARN_IF(!fontMetrics)) {
// If we cannot get font height, use frame size instead.
fontHeight = isVertical ? frame->GetSize().width : frame->GetSize().height;
} else {
fontHeight = fontMetrics->MaxAscent() + fontMetrics->MaxDescent();
}
if (isVertical) {
rect.width = fontHeight;
rect.height = caretRect.height;
} else {
rect.width = caretRect.width;
rect.height = fontHeight;
}
rv = ConvertToRootViewRelativeOffset(frame, rect);
NS_ENSURE_SUCCESS(rv, rv);
aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
rect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel()));
aEvent->mReply.mWritingMode = frame->GetWritingMode();
// If the caret rect is empty, let's make it non-empty rect.
if (!aEvent->mReply.mRect.width) {
aEvent->mReply.mRect.width = 1;
}
if (!aEvent->mReply.mRect.height) {
aEvent->mReply.mRect.height = 1;
}
aEvent->mSucceeded = true;
return NS_OK;
}

View File

@ -13,6 +13,7 @@
#include "mozilla/ipc/ChannelInfo.h"
#include "nsIJARChannel.h"
#include "nsJARChannel.h"
#include "nsNetUtil.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -20,6 +21,7 @@ using namespace mozilla::dom;
void
ChannelInfo::InitFromChannel(nsIChannel* aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mInited, "Cannot initialize the object twice");
nsCOMPtr<nsISupports> securityInfo;
@ -28,6 +30,20 @@ ChannelInfo::InitFromChannel(nsIChannel* aChannel)
SetSecurityInfo(securityInfo);
}
nsLoadFlags loadFlags = 0;
aChannel->GetLoadFlags(&loadFlags);
mRedirected = (loadFlags & nsIChannel::LOAD_REPLACE);
if (mRedirected) {
// Save the spec and not the nsIURI object itself, since those objects are
// not thread-safe, and releasing them somewhere other than the main thread
// is not possible.
nsCOMPtr<nsIURI> redirectedURI;
aChannel->GetURI(getter_AddRefs(redirectedURI));
if (redirectedURI) {
redirectedURI->GetSpec(mRedirectedURISpec);
}
}
mInited = true;
}
@ -37,6 +53,8 @@ ChannelInfo::InitFromIPCChannelInfo(const ipc::IPCChannelInfo& aChannelInfo)
MOZ_ASSERT(!mInited, "Cannot initialize the object twice");
mSecurityInfo = aChannelInfo.securityInfo();
mRedirectedURISpec = aChannelInfo.redirectedURI();
mRedirected = aChannelInfo.redirected();
mInited = true;
}
@ -56,16 +74,22 @@ ChannelInfo::SetSecurityInfo(nsISupports* aSecurityInfo)
nsresult
ChannelInfo::ResurrectInfoOnChannel(nsIChannel* aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mInited);
// These pointers may be null at this point. They must be checked before
// being dereferenced.
nsCOMPtr<nsIHttpChannel> httpChannel =
do_QueryInterface(aChannel);
nsCOMPtr<nsIJARChannel> jarChannel =
do_QueryInterface(aChannel);
if (!mSecurityInfo.IsEmpty()) {
nsCOMPtr<nsISupports> infoObj;
nsresult rv = NS_DeserializeObject(mSecurityInfo, getter_AddRefs(infoObj));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIHttpChannel> httpChannel =
do_QueryInterface(aChannel);
if (httpChannel) {
net::HttpBaseChannel* httpBaseChannel =
static_cast<net::HttpBaseChannel*>(httpChannel.get());
@ -74,8 +98,6 @@ ChannelInfo::ResurrectInfoOnChannel(nsIChannel* aChannel)
return rv;
}
} else {
nsCOMPtr<nsIJARChannel> jarChannel =
do_QueryInterface(aChannel);
if (NS_WARN_IF(!jarChannel)) {
return NS_ERROR_FAILURE;
}
@ -84,6 +106,30 @@ ChannelInfo::ResurrectInfoOnChannel(nsIChannel* aChannel)
}
}
if (mRedirected) {
nsLoadFlags flags = 0;
aChannel->GetLoadFlags(&flags);
flags |= nsIChannel::LOAD_REPLACE;
aChannel->SetLoadFlags(flags);
nsCOMPtr<nsIURI> redirectedURI;
nsresult rv = NS_NewURI(getter_AddRefs(redirectedURI),
mRedirectedURISpec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (httpChannel) {
net::HttpBaseChannel* httpBaseChannel =
static_cast<net::HttpBaseChannel*>(httpChannel.get());
httpBaseChannel->OverrideURI(redirectedURI);
} else {
if (NS_WARN_IF(!jarChannel)) {
return NS_ERROR_FAILURE;
}
static_cast<nsJARChannel*>(jarChannel.get())->OverrideURI(redirectedURI);
}
}
return NS_OK;
}
@ -98,6 +144,8 @@ ChannelInfo::AsIPCChannelInfo() const
IPCChannelInfo ipcInfo;
ipcInfo.securityInfo() = mSecurityInfo;
ipcInfo.redirectedURI() = mRedirectedURISpec;
ipcInfo.redirected() = mRedirected;
return ipcInfo;
}

View File

@ -8,8 +8,10 @@
#define mozilla_dom_ChannelInfo_h
#include "nsString.h"
#include "nsCOMPtr.h"
class nsIChannel;
class nsIURI;
namespace mozilla {
namespace ipc {
@ -42,12 +44,15 @@ public:
ChannelInfo()
: mInited(false)
, mRedirected(false)
{
}
ChannelInfo(const ChannelInfo& aRHS)
: mSecurityInfo(aRHS.mSecurityInfo)
, mRedirectedURISpec(aRHS.mRedirectedURISpec)
, mInited(aRHS.mInited)
, mRedirected(aRHS.mRedirected)
{
}
@ -55,7 +60,9 @@ public:
operator=(const ChannelInfo& aRHS)
{
mSecurityInfo = aRHS.mSecurityInfo;
mRedirectedURISpec = aRHS.mRedirectedURISpec;
mInited = aRHS.mInited;
mRedirected = aRHS.mRedirected;
return *this;
}
@ -78,7 +85,9 @@ private:
private:
nsCString mSecurityInfo;
nsCString mRedirectedURISpec;
bool mInited;
bool mRedirected;
};
} // namespace dom

View File

@ -8,6 +8,8 @@ namespace ipc {
struct IPCChannelInfo
{
nsCString securityInfo;
nsCString redirectedURI;
bool redirected;
};
} // namespace ipc

View File

@ -85,7 +85,10 @@ class ImageLoadTask : public nsRunnable
public:
explicit ImageLoadTask(HTMLImageElement *aElement) :
mElement(aElement)
{}
{
mDocument = aElement->OwnerDoc();
mDocument->BlockOnload();
}
NS_IMETHOD Run()
{
@ -93,12 +96,14 @@ public:
mElement->mPendingImageLoadTask = nullptr;
mElement->LoadSelectedImage(true, true);
}
mDocument->UnblockOnload(false);
return NS_OK;
}
private:
~ImageLoadTask() {}
nsRefPtr<HTMLImageElement> mElement;
nsCOMPtr<nsIDocument> mDocument;
};
HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)

View File

@ -3569,12 +3569,22 @@ nsHTMLDocument::QueryCommandSupported(const nsAString & commandID,
bool
nsHTMLDocument::QueryCommandSupported(const nsAString& commandID)
{
// Gecko technically supports the paste command, but non-privileged content
// will be unable to call it. For that reason, we report that paste is
// not supported to this non-privileged content (as it effectively is).
bool restricted = commandID.LowerCaseEqualsLiteral("paste");
if (restricted && !nsContentUtils::IsCallerChrome()) {
return false;
// Gecko technically supports all the clipboard commands including
// cut/copy/paste, but non-privileged content will be unable to call
// paste, and depending on the pref "dom.allow_cut_copy", cut and copy
// may also be disallowed to be called from non-privileged content.
// For that reason, we report the support status of corresponding
// command accordingly.
if (!nsContentUtils::IsCallerChrome()) {
if (commandID.LowerCaseEqualsLiteral("paste")) {
return false;
}
if (nsContentUtils::IsCutCopyRestricted()) {
if (commandID.LowerCaseEqualsLiteral("cut") ||
commandID.LowerCaseEqualsLiteral("copy")) {
return false;
}
}
}
// commandID is supported if it can be converted to a Midas command

View File

@ -594,5 +594,4 @@ support-files = file_bug871161-1.html file_bug871161-2.html
[test_window_open_close.html]
skip-if = buildapp == 'b2g' # bug 1129014
[test_img_complete.html]
[test_viewport_resize.html]
skip-if = os == 'win' || os == 'mac' # bug 1163911
[test_viewport_resize.html]

View File

@ -16,6 +16,7 @@
#include "mozilla/Mutex.h"
#include "mozilla/dom/Date.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/DetailedPromise.h"
#include "mozilla/dom/MediaKeySessionBinding.h"
#include "mozilla/dom/MediaKeysBinding.h"
#include "mozilla/dom/MediaKeyMessageEventBinding.h"

View File

@ -104,3 +104,4 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet'
[test_bug1012662_editor.html]
[test_bug1012662_noeditor.html]
[test_bug1161721.html]
[test_bug1170911.html]

View File

@ -0,0 +1,90 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1012662
-->
<head>
<title>Test for Bug 1170911</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.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=1170911">Mozilla Bug 1170911</a>
<p id="display"></p>
<div id="content">
<textarea>textarea text</textarea>
</div>
<pre id="test">
<script>
const TEXTAREA = document.querySelector('textarea');
const TEXTAREA_VALUE = TEXTAREA.value;
function doTest() {
is(document.queryCommandSupported("copy"), false,
"Copy support should have been disabled");
is(document.queryCommandSupported("cut"), false,
"Cut support should have been disabled");
document.addEventListener("keydown", tryCopy);
synthesizeKey("Q", {});
}
function tryCopy(evt) {
evt.preventDefault();
document.removeEventListener("keydown", tryCopy);
TEXTAREA.setSelectionRange(0, TEXTAREA_VALUE.length);
TEXTAREA.focus();
SimpleTest.waitForClipboard(null, function () {
is(document.queryCommandEnabled("copy"), false,
"Copy should not be allowed when dom.allow_cut_copy is off");
is(document.execCommand("copy"), false,
"Copy should not be executed when dom.allow_cut_copy is off");
is(TEXTAREA.value, TEXTAREA_VALUE,
"Content in the textarea shouldn't be changed");
TEXTAREA.value = TEXTAREA_VALUE;
},
/* success fn */ SimpleTest.finish,
/* failure fn */ function () {
document.addEventListener("keydown", tryCut);
synthesizeKey("Q", {});
},
/* flavor */ undefined,
/* timeout */ undefined,
/* expect failure */ true);
}
function tryCut(evt) {
evt.preventDefault();
document.removeEventListener("keydown", tryCut);
TEXTAREA.setSelectionRange(0, TEXTAREA_VALUE.length);
TEXTAREA.focus();
SimpleTest.waitForClipboard(null, function () {
is(document.queryCommandEnabled("cut"), false,
"Cut should not be allowed when dom.allow_cut_copy is off");
is(document.execCommand("cut"), false,
"Cut should not be executed when dom.allow_cut_copy is off");
is(TEXTAREA.value, TEXTAREA_VALUE,
"Content in the textarea shouldn't be changed");
},
/* success fn */ SimpleTest.finish,
/* failure fn */ SimpleTest.finish,
/* flavor */ undefined,
/* timeout */ undefined,
/* expect failure */ true);
}
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(() => {
SpecialPowers.pushPrefEnv({"set": [["dom.allow_cut_copy", false]]}, doTest);
});
</script>
</pre>
</body>
</html>

View File

@ -917,11 +917,11 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"Selection",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "ServiceWorker", disabled: true, b2g: false},
{name: "ServiceWorker", release: false, b2g: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "ServiceWorkerContainer", disabled: true, b2g: false},
{name: "ServiceWorkerContainer", release: false, b2g: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "ServiceWorkerRegistration", disabled: true, b2g: false},
{name: "ServiceWorkerRegistration", release: false, b2g: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
"SettingsLock",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -17,6 +17,10 @@ function runTests() {
return testFetchAppResource('test_custom_content_type',
'customContentType', 'text/html');
})
.then(testRedirectedResponse)
.then(testRedirectedHttpsResponse)
.then(testCachedRedirectedResponse)
.then(testCachedRedirectedHttpsResponse)
.then(done);
}
</script>

View File

@ -0,0 +1,2 @@
<!DOCTYPE html>
real index

View File

@ -0,0 +1 @@
Access-Control-Allow-Origin: *

View File

@ -0,0 +1,5 @@
function handleRequest(request, response) {
response.setStatusLine(null, 308, "Permanent Redirect");
response.setHeader("Access-Control-Allow-Origin", "*", false);
response.setHeader("Location", "https://example.org/tests/dom/workers/test/serviceworkers/app-protocol/realindex.html", false);
}

View File

@ -0,0 +1,5 @@
function handleRequest(request, response) {
response.setStatusLine(null, 308, "Permanent Redirect");
response.setHeader("Access-Control-Allow-Origin", "*", false);
response.setHeader("Location", "http://example.org/tests/dom/workers/test/serviceworkers/app-protocol/realindex.html", false);
}

View File

@ -1,3 +1,20 @@
const kHTTPRedirect = "http://example.com/tests/dom/workers/test/serviceworkers/app-protocol/redirect.sjs";
const kHTTPSRedirect = "https://example.com/tests/dom/workers/test/serviceworkers/app-protocol/redirect-https.sjs";
self.addEventListener('install', (event) => {
event.waitUntil(
self.caches.open("origin-app-cache")
.then(c => {
return Promise.all(
[
c.add(kHTTPRedirect),
c.add(kHTTPSRedirect),
]
);
})
);
});
self.addEventListener('fetch', (event) => {
if (event.request.url.indexOf('foo.txt') >= 0) {
event.respondWith(new Response('swresponse', {
@ -17,4 +34,30 @@ self.addEventListener('fetch', (event) => {
headers: {'Content-Type': 'text/html'}
}));
}
if (event.request.url.indexOf('redirected.html') >= 0) {
event.respondWith(fetch(kHTTPRedirect));
}
if (event.request.url.indexOf('redirected-https.html') >= 0) {
event.respondWith(fetch(kHTTPSRedirect));
}
if (event.request.url.indexOf('redirected-cached.html') >= 0) {
event.respondWith(
self.caches.open("origin-app-cache")
.then(c => {
return c.match(kHTTPRedirect);
})
);
}
if (event.request.url.indexOf('redirected-https-cached.html') >= 0) {
event.respondWith(
self.caches.open("origin-app-cache")
.then(c => {
return c.match(kHTTPSRedirect);
})
);
}
});

View File

@ -37,3 +37,36 @@ function testFetchAppResource(aUrl,
});
});
}
function testRedirectedResponse() {
return testRedirectedResponseWorker("redirected", "IFRAMELOADED");
}
function testRedirectedHttpsResponse() {
return testRedirectedResponseWorker("redirected-https", "HTTPSIFRAMELOADED");
}
function testCachedRedirectedResponse() {
return testRedirectedResponseWorker("redirected-cached", "IFRAMELOADED");
}
function testCachedRedirectedHttpsResponse() {
return testRedirectedResponseWorker("redirected-https-cached", "HTTPSIFRAMELOADED");
}
function testRedirectedResponseWorker(aFrameId, aAlert) {
// Because of the CSP policies applied to privileged apps, we cannot run
// inline script inside realindex.html, and loading a script from the app://
// URI is also not an option, so we let the parent iframe which has access
// to the SpecialPowers API use those privileges to access the document.
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
iframe.src = aFrameId + ".html";
iframe.id = aFrameId;
return new Promise(resolve => {
iframe.addEventListener("load", event => {
alert(aAlert);
resolve();
}, false);
});
}

View File

@ -0,0 +1,4 @@
function handleRequest(request, response) {
response.setStatusLine(null, 308, "Permanent Redirect");
response.setHeader("Location", "https://example.org/tests/dom/workers/test/serviceworkers/fetch/origin/https/realindex.html", false);
}

View File

@ -0,0 +1,23 @@
var prefix = "/tests/dom/workers/test/serviceworkers/fetch/origin/https/";
self.addEventListener("install", function(event) {
event.waitUntil(
self.caches.open("origin-cache")
.then(c => {
return c.add(prefix + 'index-https.sjs');
})
);
});
self.addEventListener("fetch", function(event) {
if (event.request.url.indexOf("index-cached-https.sjs") >= 0) {
event.respondWith(
self.caches.open("origin-cache")
.then(c => {
return c.match(prefix + 'index-https.sjs');
})
);
} else {
event.respondWith(fetch(event.request));
}
});

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<script>
window.opener.postMessage({status: "domain", data: document.domain}, "*");
window.opener.postMessage({status: "origin", data: location.origin}, "*");
window.opener.postMessage({status: "done"}, "*");
</script>

View File

@ -0,0 +1 @@
Access-Control-Allow-Origin: https://example.com

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<script>
function ok(v, msg) {
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
}
function done(reg) {
ok(reg.active, "The active worker should be available.");
window.parent.postMessage({status: "registrationdone"}, "*");
}
navigator.serviceWorker.ready.then(done);
navigator.serviceWorker.register("origin_test.js", {scope: "."});
</script>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<script>
navigator.serviceWorker.getRegistration(".").then(function(registration) {
registration.unregister().then(function(success) {
if (success) {
window.parent.postMessage({status: "unregistrationdone"}, "*");
}
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
});
</script>

View File

@ -0,0 +1,4 @@
function handleRequest(request, response) {
response.setStatusLine(null, 308, "Permanent Redirect");
response.setHeader("Location", "https://example.org/tests/dom/workers/test/serviceworkers/fetch/origin/realindex.html", false);
}

View File

@ -0,0 +1,4 @@
function handleRequest(request, response) {
response.setStatusLine(null, 308, "Permanent Redirect");
response.setHeader("Location", "http://example.org/tests/dom/workers/test/serviceworkers/fetch/origin/realindex.html", false);
}

View File

@ -0,0 +1,35 @@
var prefix = "/tests/dom/workers/test/serviceworkers/fetch/origin/";
self.addEventListener("install", function(event) {
event.waitUntil(
self.caches.open("origin-cache")
.then(c => {
return Promise.all(
[
c.add(prefix + 'index.sjs'),
c.add(prefix + 'index-to-https.sjs'),
]
);
})
);
});
self.addEventListener("fetch", function(event) {
if (event.request.url.indexOf("index-cached.sjs") >= 0) {
event.respondWith(
self.caches.open("origin-cache")
.then(c => {
return c.match(prefix + 'index.sjs');
})
);
} else if (event.request.url.indexOf("index-to-https-cached.sjs") >= 0) {
event.respondWith(
self.caches.open("origin-cache")
.then(c => {
return c.match(prefix + 'index-to-https.sjs');
})
);
} else {
event.respondWith(fetch(event.request));
}
});

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<script>
window.opener.postMessage({status: "domain", data: document.domain}, "*");
window.opener.postMessage({status: "origin", data: location.origin}, "*");
window.opener.postMessage({status: "done"}, "*");
</script>

View File

@ -0,0 +1 @@
Access-Control-Allow-Origin: http://mochi.test:8888

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<script>
function ok(v, msg) {
window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
}
function done(reg) {
ok(reg.active, "The active worker should be available.");
window.parent.postMessage({status: "registrationdone"}, "*");
}
navigator.serviceWorker.ready.then(done);
navigator.serviceWorker.register("origin_test.js", {scope: "."});
</script>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<script>
navigator.serviceWorker.getRegistration(".").then(function(registration) {
registration.unregister().then(function(success) {
if (success) {
window.parent.postMessage({status: "unregistrationdone"}, "*");
}
}, function(e) {
dump("Unregistering the SW failed with " + e + "\n");
});
});
</script>

View File

@ -47,6 +47,19 @@ support-files =
fetch/https/clonedresponse/register.html
fetch/https/clonedresponse/unregister.html
fetch/https/clonedresponse/https_test.js
fetch/origin/index.sjs
fetch/origin/index-to-https.sjs
fetch/origin/realindex.html
fetch/origin/realindex.html^headers^
fetch/origin/register.html
fetch/origin/unregister.html
fetch/origin/origin_test.js
fetch/origin/https/index-https.sjs
fetch/origin/https/realindex.html
fetch/origin/https/realindex.html^headers^
fetch/origin/https/register.html
fetch/origin/https/unregister.html
fetch/origin/https/origin_test.js
fetch/requesturl/index.html
fetch/requesturl/redirect.sjs
fetch/requesturl/redirector.html
@ -159,3 +172,9 @@ support-files =
[test_skip_waiting.html]
[test_strict_mode_error.html]
[test_cross_origin_url_after_redirect.html]
[test_origin_after_redirect.html]
[test_origin_after_redirect_cached.html]
[test_origin_after_redirect_to_https.html]
[test_origin_after_redirect_to_https_cached.html]
[test_https_origin_after_redirect.html]
[test_https_origin_after_redirect_cached.html]

View File

@ -28,7 +28,8 @@ function setup() {
['dom.mozBrowserFramesEnabled', true],
['dom.serviceWorkers.exemptFromPerDomainMax', true],
['dom.serviceWorkers.enabled', true],
['dom.serviceWorkers.testing.enabled', true]
['dom.serviceWorkers.testing.enabled', true],
['dom.caches.enabled', true],
]}, () => {
SpecialPowers.pushPermissions([
{ 'type': 'webapps-manage', 'allow': 1, 'context': document },
@ -103,6 +104,18 @@ function loadControlled() {
ok(true, "Message from app: " + message);
} else if (/KO/.exec(message)) {
ok(false, "Message from app: " + message);
} else if (/HTTPSIFRAMELOADED/.exec(message)) {
let doc = SpecialPowers.wrap(iframe).contentDocument;
let innerDoc = SpecialPowers.wrap(doc.getElementById("redirected-https").contentDocument);
let innerLocation = innerDoc.defaultView.location;
is(innerDoc.domain, "example.org", "Correct domain expected (https)");
is(innerLocation.origin, "https://example.org", "Correct origin expected (https)");
} else if (/IFRAMELOADED/.exec(message)) {
let doc = SpecialPowers.wrap(iframe).contentDocument;
let innerDoc = SpecialPowers.wrap(doc.getElementById("redirected").contentDocument);
let innerLocation = innerDoc.defaultView.location;
is(innerDoc.domain, "example.org", "Correct domain expected");
is(innerLocation.origin, "http://example.org", "Correct origin expected");
} else if (/DONE/.exec(message)) {
ok(true, "Messaging from app complete");
iframe.removeEventListener('mozbrowsershowmodalprompt', listener);

View File

@ -0,0 +1,56 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test the origin of a redirected response from a service worker</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var iframe;
function runTest() {
iframe = document.querySelector("iframe");
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/register.html";
var win;
window.onmessage = function(e) {
if (e.data.status == "ok") {
ok(e.data.result, e.data.message);
} else if (e.data.status == "registrationdone") {
win = window.open("https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/index-https.sjs", "mywindow", "width=100,height=100");
} else if (e.data.status == "domain") {
is(e.data.data, "example.org", "Correct domain expected");
} else if (e.data.status == "origin") {
is(e.data.data, "https://example.org", "Correct origin expected");
} else if (e.data.status == "done") {
win.close();
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/unregister.html";
} else if (e.data.status == "unregistrationdone") {
window.onmessage = null;
ok(true, "Test finished successfully");
SimpleTest.finish();
}
};
}
SimpleTest.waitForExplicitFinish();
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.caches.enabled", true],
]}, runTest);
};
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test the origin of a redirected response from a service worker</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var iframe;
function runTest() {
iframe = document.querySelector("iframe");
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/register.html";
var win;
window.onmessage = function(e) {
if (e.data.status == "ok") {
ok(e.data.result, e.data.message);
} else if (e.data.status == "registrationdone") {
win = window.open("https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/index-cached-https.sjs", "mywindow", "width=100,height=100");
} else if (e.data.status == "domain") {
is(e.data.data, "example.org", "Correct domain expected");
} else if (e.data.status == "origin") {
is(e.data.data, "https://example.org", "Correct origin expected");
} else if (e.data.status == "done") {
win.close();
iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/unregister.html";
} else if (e.data.status == "unregistrationdone") {
window.onmessage = null;
ok(true, "Test finished successfully");
SimpleTest.finish();
}
};
}
SimpleTest.waitForExplicitFinish();
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.caches.enabled", true],
]}, runTest);
};
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,57 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test the origin of a redirected response from a service worker</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var iframe;
function runTest() {
iframe = document.querySelector("iframe");
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
var win;
window.onmessage = function(e) {
if (e.data.status == "ok") {
ok(e.data.result, e.data.message);
} else if (e.data.status == "registrationdone") {
win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index.sjs", "mywindow", "width=100,height=100");
} else if (e.data.status == "domain") {
is(e.data.data, "example.org", "Correct domain expected");
} else if (e.data.status == "origin") {
is(e.data.data, "http://example.org", "Correct origin expected");
} else if (e.data.status == "done") {
win.close();
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
} else if (e.data.status == "unregistrationdone") {
window.onmessage = null;
ok(true, "Test finished successfully");
SimpleTest.finish();
}
};
}
SimpleTest.waitForExplicitFinish();
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.caches.enabled", true],
]}, runTest);
};
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,57 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test the origin of a redirected response from a service worker</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var iframe;
function runTest() {
iframe = document.querySelector("iframe");
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
var win;
window.onmessage = function(e) {
if (e.data.status == "ok") {
ok(e.data.result, e.data.message);
} else if (e.data.status == "registrationdone") {
win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index-cached.sjs", "mywindow", "width=100,height=100");
} else if (e.data.status == "domain") {
is(e.data.data, "example.org", "Correct domain expected");
} else if (e.data.status == "origin") {
is(e.data.data, "http://example.org", "Correct origin expected");
} else if (e.data.status == "done") {
win.close();
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
} else if (e.data.status == "unregistrationdone") {
window.onmessage = null;
ok(true, "Test finished successfully");
SimpleTest.finish();
}
};
}
SimpleTest.waitForExplicitFinish();
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.caches.enabled", true],
]}, runTest);
};
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,57 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test the origin of a redirected response from a service worker</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var iframe;
function runTest() {
iframe = document.querySelector("iframe");
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
var win;
window.onmessage = function(e) {
if (e.data.status == "ok") {
ok(e.data.result, e.data.message);
} else if (e.data.status == "registrationdone") {
win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index-to-https.sjs", "mywindow", "width=100,height=100");
} else if (e.data.status == "domain") {
is(e.data.data, "example.org", "Correct domain expected");
} else if (e.data.status == "origin") {
is(e.data.data, "https://example.org", "Correct origin expected");
} else if (e.data.status == "done") {
win.close();
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
} else if (e.data.status == "unregistrationdone") {
window.onmessage = null;
ok(true, "Test finished successfully");
SimpleTest.finish();
}
};
}
SimpleTest.waitForExplicitFinish();
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.caches.enabled", true],
]}, runTest);
};
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,57 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Test the origin of a redirected response from a service worker</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
<iframe></iframe>
</div>
<pre id="test"></pre>
<script class="testbody" type="text/javascript">
var iframe;
function runTest() {
iframe = document.querySelector("iframe");
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
var win;
window.onmessage = function(e) {
if (e.data.status == "ok") {
ok(e.data.result, e.data.message);
} else if (e.data.status == "registrationdone") {
win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index-to-https-cached.sjs", "mywindow", "width=100,height=100");
} else if (e.data.status == "domain") {
is(e.data.data, "example.org", "Correct domain expected");
} else if (e.data.status == "origin") {
is(e.data.data, "https://example.org", "Correct origin expected");
} else if (e.data.status == "done") {
win.close();
iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
} else if (e.data.status == "unregistrationdone") {
window.onmessage = null;
ok(true, "Test finished successfully");
SimpleTest.finish();
}
};
}
SimpleTest.waitForExplicitFinish();
onload = function() {
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.caches.enabled", true],
]}, runTest);
};
</script>
</pre>
</body>
</html>

View File

@ -157,7 +157,7 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"Response",
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "ServiceWorkerRegistration", disabled: true, b2g: false },
{ name: "ServiceWorkerRegistration", release: false, b2g: false },
// IMPORTANT: Do not change this list without review from a DOM peer!
"TextDecoder",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -2246,7 +2246,7 @@ gfxPlatform::OptimalFormatForContent(gfxContentType aContent)
*/
static bool sLayersSupportsD3D9 = false;
static bool sLayersSupportsD3D11 = false;
static bool sANGLESupportsD3D11 = false;
bool gANGLESupportsD3D11 = false;
static bool sLayersSupportsHardwareVideoDecoding = false;
static bool sLayersHardwareVideoDecodingFailed = false;
static bool sBufferRotationCheckPref = true;
@ -2291,7 +2291,7 @@ InitLayersAccelerationPrefs()
}
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, &status))) {
if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
sANGLESupportsD3D11 = true;
gANGLESupportsD3D11 = true;
}
}
}
@ -2347,7 +2347,7 @@ bool
gfxPlatform::CanUseDirect3D11ANGLE()
{
MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
return sANGLESupportsD3D11;
return gANGLESupportsD3D11;
}

View File

@ -131,6 +131,8 @@ enum eGfxLog {
// when searching through pref langs, max number of pref langs
const uint32_t kMaxLenPrefLangList = 32;
extern bool gANGLESupportsD3D11;
#define UNINITIALIZED_VALUE (-1)
inline const char*

View File

@ -577,7 +577,12 @@ static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
mozilla::TimeStamp previousVsync = display->mPreviousTimestamp;
display->mPreviousTimestamp = nextVsync;
mozilla::TimeStamp now = TimeStamp::Now();
MOZ_ASSERT(nextVsync > previousVsync);
if (nextVsync <= previousVsync) {
TimeDuration next = nextVsync - now;
TimeDuration prev = now - previousVsync;
printf_stderr("Next from now: %f, prev from now: %f\n", next.ToMilliseconds(), prev.ToMilliseconds());
MOZ_ASSERT(false, "Next vsync less than previous vsync\n");
}
// Bug 1158321 - The VsyncCallback can sometimes execute before the reported
// vsync time. In those cases, normalize the timestamp to Now() as sending

View File

@ -1718,12 +1718,14 @@ bool DoesD3D11DeviceWork(ID3D11Device *device)
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: could not parse version\n"));
#endif
gANGLESupportsD3D11 = false;
return false;
}
if (displayLinkModuleVersion <= V(8,6,1,36484)) {
#if defined(MOZ_CRASHREPORTER)
CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: too old version\n"));
#endif
gANGLESupportsD3D11 = false;
return false;
}
}

View File

@ -6,15 +6,19 @@ const expectedString = "Hello\nWorld";
function run_test() {
var failures = false;
var encodingConverter = CreateScriptableConverter();
var decoders = [
var encoders = [
"Big5",
"Big5-HKSCS",
"EUC-JP",
"EUC-KR",
"gb18030",
"gbk",
"IBM866",
"ISO-2022-JP",
"ISO-8859-1",
"ISO-8859-2",
"ISO-8859-3",
"ISO-8859-4",
"ISO-8859-5",
@ -27,7 +31,6 @@ function run_test() {
"ISO-8859-14",
"ISO-8859-15",
"ISO-8859-16",
"ISO-8859-2",
"KOI8-R",
"KOI8-U",
"Shift_JIS",
@ -41,23 +44,18 @@ function run_test() {
"windows-1257",
"windows-1258",
"windows-874",
"macintosh",
"x-mac-cyrillic",
"x-user-defined",
"UTF-8"
];
var counter = 0;
while (counter < decoders.length) {
++counter;
var charset = decoders[counter];
while (counter < encoders.length) {
var charset = encoders[counter++];
dump("testing " + counter + " " + charset + "\n");
try {
encodingConverter.charset = charset;
} catch(e) {
dump("Warning: couldn't set encoder charset to " + charset + "\n");
continue;
}
encodingConverter.charset = charset;
var codepageString = encodingConverter.ConvertFromUnicode(inString) +
encodingConverter.Finish();
if (codepageString != expectedString) {

View File

@ -4,6 +4,7 @@ load('CharsetConversionTests.js');
function run_test() {
var failures = false;
var decodingConverter = CreateScriptableConverter();
var decoders = [
"Big5",
@ -13,6 +14,8 @@ function run_test() {
"gb18030",
"IBM866",
"ISO-2022-JP",
"ISO-8859-1",
"ISO-8859-2",
"ISO-8859-3",
"ISO-8859-4",
"ISO-8859-5",
@ -25,7 +28,6 @@ function run_test() {
"ISO-8859-14",
"ISO-8859-15",
"ISO-8859-16",
"ISO-8859-2",
"KOI8-R",
"KOI8-U",
"Shift_JIS",
@ -39,22 +41,18 @@ function run_test() {
"windows-1257",
"windows-1258",
"windows-874",
"macintosh",
"x-mac-cyrillic",
"x-user-defined",
"UTF-8"
];
var counter = 0;
while (counter < decoders.length) {
++counter;
var charset = decoders[counter];
var charset = decoders[counter++];
dump("testing " + counter + " " + charset + "\n");
try {
decodingConverter.charset = charset;
} catch(e) {
dump("Warning: couldn't set decoder charset to " + charset + "\n");
continue;
}
decodingConverter.charset = charset;
for (var i = 0x80; i < 0x100; ++i) {
var inString = String.fromCharCode(i);
var outString;

View File

@ -6,7 +6,7 @@ load('CharsetConversionTests.js');
const inString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u20AC\u4E02\u4E04\u4E05\u4E06\u4E0F\u4E12\u4E17\u4E1F\u4E20\u4E21\u4E23\u4E26\u4E29\u4E2E\u4E2F\u4E31\u4E33\u4E35\u4E37\u4E3C\u4E40\u4E41\u4E42\u4E44\u4E46\u4E4A\u4E51\u4E55\u4E57\u4E5A\u4E5B\u4E62\u4E63\u4E64\u4E65\u4E67\u4E68\u4E6A\u4E6B\u4E6C\u4E6D\u4E6E\u4E6F\u4E72\u4E74\u4E75\u4E76\u4E77\u4E78\u4E79\u4E7A\u4E7B\u4E7C\u4E7D\u4E7F\u4E80\u4E81\u4E82\u4E83\u4E84\u4E85\u4E87\u4E8A\uFFFD";
const expectedString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x80\x81@\x81A\x81B\x81C\x81D\x81E\x81F\x81G\x81H\x81I\x81J\x81K\x81L\x81M\x81N\x81O\x81P\x81Q\x81R\x81S\x81T\x81U\x81V\x81W\x81X\x81Y\x81Z\x81[\x81\\\x81]\x81^\x81_\x81`\x81a\x81b\x81c\x81d\x81e\x81f\x81g\x81h\x81i\x81j\x81k\x81l\x81m\x81n\x81o\x81p\x81q\x81r\x81s\x81t\x81u\x81v\x81w\x81x\x81y\x81z\x81{\x81|\x81}\x81~";
const expectedString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x80\x81@\x81A\x81B\x81C\x81D\x81E\x81F\x81G\x81H\x81I\x81J\x81K\x81L\x81M\x81N\x81O\x81P\x81Q\x81R\x81S\x81T\x81U\x81V\x81W\x81X\x81Y\x81Z\x81[\x81\\\x81]\x81^\x81_\x81`\x81a\x81b\x81c\x81d\x81e\x81f\x81g\x81h\x81i\x81j\x81k\x81l\x81m\x81n\x81o\x81p\x81q\x81r\x81s\x81t\x81u\x81v\x81w\x81x\x81y\x81z\x81{\x81|\x81}\x81~?";
const aliases = [ "gbk", "x-gbk" ];

View File

@ -0,0 +1,77 @@
// Tests encoding of unmapped characters
load('CharsetConversionTests.js');
const inString = "\u2764";
const expectedString = "?";
function run_test() {
var failures = false;
var encodingConverter = CreateScriptableConverter();
// this list excludes codepages that can represent all Unicode
var encoders = [
"Big5",
"Big5-HKSCS",
"EUC-JP",
"EUC-KR",
"gbk",
"IBM866",
"ISO-2022-JP",
"ISO-8859-3",
"ISO-8859-4",
"ISO-8859-5",
"ISO-8859-6",
"ISO-8859-7",
"ISO-8859-8",
"ISO-8859-8-I",
"ISO-8859-10",
"ISO-8859-13",
"ISO-8859-14",
"ISO-8859-15",
"ISO-8859-16",
"ISO-8859-2",
"KOI8-R",
"KOI8-U",
"Shift_JIS",
"windows-1250",
"windows-1251",
"windows-1252",
"windows-1253",
"windows-1254",
"windows-1255",
"windows-1256",
"windows-1257",
"windows-1258",
"windows-874",
"x-mac-cyrillic"
];
var counter = 0;
while (counter < encoders.length) {
var charset = encoders[counter++];
dump("testing " + counter + " " + charset + "\n");
encodingConverter.charset = charset;
var codepageString = encodingConverter.ConvertFromUnicode(inString) +
encodingConverter.Finish();
if (codepageString != expectedString) {
dump(charset + " encoding failed\n");
for (var i = 0; i < expectedString.length; ++i) {
if (i >= codepageString.length) {
dump("output length " + codepageString.length +
" less than expected length " + expectedString.length + "\n");
break;
}
if (codepageString.charAt(i) != expectedString.charAt(i)) {
dump(i.toString(16) + ": 0x" +
codepageString.charCodeAt(i).toString(16) + " != " +
expectedString.charCodeAt(i).toString(16) + "\n");
}
}
failures = true;
}
}
if (failures) {
do_throw("test failed\n");
}
}

View File

@ -120,3 +120,4 @@ support-files =
[test_utf8_illegals.js]
[test_input_stream.js]
[test_bug1008832.js]
[test_unmapped.js]

View File

@ -1,4 +1,4 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -79,30 +79,35 @@ void nsUnicodeToGB18030::Create4BytesEncoder()
m4BytesEncoder = new nsUnicodeTo4BytesGB18030();
}
bool nsUnicodeToGB18030::EncodeSurrogate(
char16_t aSurrogateHigh,
char16_t aSurrogateLow,
char* aOut)
nsresult nsUnicodeToGB18030::EncodeSurrogate(char16_t aSurrogateHigh,
char16_t aSurrogateLow,
char* aOut,
int32_t aDestLength,
int32_t aBufferLength)
{
if( NS_IS_HIGH_SURROGATE(aSurrogateHigh) &&
if( NS_IS_HIGH_SURROGATE(aSurrogateHigh) &&
NS_IS_LOW_SURROGATE(aSurrogateLow) )
{
// notice that idx does not include the 0x10000
// notice that idx does not include the 0x10000
uint32_t idx = ((aSurrogateHigh - (char16_t)0xD800) << 10 ) |
(aSurrogateLow - (char16_t) 0xDC00);
if (aDestLength + 4 > aBufferLength) {
return NS_OK_UENC_MOREOUTPUT;
}
unsigned char *out = (unsigned char*) aOut;
// notice this is from 0x90 for supplment planes
out[0] = (idx / (10*126*10)) + 0x90;
// notice this is from 0x90 for supplementary planes
out[0] = (idx / (10*126*10)) + 0x90;
idx %= (10*126*10);
out[1] = (idx / (10*126)) + 0x30;
idx %= (10*126);
out[2] = (idx / (10)) + 0x81;
out[3] = (idx % 10) + 0x30;
return true;
}
return false;
}
return NS_OK;
}
return NS_ERROR_UENC_NOMAPPING;
}
//----------------------------------------------------------------------
// Class nsUnicodeToGBK [implementation]
@ -122,70 +127,66 @@ void nsUnicodeToGBK::Create4BytesEncoder()
{
m4BytesEncoder = nullptr;
}
bool nsUnicodeToGBK::TryExtensionEncoder(
char16_t aChar,
char* aOut,
int32_t *aOutLen
)
nsresult nsUnicodeToGBK::TryExtensionEncoder(char16_t aChar,
char* aOut,
int32_t *aOutLen)
{
if( NS_IS_HIGH_SURROGATE(aChar) ||
if( NS_IS_HIGH_SURROGATE(aChar) ||
NS_IS_LOW_SURROGATE(aChar) )
{
// performance tune for surrogate characters
return false;
return NS_ERROR_UENC_NOMAPPING;
}
if(! mExtensionEncoder )
CreateExtensionEncoder();
if(mExtensionEncoder)
if(mExtensionEncoder)
{
int32_t len = 1;
nsresult res = NS_OK;
res = mExtensionEncoder->Convert(&aChar, &len, aOut, aOutLen);
if(NS_SUCCEEDED(res) && (*aOutLen > 0))
return true;
return mExtensionEncoder->Convert(&aChar, &len, aOut, aOutLen);
}
return false;
return NS_ERROR_UENC_NOMAPPING;
}
bool nsUnicodeToGBK::Try4BytesEncoder(
nsresult nsUnicodeToGBK::Try4BytesEncoder(
char16_t aChar,
char* aOut,
int32_t *aOutLen
)
{
if( NS_IS_HIGH_SURROGATE(aChar) ||
if( NS_IS_HIGH_SURROGATE(aChar) ||
NS_IS_LOW_SURROGATE(aChar) )
{
// performance tune for surrogate characters
return false;
return NS_ERROR_UENC_NOMAPPING;
}
if(! m4BytesEncoder )
Create4BytesEncoder();
if(m4BytesEncoder)
if(m4BytesEncoder)
{
int32_t len = 1;
nsresult res = NS_OK;
res = m4BytesEncoder->Convert(&aChar, &len, aOut, aOutLen);
NS_ASSERTION(NS_FAILED(res) || ((1 == len) && (4 == *aOutLen)),
"unexpect conversion length");
if(NS_SUCCEEDED(res) && (*aOutLen > 0))
return true;
return res;
}
return false;
return NS_ERROR_UENC_NOMAPPING;
}
bool nsUnicodeToGBK::EncodeSurrogate(
char16_t aSurrogateHigh,
char16_t aSurrogateLow,
char* aOut)
{
return false; // GBK cannot encode Surrogate, let the subclass encode it.
}
NS_IMETHODIMP nsUnicodeToGBK::ConvertNoBuff(
const char16_t * aSrc,
int32_t * aSrcLength,
char * aDest,
int32_t * aDestLength)
nsresult nsUnicodeToGBK::EncodeSurrogate(char16_t aSurrogateHigh,
char16_t aSurrogateLow,
char* aOut,
int32_t aDestLength,
int32_t aBufferLength)
{
return NS_ERROR_UENC_NOMAPPING; // GBK cannot encode Surrogate, let the subclass encode it.
}
NS_IMETHODIMP nsUnicodeToGBK::ConvertNoBuffNoErr(const char16_t * aSrc,
int32_t * aSrcLength,
char * aDest,
int32_t * aDestLength)
{
int32_t iSrcLength = 0;
int32_t iDestLength = 0;
@ -217,59 +218,56 @@ NS_IMETHODIMP nsUnicodeToGBK::ConvertNoBuff(
iDestLength +=2;
} else {
int32_t aOutLen = 2;
// make sure we still have 2 bytes for output first
if(iDestLength+2 > *aDestLength)
{
res = NS_OK_UENC_MOREOUTPUT;
break;
}
// we cannot map in the common mapping. Let's try to
// call the delegated 2 byte converter for the gbk or gb18030
// unique 2 byte mapping
if(TryExtensionEncoder(unicode, aDest, &aOutLen))
{
res = TryExtensionEncoder(unicode, aDest, &aOutLen);
if (res == NS_OK) {
iDestLength += aOutLen;
aDest += aOutLen;
} else if (res == NS_OK_UENC_MOREOUTPUT) {
break;
} else {
// make sure we still have 4 bytes for output first
if(iDestLength+4 > *aDestLength)
{
res = NS_OK_UENC_MOREOUTPUT;
break;
}
// we still cannot map. Let's try to
// call the delegated GB18030 4 byte converter
// call the delegated GB18030 4 byte converter
aOutLen = 4;
if( NS_IS_HIGH_SURROGATE(unicode) )
{
if((iSrcLength+1) < *aSrcLength ) {
if(EncodeSurrogate(aSrc[0],aSrc[1], aDest)) {
res = EncodeSurrogate(aSrc[0],aSrc[1], aDest,
iDestLength, *aDestLength);
if (res == NS_OK) {
// since we got a surrogate pair, we need to increment src.
iSrcLength++ ;
iSrcLength++ ;
aSrc++;
iDestLength += aOutLen;
aDest += aOutLen;
} else {
// only get a high surrogate, but not a low surrogate
res = NS_ERROR_UENC_NOMAPPING;
iSrcLength++; // include length of the unmapped character
if (res == NS_ERROR_UENC_NOMAPPING) {
// only get a high surrogate, but not a low surrogate
iSrcLength++; // include length of the unmapped character
}
break;
}
} else {
mSurrogateHigh = aSrc[0];
res = NS_OK;
break; // this will go to afterwhileloop
}
} else {
if( NS_IS_LOW_SURROGATE(unicode) )
{
if(NS_IS_HIGH_SURROGATE(mSurrogateHigh)) {
if(EncodeSurrogate(mSurrogateHigh, aSrc[0], aDest)) {
res = EncodeSurrogate(mSurrogateHigh, aSrc[0], aDest,
iDestLength, *aDestLength);
if (res == NS_OK) {
iDestLength += aOutLen;
aDest += aOutLen;
} else {
// only get a high surrogate, but not a low surrogate
res = NS_ERROR_UENC_NOMAPPING;
iSrcLength++; // include length of the unmapped character
if (res == NS_ERROR_UENC_NOMAPPING) {
// only get a high surrogate, but not a low surrogate
iSrcLength++; // include length of the unmapped character
}
break;
}
} else {
@ -279,22 +277,23 @@ NS_IMETHODIMP nsUnicodeToGBK::ConvertNoBuff(
break;
}
} else {
if(Try4BytesEncoder(unicode, aDest, &aOutLen))
{
res = Try4BytesEncoder(unicode, aDest, &aOutLen);
if (res == NS_OK) {
NS_ASSERTION((aOutLen == 4), "we should always generate 4 bytes here");
iDestLength += aOutLen;
aDest += aOutLen;
} else {
res = NS_ERROR_UENC_NOMAPPING;
iSrcLength++; // include length of the unmapped character
if (res == NS_ERROR_UENC_NOMAPPING) {
iSrcLength++; // include length of the unmapped character
}
break;
}
}
}
}
}
}
}
iSrcLength++ ; // Each unicode char just count as one in char16_t string;
iSrcLength++ ; // Each unicode char just count as one in char16_t string;
mSurrogateHigh = 0;
aSrc++;
if ( iDestLength >= (*aDestLength) && (iSrcLength < *aSrcLength) )

View File

@ -1,4 +1,4 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -35,16 +35,10 @@ protected:
//--------------------------------------------------------------------
// Subclassing of nsEncoderSupport class [declaration]
NS_IMETHOD ConvertNoBuff(const char16_t * aSrc,
int32_t * aSrcLength,
char * aDest,
int32_t * aDestLength);
NS_IMETHOD ConvertNoBuffNoErr(const char16_t * aSrc, int32_t * aSrcLength,
char * aDest, int32_t * aDestLength)
{
return NS_OK;
} // just make it not abstract;
NS_IMETHOD ConvertNoBuffNoErr(const char16_t * aSrc,
int32_t * aSrcLength,
char * aDest,
int32_t * aDestLength);
virtual void CreateExtensionEncoder();
virtual void Create4BytesEncoder();
@ -54,9 +48,11 @@ protected:
protected:
char16_t mSurrogateHigh;
nsGBKConvUtil mUtil;
bool TryExtensionEncoder(char16_t aChar, char* aDest, int32_t* aOutLen);
bool Try4BytesEncoder(char16_t aChar, char* aDest, int32_t* aOutLen);
virtual bool EncodeSurrogate(char16_t aSurrogateHigh, char16_t aSurrogateLow, char* aDest);
nsresult TryExtensionEncoder(char16_t aChar, char* aDest, int32_t* aOutLen);
nsresult Try4BytesEncoder(char16_t aChar, char* aDest, int32_t* aOutLen);
virtual nsresult EncodeSurrogate(char16_t aSurrogateHigh,
char16_t aSurrogateLow, char* aDest,
int32_t aDestLength, int32_t aBufferLength);
};
class nsUnicodeToGB18030: public nsUnicodeToGBK
@ -67,7 +63,9 @@ public:
protected:
virtual void CreateExtensionEncoder();
virtual void Create4BytesEncoder();
virtual bool EncodeSurrogate(char16_t aSurrogateHigh, char16_t aSurrogateLow, char* aDest);
virtual nsresult EncodeSurrogate(char16_t aSurrogateHigh,
char16_t aSurrogateLow, char* aDest,
int32_t aDestLength, int32_t aBufferLength);
};
#endif /* nsUnicodeToGBK_h___ */

View File

@ -1,145 +0,0 @@
/*
* Header file of Pure API function declarations.
*
* (C) Copyright IBM Corporation. 2006, 2006. All Rights Reserved.
* You may recompile and redistribute these definitions as required.
*
* Version 1.0
*/
#if defined(PURIFY) || defined(QUANTIFY)
#if defined(c_plusplus) || defined(__cplusplus)
extern "C" {
#endif
// Don't include this file directly, use purify.h instead.
// If you need something that's not there, add it.
#ifdef PURIFY_PRIVATE_INCLUDE
#define PURE_H_VERSION 1
#include <stddef.h>
//////////////////////////////
// API's Specific to Purify //
//////////////////////////////
// TRUE when Purify is running.
int __cdecl PurifyIsRunning(void) ;
//
// Print a string to the viewer.
//
int __cdecl PurePrintf(const char *fmt, ...) ;
int __cdecl PurifyPrintf(const char *fmt, ...) ;
//
// Purify functions for leak and memory-in-use functionalty.
//
size_t __cdecl PurifyNewInuse(void) ;
size_t __cdecl PurifyAllInuse(void) ;
size_t __cdecl PurifyClearInuse(void) ;
size_t __cdecl PurifyNewLeaks(void) ;
size_t __cdecl PurifyAllLeaks(void) ;
size_t __cdecl PurifyClearLeaks(void) ;
//
// Purify functions for handle leakage.
//
size_t __cdecl PurifyAllHandlesInuse(void) ;
size_t __cdecl PurifyNewHandlesInuse(void) ;
//
// Functions that tell you about the state of memory.
//
size_t __cdecl PurifyDescribe(void *addr) ;
size_t __cdecl PurifyWhatColors(void *addr, size_t size) ;
//
// Functions to test the state of memory. If the memory is not
// accessable, an error is signaled just as if there were a memory
// reference and the function returns false.
//
int __cdecl PurifyAssertIsReadable(const void *addr, size_t size) ; // size used to be an int, until IA64 came along
int __cdecl PurifyAssertIsWritable(const void *addr, size_t size) ;
//
// Functions to test the state of memory. If the memory is not
// accessable, these functions return false. No error is signaled.
//
int __cdecl PurifyIsReadable(const void *addr, size_t size) ;
int __cdecl PurifyIsWritable(const void *addr, size_t size) ;
int __cdecl PurifyIsInitialized(const void *addr, size_t size) ;
//
// Functions to set the state of memory.
//
void __cdecl PurifyMarkAsInitialized(void *addr, size_t size) ;
void __cdecl PurifyMarkAsUninitialized(void *addr, size_t size) ;
//
// Functions to do late detection of ABWs, FMWs, IPWs.
//
#define PURIFY_HEAP_CRT (HANDLE) ~(__int64) 1 /* 0xfffffffe */
#define PURIFY_HEAP_ALL (HANDLE) ~(__int64) 2 /* 0xfffffffd */
#define PURIFY_HEAP_BLOCKS_LIVE 0x80000000
#define PURIFY_HEAP_BLOCKS_DEFERRED_FREE 0x40000000
#define PURIFY_HEAP_BLOCKS_ALL (PURIFY_HEAP_BLOCKS_LIVE|PURIFY_HEAP_BLOCKS_DEFERRED_FREE)
int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr) ;
int __cdecl PurifySetLateDetectScanCounter(int counter);
int __cdecl PurifySetLateDetectScanInterval(int seconds);
//
// Functions to support pool allocators
//
void __cdecl PurifySetPoolId(const void *mem, int id);
int __cdecl PurifyGetPoolId(const void *mem);
void __cdecl PurifySetUserData(const void *mem, void *data);
void * __cdecl PurifyGetUserData(const void *mem);
void __cdecl PurifyMapPool(int id, void(*fn)());
////////////////////////////////
// API's Specific to Quantify //
////////////////////////////////
// TRUE when Quantify is running.
int __cdecl QuantifyIsRunning(void) ;
//
// Functions for controlling collection
//
int __cdecl QuantifyDisableRecordingData(void) ;
int __cdecl QuantifyStartRecordingData(void) ;
int __cdecl QuantifyStopRecordingData(void) ;
int __cdecl QuantifyClearData(void) ;
int __cdecl QuantifyIsRecordingData(void) ;
// Add a comment to the dataset
int __cdecl QuantifyAddAnnotation(char *) ;
// Save the current data, creating a "checkpoint" dataset
int __cdecl QuantifySaveData(void) ;
// Set the name of the current thread in the viewer
int __cdecl QuantifySetThreadName(char *) ;
////////////////////////////////
// API's Specific to Coverage //
////////////////////////////////
// TRUE when Coverage is running.
int __cdecl CoverageIsRunning(void) ;
//
// Functions for controlling collection
//
int __cdecl CoverageDisableRecordingData(void) ;
int __cdecl CoverageStartRecordingData(void) ;
int __cdecl CoverageStopRecordingData(void) ;
int __cdecl CoverageClearData(void) ;
int __cdecl CoverageIsRecordingData(void) ;
// Add a comment to the dataset
int __cdecl CoverageAddAnnotation(char *) ;
// Save the current data, creating a "checkpoint" dataset
int __cdecl CoverageSaveData(void) ;
#endif // PURIFY_PRIVATE_INCLUDE
#if defined(c_plusplus) || defined(__cplusplus)
}
#endif
#endif // defined(PURIFY) || defined(QUANTIFY)

View File

@ -1,152 +0,0 @@
/*
* Header file of Pure API function declarations.
*
* Explicitly no copyright.
* You may recompile and redistribute these definitions as required.
*
* NOTE1: In some situations when compiling with MFC, you should
* enable the setting 'Not using precompiled headers' in Visual C++
* to avoid a compiler diagnostic.
*
* NOTE2: This file works through the use of deep magic. Calls to functions
* in this file are replaced with calls into the OCI runtime system
* when an instrumented version of this program is run.
*
* NOTE3: The static vars avoidGy_n (where n is a unique number) are used
* to prevent optimizing the functions away when compiler option
* /Gy is set. This is needed so that NOTE2 works properly.
*/
// Chromium note: We used to only compile this code if PURIFY was defined,
// because we did special builds with all optimizations turned off for Purify.
// However, for profiling with Quantify, we want most/all optimizations turned
// on so that we measure something closer to real execution.
#ifdef _WINDOWS // we only use Purify/Quantify on Windows
#pragma once
extern int errno;
typedef int ptrdiff_t;
typedef unsigned int size_t;
typedef unsigned short wchar_t;
static int avoidGy_1 = 0;
static int avoidGy_2 = 0;
static int avoidGy_3 = 0;
static int avoidGy_4 = 0;
static int avoidGy_5 = 0;
static int avoidGy_6 = 0;
static int avoidGy_7 = 0;
static int avoidGy_8 = 0;
static int avoidGy_9 = 0;
static int avoidGy_10 = 0;
static int avoidGy_11 = 0;
static int avoidGy_12 = 0;
static int avoidGy_13 = 0;
static int avoidGy_14 = 0;
static int avoidGy_15 = 0;
static int avoidGy_16 = 0;
static int avoidGy_17 = 0;
static int avoidGy_18 = 0;
static int avoidGy_19 = 0;
static int avoidGy_20 = 0;
static int avoidGy_21 = 0;
static int avoidGy_22 = 0;
static int avoidGy_23 = 0;
static int avoidGy_24 = 0;
static int avoidGy_25 = 0;
static int avoidGy_26 = 0;
static int avoidGy_27 = 0;
static int avoidGy_28 = 0;
static int avoidGy_29 = 0;
static int avoidGy_30 = 0;
static int avoidGy_31 = 0;
static int avoidGy_32 = 0;
static int avoidGy_33 = 0;
static int avoidGy_34 = 0;
static int avoidGy_35 = 0;
static int avoidGy_36 = 0;
static int avoidGy_37 = 0;
static int avoidGy_38 = 0;
static int avoidGy_39 = 0;
static int avoidGy_40 = 0;
static int avoidGy_41 = 0;
static int avoidGy_42 = 0;
static int avoidGy_43 = 0;
static int avoidGy_44 = 0;
static int avoidGy_45 = 0;
static int avoidGy_46 = 0;
static int avoidGy_47 = 0;
static int avoidGy_48 = 0;
static int avoidGy_49 = 0;
static int avoidGy_50 = 0;
static int avoidGy_51 = 0;
static int avoidGy_52 = 0;
static int avoidGy_53 = 0;
static int avoidGy_54 = 0;
static int avoidGy_55 = 0;
static int avoidGy_56 = 0;
static int avoidGy_57 = 0;
static int avoidGy_58 = 0;
static int avoidGy_59 = 0;
static int avoidGy_60 = 0;
static int avoidGy_61 = 0;
static int avoidGy_62 = 0;
static int avoidGy_63 = 0;
static int avoidGy_64 = 0;
static int avoidGy_65 = 0;
static int avoidGy_PL_01 = 0;
static int avoidGy_PL_02 = 0;
__declspec(dllexport) int __cdecl PurePrintf(const char *fmt, ...) { if(!++avoidGy_1); fmt; return 0; }
__declspec(dllexport) int __cdecl PurifyIsRunning(void) { if(!++avoidGy_2); return 0; }
__declspec(dllexport) int __cdecl PurifyPrintf(const char *fmt, ...) { if(!++avoidGy_3); fmt; return 0; }
__declspec(dllexport) size_t __cdecl PurifyNewInuse(void) { if(!++avoidGy_4); return 0; }
__declspec(dllexport) size_t __cdecl PurifyAllInuse(void) { if(!++avoidGy_5); return 0; }
__declspec(dllexport) size_t __cdecl PurifyClearInuse(void) { if(!++avoidGy_6); return 0; }
__declspec(dllexport) size_t __cdecl PurifyNewLeaks(void) { if(!++avoidGy_7); return 0; }
__declspec(dllexport) size_t __cdecl PurifyAllLeaks(void) { if(!++avoidGy_8); return 0; }
__declspec(dllexport) size_t __cdecl PurifyClearLeaks(void) { if(!++avoidGy_9); return 0; }
__declspec(dllexport) size_t __cdecl PurifyAllHandlesInuse(void) { if(!++avoidGy_10); return 0; }
__declspec(dllexport) size_t __cdecl PurifyNewHandlesInuse(void) { if(!++avoidGy_11); return 0; }
__declspec(dllexport) size_t __cdecl PurifyDescribe(void *addr) { if(!++avoidGy_12); addr; return 0; }
__declspec(dllexport) int __cdecl PurifyWhatColors(void *addr, size_t size) { if(!++avoidGy_13); addr; size; return 0; }
__declspec(dllexport) int __cdecl PurifyAssertIsReadable(const void *addr, size_t size) { if(!++avoidGy_14); addr; size; return 1; }
__declspec(dllexport) int __cdecl PurifyAssertIsWritable(const void *addr, size_t size) { if(!++avoidGy_15); addr; size; return 1; }
__declspec(dllexport) int __cdecl PurifyIsReadable(const void *addr, size_t size) { if(!++avoidGy_16); addr; size; return 1; }
__declspec(dllexport) int __cdecl PurifyIsWritable(const void *addr, size_t size) { if(!++avoidGy_17); addr; size; return 1; }
__declspec(dllexport) int __cdecl PurifyIsInitialized(const void *addr, size_t size) { if(!++avoidGy_18); addr; size; return 1; }
__declspec(dllexport) int __cdecl PurifyRed(void *addr, size_t size) { if(!++avoidGy_19); addr; size; return 0; }
__declspec(dllexport) int __cdecl PurifyGreen(void *addr, size_t size) { if(!++avoidGy_20); addr; size; return 0; }
__declspec(dllexport) int __cdecl PurifyYellow(void *addr, size_t size) { if(!++avoidGy_21); addr; size; return 0; }
__declspec(dllexport) int __cdecl PurifyBlue(void *addr, size_t size) { if(!++avoidGy_22); addr; size; return 0; }
__declspec(dllexport) int __cdecl PurifyMarkAsInitialized(void *addr, size_t size) { if(!++avoidGy_23); addr; size; return 0; }
__declspec(dllexport) int __cdecl PurifyMarkAsUninitialized(void *addr, size_t size) { if(!++avoidGy_24); addr; size; return 0; }
__declspec(dllexport) int __cdecl PurifyMarkForTrap(void *addr, size_t size) { if(!++avoidGy_25); addr; size; return 0; }
__declspec(dllexport) int __cdecl PurifyMarkForNoTrap(void *addr, size_t size) { if(!++avoidGy_26); addr; size; return 0; }
__declspec(dllexport) int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr)
{ if(!++avoidGy_27); hHeap; dwFlags; addr; return 1; }
__declspec(dllexport) int __cdecl PurifySetLateDetectScanCounter(int counter) { if(!++avoidGy_28); counter; return 0; };
__declspec(dllexport) int __cdecl PurifySetLateDetectScanInterval(int seconds) { if(!++avoidGy_29); seconds; return 0; };
__declspec(dllexport) void __cdecl PurifySetPoolId(const void *mem, int id) { if(!++avoidGy_61); mem; id; return; };
__declspec(dllexport) int __cdecl PurifyGetPoolId(const void *mem) { if(!++avoidGy_62); mem; return 0; };
__declspec(dllexport) void __cdecl PurifySetUserData(const void *mem, void *data) { if(!++avoidGy_63); mem; data; return; };
__declspec(dllexport) void * __cdecl PurifyGetUserData(const void *mem) { if(!++avoidGy_64); mem; return 0; };
__declspec(dllexport) void __cdecl PurifyMapPool(int id, void(*fn)()) { if(!++avoidGy_65); id; fn; return; };
__declspec(dllexport) int __cdecl CoverageIsRunning(void) { if(!++avoidGy_30); return 0; }
__declspec(dllexport) int __cdecl CoverageDisableRecordingData(void) { if(!++avoidGy_31); return 0; }
__declspec(dllexport) int __cdecl CoverageStartRecordingData(void) { if(!++avoidGy_32); return 0; }
__declspec(dllexport) int __cdecl CoverageStopRecordingData(void) { if(!++avoidGy_33); return 0; }
__declspec(dllexport) int __cdecl CoverageClearData(void) { if(!++avoidGy_34); return 0; }
__declspec(dllexport) int __cdecl CoverageIsRecordingData(void) { if(!++avoidGy_35); return 0; }
__declspec(dllexport) int __cdecl CoverageAddAnnotation(char *str) { if(!++avoidGy_36); str; return 0; }
__declspec(dllexport) int __cdecl CoverageSaveData(void) { if(!++avoidGy_37); return 0; }
__declspec(dllexport) int __cdecl QuantifyIsRunning(void) { if(!++avoidGy_42); return 0; }
__declspec(dllexport) int __cdecl QuantifyDisableRecordingData(void) { if(!++avoidGy_43); return 0; }
__declspec(dllexport) int __cdecl QuantifyStartRecordingData(void) { if(!++avoidGy_44); return 0; }
__declspec(dllexport) int __cdecl QuantifyStopRecordingData(void) { if(!++avoidGy_45); return 0; }
__declspec(dllexport) int __cdecl QuantifyClearData(void) { if(!++avoidGy_46); return 0; }
__declspec(dllexport) int __cdecl QuantifyIsRecordingData(void) { if(!++avoidGy_47); return 0; }
__declspec(dllexport) int __cdecl QuantifyAddAnnotation(char *str) { if(!++avoidGy_48); str; return 0; }
__declspec(dllexport) int __cdecl QuantifySaveData(void) { if(!++avoidGy_49); return 0; }
__declspec(dllexport) int __cdecl QuantifySetThreadName(const char *szName) { if(!++avoidGy_50) ; szName; return 0; }
#endif // _WINDOWS

View File

@ -147,7 +147,7 @@ public:
};
template<class ListenerT>
class /*NS_INTERFACE_CLASS*/ IProtocolManager
class IProtocolManager
{
public:
enum ActorDestroyReason {

View File

@ -125,17 +125,11 @@ class CxxCodeGen(CodePrinter, Visitor):
def visitClass(self, c):
if c.specializes is not None:
self.printdentln('template<>')
if c.struct:
self.printdent('struct')
else:
self.printdent('class')
if c.interface:
# FIXME/cjones: turn this "on" when we get the analysis
self.write(' /*NS_INTERFACE_CLASS*/')
if c.abstract:
# FIXME/cjones: turn this "on" when we get the analysis
self.write(' /*NS_ABSTRACT_CLASS*/')
self.write(' '+ c.name)
if c.final:
self.write(' final')

View File

@ -0,0 +1,3 @@
x = Array(4294967295);
x[1] = 0;
Array.prototype.shift.call(x);

View File

@ -325,14 +325,19 @@ VirtualRegister::setInitialDefinition(CodePosition from)
}
LiveRange*
VirtualRegister::rangeFor(CodePosition pos) const
VirtualRegister::rangeFor(CodePosition pos, bool preferRegister /* = false */) const
{
LiveRange* found = nullptr;
for (LiveRange::RegisterLinkIterator iter = rangesBegin(); iter; iter++) {
LiveRange* range = LiveRange::get(*iter);
if (range->covers(pos))
return range;
if (range->covers(pos)) {
if (!preferRegister || range->bundle()->allocation().isRegister())
return range;
if (!found)
found = range;
}
}
return nullptr;
return found;
}
void
@ -1706,7 +1711,7 @@ BacktrackingAllocator::resolveControlFlow()
if (skip)
continue;
LiveRange* predecessorRange = reg.rangeFor(start.previous());
LiveRange* predecessorRange = reg.rangeFor(start.previous(), /* preferRegister = */ true);
if (start.subpos() == CodePosition::INPUT) {
if (!moveInput(ins->toInstruction(), predecessorRange, range, reg.type()))
return false;
@ -1742,7 +1747,7 @@ BacktrackingAllocator::resolveControlFlow()
MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1);
LAllocation* input = phi->getOperand(k);
LiveRange* from = vreg(input).rangeFor(exitOf(predecessor));
LiveRange* from = vreg(input).rangeFor(exitOf(predecessor), /* preferRegister = */ true);
MOZ_ASSERT(from);
if (!moveAtExit(predecessor, from, to, def->type()))
@ -1767,7 +1772,7 @@ BacktrackingAllocator::resolveControlFlow()
if (to->covers(exitOf(predecessor)))
continue;
LiveRange* from = reg.rangeFor(exitOf(predecessor));
LiveRange* from = reg.rangeFor(exitOf(predecessor), /* preferRegister = */ true);
if (mSuccessor->numPredecessors() > 1) {
MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1);
@ -2326,11 +2331,12 @@ BacktrackingAllocator::minimalDef(LiveRange* range, LNode* ins)
}
bool
BacktrackingAllocator::minimalUse(LiveRange* range, LNode* ins)
BacktrackingAllocator::minimalUse(LiveRange* range, UsePosition* use)
{
// Whether this is a minimal range capturing a use at ins.
// Whether this is a minimal range capturing |use|.
LNode* ins = insData[use->pos];
return (range->from() == inputOf(ins)) &&
(range->to() == outputOf(ins) || range->to() == outputOf(ins).next());
(range->to() == (use->use->usedAtStart() ? outputOf(ins) : outputOf(ins).next()));
}
bool
@ -2368,12 +2374,12 @@ BacktrackingAllocator::minimalBundle(LiveBundle* bundle, bool* pfixed)
if (fixed)
return false;
fixed = true;
if (minimalUse(range, insData[iter->pos]))
if (minimalUse(range, *iter))
minimal = true;
break;
case LUse::REGISTER:
if (minimalUse(range, insData[iter->pos]))
if (minimalUse(range, *iter))
minimal = true;
break;

View File

@ -524,7 +524,7 @@ class VirtualRegister
LiveRange* lastRange() const {
return LiveRange::get(ranges_.back());
}
LiveRange* rangeFor(CodePosition pos) const;
LiveRange* rangeFor(CodePosition pos, bool preferRegister = false) const;
void removeRange(LiveRange* range);
void addRange(LiveRange* range);
@ -707,7 +707,7 @@ class BacktrackingAllocator : protected RegisterAllocator
struct PrintLiveRange;
bool minimalDef(LiveRange* range, LNode* ins);
bool minimalUse(LiveRange* range, LNode* ins);
bool minimalUse(LiveRange* range, UsePosition* use);
bool minimalBundle(LiveBundle* bundle, bool* pfixed = nullptr);
// Heuristic methods.

View File

@ -2208,8 +2208,14 @@ CodeGenerator::visitMoveGroup(LMoveGroup* group)
masm.propagateOOM(resolver.resolve());
MoveEmitter emitter(masm);
#ifdef JS_CODEGEN_X86
if (group->maybeScratchRegister().isGeneralReg())
emitter.setScratchRegister(group->maybeScratchRegister().toGeneralReg()->reg());
else
resolver.sortMemoryToMemoryMoves();
#endif
emitter.emit(resolver);
emitter.finish();
}

View File

@ -119,14 +119,10 @@ class LMoveGroup : public LInstructionHelper<0, 0, 0>
void setScratchRegister(Register reg) {
scratchRegister_ = LGeneralReg(reg);
}
#endif
LAllocation maybeScratchRegister() {
#ifdef JS_CODEGEN_X86
return scratchRegister_;
#else
return LAllocation();
#endif
}
#endif
bool uses(Register reg) {
for (size_t i = 0; i < numMoves(); i++) {

View File

@ -201,14 +201,90 @@ MoveResolver::addOrderedMove(const MoveOp& move)
}
}
if (existing.to().aliases(move.from()) ||
existing.to().aliases(move.to()) ||
existing.from().aliases(move.to()) ||
existing.from().aliases(move.from()))
{
if (existing.aliases(move))
break;
}
}
return orderedMoves_.append(move);
}
void
MoveResolver::reorderMove(size_t from, size_t to)
{
MOZ_ASSERT(from != to);
MoveOp op = orderedMoves_[from];
if (from < to) {
for (size_t i = from; i < to; i++)
orderedMoves_[i] = orderedMoves_[i + 1];
} else {
for (size_t i = from; i > to; i--)
orderedMoves_[i] = orderedMoves_[i - 1];
}
orderedMoves_[to] = op;
}
void
MoveResolver::sortMemoryToMemoryMoves()
{
// Try to reorder memory->memory moves so that they are executed right
// before a move that clobbers some register. This will allow the move
// emitter to use that clobbered register as a scratch register for the
// memory->memory move, if necessary.
for (size_t i = 0; i < orderedMoves_.length(); i++) {
const MoveOp& base = orderedMoves_[i];
if (!base.from().isMemory() || !base.to().isMemory())
continue;
if (base.type() != MoveOp::GENERAL && base.type() != MoveOp::INT32)
continue;
// Look for an earlier move clobbering a register.
bool found = false;
for (int j = i - 1; j >= 0; j--) {
const MoveOp& previous = orderedMoves_[j];
if (previous.aliases(base) || previous.isCycleBegin() || previous.isCycleEnd())
break;
if (previous.to().isGeneralReg()) {
reorderMove(i, j);
found = true;
break;
}
}
if (found)
continue;
// Look for a later move clobbering a register.
if (i + 1 < orderedMoves_.length()) {
bool found = false, skippedRegisterUse = false;
for (size_t j = i + 1; j < orderedMoves_.length(); j++) {
const MoveOp& later = orderedMoves_[j];
if (later.aliases(base) || later.isCycleBegin() || later.isCycleEnd())
break;
if (later.to().isGeneralReg()) {
if (skippedRegisterUse) {
reorderMove(i, j);
found = true;
} else {
// There is no move that uses a register between the
// original memory->memory move and this move that
// clobbers a register. The move should already be able
// to use a scratch register, so don't shift anything
// around.
}
break;
}
if (later.from().isGeneralReg())
skippedRegisterUse = true;
}
if (found) {
// Redo the search for memory->memory moves at the current
// index, so we don't skip the move just shifted back.
i--;
}
}
}
}

View File

@ -197,6 +197,12 @@ class MoveOp
MOZ_ASSERT(isCycleBegin());
return endCycleType_;
}
bool aliases(const MoveOperand& op) const {
return from().aliases(op) || to().aliases(op);
}
bool aliases(const MoveOp& other) const {
return aliases(other.from()) || aliases(other.to());
}
};
class MoveResolver
@ -229,8 +235,6 @@ class MoveResolver
typedef InlineList<MoveResolver::PendingMove>::iterator PendingMoveIterator;
private:
// Moves that are definitely unblocked (constants to registers). These are
// emitted last.
js::Vector<MoveOp, 16, SystemAllocPolicy> orderedMoves_;
int numCycles_;
int curCycles_;
@ -241,6 +245,7 @@ class MoveResolver
PendingMove* findBlockingMove(const PendingMove* last);
PendingMove* findCycledMove(PendingMoveIterator* stack, PendingMoveIterator end, const PendingMove* first);
bool addOrderedMove(const MoveOp& move);
void reorderMove(size_t from, size_t to);
// Internal reset function. Does not clear lists.
void resetState();
@ -257,6 +262,7 @@ class MoveResolver
// cycle resolution algorithm. Calling addMove() again resets the resolver.
bool addMove(const MoveOperand& from, const MoveOperand& to, MoveOp::Type type);
bool resolve();
void sortMemoryToMemoryMoves();
size_t numMoves() const {
return orderedMoves_.length();

View File

@ -11,6 +11,8 @@
using namespace js;
using namespace js::jit;
using mozilla::Maybe;
MoveEmitterX86::MoveEmitterX86(MacroAssembler& masm)
: inCycle_(false),
masm(masm),
@ -101,11 +103,19 @@ MoveEmitterX86::emit(const MoveResolver& moves)
{
#if defined(JS_CODEGEN_X86) && defined(DEBUG)
// Clobber any scratch register we have, to make regalloc bugs more visible.
if (hasScratchRegister())
masm.mov(ImmWord(0xdeadbeef), scratchRegister());
if (scratchRegister_.isSome())
masm.mov(ImmWord(0xdeadbeef), scratchRegister_.value());
#endif
for (size_t i = 0; i < moves.numMoves(); i++) {
#if defined(JS_CODEGEN_X86) && defined(DEBUG)
if (!scratchRegister_.isSome()) {
Maybe<Register> reg = findScratchRegister(moves, i);
if (reg.isSome())
masm.mov(ImmWord(0xdeadbeef), reg.value());
}
#endif
const MoveOp& move = moves.getMove(i);
const MoveOperand& from = move.from();
const MoveOperand& to = move.to();
@ -144,10 +154,10 @@ MoveEmitterX86::emit(const MoveResolver& moves)
emitDoubleMove(from, to);
break;
case MoveOp::INT32:
emitInt32Move(from, to);
emitInt32Move(from, to, moves, i);
break;
case MoveOp::GENERAL:
emitGeneralMove(from, to);
emitGeneralMove(from, to, moves, i);
break;
case MoveOp::INT32X4:
emitInt32X4Move(from, to);
@ -363,7 +373,8 @@ MoveEmitterX86::completeCycle(const MoveOperand& to, MoveOp::Type type)
}
void
MoveEmitterX86::emitInt32Move(const MoveOperand& from, const MoveOperand& to)
MoveEmitterX86::emitInt32Move(const MoveOperand& from, const MoveOperand& to,
const MoveResolver& moves, size_t i)
{
if (from.isGeneralReg()) {
masm.move32(from.reg(), toOperand(to));
@ -373,10 +384,10 @@ MoveEmitterX86::emitInt32Move(const MoveOperand& from, const MoveOperand& to)
} else {
// Memory to memory gpr move.
MOZ_ASSERT(from.isMemory());
if (hasScratchRegister()) {
Register reg = scratchRegister();
masm.load32(toAddress(from), reg);
masm.move32(reg, toOperand(to));
Maybe<Register> reg = findScratchRegister(moves, i);
if (reg.isSome()) {
masm.load32(toAddress(from), reg.value());
masm.move32(reg.value(), toOperand(to));
} else {
// No scratch register available; bounce it off the stack.
masm.Push(toOperand(from));
@ -386,7 +397,8 @@ MoveEmitterX86::emitInt32Move(const MoveOperand& from, const MoveOperand& to)
}
void
MoveEmitterX86::emitGeneralMove(const MoveOperand& from, const MoveOperand& to)
MoveEmitterX86::emitGeneralMove(const MoveOperand& from, const MoveOperand& to,
const MoveResolver& moves, size_t i)
{
if (from.isGeneralReg()) {
masm.mov(from.reg(), toOperand(to));
@ -398,10 +410,10 @@ MoveEmitterX86::emitGeneralMove(const MoveOperand& from, const MoveOperand& to)
masm.lea(toOperand(from), to.reg());
} else if (from.isMemory()) {
// Memory to memory gpr move.
if (hasScratchRegister()) {
Register reg = scratchRegister();
masm.loadPtr(toAddress(from), reg);
masm.mov(reg, toOperand(to));
Maybe<Register> reg = findScratchRegister(moves, i);
if (reg.isSome()) {
masm.loadPtr(toAddress(from), reg.value());
masm.mov(reg.value(), toOperand(to));
} else {
// No scratch register available; bounce it off the stack.
masm.Push(toOperand(from));
@ -410,10 +422,10 @@ MoveEmitterX86::emitGeneralMove(const MoveOperand& from, const MoveOperand& to)
} else {
// Effective address to memory move.
MOZ_ASSERT(from.isEffectiveAddress());
if (hasScratchRegister()) {
Register reg = scratchRegister();
masm.lea(toOperand(from), reg);
masm.mov(reg, toOperand(to));
Maybe<Register> reg = findScratchRegister(moves, i);
if (reg.isSome()) {
masm.lea(toOperand(from), reg.value());
masm.mov(reg.value(), toOperand(to));
} else {
// This is tricky without a scratch reg. We can't do an lea. Bounce the
// base register off the stack, then add the offset in place. Note that
@ -523,3 +535,34 @@ MoveEmitterX86::finish()
masm.freeStack(masm.framePushed() - pushedAtStart_);
}
Maybe<Register>
MoveEmitterX86::findScratchRegister(const MoveResolver& moves, size_t initial)
{
#ifdef JS_CODEGEN_X86
if (scratchRegister_.isSome())
return scratchRegister_;
// All registers are either in use by this move group or are live
// afterwards. Look through the remaining moves for a register which is
// clobbered before it is used, and is thus dead at this point.
AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
for (size_t i = initial; i < moves.numMoves(); i++) {
const MoveOp& move = moves.getMove(i);
if (move.from().isGeneralReg())
regs.takeUnchecked(move.from().reg());
else if (move.from().isMemoryOrEffectiveAddress())
regs.takeUnchecked(move.from().base());
if (move.to().isGeneralReg()) {
if (i != initial && !move.isCycleBegin() && regs.has(move.to().reg()))
return mozilla::Some(move.to().reg());
regs.takeUnchecked(move.to().reg());
} else if (move.to().isMemoryOrEffectiveAddress()) {
regs.takeUnchecked(move.to().base());
}
}
return mozilla::Nothing();
#else
return mozilla::Some(ScratchReg);
#endif
}

View File

@ -40,8 +40,10 @@ class MoveEmitterX86
bool* allGeneralRegs, bool* allFloatRegs);
bool maybeEmitOptimizedCycle(const MoveResolver& moves, size_t i,
bool allGeneralRegs, bool allFloatRegs, size_t swapCount);
void emitInt32Move(const MoveOperand& from, const MoveOperand& to);
void emitGeneralMove(const MoveOperand& from, const MoveOperand& to);
void emitInt32Move(const MoveOperand& from, const MoveOperand& to,
const MoveResolver& moves, size_t i);
void emitGeneralMove(const MoveOperand& from, const MoveOperand& to,
const MoveResolver& moves, size_t i);
void emitFloat32Move(const MoveOperand& from, const MoveOperand& to);
void emitDoubleMove(const MoveOperand& from, const MoveOperand& to);
void emitFloat32X4Move(const MoveOperand& from, const MoveOperand& to);
@ -61,22 +63,7 @@ class MoveEmitterX86
#endif
}
bool hasScratchRegister() {
#ifdef JS_CODEGEN_X86
return scratchRegister_.isSome();
#else
return true;
#endif
}
Register scratchRegister() {
MOZ_ASSERT(hasScratchRegister());
#ifdef JS_CODEGEN_X86
return scratchRegister_.value();
#else
return ScratchReg;
#endif
}
mozilla::Maybe<Register> findScratchRegister(const MoveResolver& moves, size_t i);
};
typedef MoveEmitterX86 MoveEmitter;

View File

@ -49,7 +49,7 @@ BEGIN_TEST(testDefinePropertyIgnoredAttributes)
JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_PERMANENT | JSPROP_SHARED,
Getter));
CHECK(JS_GetPropertyDescriptor(cx, obj, "foo", &desc));
CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "foo", &desc));
// Note that JSPROP_READONLY is meaningless for accessor properties.
CHECK(CheckDescriptor(desc, AccessorDescriptor, false, true, false));
@ -58,7 +58,7 @@ BEGIN_TEST(testDefinePropertyIgnoredAttributes)
CHECK(JS_DefineProperty(cx, obj, "bar", defineValue,
JSPROP_IGNORE_ENUMERATE | JSPROP_SHARED,
Getter));
CHECK(JS_GetPropertyDescriptor(cx, obj, "bar", &desc));
CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "bar", &desc));
CHECK(CheckDescriptor(desc, AccessorDescriptor, false, true, true));
// Rewrite the descriptor to now be enumerable, leaving the configurability
@ -66,7 +66,7 @@ BEGIN_TEST(testDefinePropertyIgnoredAttributes)
CHECK(JS_DefineProperty(cx, obj, "bar", defineValue,
JSPROP_IGNORE_PERMANENT | JSPROP_ENUMERATE | JSPROP_SHARED,
Getter));
CHECK(JS_GetPropertyDescriptor(cx, obj, "bar", &desc));
CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "bar", &desc));
CHECK(CheckDescriptor(desc, AccessorDescriptor, true, true, true));
// Now try the same game with a value property
@ -75,13 +75,13 @@ BEGIN_TEST(testDefinePropertyIgnoredAttributes)
JSPROP_IGNORE_ENUMERATE |
JSPROP_IGNORE_READONLY |
JSPROP_IGNORE_PERMANENT));
CHECK(JS_GetPropertyDescriptor(cx, obj, "baz", &desc));
CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "baz", &desc));
CHECK(CheckDescriptor(desc, DataDescriptor, false, false, false));
// Now again with a configurable property
CHECK(JS_DefineProperty(cx, obj, "quux", defineValue,
JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY));
CHECK(JS_GetPropertyDescriptor(cx, obj, "quux", &desc));
CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "quux", &desc));
CHECK(CheckDescriptor(desc, DataDescriptor, false, false, true));
// Just make it writable. Leave the old value and everything else alone.
@ -91,7 +91,7 @@ BEGIN_TEST(testDefinePropertyIgnoredAttributes)
JSPROP_IGNORE_PERMANENT |
JSPROP_IGNORE_VALUE));
CHECK(JS_GetPropertyDescriptor(cx, obj, "quux", &desc));
CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "quux", &desc));
CHECK(CheckDescriptor(desc, DataDescriptor, false, true, true));
CHECK_SAME(JS::ObjectValue(*obj), desc.value());

View File

@ -2169,7 +2169,10 @@ js::array_shift(JSContext* cx, unsigned argc, Value* vp)
if (!SetLengthProperty(cx, obj, newlen))
return false;
return SuppressDeletedProperty(cx, obj, INT_TO_JSID(newlen));
RootedId id(cx);
if (!IndexToId(cx, newlen, &id))
return false;
return SuppressDeletedProperty(cx, obj, id);
}
/* Steps 5, 10. */

View File

@ -0,0 +1,10 @@
// Make sure that we can plumb new.target, even if the results are going to
// throw.
assertThrowsInstanceOf(() => new ""(...Array()), TypeError);
assertThrowsInstanceOf(() => new ""(), TypeError);
assertThrowsInstanceOf(() => new ""(1), TypeError);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -4587,10 +4587,8 @@ js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, Hand
if (!GetElements(cx, aobj, length, args.array()))
return false;
if (constructing) {
MOZ_ASSERT(newTarget.isObject());
if (constructing)
args.newTarget().set(newTarget);
}
switch (op) {
case JSOP_SPREADNEW:

View File

@ -1261,25 +1261,33 @@ nsGridContainerFrame::ReflowChildren(GridItemCSSOrderIterator& aIter,
} else {
cb = aContentArea;
}
nsHTMLReflowState childRS(pc, aReflowState, child, cb.Size(wm));
WritingMode childWM = child->GetWritingMode();
LogicalSize childCBSize = cb.Size(wm).ConvertTo(childWM, wm);
nsHTMLReflowState childRS(pc, aReflowState, child, childCBSize);
const LogicalMargin margin = childRS.ComputedLogicalMargin();
if (childRS.ComputedBSize() == NS_AUTOHEIGHT && MOZ_LIKELY(isGridItem)) {
// XXX the start of an align-self:stretch impl. Needs min-/max-bsize
// clamping though, and check the prop value is actually 'stretch'!
LogicalMargin bp = childRS.ComputedLogicalBorderPadding();
bp.ApplySkipSides(child->GetLogicalSkipSides());
nscoord bSize = cb.BSize(wm) - bp.BStartEnd(wm) - margin.BStartEnd(wm);
nscoord bSize = childCBSize.BSize(childWM) - bp.BStartEnd(childWM) -
margin.BStartEnd(childWM);
childRS.SetComputedBSize(std::max(bSize, 0));
}
LogicalPoint childPos = cb.Origin(wm);
childPos.I(wm) += margin.IStart(wm);
childPos.B(wm) += margin.BStart(wm);
// We need the width of the child before we can correctly convert
// the writing-mode of its origin, so we reflow at (0, 0) and then
// pass the correct position to FinishReflowChild.
nsHTMLReflowMetrics childSize(childRS);
nsReflowStatus childStatus;
ReflowChild(child, pc, childSize, childRS, wm, childPos,
containerWidth, 0, childStatus);
ReflowChild(child, pc, childSize, childRS, childWM, LogicalPoint(childWM),
0, 0, childStatus);
LogicalPoint childPos =
cb.Origin(wm).ConvertTo(childWM, wm, containerWidth - childSize.Width() -
margin.LeftRight(childWM));
childPos.I(childWM) += margin.IStart(childWM);
childPos.B(childWM) += margin.BStart(childWM);
childRS.ApplyRelativePositioning(&childPos, containerWidth);
FinishReflowChild(child, pc, childSize, &childRS, wm, childPos,
FinishReflowChild(child, pc, childSize, &childRS, childWM, childPos,
containerWidth, 0);
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
// XXX deal with 'childStatus' not being COMPLETE

View File

@ -0,0 +1,45 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
.grid {
border: 1px solid gray;
font-size: 0;
}
.grid > div {
display: inline-block;
margin: 2px;
}
#a { background: #006; height: 46px; width: 96px; }
#b { background: #009; height: 46px; width: 146px; }
#c { background: #00c; height: 46px; width: 46px; }
#d { background: #00f; height: 46px; width: 16px; }
#e { background: #060; height: 96px; width: 96px; }
#f { background: #090; height: 96px; width: 146px; }
#g { background: #0c0; height: 96px; width: 46px; }
#h { background: #0f0; height: 96px; width: 16px; }
#i { background: #600; height: 16px; width: 96px; }
#j { background: #900; height: 16px; width: 146px; }
#k { background: #c00; height: 16px; width: 46px; }
#l { background: #f00; height: 16px; width: 16px; }
</style>
</head>
<body>
<div class=grid>
<div id=a></div>
<div id=b></div>
<div id=c></div>
<div id=d></div><br>
<div id=e></div>
<div id=f></div>
<div id=g></div>
<div id=h></div><br>
<div id=i></div>
<div id=j></div>
<div id=k></div>
<div id=l></div>
</div>
</body>
</html>

View File

@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
.grid {
display: grid;
border: 1px solid gray;
grid-template-columns: 100px 150px 50px 20px;
grid-template-rows: 50px 100px 20px;
}
.grid > div {
margin: 2px;
}
#a { background: #006; }
#b { background: #009; }
#c { background: #00c; }
#d { background: #00f; }
#e { background: #060; }
#f { background: #090; }
#g { background: #0c0; }
#h { background: #0f0; }
#i { background: #600; }
#j { background: #900; }
#k { background: #c00; }
#l { background: #f00; }
</style>
</head>
<body>
<div class=grid>
<div id=a></div>
<div id=b></div>
<div id=c></div>
<div id=d></div>
<div id=e dir=rtl></div>
<div id=f dir=rtl></div>
<div id=g dir=rtl></div>
<div id=h dir=rtl></div>
<div id=i></div>
<div id=j dir=rtl></div>
<div id=k></div>
<div id=l dir=rtl></div>
</div>
</body>
</html>

View File

@ -25,3 +25,4 @@ pref(layout.css.vertical-text.enabled,true) == rtl-grid-placement-auto-row-spars
pref(layout.css.vertical-text.enabled,true) == vlr-grid-placement-auto-row-sparse-001.html vlr-grid-placement-auto-row-sparse-001-ref.html
pref(layout.css.vertical-text.enabled,true) == vrl-grid-placement-auto-row-sparse-001.html vrl-grid-placement-auto-row-sparse-001-ref.html
== grid-relpos-items-001.html grid-relpos-items-001-ref.html
== grid-item-dir-001.html grid-item-dir-001-ref.html

View File

@ -243,7 +243,11 @@ ErrorReporter::AddToError(const nsString &aErrorText)
// for all errors on that line. That causes the text of the line to
// be shared among all the nsIScriptError objects.
if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
mErrorLine = mScanner->GetCurrentLine();
// Be careful here: the error line might be really long and OOM
// when we try to make a copy here. If so, just leave it empty.
if (!mErrorLine.Assign(mScanner->GetCurrentLine(), fallible)) {
mErrorLine.Truncate();
}
mPrevErrorLineNumber = mErrorLineNumber;
}
} else {

View File

@ -159,6 +159,7 @@ nsTableFrame::Init(nsIContent* aContent,
nsIFrame* aPrevInFlow)
{
NS_PRECONDITION(!mCellMap, "Init called twice");
NS_PRECONDITION(!mTableLayoutStrategy, "Init called twice");
NS_PRECONDITION(!aPrevInFlow ||
aPrevInFlow->GetType() == nsGkAtoms::tableFrame,
"prev-in-flow must be of same type");
@ -171,24 +172,20 @@ nsTableFrame::Init(nsIContent* aContent,
bool borderCollapse = (NS_STYLE_BORDER_COLLAPSE == tableStyle->mBorderCollapse);
SetBorderCollapse(borderCollapse);
// Create the cell map if this frame is the first-in-flow.
if (!aPrevInFlow) {
// If we're the first-in-flow, we manage the cell map & layout strategy that
// get used by our continuation chain:
mCellMap = new nsTableCellMap(*this, borderCollapse);
}
if (aPrevInFlow) {
if (IsAutoLayout()) {
mTableLayoutStrategy = new BasicTableLayoutStrategy(this);
} else {
mTableLayoutStrategy = new FixedTableLayoutStrategy(this);
}
} else {
// set my width, because all frames in a table flow are the same width and
// code in nsTableOuterFrame depends on this being set
mRect.width = aPrevInFlow->GetSize().width;
}
else {
NS_ASSERTION(!mTableLayoutStrategy, "strategy was created before Init was called");
// create the strategy
if (IsAutoLayout())
mTableLayoutStrategy = new BasicTableLayoutStrategy(this);
else
mTableLayoutStrategy = new FixedTableLayoutStrategy(this);
}
}
nsTableFrame::~nsTableFrame()
@ -305,8 +302,7 @@ nsTableFrame::UnregisterPositionedTablePart(nsIFrame* aFrame,
static_cast<FrameTArray*>(props.Get(PositionedTablePartArray()));
// Remove the frame.
MOZ_ASSERT(positionedParts &&
positionedParts->IndexOf(aFrame) != FrameTArray::NoIndex,
MOZ_ASSERT(positionedParts && positionedParts->Contains(aFrame),
"Asked to unregister a positioned table part that wasn't registered");
if (positionedParts) {
positionedParts->RemoveElement(aFrame);
@ -1792,7 +1788,7 @@ nsTableFrame::Reflow(nsPresContext* aPresContext,
aStatus = NS_FRAME_COMPLETE;
if (!GetPrevInFlow() && !mTableLayoutStrategy) {
NS_ASSERTION(false, "strategy should have been created in Init");
NS_ERROR("strategy should have been created in Init");
return;
}
@ -1892,7 +1888,7 @@ nsTableFrame::Reflow(nsPresContext* aPresContext,
}
else {
// Calculate the overflow area contribution from our children.
for (nsIFrame* kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
for (nsIFrame* kid : mFrames) {
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kid);
}
}
@ -2051,7 +2047,7 @@ nsTableFrame::GetFirstBodyRowGroupFrame()
nsIFrame* headerFrame = nullptr;
nsIFrame* footerFrame = nullptr;
for (nsIFrame* kidFrame = mFrames.FirstChild(); nullptr != kidFrame; ) {
for (nsIFrame* kidFrame : mFrames) {
const nsStyleDisplay* childDisplay = kidFrame->StyleDisplay();
// We expect the header and footer row group frames to be first, and we only
@ -2075,9 +2071,6 @@ nsTableFrame::GetFirstBodyRowGroupFrame()
} else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay) {
return kidFrame;
}
// Get the next child
kidFrame = kidFrame->GetNextSibling();
}
return nullptr;
@ -2170,8 +2163,7 @@ nsTableFrame::GetCollapsedWidth(nsMargin aBorderPadding)
NS_ASSERTION(!GetPrevInFlow(), "GetCollapsedWidth called on next in flow");
nscoord width = GetColSpacing(GetColCount());
width += aBorderPadding.left + aBorderPadding.right;
for (nsIFrame* groupFrame = mColGroups.FirstChild(); groupFrame;
groupFrame = groupFrame->GetNextSibling()) {
for (nsIFrame* groupFrame : mColGroups) {
const nsStyleVisibility* groupVis = groupFrame->StyleVisibility();
bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
nsTableColGroupFrame* cgFrame = (nsTableColGroupFrame*)groupFrame;
@ -3200,8 +3192,7 @@ nsTableFrame::ReflowColGroups(nsRenderingContext *aRenderingContext)
if (!GetPrevInFlow() && !HaveReflowedColGroups()) {
nsHTMLReflowMetrics kidMet(GetWritingMode());
nsPresContext *presContext = PresContext();
for (nsIFrame* kidFrame = mColGroups.FirstChild(); kidFrame;
kidFrame = kidFrame->GetNextSibling()) {
for (nsIFrame* kidFrame : mColGroups) {
if (NS_SUBTREE_DIRTY(kidFrame)) {
// The column groups don't care about dimensions or reflow states.
nsHTMLReflowState
@ -3223,7 +3214,7 @@ nsTableFrame::CalcDesiredHeight(const nsHTMLReflowState& aReflowState,
{
nsTableCellMap* cellMap = GetCellMap();
if (!cellMap) {
NS_ASSERTION(false, "never ever call me until the cell map is built!");
NS_ERROR("never ever call me until the cell map is built!");
aDesiredSize.Height() = 0;
return;
}
@ -3267,7 +3258,7 @@ nsTableFrame::CalcDesiredHeight(const nsHTMLReflowState& aReflowState,
// unconstrained row group.
DistributeHeightToRows(aReflowState, tableSpecifiedHeight - desiredHeight);
// this might have changed the overflow area incorporate the childframe overflow area.
for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame; kidFrame = kidFrame->GetNextSibling()) {
for (nsIFrame* kidFrame : mFrames) {
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame);
}
desiredHeight = tableSpecifiedHeight;
@ -3875,8 +3866,7 @@ nsTableFrame::Dump(bool aDumpRows,
}
}
printf("\n colgroups->");
for (nsIFrame* childFrame = mColGroups.FirstChild(); childFrame;
childFrame = childFrame->GetNextSibling()) {
for (nsIFrame* childFrame : mColGroups) {
if (nsGkAtoms::tableColGroupFrame == childFrame->GetType()) {
nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame *)childFrame;
colGroupFrame->Dump(1);
@ -4407,7 +4397,7 @@ BCMapCellInfo::SetInfo(nsTableRowFrame* aNewRow,
NS_ASSERTION(mEndRow, "spanned row not found");
}
else {
NS_ASSERTION(false, "error in cell map");
NS_ERROR("error in cell map");
mRowSpan = 1;
mEndRow = mStartRow;
}
@ -6996,7 +6986,7 @@ BCVerticalSeg::Paint(BCPaintBorderIterator& aIter,
owner = mFirstRowGroup;
break;
case eAjaRowOwner:
NS_ASSERTION(false, "program error"); // and fall through
NS_ERROR("program error"); // and fall through
case eRowOwner:
NS_ASSERTION(aIter.IsTableLeftMost() || aIter.IsTableRightMost(),
"row can own border only at table edge");

View File

@ -17,29 +17,54 @@ namespace mozilla {
class DataBuffer {
public:
DataBuffer() : data_(nullptr), len_(0) {}
DataBuffer() : data_(nullptr), len_(0), capacity_(0) {}
DataBuffer(const uint8_t *data, size_t len) {
Assign(data, len);
Assign(data, len, len);
}
DataBuffer(const uint8_t *data, size_t len, size_t capacity) {
Assign(data, len, capacity);
}
void Assign(const uint8_t *data, size_t len) {
Allocate(len);
// to ensure extra space for expansion
void Assign(const uint8_t *data, size_t len, size_t capacity) {
MOZ_RELEASE_ASSERT(len <= capacity);
Allocate(capacity); // sets len_ = capacity
memcpy(static_cast<void *>(data_.get()),
static_cast<const void *>(data), len);
len_ = len;
}
void Allocate(size_t len) {
data_.reset(new uint8_t[len ? len : 1]); // Don't depend on new [0].
void Allocate(size_t capacity) {
data_.reset(new uint8_t[capacity ? capacity : 1]); // Don't depend on new [0].
len_ = capacity_ = capacity;
}
void EnsureCapacity(size_t capacity) {
if (capacity_ < capacity) {
uint8_t *new_data = new uint8_t[ capacity ? capacity : 1];
memcpy(static_cast<void *>(new_data),
static_cast<const void *>(data_.get()), len_);
data_.reset(new_data); // after copying! Deletes old data
capacity_ = capacity;
}
}
// used when something writes to the buffer (having checked
// capacity() or used EnsureCapacity()) and increased the length.
void SetLength(size_t len) {
MOZ_RELEASE_ASSERT(len <= capacity_);
len_ = len;
}
const uint8_t *data() const { return data_.get(); }
uint8_t *data() { return data_.get(); }
size_t len() const { return len_; }
size_t capacity() const { return capacity_; }
private:
UniquePtr<uint8_t[]> data_;
size_t len_;
size_t capacity_;
DISALLOW_COPY_ASSIGN(DataBuffer);
};

View File

@ -69,7 +69,6 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
{
delete mRecvCodecList[i];
}
delete mCurSendCodecConfig;
// The first one of a pair to be deleted shuts down media for both
if(mPtrVoEXmedia)
@ -360,10 +359,12 @@ WebrtcAudioConduit::ConfigureSendMediaCodec(const AudioCodecConfig* codecConfig)
int error = 0;//webrtc engine errors
webrtc::CodecInst cinst;
//validate codec param
if((condError = ValidateCodecConfig(codecConfig, true)) != kMediaConduitNoError)
{
return condError;
//validate codec param
if((condError = ValidateCodecConfig(codecConfig, true)) != kMediaConduitNoError)
{
return condError;
}
}
condError = StopTransmitting();
@ -411,16 +412,17 @@ WebrtcAudioConduit::ConfigureSendMediaCodec(const AudioCodecConfig* codecConfig)
return condError;
}
//Copy the applied config for future reference.
delete mCurSendCodecConfig;
mCurSendCodecConfig = new AudioCodecConfig(codecConfig->mType,
codecConfig->mName,
codecConfig->mFreq,
codecConfig->mPacSize,
codecConfig->mChannels,
codecConfig->mRate);
{
MutexAutoLock lock(mCodecMutex);
//Copy the applied config for future reference.
mCurSendCodecConfig = new AudioCodecConfig(codecConfig->mType,
codecConfig->mName,
codecConfig->mFreq,
codecConfig->mPacSize,
codecConfig->mChannels,
codecConfig->mRate);
}
return kMediaConduitNoError;
}
@ -1018,7 +1020,7 @@ WebrtcAudioConduit::CheckCodecForMatch(const AudioCodecConfig* codecInfo) const
*/
MediaConduitErrorCode
WebrtcAudioConduit::ValidateCodecConfig(const AudioCodecConfig* codecInfo,
bool send) const
bool send)
{
bool codecAppliedAlready = false;
@ -1045,6 +1047,8 @@ WebrtcAudioConduit::ValidateCodecConfig(const AudioCodecConfig* codecInfo,
//check if we have the same codec already applied
if(send)
{
MutexAutoLock lock(mCodecMutex);
codecAppliedAlready = CheckCodecsForMatch(mCurSendCodecConfig,codecInfo);
} else {
codecAppliedAlready = CheckCodecForMatch(codecInfo);

View File

@ -169,7 +169,7 @@ public:
mEngineTransmitting(false),
mEngineReceiving(false),
mChannel(-1),
mCurSendCodecConfig(nullptr),
mCodecMutex("AudioConduit codec db"),
mCaptureDelay(150),
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
mLastTimestamp(0),
@ -245,7 +245,7 @@ private:
bool CheckCodecsForMatch(const AudioCodecConfig* curCodecConfig,
const AudioCodecConfig* codecInfo) const;
//Checks the codec to be applied
MediaConduitErrorCode ValidateCodecConfig(const AudioCodecConfig* codecInfo, bool send) const;
MediaConduitErrorCode ValidateCodecConfig(const AudioCodecConfig* codecInfo, bool send);
//Utility function to dump recv codec database
void DumpCodecDB() const;
@ -277,7 +277,9 @@ private:
int mChannel;
RecvCodecList mRecvCodecList;
AudioCodecConfig* mCurSendCodecConfig;
Mutex mCodecMutex; // protects mCurSendCodecConfig
nsAutoPtr<AudioCodecConfig> mCurSendCodecConfig;
// Current "capture" delay (really output plus input delay)
int32_t mCaptureDelay;

View File

@ -74,7 +74,7 @@ WebrtcVideoConduit::WebrtcVideoConduit():
mEngineReceiving(false),
mChannel(-1),
mCapId(-1),
mCurSendCodecConfig(nullptr),
mCodecMutex("VideoConduit codec db"),
mSendingWidth(0),
mSendingHeight(0),
mReceivingWidth(640),
@ -101,8 +101,6 @@ WebrtcVideoConduit::~WebrtcVideoConduit()
delete mRecvCodecList[i];
}
delete mCurSendCodecConfig;
// The first one of a pair to be deleted shuts down media for both
//Deal with External Capturer
if(mPtrViECapture)
@ -236,8 +234,9 @@ bool WebrtcVideoConduit::GetVideoEncoderStats(double* framerateMean,
// unchanged resolution, but adjust bandwidth limits to match camera fps
CSFLogDebug(logTag, "Encoder frame rate changed from %f to %f",
(mLastFramerateTenths/10.0), *framerateMean);
MutexAutoLock lock(mCodecMutex);
mLastFramerateTenths = *framerateMean * 10;
SelectSendResolution(mSendingWidth, mSendingHeight, true);
SelectSendResolution(mSendingWidth, mSendingHeight);
}
return true;
}
@ -595,6 +594,12 @@ WebrtcVideoConduit::ConfigureCodecMode(webrtc::VideoCodecMode mode)
/**
* Note: Setting the send-codec on the Video Engine will restart the encoder,
* sets up new SSRC and reset RTP_RTCP module with the new codec setting.
*
* Note: this is called from MainThread, and the codec settings are read on
* videoframe delivery threads (i.e in SendVideoFrame(). With
* renegotiation/reconfiguration, this now needs a lock! Alternatively
* changes could be queued until the next frame is delivered using an
* Atomic pointer and swaps.
*/
MediaConduitErrorCode
WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig)
@ -608,16 +613,12 @@ WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig)
memset(&video_codec, 0, sizeof(video_codec));
//validate basic params
if((condError = ValidateCodecConfig(codecConfig,true)) != kMediaConduitNoError)
{
return condError;
}
//Check if we have same codec already applied
if(CheckCodecsForMatch(mCurSendCodecConfig, codecConfig))
{
CSFLogDebug(logTag, "%s Codec has been applied already ", __FUNCTION__);
//validate basic params
if((condError = ValidateCodecConfig(codecConfig,true)) != kMediaConduitNoError)
{
return condError;
}
}
condError = StopTransmitting();
@ -709,10 +710,12 @@ WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig)
return condError;
}
//Copy the applied config for future reference.
delete mCurSendCodecConfig;
{
MutexAutoLock lock(mCodecMutex);
mCurSendCodecConfig = new VideoCodecConfig(*codecConfig);
//Copy the applied config for future reference.
mCurSendCodecConfig = new VideoCodecConfig(*codecConfig);
}
mPtrRTP->SetRembStatus(mChannel, true, false);
@ -997,11 +1000,12 @@ WebrtcVideoConduit::SelectBandwidth(webrtc::VideoCodec& vie_codec,
// XXX we need to figure out how to feed back changes in preferred capture
// resolution to the getUserMedia source
// Invoked under lock of mCodecMutex!
bool
WebrtcVideoConduit::SelectSendResolution(unsigned short width,
unsigned short height,
bool force)
unsigned short height)
{
mCodecMutex.AssertCurrentThreadOwns();
// XXX This will do bandwidth-resolution adaptation as well - bug 877954
// Limit resolution to max-fs while keeping same aspect ratio as the
@ -1071,15 +1075,25 @@ WebrtcVideoConduit::SelectSendResolution(unsigned short width,
// Adapt to getUserMedia resolution changes
// check if we need to reconfigure the sending resolution.
// force tells us to do it regardless, such as when the FPS changes
if (mSendingWidth != width || mSendingHeight != height || force)
bool changed = false;
if (mSendingWidth != width || mSendingHeight != height)
{
// This will avoid us continually retrying this operation if it fails.
// If the resolution changes, we'll try again. In the meantime, we'll
// keep using the old size in the encoder.
mSendingWidth = width;
mSendingHeight = height;
changed = true;
}
// uses mSendingWidth/Height
unsigned int framerate = SelectSendFrameRate(mSendingFramerate);
if (mSendingFramerate != framerate) {
mSendingFramerate = framerate;
changed = true;
}
if (changed) {
// Get current vie codec.
webrtc::VideoCodec vie_codec;
int32_t err;
@ -1089,10 +1103,13 @@ WebrtcVideoConduit::SelectSendResolution(unsigned short width,
CSFLogError(logTag, "%s: GetSendCodec failed, err %d", __FUNCTION__, err);
return false;
}
if (vie_codec.width != width || vie_codec.height != height || force)
// Likely spurious unless there was some error, but rarely checked
if (vie_codec.width != width || vie_codec.height != height ||
vie_codec.maxFramerate != mSendingFramerate)
{
vie_codec.width = width;
vie_codec.height = height;
vie_codec.maxFramerate = mSendingFramerate;
SelectBandwidth(vie_codec, width, height);
if ((err = mPtrViECodec->SetSendCodec(mChannel, vie_codec)) != 0)
@ -1101,19 +1118,22 @@ WebrtcVideoConduit::SelectSendResolution(unsigned short width,
__FUNCTION__, width, height, err);
return false;
}
CSFLogDebug(logTag, "%s: Encoder resolution changed to %ux%u, bitrate %u:%u",
__FUNCTION__, width, height,
CSFLogDebug(logTag, "%s: Encoder resolution changed to %ux%u @ %ufps, bitrate %u:%u",
__FUNCTION__, width, height, mSendingFramerate,
vie_codec.minBitrate, vie_codec.maxBitrate);
} // else no change; mSendingWidth likely was 0
}
return true;
}
// TODO(ruil2@cisco.com):combine SelectSendResolution with SelectSendFrameRate Bug 1132318
bool
WebrtcVideoConduit::SelectSendFrameRate(unsigned int framerate)
// Invoked under lock of mCodecMutex!
unsigned int
WebrtcVideoConduit::SelectSendFrameRate(unsigned int framerate) const
{
mCodecMutex.AssertCurrentThreadOwns();
unsigned int new_framerate = framerate;
// Limit frame rate based on max-mbps
mSendingFramerate = framerate;
if (mCurSendCodecConfig && mCurSendCodecConfig->mMaxMBPS)
{
unsigned int cur_fs, mb_width, mb_height, max_fps;
@ -1124,39 +1144,15 @@ WebrtcVideoConduit::SelectSendFrameRate(unsigned int framerate)
cur_fs = mb_width * mb_height;
max_fps = mCurSendCodecConfig->mMaxMBPS/cur_fs;
if (max_fps < mSendingFramerate) {
mSendingFramerate = max_fps;
new_framerate = max_fps;
}
if (mCurSendCodecConfig->mMaxFrameRate != 0 &&
mCurSendCodecConfig->mMaxFrameRate < mSendingFramerate) {
mSendingFramerate = mCurSendCodecConfig->mMaxFrameRate;
new_framerate = mCurSendCodecConfig->mMaxFrameRate;
}
}
if (mSendingFramerate != framerate)
{
// Get current vie codec.
webrtc::VideoCodec vie_codec;
int32_t err;
if ((err = mPtrViECodec->GetSendCodec(mChannel, vie_codec)) != 0)
{
CSFLogError(logTag, "%s: GetSendCodec failed, err %d", __FUNCTION__, err);
return false;
}
if (vie_codec.maxFramerate != mSendingFramerate)
{
vie_codec.maxFramerate = mSendingFramerate;
if ((err = mPtrViECodec->SetSendCodec(mChannel, vie_codec)) != 0)
{
CSFLogError(logTag, "%s: SetSendCodec(%u) failed, err %d",
__FUNCTION__, mSendingFramerate, err);
return false;
}
CSFLogDebug(logTag, "%s: Encoder framerate changed to %u",
__FUNCTION__, mSendingFramerate);
}
}
return true;
return new_framerate;
}
MediaConduitErrorCode
@ -1221,13 +1217,12 @@ WebrtcVideoConduit::SendVideoFrame(unsigned char* video_frame,
return kMediaConduitSessionNotInited;
}
if (!SelectSendResolution(width, height, false))
{
return kMediaConduitCaptureError;
}
if (!SelectSendFrameRate(mSendingFramerate))
{
return kMediaConduitCaptureError;
MutexAutoLock lock(mCodecMutex);
if (!SelectSendResolution(width, height))
{
return kMediaConduitCaptureError;
}
}
// insert the frame to video engine in I420 format only
MOZ_ASSERT(mPtrExtCapture);
@ -1609,7 +1604,7 @@ WebrtcVideoConduit::CheckCodecForMatch(const VideoCodecConfig* codecInfo) const
*/
MediaConduitErrorCode
WebrtcVideoConduit::ValidateCodecConfig(const VideoCodecConfig* codecInfo,
bool send) const
bool send)
{
bool codecAppliedAlready = false;
@ -1629,6 +1624,8 @@ WebrtcVideoConduit::ValidateCodecConfig(const VideoCodecConfig* codecInfo,
//check if we have the same codec already applied
if(send)
{
MutexAutoLock lock(mCodecMutex);
codecAppliedAlready = CheckCodecsForMatch(mCurSendCodecConfig,codecInfo);
} else {
codecAppliedAlready = CheckCodecForMatch(codecInfo);

View File

@ -145,15 +145,15 @@ public:
* @param force: force setting the codec config if framerate may require a bandwidth change
*/
bool SelectSendResolution(unsigned short width,
unsigned short height,
bool force);
unsigned short height);
/**
* Function to select and change the encoding frame rate based on incoming frame rate
* and max-mbps setting.
* @param framerate
* @param current framerate
* @result new framerate
*/
bool SelectSendFrameRate(unsigned int framerate);
unsigned int SelectSendFrameRate(unsigned int framerate) const;
/**
* Function to deliver a capture video frame for encoding and transport
@ -306,7 +306,7 @@ private:
const VideoCodecConfig* codecInfo) const;
//Checks the codec to be applied
MediaConduitErrorCode ValidateCodecConfig(const VideoCodecConfig* codecInfo, bool send) const;
MediaConduitErrorCode ValidateCodecConfig(const VideoCodecConfig* codecInfo, bool send);
//Utility function to dump recv codec database
void DumpCodecDB() const;
@ -337,7 +337,10 @@ private:
int mChannel; // Video Channel for this conduit
int mCapId; // Capturer for this conduit
RecvCodecList mRecvCodecList;
VideoCodecConfig* mCurSendCodecConfig;
Mutex mCodecMutex; // protects mCurrSendCodecConfig
nsAutoPtr<VideoCodecConfig> mCurSendCodecConfig;
unsigned short mSendingWidth;
unsigned short mSendingHeight;
unsigned short mReceivingWidth;

View File

@ -750,109 +750,85 @@ nsresult MediaPipeline::PipelineTransport::SendRtpPacket(
const void *data, int len) {
nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
len));
len, len + SRTP_MAX_EXPANSION));
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtpPacket_s,
buf),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf, true),
NS_DISPATCH_NORMAL);
return NS_OK;
}
nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s(
nsAutoPtr<DataBuffer> data) {
ASSERT_ON_THREAD(sts_thread_);
if (!pipeline_)
return NS_OK; // Detached
nsresult MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
nsAutoPtr<DataBuffer> data,
bool is_rtp) {
if (!pipeline_->rtp_.send_srtp_) {
MOZ_MTLOG(ML_DEBUG, "Couldn't write RTP packet; SRTP not set up yet");
ASSERT_ON_THREAD(sts_thread_);
if (!pipeline_) {
return NS_OK; // Detached
}
TransportInfo& transport = is_rtp ? pipeline_->rtp_ : pipeline_->rtcp_;
if (!transport.send_srtp_) {
MOZ_MTLOG(ML_DEBUG, "Couldn't write RTP/RTCP packet; SRTP not set up yet");
return NS_OK;
}
MOZ_ASSERT(pipeline_->rtp_.transport_);
NS_ENSURE_TRUE(pipeline_->rtp_.transport_, NS_ERROR_NULL_POINTER);
MOZ_ASSERT(transport.transport_);
NS_ENSURE_TRUE(transport.transport_, NS_ERROR_NULL_POINTER);
// libsrtp enciphers in place, so we need a new, big enough
// buffer.
// XXX. allocates and deletes one buffer per packet sent.
// Bug 822129
int max_len = data->len() + SRTP_MAX_EXPANSION;
ScopedDeletePtr<unsigned char> inner_data(
new unsigned char[max_len]);
memcpy(inner_data, data->data(), data->len());
// libsrtp enciphers in place, so we need a big enough buffer.
MOZ_ASSERT(data->capacity() >= data->len() + SRTP_MAX_EXPANSION);
int out_len;
nsresult res = pipeline_->rtp_.send_srtp_->ProtectRtp(inner_data,
data->len(),
max_len,
&out_len);
if (!NS_SUCCEEDED(res))
nsresult res;
if (is_rtp) {
res = transport.send_srtp_->ProtectRtp(data->data(),
data->len(),
data->capacity(),
&out_len);
} else {
res = transport.send_srtp_->ProtectRtcp(data->data(),
data->len(),
data->capacity(),
&out_len);
}
if (!NS_SUCCEEDED(res)) {
return res;
}
MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending RTP packet.");
pipeline_->increment_rtp_packets_sent(out_len);
return pipeline_->SendPacket(pipeline_->rtp_.transport_, inner_data,
out_len);
// paranoia; don't have uninitialized bytes included in data->len()
data->SetLength(out_len);
MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending " <<
(is_rtp ? "RTP" : "RTCP") << " packet");
if (is_rtp) {
pipeline_->increment_rtp_packets_sent(out_len);
} else {
pipeline_->increment_rtcp_packets_sent();
}
return pipeline_->SendPacket(transport.transport_, data->data(), out_len);
}
nsresult MediaPipeline::PipelineTransport::SendRtcpPacket(
const void *data, int len) {
nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
len));
len, len + SRTP_MAX_EXPANSION));
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtcpPacket_s,
buf),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf, false),
NS_DISPATCH_NORMAL);
return NS_OK;
}
nsresult MediaPipeline::PipelineTransport::SendRtcpPacket_s(
nsAutoPtr<DataBuffer> data) {
ASSERT_ON_THREAD(sts_thread_);
if (!pipeline_)
return NS_OK; // Detached
if (!pipeline_->rtcp_.send_srtp_) {
MOZ_MTLOG(ML_DEBUG, "Couldn't write RTCP packet; SRTCP not set up yet");
return NS_OK;
}
MOZ_ASSERT(pipeline_->rtcp_.transport_);
NS_ENSURE_TRUE(pipeline_->rtcp_.transport_, NS_ERROR_NULL_POINTER);
// libsrtp enciphers in place, so we need a new, big enough
// buffer.
// XXX. allocates and deletes one buffer per packet sent.
// Bug 822129.
int max_len = data->len() + SRTP_MAX_EXPANSION;
ScopedDeletePtr<unsigned char> inner_data(
new unsigned char[max_len]);
memcpy(inner_data, data->data(), data->len());
int out_len;
nsresult res = pipeline_->rtcp_.send_srtp_->ProtectRtcp(inner_data,
data->len(),
max_len,
&out_len);
if (!NS_SUCCEEDED(res))
return res;
MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending RTCP packet.");
pipeline_->increment_rtcp_packets_sent();
return pipeline_->SendPacket(pipeline_->rtcp_.transport_, inner_data,
out_len);
}
void MediaPipelineTransmit::PipelineListener::
UnsetTrackId(MediaStreamGraphImpl* graph) {
#ifndef USE_FAKE_MEDIA_STREAMS

View File

@ -191,8 +191,8 @@ class MediaPipeline : public sigslot::has_slots<> {
virtual nsresult SendRtcpPacket(const void* data, int len);
private:
virtual nsresult SendRtpPacket_s(nsAutoPtr<DataBuffer> data);
virtual nsresult SendRtcpPacket_s(nsAutoPtr<DataBuffer> data);
nsresult SendRtpRtcpPacket_s(nsAutoPtr<DataBuffer> data,
bool is_rtp);
MediaPipeline *pipeline_; // Raw pointer to avoid cycles
nsCOMPtr<nsIEventTarget> sts_thread_;

View File

@ -22,9 +22,9 @@ namespace mozilla {
#define SRTP_MASTER_SALT_LENGTH 14
#define SRTP_TOTAL_KEY_LENGTH (SRTP_MASTER_KEY_LENGTH + SRTP_MASTER_SALT_LENGTH)
// For some reason libsrtp increases packet size by > 12 for RTCP even though
// the doc claims otherwise.
#define SRTP_MAX_EXPANSION 20
// SRTCP requires an auth tag *plus* a 4-byte index-plus-'E'-bit value (see
// RFC 3711)
#define SRTP_MAX_EXPANSION (SRTP_MAX_TRAILER_LEN+4)
class SrtpFlow {

View File

@ -370,6 +370,8 @@ public:
bool IsDarkMatterMode() const { return mMode == DarkMatter; }
bool IsCumulativeMode() const { return mMode == Cumulative; }
const char* ModeString() const;
const char* DMDEnvVar() const { return mDMDEnvVar; }
size_t SampleBelowSize() const { return mSampleBelowSize.mActual; }
@ -1498,6 +1500,22 @@ Options::BadArg(const char* aArg)
exit(1);
}
const char*
Options::ModeString() const
{
switch (mMode) {
case Live:
return "live";
case DarkMatter:
return "dark-matter";
case Cumulative:
return "cumulative";
default:
MOZ_ASSERT(false);
return "(unknown DMD mode)";
}
}
//---------------------------------------------------------------------------
// DMD start-up
//---------------------------------------------------------------------------
@ -1780,19 +1798,7 @@ AnalyzeImpl(UniquePtr<JSONWriteFunc> aWriter)
writer.NullProperty("dmdEnvVar");
}
const char* mode;
if (gOptions->IsLiveMode()) {
mode = "live";
} else if (gOptions->IsDarkMatterMode()) {
mode = "dark-matter";
} else if (gOptions->IsCumulativeMode()) {
mode = "cumulative";
} else {
MOZ_ASSERT(false);
mode = "(unknown DMD mode)";
}
writer.StringProperty("mode", mode);
writer.StringProperty("mode", gOptions->ModeString());
writer.IntProperty("sampleBelowSize", gOptions->SampleBelowSize());
}
writer.EndObject();
@ -1818,7 +1824,6 @@ AnalyzeImpl(UniquePtr<JSONWriteFunc> aWriter)
}
writer.StringProperty("alloc", isc.ToIdString(b.AllocStackTrace()));
if (gOptions->IsDarkMatterMode() && b.NumReports() > 0) {
MOZ_ASSERT(gOptions->IsDarkMatterMode());
writer.StartArrayProperty("reps");
{
if (b.ReportStackTrace1()) {

View File

@ -916,3 +916,8 @@ pref("consoleservice.logcat", false);
#else
pref("consoleservice.logcat", true);
#endif
// Enable Service Workers for Android on non-release builds
#ifndef RELEASE_BUILD
pref("dom.serviceWorkers.enabled", true);
#endif

View File

@ -695,6 +695,16 @@ nsJARChannel::OverrideSecurityInfo(nsISupports* aSecurityInfo)
return NS_OK;
}
void
nsJARChannel::OverrideURI(nsIURI* aRedirectedURI)
{
MOZ_RELEASE_ASSERT(mLoadFlags & LOAD_REPLACE,
"This can only happen if the LOAD_REPLACE flag is set");
MOZ_RELEASE_ASSERT(ShouldIntercept(),
"This can only be called on channels that can be intercepted");
mAppURI = aRedirectedURI;
}
NS_IMETHODIMP
nsJARChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
{

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