Merge inbound to mozilla-central r=merge a=merge on a CLOSED TREE

This commit is contained in:
Bogdan Tara 2017-11-30 00:41:09 +02:00
Родитель dbf72d85a4 fba16646be
Коммит d8635b15e4
146 изменённых файлов: 2069 добавлений и 1117 удалений

Просмотреть файл

@ -30,8 +30,12 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(AccessibleNode)
AccessibleNode::AccessibleNode(nsINode* aNode) : mDOMNode(aNode)
{
DocAccessible* doc =
GetOrCreateAccService()->GetDocAccessible(mDOMNode->OwnerDoc());
nsAccessibilityService* accService = GetOrCreateAccService();
if (!accService) {
return;
}
DocAccessible* doc = accService->GetDocAccessible(mDOMNode->OwnerDoc());
if (doc) {
mIntl = doc->GetAccessible(mDOMNode);
}
@ -57,8 +61,11 @@ void
AccessibleNode::GetRole(nsAString& aRole)
{
if (mIntl) {
GetOrCreateAccService()->GetStringRole(mIntl->Role(), aRole);
return;
nsAccessibilityService* accService = GetOrCreateAccService();
if (accService) {
accService->GetStringRole(mIntl->Role(), aRole);
return;
}
}
aRole.AssignLiteral("unknown");
@ -67,15 +74,19 @@ AccessibleNode::GetRole(nsAString& aRole)
void
AccessibleNode::GetStates(nsTArray<nsString>& aStates)
{
if (mIntl) {
if (!mStates) {
mStates = GetOrCreateAccService()->GetStringStates(mIntl->State());
}
nsAccessibilityService* accService = GetOrCreateAccService();
if (!mIntl || !accService) {
aStates.AppendElement(NS_LITERAL_STRING("defunct"));
return;
}
if (mStates) {
aStates = mStates->StringArray();
return;
}
aStates.AppendElement(NS_LITERAL_STRING("defunct"));
mStates = accService->GetStringStates(mIntl->State());
aStates = mStates->StringArray();
}
void
@ -106,7 +117,8 @@ AccessibleNode::GetAttributes(nsTArray<nsString>& aAttributes)
bool
AccessibleNode::Is(const Sequence<nsString>& aFlavors)
{
if (!mIntl) {
nsAccessibilityService* accService = GetOrCreateAccService();
if (!mIntl || !accService) {
for (const auto& flavor : aFlavors) {
if (!flavor.EqualsLiteral("unknown") && !flavor.EqualsLiteral("defunct")) {
return false;
@ -116,10 +128,10 @@ AccessibleNode::Is(const Sequence<nsString>& aFlavors)
}
nsAutoString role;
GetOrCreateAccService()->GetStringRole(mIntl->Role(), role);
accService->GetStringRole(mIntl->Role(), role);
if (!mStates) {
mStates = GetOrCreateAccService()->GetStringStates(mIntl->State());
mStates = accService->GetStringStates(mIntl->State());
}
for (const auto& flavor : aFlavors) {

Просмотреть файл

@ -1904,6 +1904,11 @@ nsAccessibilityService::NotifyOfConsumersChange()
nsAccessibilityService*
GetOrCreateAccService(uint32_t aNewConsumer)
{
// Do not initialize accessibility if it is force disabled.
if (PlatformDisabledState() == ePlatformIsDisabled) {
return nullptr;
}
if (!nsAccessibilityService::gAccessibilityService) {
RefPtr<nsAccessibilityService> service = new nsAccessibilityService();
if (!service->Init()) {

Просмотреть файл

@ -46,7 +46,7 @@ xpcAccessibilityService::AddRef(void)
// We want refcount to be > 1 because one reference is added in the XPCOM
// accessibility service getter.
if (mRefCnt > 1 && PlatformDisabledState() != ePlatformIsDisabled) {
if (mRefCnt > 1) {
GetOrCreateAccService(nsAccessibilityService::eXPCOM);
}
@ -280,13 +280,10 @@ NS_GetAccessibilityService(nsIAccessibilityService** aResult)
NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
*aResult = nullptr;
// Do not initialize accessibility if it is force disabled.
if (PlatformDisabledState() == ePlatformIsDisabled) {
if (!GetOrCreateAccService(nsAccessibilityService::eXPCOM)) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
GetOrCreateAccService(nsAccessibilityService::eXPCOM);
xpcAccessibilityService* service = new xpcAccessibilityService();
NS_ENSURE_TRUE(service, NS_ERROR_OUT_OF_MEMORY);
xpcAccessibilityService::gXPCAccessibilityService = service;

Просмотреть файл

@ -297,7 +297,9 @@ add_task(async function wrapped_text_in_dialog_should_have_expected_scrollHeight
Assert.ok(docEl.scrollHeight > contentOldHeight,
"Content height increased (from " + contentOldHeight + " to " + docEl.scrollHeight + ").");
Assert.equal(frame.style.height, docEl.scrollHeight + "px",
"Height on the frame should be higher now");
"Height on the frame should be higher now. " +
"This test may fail on certain screen resoluition. " +
"See bug 1420576 and bug 1205717.");
});
await close_subdialog_and_test_generic_end_state(tab.linkedBrowser,

Просмотреть файл

@ -8,6 +8,8 @@ var initialPageZoom = ZoomManager.zoom;
const kTimeoutInMS = 20000;
async function testZoomButtonAppearsAndDisappearsBasedOnZoomChanges(zoomEventType) {
let tab = await BrowserTestUtils.openNewForegroundTab({ gBrowser, waitForStateStop: true });
info("Running this test with " + zoomEventType.substring(0, 9));
info("Confirm whether the browser zoom is set to the default level");
is(initialPageZoom, 1, "Page zoom is set to default (100%)");
@ -32,6 +34,8 @@ async function testZoomButtonAppearsAndDisappearsBasedOnZoomChanges(zoomEventTyp
expectedZoomLevel = 100;
is(pageZoomLevel, expectedZoomLevel, "Clicking zoom button successfully resets browser zoom to 100%");
is(zoomResetButton.hidden, true, "Zoom reset button returns to being hidden");
await BrowserTestUtils.removeTab(tab);
}
add_task(async function() {

Просмотреть файл

@ -19,7 +19,7 @@ function test() {
"<script type='text/javascript'>",
"let b = 42;",
"</script>",
"<script type='text/javascript;version=1.8'>",
"<script type='text/javascript'>",
"let c = 42;",
"</script>",
"</head>"
@ -44,14 +44,14 @@ function test() {
"The first script was located correctly.");
is(parsed.getScriptInfo(source.indexOf("let b")).toSource(), "({start:85, length:13, index:1})",
"The second script was located correctly.");
is(parsed.getScriptInfo(source.indexOf("let c")).toSource(), "({start:151, length:13, index:2})",
is(parsed.getScriptInfo(source.indexOf("let c")).toSource(), "({start:139, length:13, index:2})",
"The third script was located correctly.");
is(parsed.getScriptInfo(source.indexOf("let a") - 1).toSource(), "({start:31, length:13, index:0})",
"The left edge of the first script was interpreted correctly.");
is(parsed.getScriptInfo(source.indexOf("let b") - 1).toSource(), "({start:85, length:13, index:1})",
"The left edge of the second script was interpreted correctly.");
is(parsed.getScriptInfo(source.indexOf("let c") - 1).toSource(), "({start:151, length:13, index:2})",
is(parsed.getScriptInfo(source.indexOf("let c") - 1).toSource(), "({start:139, length:13, index:2})",
"The left edge of the third script was interpreted correctly.");
is(parsed.getScriptInfo(source.indexOf("let a") - 2).toSource(), "({start:-1, length:-1, index:-1})",
@ -65,7 +65,7 @@ function test() {
"The right edge of the first script was interpreted correctly.");
is(parsed.getScriptInfo(source.indexOf("let b") + 12).toSource(), "({start:85, length:13, index:1})",
"The right edge of the second script was interpreted correctly.");
is(parsed.getScriptInfo(source.indexOf("let c") + 12).toSource(), "({start:151, length:13, index:2})",
is(parsed.getScriptInfo(source.indexOf("let c") + 12).toSource(), "({start:139, length:13, index:2})",
"The right edge of the third script was interpreted correctly.");
is(parsed.getScriptInfo(source.indexOf("let a") + 13).toSource(), "({start:-1, length:-1, index:-1})",

Просмотреть файл

@ -19,7 +19,7 @@ function test() {
"a.push('<script type=\"text/javascript\">');",
"a.push('var b = 42;');",
"a.push('</script>');",
"a.push('<script type=\"text/javascript;version=1.8\">');",
"a.push('<script type=\"text/javascript\">');",
"a.push('var c = 42;');",
"a.push('</script>');"
].join("\n");
@ -34,11 +34,11 @@ function test() {
is(parsed.scriptCount, 1,
"There should be 1 script parsed in the parent source.");
is(parsed.getScriptInfo(source.indexOf("let a")).toSource(), "({start:0, length:261, index:0})",
is(parsed.getScriptInfo(source.indexOf("let a")).toSource(), "({start:0, length:249, index:0})",
"The script location is correct (1).");
is(parsed.getScriptInfo(source.indexOf("<script>")).toSource(), "({start:0, length:261, index:0})",
is(parsed.getScriptInfo(source.indexOf("<script>")).toSource(), "({start:0, length:249, index:0})",
"The script location is correct (2).");
is(parsed.getScriptInfo(source.indexOf("</script>")).toSource(), "({start:0, length:261, index:0})",
is(parsed.getScriptInfo(source.indexOf("</script>")).toSource(), "({start:0, length:249, index:0})",
"The script location is correct (3).");
finish();

Просмотреть файл

@ -12,7 +12,7 @@ function test() {
let source = [
'<script type="text/javascript" src="chrome://foo.js"/>',
'<script type="application/javascript;version=1.8" src="chrome://baz.js"/>',
'<script type="application/javascript" src="chrome://baz.js"/>',
'<script async defer src="chrome://foobar.js"/>',
'<script type="application/javascript"/>"hello third"',
'<script type="application/javascript">"hello fourth"</script>',
@ -34,7 +34,7 @@ function test() {
is(parsed.getScriptInfo(source.indexOf("hello third!")).toSource(), "({start:-1, length:-1, index:-1})",
"Inline script on self-closing tag not considered a script");
is(parsed.getScriptInfo(source.indexOf("hello fourth")).toSource(), "({start:267, length:14, index:4})",
is(parsed.getScriptInfo(source.indexOf("hello fourth")).toSource(), "({start:255, length:14, index:4})",
"The fourth script was located correctly.");
finish();

Просмотреть файл

@ -5,7 +5,7 @@
<title>Web Console test for bug 632347 - generators</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="application/javascript;version=1.8">
<script type="application/javascript">
(function(){
function genFunc() {
var a = 5;

Просмотреть файл

@ -5,7 +5,7 @@
<title>Web Console test for bug 632347 - generators</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<script type="application/javascript;version=1.8">
<script type="application/javascript">
(function(){
function* genFunc() {
var a = 5;

Просмотреть файл

@ -28,7 +28,7 @@
#include "nsIUUIDGenerator.h"
#include "nsNetUtil.h"
#define RELEASING_TIMER 1000
#define RELEASING_TIMER 5000
using namespace mozilla;
using namespace mozilla::dom;
@ -48,18 +48,21 @@ struct DataInfo
: mObjectType(eBlobImpl)
, mBlobImpl(aBlobImpl)
, mPrincipal(aPrincipal)
, mRevoked(false)
{}
DataInfo(DOMMediaStream* aMediaStream, nsIPrincipal* aPrincipal)
: mObjectType(eMediaStream)
, mMediaStream(aMediaStream)
, mPrincipal(aPrincipal)
, mRevoked(false)
{}
DataInfo(MediaSource* aMediaSource, nsIPrincipal* aPrincipal)
: mObjectType(eMediaSource)
, mMediaSource(aMediaSource)
, mPrincipal(aPrincipal)
, mRevoked(false)
{}
ObjectType mObjectType;
@ -73,12 +76,17 @@ struct DataInfo
// WeakReferences of nsHostObjectURI objects.
nsTArray<nsWeakPtr> mURIs;
// When a blobURL is revoked, we keep it alive for RELEASING_TIMER
// milliseconds in order to support pending operations such as navigation,
// download and so on.
bool mRevoked;
};
static nsClassHashtable<nsCStringHashKey, DataInfo>* gDataTable;
static DataInfo*
GetDataInfo(const nsACString& aUri)
GetDataInfo(const nsACString& aUri, bool aAlsoIfRevoked = false)
{
if (!gDataTable) {
return nullptr;
@ -105,6 +113,10 @@ GetDataInfo(const nsACString& aUri)
gDataTable->Get(StringHead(aUri, pos), &res);
}
if (!aAlsoIfRevoked && res && res->mRevoked) {
return nullptr;
}
return res;
}
@ -154,9 +166,8 @@ BroadcastBlobURLRegistration(const nsACString& aURI,
}
void
BroadcastBlobURLUnregistration(const nsACString& aURI, DataInfo* aInfo)
BroadcastBlobURLUnregistration(const nsCString& aURI)
{
MOZ_ASSERT(aInfo);
MOZ_ASSERT(NS_IsMainThread());
if (XRE_IsParentProcess()) {
@ -165,8 +176,7 @@ BroadcastBlobURLUnregistration(const nsACString& aURI, DataInfo* aInfo)
}
dom::ContentChild* cc = dom::ContentChild::GetSingleton();
Unused << NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration(
nsCString(aURI)));
Unused << NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration(aURI));
}
class HostObjectURLsReporter final : public nsIMemoryReporter
@ -432,9 +442,10 @@ public:
NS_DECL_ISUPPORTS
static void
Create(nsTArray<nsWeakPtr>&& aArray)
Create(const nsACString& aURI, bool aBroadcastToOtherProcesses)
{
RefPtr<ReleasingTimerHolder> holder = new ReleasingTimerHolder(Move(aArray));
RefPtr<ReleasingTimerHolder> holder =
new ReleasingTimerHolder(aURI, aBroadcastToOtherProcesses);
nsresult rv = NS_NewTimerWithCallback(getter_AddRefs(holder->mTimer),
holder, RELEASING_TIMER,
nsITimer::TYPE_ONE_SHOT,
@ -445,13 +456,32 @@ public:
NS_IMETHOD
Notify(nsITimer* aTimer) override
{
for (uint32_t i = 0; i < mURIs.Length(); ++i) {
nsCOMPtr<nsIURI> uri = do_QueryReferent(mURIs[i]);
// If we have to broadcast the unregistration, let's do it now.
if (mBroadcastToOtherProcesses) {
BroadcastBlobURLUnregistration(mURI);
}
DataInfo* info = GetDataInfo(mURI, true /* We care about revoked dataInfo */);
if (!info) {
// Already gone!
return NS_OK;
}
MOZ_ASSERT(info->mRevoked);
for (uint32_t i = 0; i < info->mURIs.Length(); ++i) {
nsCOMPtr<nsIURI> uri = do_QueryReferent(info->mURIs[i]);
if (uri) {
static_cast<nsHostObjectURI*>(uri.get())->ForgetBlobImpl();
}
}
gDataTable->Remove(mURI);
if (gDataTable->Count() == 0) {
delete gDataTable;
gDataTable = nullptr;
}
return NS_OK;
}
@ -463,14 +493,17 @@ public:
}
private:
explicit ReleasingTimerHolder(nsTArray<nsWeakPtr>&& aArray)
: mURIs(aArray)
ReleasingTimerHolder(const nsACString& aURI, bool aBroadcastToOtherProcesses)
: mURI(aURI)
, mBroadcastToOtherProcesses(aBroadcastToOtherProcesses)
{}
~ReleasingTimerHolder()
{}
nsTArray<nsWeakPtr> mURIs;
nsCString mURI;
bool mBroadcastToOtherProcesses;
nsCOMPtr<nsITimer> mTimer;
};
@ -596,7 +629,8 @@ nsHostObjectProtocolHandler::GetAllBlobURLEntries(
}
aRegistrations.AppendElement(BlobURLRegistrationData(
nsCString(iter.Key()), ipcBlob, IPC::Principal(info->mPrincipal)));
nsCString(iter.Key()), ipcBlob, IPC::Principal(info->mPrincipal),
info->mRevoked));
}
return true;
@ -615,26 +649,19 @@ nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri,
return;
}
if (aBroadcastToOtherProcesses && info->mObjectType == DataInfo::eBlobImpl) {
BroadcastBlobURLUnregistration(aUri, info);
}
info->mRevoked = true;
if (!info->mURIs.IsEmpty()) {
ReleasingTimerHolder::Create(Move(info->mURIs));
}
gDataTable->Remove(aUri);
if (gDataTable->Count() == 0) {
delete gDataTable;
gDataTable = nullptr;
}
// The timer will take care of removing the entry for real after
// RELEASING_TIMER milliseconds. In the meantime, the DataInfo, marked as
// revoked, will not be exposed.
ReleasingTimerHolder::Create(aUri,
aBroadcastToOtherProcesses &&
info->mObjectType == DataInfo::eBlobImpl);
}
/* static */ void
nsHostObjectProtocolHandler::RemoveDataEntries()
{
MOZ_ASSERT(XRE_IsContentProcess());
if (!gDataTable) {
return;
}

Просмотреть файл

@ -77,7 +77,6 @@ public:
static void RemoveDataEntry(const nsACString& aUri,
bool aBroadcastToOTherProcesses = true);
// This is for IPC only.
static void RemoveDataEntries();
static bool HasDataEntry(const nsACString& aUri);

Просмотреть файл

@ -2704,6 +2704,13 @@ ContentChild::RecvInitBlobURLs(nsTArray<BlobURLRegistrationData>&& aRegistration
nsHostObjectProtocolHandler::AddDataEntry(registration.url(),
registration.principal(),
blobImpl);
// If we have received an already-revoked blobURL, we have to keep it alive
// for a while (see nsHostObjectProtocolHandler) in order to support pending
// operations such as navigation, download and so on.
if (registration.revoked()) {
nsHostObjectProtocolHandler::RemoveDataEntry(registration.url(),
false);
}
}
return IPC_OK();

Просмотреть файл

@ -2796,7 +2796,7 @@ ContentParent::Observe(nsISupports* aSubject,
// We know prefs are ASCII here.
NS_LossyConvertUTF16toASCII strData(aData);
Pref pref(strData, null_t(), null_t());
Pref pref(strData, /* isLocked */ false, null_t(), null_t());
Preferences::GetPreference(&pref);
if (!SendPreferenceUpdate(pref)) {
return NS_ERROR_NOT_AVAILABLE;

Просмотреть файл

@ -156,7 +156,11 @@ ContentProcess::Init(int aArgc, char* aArgv[])
MaybePrefValue value(PrefValue(static_cast<int32_t>(strtol(str, &str, 10))));
MOZ_ASSERT(str[0] == '|');
str++;
Pref pref(nsCString(ContentPrefs::GetContentPref(index)), value, MaybePrefValue());
// XXX: we assume these values as default values, which may not be
// true. We also assume they are unlocked. Fortunately, these prefs
// get reset properly by the first IPC message.
Pref pref(nsCString(ContentPrefs::GetContentPref(index)),
/* isLocked */ false, value, MaybePrefValue());
prefsArray.AppendElement(pref);
}
SET_PREF_PHASE(END_INIT_PREFS);
@ -171,7 +175,8 @@ ContentProcess::Init(int aArgc, char* aArgv[])
MaybePrefValue value(PrefValue(!!strtol(str, &str, 10)));
MOZ_ASSERT(str[0] == '|');
str++;
Pref pref(nsCString(ContentPrefs::GetContentPref(index)), value, MaybePrefValue());
Pref pref(nsCString(ContentPrefs::GetContentPref(index)),
/* isLocked */ false, value, MaybePrefValue());
prefsArray.AppendElement(pref);
}
SET_PREF_PHASE(END_INIT_PREFS);
@ -187,7 +192,8 @@ ContentProcess::Init(int aArgc, char* aArgv[])
MOZ_ASSERT(str[0] == ';');
str++;
MaybePrefValue value(PrefValue(nsCString(str, length)));
Pref pref(nsCString(ContentPrefs::GetContentPref(index)), value, MaybePrefValue());
Pref pref(nsCString(ContentPrefs::GetContentPref(index)),
/* isLocked */ false, value, MaybePrefValue());
prefsArray.AppendElement(pref);
str += length + 1;
MOZ_ASSERT(*(str - 1) == '|');

Просмотреть файл

@ -156,6 +156,7 @@ union MaybePrefValue {
struct Pref {
nsCString name;
bool isLocked;
MaybePrefValue defaultValue;
MaybePrefValue userValue;
};
@ -234,9 +235,10 @@ union FileCreationResult
struct BlobURLRegistrationData
{
nsCString url;
IPCBlob blob;
Principal principal;
nsCString url;
IPCBlob blob;
Principal principal;
bool revoked;
};
struct GMPAPITags

Просмотреть файл

@ -1207,12 +1207,22 @@ ParseTypeAttribute(const nsAString& aType, ValidJSVersion* aVersion)
nsAutoString versionName;
rv = parser.GetParameter("version", versionName);
if (NS_SUCCEEDED(rv)) {
*aVersion = ParseJavascriptVersion(versionName);
} else if (rv != NS_ERROR_INVALID_ARG) {
if (rv == NS_ERROR_INVALID_ARG) {
Telemetry::Accumulate(Telemetry::SCRIPT_LOADED_WITH_VERSION, false);
// Argument not set.
return true;
}
if (NS_FAILED(rv)) {
return false;
}
*aVersion = ParseJavascriptVersion(versionName);
if (*aVersion == ValidJSVersion::Valid) {
Telemetry::Accumulate(Telemetry::SCRIPT_LOADED_WITH_VERSION, true);
return true;
}
return true;
}

Просмотреть файл

@ -419,11 +419,17 @@ U2F::Register(const nsAString& aAppId,
// Always blank for U2F
nsTArray<WebAuthnExtension> extensions;
WebAuthnTransactionInfo info(rpIdHash,
clientDataHash,
adjustedTimeoutMillis,
excludeList,
extensions);
// Default values for U2F.
WebAuthnAuthenticatorSelection authSelection(false /* requireResidentKey */,
false /* requireUserVerification */,
false /* requirePlatformAttachment */);
WebAuthnMakeCredentialInfo info(rpIdHash,
clientDataHash,
adjustedTimeoutMillis,
excludeList,
extensions,
authSelection);
MOZ_ASSERT(mTransaction.isNothing());
mTransaction = Some(U2FTransaction(clientData));
@ -548,11 +554,11 @@ U2F::Sign(const nsAString& aAppId,
// Always blank for U2F
nsTArray<WebAuthnExtension> extensions;
WebAuthnTransactionInfo info(rpIdHash,
clientDataHash,
adjustedTimeoutMillis,
permittedList,
extensions);
WebAuthnGetAssertionInfo info(rpIdHash,
clientDataHash,
adjustedTimeoutMillis,
permittedList,
extensions);
MOZ_ASSERT(mTransaction.isNothing());
mTransaction = Some(U2FTransaction(clientData));

Просмотреть файл

@ -13,7 +13,7 @@ namespace dom {
mozilla::ipc::IPCResult
U2FTransactionParent::RecvRequestRegister(const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo)
const WebAuthnMakeCredentialInfo& aTransactionInfo)
{
AssertIsOnBackgroundThread();
U2FTokenManager* mgr = U2FTokenManager::Get();
@ -23,7 +23,7 @@ U2FTransactionParent::RecvRequestRegister(const uint64_t& aTransactionId,
mozilla::ipc::IPCResult
U2FTransactionParent::RecvRequestSign(const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo)
const WebAuthnGetAssertionInfo& aTransactionInfo)
{
AssertIsOnBackgroundThread();
U2FTokenManager* mgr = U2FTokenManager::Get();

Просмотреть файл

@ -26,11 +26,11 @@ public:
virtual mozilla::ipc::IPCResult
RecvRequestRegister(const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo) override;
const WebAuthnMakeCredentialInfo& aTransactionInfo) override;
virtual mozilla::ipc::IPCResult
RecvRequestSign(const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo) override;
const WebAuthnGetAssertionInfo& aTransactionInfo) override;
virtual mozilla::ipc::IPCResult
RecvRequestCancel(const uint64_t& aTransactionId) override;

Просмотреть файл

@ -19,6 +19,12 @@ include protocol PBackground;
namespace mozilla {
namespace dom {
struct WebAuthnAuthenticatorSelection {
bool requireResidentKey;
bool requireUserVerification;
bool requirePlatformAttachment;
};
struct WebAuthnScopedCredentialDescriptor {
uint8_t[] id;
};
@ -27,11 +33,20 @@ struct WebAuthnExtension {
/* TODO Fill in with predefined extensions */
};
struct WebAuthnTransactionInfo {
struct WebAuthnMakeCredentialInfo {
uint8_t[] RpIdHash;
uint8_t[] ClientDataHash;
uint32_t TimeoutMS;
WebAuthnScopedCredentialDescriptor[] Descriptors;
WebAuthnScopedCredentialDescriptor[] ExcludeList;
WebAuthnExtension[] Extensions;
WebAuthnAuthenticatorSelection AuthenticatorSelection;
};
struct WebAuthnGetAssertionInfo {
uint8_t[] RpIdHash;
uint8_t[] ClientDataHash;
uint32_t TimeoutMS;
WebAuthnScopedCredentialDescriptor[] AllowList;
WebAuthnExtension[] Extensions;
};
@ -39,8 +54,8 @@ async protocol PWebAuthnTransaction {
manager PBackground;
parent:
async __delete__();
async RequestRegister(uint64_t aTransactionId, WebAuthnTransactionInfo aTransactionInfo);
async RequestSign(uint64_t aTransactionId, WebAuthnTransactionInfo aTransactionInfo);
async RequestRegister(uint64_t aTransactionId, WebAuthnMakeCredentialInfo aTransactionInfo);
async RequestSign(uint64_t aTransactionId, WebAuthnGetAssertionInfo aTransactionInfo);
async RequestCancel(uint64_t aTransactionId);
child:
async ConfirmRegister(uint64_t aTransactionId, uint8_t[] RegBuffer);

Просмотреть файл

@ -101,14 +101,29 @@ U2FHIDTokenManager::~U2FHIDTokenManager()
//
RefPtr<U2FRegisterPromise>
U2FHIDTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
uint32_t aTimeoutMS)
{
MOZ_ASSERT(NS_GetCurrentThread() == gPBackgroundThread);
uint64_t registerFlags = 0;
// Set flags for credential creation.
if (aAuthenticatorSelection.requireResidentKey()) {
registerFlags |= U2F_FLAG_REQUIRE_RESIDENT_KEY;
}
if (aAuthenticatorSelection.requireUserVerification()) {
registerFlags |= U2F_FLAG_REQUIRE_USER_VERIFICATION;
}
if (aAuthenticatorSelection.requirePlatformAttachment()) {
registerFlags |= U2F_FLAG_REQUIRE_PLATFORM_ATTACHMENT;
}
ClearPromises();
mTransactionId = rust_u2f_mgr_register(mU2FManager,
registerFlags,
(uint64_t)aTimeoutMS,
u2f_register_callback,
aChallenge.Elements(),

Просмотреть файл

@ -92,6 +92,7 @@ public:
virtual RefPtr<U2FRegisterPromise>
Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
uint32_t aTimeoutMS) override;

Просмотреть файл

@ -626,6 +626,7 @@ U2FSoftTokenManager::IsRegistered(const nsTArray<uint8_t>& aKeyHandle,
//
RefPtr<U2FRegisterPromise>
U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
uint32_t aTimeoutMS)
@ -642,6 +643,14 @@ U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>
}
}
// The U2F softtoken neither supports resident keys or
// user verification, nor is it a platform authenticator.
if (aAuthenticatorSelection.requireResidentKey() ||
aAuthenticatorSelection.requireUserVerification() ||
aAuthenticatorSelection.requirePlatformAttachment()) {
return U2FRegisterPromise::CreateAndReject(NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
}
// Optional exclusion list.
for (auto desc: aDescriptors) {
bool isRegistered = false;

Просмотреть файл

@ -27,6 +27,7 @@ public:
virtual RefPtr<U2FRegisterPromise>
Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
uint32_t aTimeoutMS) override;

Просмотреть файл

@ -220,7 +220,7 @@ U2FTokenManager::GetTokenManagerImpl()
void
U2FTokenManager::Register(PWebAuthnTransactionParent* aTransactionParent,
const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo)
const WebAuthnMakeCredentialInfo& aTransactionInfo)
{
MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthRegister"));
@ -245,7 +245,8 @@ U2FTokenManager::Register(PWebAuthnTransactionParent* aTransactionParent,
uint64_t tid = mLastTransactionId = aTransactionId;
mozilla::TimeStamp startTime = mozilla::TimeStamp::Now();
mTokenManagerImpl->Register(aTransactionInfo.Descriptors(),
mTokenManagerImpl->Register(aTransactionInfo.ExcludeList(),
aTransactionInfo.AuthenticatorSelection(),
aTransactionInfo.RpIdHash(),
aTransactionInfo.ClientDataHash(),
aTransactionInfo.TimeoutMS())
@ -297,7 +298,7 @@ U2FTokenManager::MaybeAbortRegister(const uint64_t& aTransactionId,
void
U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo)
const WebAuthnGetAssertionInfo& aTransactionInfo)
{
MOZ_LOG(gU2FTokenManagerLog, LogLevel::Debug, ("U2FAuthSign"));
@ -318,7 +319,7 @@ U2FTokenManager::Sign(PWebAuthnTransactionParent* aTransactionParent,
uint64_t tid = mLastTransactionId = aTransactionId;
mozilla::TimeStamp startTime = mozilla::TimeStamp::Now();
mTokenManagerImpl->Sign(aTransactionInfo.Descriptors(),
mTokenManagerImpl->Sign(aTransactionInfo.AllowList(),
aTransactionInfo.RpIdHash(),
aTransactionInfo.ClientDataHash(),
aTransactionInfo.TimeoutMS())

Просмотреть файл

@ -32,10 +32,10 @@ public:
static U2FTokenManager* Get();
void Register(PWebAuthnTransactionParent* aTransactionParent,
const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo);
const WebAuthnMakeCredentialInfo& aTransactionInfo);
void Sign(PWebAuthnTransactionParent* aTransactionParent,
const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo);
const WebAuthnGetAssertionInfo& aTransactionInfo);
void Cancel(PWebAuthnTransactionParent* aTransactionParent,
const uint64_t& aTransactionId);
void MaybeClearTransaction(PWebAuthnTransactionParent* aParent);

Просмотреть файл

@ -64,6 +64,7 @@ public:
virtual RefPtr<U2FRegisterPromise>
Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const WebAuthnAuthenticatorSelection &aAuthenticatorSelection,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
uint32_t aTimeoutMS) = 0;

Просмотреть файл

@ -475,11 +475,28 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
// TODO: Add extension list building
nsTArray<WebAuthnExtension> extensions;
WebAuthnTransactionInfo info(rpIdHash,
clientDataHash,
adjustedTimeout,
excludeList,
extensions);
const auto& selection = aOptions.mAuthenticatorSelection;
const auto& attachment = selection.mAuthenticatorAttachment;
// Does the RP require attachment == "platform"?
bool requirePlatformAttachment =
attachment.WasPassed() && attachment.Value() == AuthenticatorAttachment::Platform;
// Does the RP require user verification?
bool requireUserVerification =
selection.mUserVerification == UserVerificationRequirement::Required;
// Create and forward authenticator selection criteria.
WebAuthnAuthenticatorSelection authSelection(selection.mRequireResidentKey,
requireUserVerification,
requirePlatformAttachment);
WebAuthnMakeCredentialInfo info(rpIdHash,
clientDataHash,
adjustedTimeout,
excludeList,
extensions,
authSelection);
ListenForVisibilityEvents(aParent, this);
@ -492,11 +509,11 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
MOZ_ASSERT(mTransaction.isNothing());
mTransaction = Some(WebAuthnTransaction(aParent,
promise,
Move(info),
Move(clientDataJSON),
rpIdHash,
clientDataJSON,
signal));
mChild->SendRequestRegister(mTransaction.ref().mId, mTransaction.ref().mInfo);
mChild->SendRequestRegister(mTransaction.ref().mId, info);
return promise.forget();
}
@ -638,11 +655,11 @@ WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
// result of this processing clientExtensions.
nsTArray<WebAuthnExtension> extensions;
WebAuthnTransactionInfo info(rpIdHash,
clientDataHash,
adjustedTimeout,
allowList,
extensions);
WebAuthnGetAssertionInfo info(rpIdHash,
clientDataHash,
adjustedTimeout,
allowList,
extensions);
ListenForVisibilityEvents(aParent, this);
@ -655,11 +672,11 @@ WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
MOZ_ASSERT(mTransaction.isNothing());
mTransaction = Some(WebAuthnTransaction(aParent,
promise,
Move(info),
Move(clientDataJSON),
rpIdHash,
clientDataJSON,
signal));
mChild->SendRequestSign(mTransaction.ref().mId, mTransaction.ref().mInfo);
mChild->SendRequestSign(mTransaction.ref().mId, info);
return promise.forget();
}
@ -743,7 +760,7 @@ WebAuthnManager::FinishMakeCredential(const uint64_t& aTransactionId,
}
CryptoBuffer rpIdHashBuf;
if (!rpIdHashBuf.Assign(mTransaction.ref().mInfo.RpIdHash())) {
if (!rpIdHashBuf.Assign(mTransaction.ref().mRpIdHash)) {
RejectTransaction(NS_ERROR_OUT_OF_MEMORY);
return;
}
@ -840,7 +857,7 @@ WebAuthnManager::FinishGetAssertion(const uint64_t& aTransactionId,
}
CryptoBuffer rpIdHashBuf;
if (!rpIdHashBuf.Assign(mTransaction.ref().mInfo.RpIdHash())) {
if (!rpIdHashBuf.Assign(mTransaction.ref().mRpIdHash)) {
RejectTransaction(NS_ERROR_OUT_OF_MEMORY);
return;
}

Просмотреть файл

@ -65,12 +65,12 @@ class WebAuthnTransaction
public:
WebAuthnTransaction(nsPIDOMWindowInner* aParent,
const RefPtr<Promise>& aPromise,
const WebAuthnTransactionInfo&& aInfo,
const nsAutoCString&& aClientData,
const nsTArray<uint8_t>& aRpIdHash,
const nsCString& aClientData,
AbortSignal* aSignal)
: mParent(aParent)
, mPromise(aPromise)
, mInfo(aInfo)
, mRpIdHash(aRpIdHash)
, mClientData(aClientData)
, mSignal(aSignal)
, mId(NextId())
@ -84,9 +84,8 @@ public:
// JS Promise representing the transaction status.
RefPtr<Promise> mPromise;
// Holds the parameters of the current transaction, as we need them both
// before the transaction request is sent, and on successful return.
WebAuthnTransactionInfo mInfo;
// The RP ID hash.
nsTArray<uint8_t> mRpIdHash;
// Client data used to assemble reply objects.
nsCString mClientData;

Просмотреть файл

@ -13,7 +13,7 @@ namespace dom {
mozilla::ipc::IPCResult
WebAuthnTransactionParent::RecvRequestRegister(const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo)
const WebAuthnMakeCredentialInfo& aTransactionInfo)
{
AssertIsOnBackgroundThread();
U2FTokenManager* mgr = U2FTokenManager::Get();
@ -23,7 +23,7 @@ WebAuthnTransactionParent::RecvRequestRegister(const uint64_t& aTransactionId,
mozilla::ipc::IPCResult
WebAuthnTransactionParent::RecvRequestSign(const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo)
const WebAuthnGetAssertionInfo& aTransactionInfo)
{
AssertIsOnBackgroundThread();
U2FTokenManager* mgr = U2FTokenManager::Get();

Просмотреть файл

@ -26,11 +26,11 @@ public:
virtual mozilla::ipc::IPCResult
RecvRequestRegister(const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo) override;
const WebAuthnMakeCredentialInfo& aTransactionInfo) override;
virtual mozilla::ipc::IPCResult
RecvRequestSign(const uint64_t& aTransactionId,
const WebAuthnTransactionInfo& aTransactionInfo) override;
const WebAuthnGetAssertionInfo& aTransactionInfo) override;
virtual mozilla::ipc::IPCResult
RecvRequestCancel(const uint64_t& aTransactionId) override;

Просмотреть файл

@ -7,6 +7,7 @@ skip-if = !e10s
scheme = https
[test_webauthn_abort_signal.html]
[test_webauthn_authenticator_selection.html]
[test_webauthn_loopback.html]
[test_webauthn_no_token.html]
[test_webauthn_make_credential.html]

Просмотреть файл

@ -0,0 +1,101 @@
<!DOCTYPE html>
<meta charset=utf-8>
<head>
<title>W3C Web Authentication - Authenticator Selection Criteria</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="u2futil.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<h1>W3C Web Authentication - Authenticator Selection Criteria</h1>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1406462">Mozilla Bug 1406462</a>
<script class="testbody" type="text/javascript">
"use strict";
function arrivingHereIsGood(aResult) {
ok(true, "Good result! Received a: " + aResult);
}
function arrivingHereIsBad(aResult) {
ok(false, "Bad result! Received a: " + aResult);
}
function expectNotAllowedError(aResult) {
ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError, got " + aResult);
}
add_task(() => {
// Enable the softtoken.
return SpecialPowers.pushPrefEnv({"set": [
["security.webauth.webauthn", true],
["security.webauth.webauthn_enable_softtoken", true],
["security.webauth.webauthn_enable_usbtoken", false],
]});
});
// Start a new MakeCredential() request.
function requestMakeCredential(authenticatorSelection) {
let publicKey = {
rp: {id: document.domain, name: "none", icon: "none"},
user: {id: new Uint8Array(), name: "none", icon: "none", displayName: "none"},
challenge: crypto.getRandomValues(new Uint8Array(16)),
timeout: 5000, // the minimum timeout is actually 15 seconds
pubKeyCredParams: [{type: "public-key", alg: cose_alg_ECDSA_w_SHA256}],
authenticatorSelection,
};
return navigator.credentials.create({publicKey});
}
// Test success cases.
add_task(async () => {
// No selection criteria.
await requestMakeCredential({})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
// Request a cross-platform authenticator.
await requestMakeCredential({authenticatorAttachment: "cross-platform"})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
// Don't require a resident key.
await requestMakeCredential({requireResidentKey: false})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
// Prefer user verification.
await requestMakeCredential({userVerification: "preferred"})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
// Discourage user verification.
await requestMakeCredential({userVerification: "discouraged"})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
});
// Test the failure cases.
add_task(async () => {
// Request a platform authenticator.
await requestMakeCredential({authenticatorAttachment: "platform"})
.then(arrivingHereIsBad)
.catch(expectNotAllowedError);
// Require a resident key.
await requestMakeCredential({requireResidentKey: true})
.then(arrivingHereIsBad)
.catch(expectNotAllowedError);
// Require user verification.
await requestMakeCredential({userVerification: "required"})
.then(arrivingHereIsBad)
.catch(expectNotAllowedError);
});
</script>
</body>
</html>

Просмотреть файл

@ -19,6 +19,7 @@ env_logger = "0.4.1"
libc = "^0.2"
boxfnonce = "0.0.3"
runloop = "0.1.0"
bitflags = "1.0"
[dev-dependencies]
rust-crypto = "^0.2"

Просмотреть файл

@ -9,7 +9,7 @@ use crypto::digest::Digest;
use crypto::sha2::Sha256;
use std::io;
use std::sync::mpsc::channel;
use u2fhid::U2FManager;
use u2fhid::{RegisterFlags, U2FManager};
extern crate log;
extern crate env_logger;
@ -49,10 +49,12 @@ fn main() {
application.result(&mut app_bytes);
let manager = U2FManager::new().unwrap();
let flags = RegisterFlags::empty();
let (tx, rx) = channel();
manager
.register(
flags,
15_000,
chall_bytes.clone(),
app_bytes.clone(),

Просмотреть файл

@ -109,6 +109,7 @@ pub unsafe extern "C" fn rust_u2f_res_free(res: *mut U2FResult) {
#[no_mangle]
pub unsafe extern "C" fn rust_u2f_mgr_register(
mgr: *mut U2FManager,
flags: u64,
timeout: u64,
callback: U2FCallback,
challenge_ptr: *const u8,
@ -126,20 +127,28 @@ pub unsafe extern "C" fn rust_u2f_mgr_register(
return 0;
}
let flags = ::RegisterFlags::from_bits_truncate(flags);
let challenge = from_raw(challenge_ptr, challenge_len);
let application = from_raw(application_ptr, application_len);
let key_handles = (*khs).clone();
let tid = new_tid();
let res = (*mgr).register(timeout, challenge, application, key_handles, move |rv| {
if let Ok(registration) = rv {
let mut result = U2FResult::new();
result.insert(RESBUF_ID_REGISTRATION, registration);
callback(tid, Box::into_raw(Box::new(result)));
} else {
callback(tid, ptr::null_mut());
};
});
let res = (*mgr).register(
flags,
timeout,
challenge,
application,
key_handles,
move |rv| {
if let Ok(registration) = rv {
let mut result = U2FResult::new();
result.insert(RESBUF_ID_REGISTRATION, registration);
callback(tid, Box::into_raw(Box::new(result)));
} else {
callback(tid, ptr::null_mut());
};
},
);
if res.is_ok() { tid } else { 0 }
}

Просмотреть файл

@ -34,6 +34,9 @@ extern crate libc;
extern crate boxfnonce;
extern crate runloop;
#[macro_use]
extern crate bitflags;
mod consts;
mod statemachine;
mod u2ftypes;
@ -45,6 +48,15 @@ pub use manager::U2FManager;
mod capi;
pub use capi::*;
// Keep this in sync with the constants in u2fhid-capi.h.
bitflags! {
pub struct RegisterFlags: u64 {
const REQUIRE_RESIDENT_KEY = 1;
const REQUIRE_USER_VERIFICATION = 2;
const REQUIRE_PLATFORM_ATTACHMENT = 4;
}
}
#[cfg(fuzzing)]
pub use u2fprotocol::*;
#[cfg(fuzzing)]

Просмотреть файл

@ -11,8 +11,9 @@ use statemachine::StateMachine;
use runloop::RunLoop;
use util::{to_io_err, OnceCallback};
pub enum QueueAction {
enum QueueAction {
Register {
flags: ::RegisterFlags,
timeout: u64,
challenge: Vec<u8>,
application: Vec<u8>,
@ -45,6 +46,7 @@ impl U2FManager {
while alive() {
match rx.recv_timeout(Duration::from_millis(50)) {
Ok(QueueAction::Register {
flags,
timeout,
challenge,
application,
@ -52,7 +54,14 @@ impl U2FManager {
callback,
}) => {
// This must not block, otherwise we can't cancel.
sm.register(timeout, challenge, application, key_handles, callback);
sm.register(
flags,
timeout,
challenge,
application,
key_handles,
callback,
);
}
Ok(QueueAction::Sign {
timeout,
@ -88,6 +97,7 @@ impl U2FManager {
pub fn register<F>(
&self,
flags: ::RegisterFlags,
timeout: u64,
challenge: Vec<u8>,
application: Vec<u8>,
@ -116,6 +126,7 @@ impl U2FManager {
let callback = OnceCallback::new(callback);
let action = QueueAction::Register {
flags,
timeout,
challenge,
application,

Просмотреть файл

@ -22,6 +22,7 @@ impl StateMachine {
pub fn register(
&mut self,
flags: ::RegisterFlags,
timeout: u64,
challenge: Vec<u8>,
application: Vec<u8>,
@ -45,6 +46,17 @@ impl StateMachine {
return;
}
// We currently support none of the authenticator selection
// criteria because we can't ask tokens whether they do support
// those features. If flags are set, ignore all tokens for now.
//
// Technically, this is a ConstraintError because we shouldn't talk
// to this authenticator in the first place. But the result is the
// same anyway.
if !flags.is_empty() {
return;
}
// Iterate the exclude list and see if there are any matches.
// Abort the state machine if we found a valid key handle.
if key_handles.iter().any(|key_handle| {

Просмотреть файл

@ -15,6 +15,10 @@ const uint8_t U2F_RESBUF_ID_REGISTRATION = 0;
const uint8_t U2F_RESBUF_ID_KEYHANDLE = 1;
const uint8_t U2F_RESBUF_ID_SIGNATURE = 2;
const uint64_t U2F_FLAG_REQUIRE_RESIDENT_KEY = 1;
const uint64_t U2F_FLAG_REQUIRE_USER_VERIFICATION = 2;
const uint64_t U2F_FLAG_REQUIRE_PLATFORM_ATTACHMENT = 4;
// NOTE: Preconditions
// * All rust_u2f_mgr* pointers must refer to pointers which are returned
// by rust_u2f_mgr_new, and must be freed with rust_u2f_mgr_free.
@ -42,6 +46,7 @@ rust_u2f_manager* rust_u2f_mgr_new();
/* unsafe */ void rust_u2f_mgr_free(rust_u2f_manager* mgr);
uint64_t rust_u2f_mgr_register(rust_u2f_manager* mgr,
uint64_t flags,
uint64_t timeout,
rust_u2f_callback,
const uint8_t* challenge_ptr,

Просмотреть файл

@ -75,7 +75,7 @@ dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
dictionary AuthenticatorSelectionCriteria {
AuthenticatorAttachment authenticatorAttachment;
boolean requireResidentKey = false;
boolean requireUserVerification = false;
UserVerificationRequirement userVerification = "preferred";
};
enum AuthenticatorAttachment {
@ -83,6 +83,12 @@ enum AuthenticatorAttachment {
"cross-platform" // Cross-platform attachment
};
enum UserVerificationRequirement {
"required",
"preferred",
"discouraged"
};
dictionary PublicKeyCredentialRequestOptions {
required BufferSource challenge;
unsigned long timeout;

Просмотреть файл

@ -1,6 +1,6 @@
<html><body>
<iframe id="frame" sandbox="allow-scripts allow-popups"></iframe>
<script type="application/javascript;version=1.8">
<script type="application/javascript">
onmessage = function(e) {
parent.postMessage(e.data, '*');
}

Просмотреть файл

@ -8,7 +8,7 @@
<body>
<div id="container"></div>
<iframe id="frame"></iframe>
<script type="application/javascript;version=1.8">
<script type="application/javascript">
var urls = [ "https://example.com/tests/dom/websocket/tests/iframe_webSocket_sandbox.html",
"https://example.com/tests/dom/websocket/tests/iframe_webSocket_sandbox.html?nested",
"https://example.com/tests/dom/websocket/tests/iframe_webSocket_sandbox.html?popup" ];

Просмотреть файл

@ -113,15 +113,16 @@ ConvolutionFilter::ComputeResizeFilter(ResizeMethod aResizeMethod, int32_t aSrcS
// filter values for each one. Those values will tell us how to blend the
// source pixels to compute the destination pixel.
// This is the pixel in the source directly under the pixel in the dest.
// Note that we base computations on the "center" of the pixels. To see
// why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
// downscale should "cover" the pixels around the pixel with *its center*
// at coordinates (2.5, 2.5) in the source, not those around (0, 0).
// Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
float srcPixel = 0.5f * invScale;
mFilter->reserveAdditional(aDstSize, int32_t(ceil(aDstSize * srcSupport * 2)));
for (int32_t destI = 0; destI < aDstSize; destI++) {
// This is the pixel in the source directly under the pixel in the dest.
// Note that we base computations on the "center" of the pixels. To see
// why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
// downscale should "cover" the pixels around the pixel with *its center*
// at coordinates (2.5, 2.5) in the source, not those around (0, 0).
// Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
float srcPixel = (static_cast<float>(destI) + 0.5f) * invScale;
// Compute the (inclusive) range of source pixels the filter covers.
float srcBegin = std::max(0.0f, floorf(srcPixel - srcSupport));
float srcEnd = std::min(aSrcSize - 1.0f, ceilf(srcPixel + srcSupport));
@ -165,8 +166,6 @@ ConvolutionFilter::ComputeResizeFilter(ResizeMethod aResizeMethod, int32_t aSrcS
fixedFilterValues[filterCount / 2] += leftovers;
mFilter->AddFilter(int32_t(srcBegin), fixedFilterValues.begin(), filterCount);
srcPixel += invScale;
}
return mFilter->maxFilter() > 0 && mFilter->numValues() == aDstSize;

Просмотреть файл

@ -50,7 +50,7 @@ parent:
sync Create(IntSize aSize);
async DeleteCompositorAnimations(uint64_t[] aIds);
async SetDisplayList(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
LayoutSize aContentSize, ByteBuffer aDL, BuiltDisplayListDescriptor aDLDesc,
LayoutSize aContentSize, ByteBuf aDL, BuiltDisplayListDescriptor aDLDesc,
WebRenderScrollData aScrollData,
OpUpdateResource[] aResourceUpdates, Shmem[] aSmallShmems, Shmem[] aLargeShmems,
IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);

Просмотреть файл

@ -144,7 +144,9 @@ WebRenderBridgeChild::EndTransaction(const wr::LayoutSize& aContentSize,
MOZ_ASSERT(!mDestroyed);
MOZ_ASSERT(mIsInTransaction);
ByteBuffer dlData(Move(aDL.dl));
ByteBuf dlData(aDL.dl.inner.data, aDL.dl.inner.length, aDL.dl.inner.capacity);
aDL.dl.inner.capacity = 0;
aDL.dl.inner.data = nullptr;
TimeStamp fwdTime;
#if defined(ENABLE_FRAME_LATENCY_LOG)

Просмотреть файл

@ -561,7 +561,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
const uint64_t& aFwdTransactionId,
const uint64_t& aTransactionId,
const wr::LayoutSize& aContentSize,
const wr::ByteBuffer& dl,
ipc::ByteBuf&& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
nsTArray<OpUpdateResource>&& aResourceUpdates,
@ -609,7 +609,7 @@ WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
gfx::Color clearColor(0.f, 0.f, 0.f, 0.f);
mApi->SetDisplayList(clearColor, wr::NewEpoch(wrEpoch), LayerSize(aSize.width, aSize.height),
mPipelineId, aContentSize,
dlDesc, dl.mData, dl.mLength,
dlDesc, dl.mData, dl.mLen,
resources);
ScheduleComposition();

Просмотреть файл

@ -82,7 +82,7 @@ public:
const uint64_t& aFwdTransactionId,
const uint64_t& aTransactionId,
const wr::LayoutSize& aContentSize,
const wr::ByteBuffer& dl,
ipc::ByteBuf&& dl,
const wr::BuiltDisplayListDescriptor& dlDesc,
const WebRenderScrollData& aScrollData,
nsTArray<OpUpdateResource>&& aResourceUpdates,

Просмотреть файл

@ -209,6 +209,7 @@ void TestSchedulerChain(uint32_t aNumThreads, uint32_t aNumCmdBuffers)
} // namespace test_scheduler
#if !defined(MOZ_CODE_COVERAGE) || !defined(XP_WIN)
TEST(Moz2D, JobScheduler_Shutdown) {
srand(time(nullptr));
for (uint32_t threads = 1; threads < 16; ++threads) {
@ -218,6 +219,7 @@ TEST(Moz2D, JobScheduler_Shutdown) {
}
}
}
#endif
TEST(Moz2D, JobScheduler_Join) {
srand(time(nullptr));

Просмотреть файл

@ -0,0 +1,20 @@
<html reftest-zoom="1.6">
<head>
<style>
#xx {
background-image: url("1421191-1.png");
background-position: -61px -797px;
background-position-x: -61px;
background-position-y: -797px;
background-repeat: no-repeat;
background-size: 82px auto;
display: block;
height: 24px;
width: 22px;
}
</style>
</head>
<body>
<span id="xx"></span>
</body>
</html>

Двоичные данные
image/test/reftest/downscaling/1421191-1.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 90 KiB

Просмотреть файл

@ -205,3 +205,6 @@ fuzzy(18,128) == downscale-32px.html?-png-in.ico downscale-32px-ref.html
== huge-1.html?100x32768.jpg,100,32768 huge-1.html?100x100.jpg,100,32768
== huge-1.html?32768x100.jpg,100,100 huge-1.html?100x100.jpg,100,100
== huge-1.html?32768x100.jpg,32768,100 huge-1.html?100x100.jpg,32768,100
# Only need to run this with downscaling on
!= 1421191-1.html about:blank

Просмотреть файл

@ -627,6 +627,16 @@ bool Pickle::WriteUnsignedChar(unsigned char value) {
return WriteBytes(&value, sizeof(value));
}
bool Pickle::WriteBytesZeroCopy(void* data, uint32_t data_len, uint32_t capacity) {
BeginWrite(data_len, sizeof(memberAlignmentType));
buffers_.WriteBytesZeroCopy(reinterpret_cast<char*>(data), data_len, capacity);
EndWrite(data_len);
return true;
}
bool Pickle::WriteBytes(const void* data, uint32_t data_len, uint32_t alignment) {
DCHECK(alignment == 4 || alignment == 8);
DCHECK(intptr_t(header_) % alignment == 0);

Просмотреть файл

@ -162,6 +162,8 @@ class Pickle {
bool WriteData(const char* data, uint32_t length);
bool WriteBytes(const void* data, uint32_t data_len,
uint32_t alignment = sizeof(memberAlignmentType));
// Takes ownership of data
bool WriteBytesZeroCopy(void* data, uint32_t data_len, uint32_t capacity);
bool WriteSentinel(uint32_t sentinel)
#ifdef MOZ_PICKLE_SENTINEL_CHECKING

Просмотреть файл

@ -111,6 +111,11 @@ static inline void WriteParam(Message* m, const P& p) {
ParamTraits<P>::Write(m, p);
}
template <class P>
static inline void WriteParam(Message* m, P& p) {
ParamTraits<P>::Write(m, p);
}
template <class P>
static inline bool WARN_UNUSED_RESULT ReadParam(const Message* m, PickleIterator* iter,
P* p) {

116
ipc/glue/ByteBuf.h Normal file
Просмотреть файл

@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A type that can be sent without needing to make a copy during
* serialization. In addition the receiver can take ownership of the
* data to avoid having to make an additional copy. */
#ifndef mozilla_ipc_ByteBuf_h
#define mozilla_ipc_ByteBuf_h
#include "ipc/IPCMessageUtils.h"
namespace mozilla {
namespace ipc {
class ByteBuf final
{
friend struct IPC::ParamTraits<mozilla::ipc::ByteBuf>;
public:
bool
Allocate(size_t aLength)
{
MOZ_ASSERT(mData == nullptr);
mData = (uint8_t*)malloc(aLength);
if (!mData) {
return false;
}
mLen = aLength;
mCapacity = aLength;
return true;
}
ByteBuf()
: mData(nullptr)
, mLen(0)
, mCapacity(0)
{}
ByteBuf(uint8_t *aData, size_t aLen, size_t aCapacity)
: mData(aData)
, mLen(aLen)
, mCapacity(aCapacity)
{}
ByteBuf(const ByteBuf& aFrom) = delete;
ByteBuf(ByteBuf&& aFrom)
: mData(aFrom.mData)
, mLen(aFrom.mLen)
, mCapacity(aFrom.mCapacity)
{
aFrom.mData = nullptr;
aFrom.mLen = 0;
aFrom.mCapacity = 0;
}
~ByteBuf()
{
free(mData);
}
uint8_t* mData;
size_t mLen;
size_t mCapacity;
};
} // namespace ipc
} // namespace mozilla
namespace IPC {
template<>
struct ParamTraits<mozilla::ipc::ByteBuf>
{
typedef mozilla::ipc::ByteBuf paramType;
// this is where we transfer the memory from the ByteBuf to IPDL, avoiding a copy
static void Write(Message* aMsg, paramType& aParam)
{
WriteParam(aMsg, aParam.mLen);
// hand over ownership of the buffer to the Message
aMsg->WriteBytesZeroCopy(aParam.mData, aParam.mLen, aParam.mCapacity);
aParam.mData = nullptr;
aParam.mCapacity = 0;
aParam.mLen = 0;
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
// We make a copy from the BufferList so that we get a contigous result.
// For users the can handle a non-contiguous result using ExtractBuffers
// is an option, alternatively if the users don't need to take ownership of
// the data they can use the removed FlattenBytes (bug 1297981)
size_t length;
return ReadParam(aMsg, aIter, &length)
&& aResult->Allocate(length)
&& aMsg->ReadBytesInto(aIter, aResult->mData, length);
}
static void Log(const paramType& aParam, std::wstring* aLog)
{
aLog->append(L"(byte buf)");
}
};
} // namespace IPC
#endif // ifndef mozilla_ipc_Shmem_h

Просмотреть файл

@ -18,6 +18,7 @@
#include "IPCMessageStart.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/Attributes.h"
#include "mozilla/ipc/ByteBuf.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/Transport.h"

Просмотреть файл

@ -15,6 +15,7 @@ EXPORTS.mozilla.ipc += [
'BackgroundParent.h',
'BackgroundUtils.h',
'BrowserProcessSubThread.h',
'ByteBuf.h',
'CrashReporterClient.h',
'CrashReporterHost.h',
'CrashReporterMetadataShmem.h',

Просмотреть файл

@ -39,6 +39,7 @@ Types = (
'nsDependentSubstring',
'nsDependentCSubstring',
'mozilla::ipc::Shmem',
'mozilla::ipc::ByteBuf',
'mozilla::ipc::FileDescriptor'
)

Просмотреть файл

@ -560,6 +560,9 @@ class _ConvertToCxxType(TypeVisitor):
def visitShmemType(self, s):
return Type(self.typename(s))
def visitByteBufType(self, s):
return Type(self.typename(s))
def visitFDType(self, s):
return Type(self.typename(s))
@ -586,6 +589,9 @@ def _cxxConstRefType(ipdltype, side):
if ipdltype.isIPDL() and ipdltype.isShmem():
t.ref = 1
return t
if ipdltype.isIPDL() and ipdltype.isByteBuf():
t.ref = 1
return t
t.const = 1
t.ref = 1
return t
@ -593,6 +599,7 @@ def _cxxConstRefType(ipdltype, side):
def _cxxTypeNeedsMove(ipdltype):
return ipdltype.isIPDL() and (ipdltype.isArray() or
ipdltype.isShmem() or
ipdltype.isByteBuf() or
ipdltype.isEndpoint())
def _cxxMoveRefType(ipdltype, side):
@ -768,6 +775,8 @@ class _StructField(_CompoundTypeComponent):
refexpr = self.refExpr(thisexpr)
if 'Shmem' == self.ipdltype.name():
refexpr = ExprCast(refexpr, Type('Shmem', ref=1), const=1)
if 'ByteBuf' == self.ipdltype.name():
refexpr = ExprCast(refexpr, Type('ByteBuf', ref=1), const=1)
if 'FileDescriptor' == self.ipdltype.name():
refexpr = ExprCast(refexpr, Type('FileDescriptor', ref=1), const=1)
return refexpr
@ -931,6 +940,8 @@ IPDL union type."""
def getConstValue(self):
v = ExprDeref(self.callGetConstPtr())
# sigh
if 'ByteBuf' == self.ipdltype.name():
v = ExprCast(v, Type('ByteBuf', ref=1), const=1)
if 'Shmem' == self.ipdltype.name():
v = ExprCast(v, Type('Shmem', ref=1), const=1)
if 'FileDescriptor' == self.ipdltype.name():
@ -1870,6 +1881,11 @@ stmt. Some types generate both kinds.'''
self.visited.add(s)
self.maybeTypedef('mozilla::ipc::Shmem', 'Shmem')
def visitByteBufType(self, s):
if s in self.visited: return
self.visited.add(s)
self.maybeTypedef('mozilla::ipc::ByteBuf', 'ByteBuf')
def visitFDType(self, s):
if s in self.visited: return
self.visited.add(s)
@ -3384,6 +3400,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
class findSpecialTypes(TypeVisitor):
def visitActorType(self, a): specialtypes.add(a)
def visitShmemType(self, s): specialtypes.add(s)
def visitByteBufType(self, s): specialtypes.add(s)
def visitFDType(self, s): specialtypes.add(s)
def visitStructType(self, s):
specialtypes.add(s)
@ -3408,12 +3425,13 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
ret.ipdltype.accept(findSpecialTypes())
for t in specialtypes:
if t.isActor(): self.implementActorPickling(t)
elif t.isArray(): self.implementSpecialArrayPickling(t)
elif t.isShmem(): self.implementShmemPickling(t)
elif t.isFD(): self.implementFDPickling(t)
elif t.isStruct(): self.implementStructPickling(t)
elif t.isUnion(): self.implementUnionPickling(t)
if t.isActor(): self.implementActorPickling(t)
elif t.isArray(): self.implementSpecialArrayPickling(t)
elif t.isShmem(): self.implementShmemPickling(t)
elif t.isByteBuf(): self.implementByteBufPickling(t)
elif t.isFD(): self.implementFDPickling(t)
elif t.isStruct(): self.implementStructPickling(t)
elif t.isUnion(): self.implementUnionPickling(t)
else:
assert 0 and 'unknown special type'
@ -3434,6 +3452,19 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
self.cls.addstmts([ write, Whitespace.NL, read, Whitespace.NL ])
def implementByteBufPickling(self, bytebuftype):
var = self.var
msgvar = self.msgvar
itervar = self.itervar
intype = _cxxRefType(bytebuftype, self.side)
write = MethodDefn(self.writeMethodDecl(intype, var))
write.addstmt(StmtExpr(ExprCall(ExprVar('IPC::WriteParam'),
args=[ msgvar, var ])))
self.cls.addstmts([ write, Whitespace.NL ])
# the rest of generic pickling will work fine for us
def implementActorPickling(self, actortype):
# Note that we pickle based on *protocol* type and *not* actor
# type. The actor type includes a |nullable| qualifier, but

Просмотреть файл

@ -67,6 +67,9 @@ class TypeVisitor:
def visitShmemType(self, s, *args):
pass
def visitByteBufType(self, s, *args):
pass
def visitShmemChmodType(self, c, *args):
c.shmem.accept(self)
@ -147,6 +150,7 @@ class IPDLType(Type):
def isAtom(self): return True
def isCompound(self): return False
def isShmem(self): return False
def isByteBuf(self): return False
def isFD(self): return False
def isEndpoint(self): return False
@ -368,6 +372,16 @@ class ShmemType(IPDLType):
def fullname(self):
return str(self.qname)
class ByteBufType(IPDLType):
def __init__(self, qname):
self.qname = qname
def isByteBuf(self): return True
def name(self):
return self.qname.baseid
def fullname(self):
return str(self.qname)
class FDType(IPDLType):
def __init__(self, qname):
self.qname = qname
@ -725,6 +739,8 @@ class GatherDecls(TcheckVisitor):
fullname = None
if fullname == 'mozilla::ipc::Shmem':
ipdltype = ShmemType(using.type.spec)
elif fullname == 'mozilla::ipc::ByteBuf':
ipdltype = ByteBufType(using.type.spec)
elif fullname == 'mozilla::ipc::FileDescriptor':
ipdltype = FDType(using.type.spec)
else:

Просмотреть файл

@ -7434,11 +7434,9 @@ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitte
if (!emitTreeInBranch(expr)) // EXPR
return false;
// Convert the value to the appropriate sort of iterator object for the
// loop variant (for-in, for-each-in, or destructuring for-in).
unsigned iflags = forInLoop->pn_iflags;
MOZ_ASSERT(0 == (iflags & ~JSITER_ENUMERATE));
if (!emit2(JSOP_ITER, AssertedCast<uint8_t>(iflags))) // ITER
MOZ_ASSERT(forInLoop->pn_iflags == 0);
if (!emit1(JSOP_ITER)) // ITER
return false;
// For-in loops have both the iterator and the value on the stack. Push
@ -7491,10 +7489,8 @@ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitte
#endif
MOZ_ASSERT(loopDepth >= 2);
if (iflags == JSITER_ENUMERATE) {
if (!emit1(JSOP_ITERNEXT)) // ITER ITERVAL
return false;
}
if (!emit1(JSOP_ITERNEXT)) // ITER ITERVAL
return false;
if (!emitInitializeForInOrOfTarget(forInHead)) // ITER ITERVAL
return false;

Просмотреть файл

@ -6306,12 +6306,10 @@ Parser<ParseHandler, CharT>::forStatement(YieldHandling yieldHandling)
Node target = startNode;
// Parse the rest of the for-in/of head.
if (headKind == PNK_FORIN) {
if (headKind == PNK_FORIN)
stmt.refineForKind(StatementKind::ForInLoop);
iflags |= JSITER_ENUMERATE;
} else {
else
stmt.refineForKind(StatementKind::ForOfLoop);
}
// Parser::declaration consumed everything up to the closing ')'. That
// token follows an {Assignment,}Expression and so must be interpreted

Просмотреть файл

@ -237,15 +237,14 @@ AtomMarkingRuntime::atomIsMarked(Zone* zone, TenuredCell* thing)
if (!thing)
return true;
JS::TraceKind kind = thing->getTraceKind();
if (kind == JS::TraceKind::String) {
JSString* str = static_cast<JSString*>(thing);
if (str->isAtom())
return atomIsMarked(zone, &str->asAtom());
return true;
if (thing->is<JSString>()) {
JSString* str = thing->as<JSString>();
return str->isAtom() ? atomIsMarked(zone, &str->asAtom()) : true;
}
if (kind == JS::TraceKind::Symbol)
return atomIsMarked(zone, static_cast<JS::Symbol*>(thing));
if (thing->is<JS::Symbol>())
return atomIsMarked(zone, thing->as<JS::Symbol>());
return true;
}

Просмотреть файл

@ -138,6 +138,23 @@ class TenuredCell : public Cell
return JS::shadow::Zone::asShadowZone(zoneFromAnyThread());
}
template <class T>
inline bool is() const {
return getTraceKind() == JS::MapTypeToTraceKind<T>::kind;
}
template<class T>
inline T* as() {
MOZ_ASSERT(is<T>());
return static_cast<T*>(this);
}
template <class T>
inline const T* as() const {
MOZ_ASSERT(is<T>());
return static_cast<const T*>(this);
}
static MOZ_ALWAYS_INLINE void readBarrier(TenuredCell* thing);
static MOZ_ALWAYS_INLINE void writeBarrierPre(TenuredCell* thing);

79
js/src/gc/DeletePolicy.h Normal file
Просмотреть файл

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef gc_DeletePolicy_h
#define gc_DeletePolicy_h
#include "js/TracingAPI.h"
namespace js {
namespace gc {
struct ClearEdgesTracer : public JS::CallbackTracer
{
ClearEdgesTracer();
#ifdef DEBUG
TracerKind getTracerKind() const override { return TracerKind::ClearEdges; }
#endif
template <typename T>
inline void clearEdge(T** thingp);
void onObjectEdge(JSObject** objp) override;
void onStringEdge(JSString** strp) override;
void onSymbolEdge(JS::Symbol** symp) override;
void onScriptEdge(JSScript** scriptp) override;
void onShapeEdge(js::Shape** shapep) override;
void onObjectGroupEdge(js::ObjectGroup** groupp) override;
void onBaseShapeEdge(js::BaseShape** basep) override;
void onJitCodeEdge(js::jit::JitCode** codep) override;
void onLazyScriptEdge(js::LazyScript** lazyp) override;
void onScopeEdge(js::Scope** scopep) override;
void onRegExpSharedEdge(js::RegExpShared** sharedp) override;
void onChild(const JS::GCCellPtr& thing) override;
};
#ifdef DEBUG
inline bool
IsClearEdgesTracer(JSTracer *trc)
{
return trc->isCallbackTracer() &&
trc->asCallbackTracer()->getTracerKind() == JS::CallbackTracer::TracerKind::ClearEdges;
}
#endif
} // namespace gc
/*
* Provides a delete policy that can be used for objects which have their
* lifetime managed by the GC so they can be safely destroyed outside of GC.
*
* This is necessary for example when initializing such an object may fail after
* the initial allocation. The partially-initialized object must be destroyed,
* but it may not be safe to do so at the current time as the store buffer may
* contain pointers into it.
*
* This policy traces GC pointers in the object and clears them, making sure to
* trigger barriers while doing so. This will remove any store buffer pointers
* into the object and make it safe to delete.
*/
template <typename T>
struct GCManagedDeletePolicy
{
void operator()(const T* constPtr) {
if (constPtr) {
auto ptr = const_cast<T*>(constPtr);
gc::ClearEdgesTracer trc;
ptr->trace(&trc);
js_delete(ptr);
}
}
};
} // namespace js
#endif // gc_DeletePolicy_h

Просмотреть файл

@ -2016,7 +2016,8 @@ inline T*
MarkStack::TaggedPtr::as() const
{
MOZ_ASSERT(tag() == MapTypeToMarkStackTag<T*>::value);
MOZ_ASSERT(ptr()->asTenured().getTraceKind() == MapTypeToTraceKind<T>::kind);
MOZ_ASSERT(ptr()->isTenured());
MOZ_ASSERT(ptr()->is<T>());
return static_cast<T*>(ptr());
}
@ -2024,7 +2025,8 @@ inline JSObject*
MarkStack::TaggedPtr::asValueArrayObject() const
{
MOZ_ASSERT(tag() == ValueArrayTag);
MOZ_ASSERT(ptr()->asTenured().getTraceKind() == JS::TraceKind::Object);
MOZ_ASSERT(ptr()->isTenured());
MOZ_ASSERT(ptr()->is<JSObject>());
return static_cast<JSObject*>(ptr());
}
@ -2032,7 +2034,8 @@ inline JSObject*
MarkStack::TaggedPtr::asSavedValueArrayObject() const
{
MOZ_ASSERT(tag() == SavedValueArrayTag);
MOZ_ASSERT(ptr()->asTenured().getTraceKind() == JS::TraceKind::Object);
MOZ_ASSERT(ptr()->isTenured());
MOZ_ASSERT(ptr()->is<JSObject>());
return static_cast<JSObject*>(ptr());
}
@ -2040,7 +2043,8 @@ inline JSRope*
MarkStack::TaggedPtr::asTempRope() const
{
MOZ_ASSERT(tag() == TempRopeTag);
MOZ_ASSERT(ptr()->asTenured().getTraceKind() == JS::TraceKind::String);
MOZ_ASSERT(ptr()->isTenured());
MOZ_ASSERT(ptr()->is<JSString>());
return static_cast<JSRope*>(ptr());
}

Просмотреть файл

@ -9,21 +9,20 @@
#include "mozilla/Atomics.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/MemoryReporting.h"
#include "jscntxt.h"
#include "ds/SplayTree.h"
#include "gc/FindSCCs.h"
#include "gc/GCRuntime.h"
#include "js/GCHashTable.h"
#include "js/TracingAPI.h"
#include "vm/MallocProvider.h"
#include "vm/RegExpShared.h"
#include "vm/TypeInference.h"
#include "vm/Runtime.h"
struct JSContext;
namespace js {
class Debugger;
namespace jit {
class JitZone;
} // namespace jit
@ -987,92 +986,6 @@ ZoneAllocPolicy::pod_realloc(T* p, size_t oldSize, size_t newSize)
return zone->pod_realloc<T>(p, oldSize, newSize);
}
/*
* Provides a delete policy that can be used for objects which have their
* lifetime managed by the GC so they can be safely destroyed outside of GC.
*
* This is necessary for example when initializing such an object may fail after
* the initial allocation. The partially-initialized object must be destroyed,
* but it may not be safe to do so at the current time as the store buffer may
* contain pointers into it.
*
* This policy traces GC pointers in the object and clears them, making sure to
* trigger barriers while doing so. This will remove any store buffer pointers
* into the object and make it safe to delete.
*/
template <typename T>
struct GCManagedDeletePolicy
{
struct ClearEdgesTracer : public JS::CallbackTracer
{
explicit ClearEdgesTracer(JSContext* cx) : CallbackTracer(cx, TraceWeakMapKeysValues) {}
#ifdef DEBUG
TracerKind getTracerKind() const override { return TracerKind::ClearEdges; }
#endif
template <typename S>
void clearEdge(S** thingp) {
InternalBarrierMethods<S*>::preBarrier(*thingp);
InternalBarrierMethods<S*>::postBarrier(thingp, *thingp, nullptr);
*thingp = nullptr;
}
void onObjectEdge(JSObject** objp) override { clearEdge(objp); }
void onStringEdge(JSString** strp) override { clearEdge(strp); }
void onSymbolEdge(JS::Symbol** symp) override { clearEdge(symp); }
void onScriptEdge(JSScript** scriptp) override { clearEdge(scriptp); }
void onShapeEdge(js::Shape** shapep) override { clearEdge(shapep); }
void onObjectGroupEdge(js::ObjectGroup** groupp) override { clearEdge(groupp); }
void onBaseShapeEdge(js::BaseShape** basep) override { clearEdge(basep); }
void onJitCodeEdge(js::jit::JitCode** codep) override { clearEdge(codep); }
void onLazyScriptEdge(js::LazyScript** lazyp) override { clearEdge(lazyp); }
void onScopeEdge(js::Scope** scopep) override { clearEdge(scopep); }
void onRegExpSharedEdge(js::RegExpShared** sharedp) override { clearEdge(sharedp); }
void onChild(const JS::GCCellPtr& thing) override { MOZ_CRASH(); }
};
void operator()(const T* constPtr) {
if (constPtr) {
auto ptr = const_cast<T*>(constPtr);
ClearEdgesTracer trc(TlsContext.get());
ptr->trace(&trc);
js_delete(ptr);
}
}
};
#ifdef DEBUG
inline bool
IsClearEdgesTracer(JSTracer *trc)
{
return trc->isCallbackTracer() &&
trc->asCallbackTracer()->getTracerKind() == JS::CallbackTracer::TracerKind::ClearEdges;
}
#endif
} // namespace js
namespace JS {
// Scope data that contain GCPtrs must use the correct DeletePolicy.
//
// This is defined here because vm/Scope.h cannot #include "vm/Runtime.h"
template <>
struct DeletePolicy<js::FunctionScope::Data>
: public js::GCManagedDeletePolicy<js::FunctionScope::Data>
{ };
template <>
struct DeletePolicy<js::ModuleScope::Data>
: public js::GCManagedDeletePolicy<js::ModuleScope::Data>
{ };
template <>
struct DeletePolicy<js::WasmInstanceScope::Data>
: public js::GCManagedDeletePolicy<js::WasmInstanceScope::Data>
{ };
} // namespace JS
#endif // gc_Zone_h

Просмотреть файл

@ -0,0 +1,5 @@
var g = newGlobal();
g.eval("azx918 = 1");
for (var x in g) {
assertEq(x, x);
}

Просмотреть файл

@ -0,0 +1,12 @@
function g(s) {
for (var i = s; ; i--) {
if (s[i] !== ' ')
return;
}
}
function f() {
var s = "foo".match(/(.*)$/)[0];
return g(s);
}
for (var i = 0; i < 10; i++)
f();

Просмотреть файл

@ -4087,7 +4087,6 @@ static bool
DoGetIteratorFallback(JSContext* cx, BaselineFrame* frame, ICGetIterator_Fallback* stub,
HandleValue value, MutableHandleValue res)
{
jsbytecode* pc = stub->icEntry()->pc(frame->script());
FallbackICSpew(cx, stub, "GetIterator");
if (stub->state().maybeTransition())
@ -4111,8 +4110,7 @@ DoGetIteratorFallback(JSContext* cx, BaselineFrame* frame, ICGetIterator_Fallbac
stub->state().trackNotAttached();
}
uint8_t flags = GET_UINT8(pc);
JSObject* iterobj = ValueToIterator(cx, flags, value);
JSObject* iterobj = ValueToIterator(cx, value);
if (!iterobj)
return false;

Просмотреть файл

@ -4009,9 +4009,6 @@ GetIteratorIRGenerator::tryAttachNativeIterator(ObjOperandId objId, HandleObject
{
MOZ_ASSERT(JSOp(*pc_) == JSOP_ITER);
if (GET_UINT8(pc_) != JSITER_ENUMERATE)
return false;
PropertyIteratorObject* iterobj = LookupInIteratorCache(cx_, obj);
if (!iterobj)
return false;

Просмотреть файл

@ -470,8 +470,6 @@ CacheRegisterAllocator::fixupAliasedInputs(MacroAssembler& masm)
// PayloadReg: spilling the ValueReg instead would leave its type
// register unallocated on 32-bit platforms.
if (loc1.kind() == OperandLocation::ValueReg) {
MOZ_ASSERT_IF(loc2.kind() == OperandLocation::ValueReg,
loc1 == loc2);
spillOperandToStack(masm, &loc2);
} else {
MOZ_ASSERT(loc1.kind() == OperandLocation::PayloadReg);

Просмотреть файл

@ -9291,9 +9291,6 @@ CodeGenerator::visitIteratorEnd(LIteratorEnd* lir)
LoadNativeIterator(masm, obj, temp1, ool->entry());
masm.branchTest32(Assembler::Zero, Address(temp1, offsetof(NativeIterator, flags)),
Imm32(JSITER_ENUMERATE), ool->entry());
// Clear active bit.
masm.and32(Imm32(~JSITER_ACTIVE), Address(temp1, offsetof(NativeIterator, flags)));

Просмотреть файл

@ -2305,7 +2305,7 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_copylexicalenv(false);
case JSOP_ITER:
return jsop_iter(GET_INT8(pc));
return jsop_iter();
case JSOP_MOREITER:
return jsop_itermore();
@ -12577,7 +12577,7 @@ IonBuilder::jsop_toid()
}
AbortReasonOr<Ok>
IonBuilder::jsop_iter(uint8_t flags)
IonBuilder::jsop_iter()
{
MDefinition* obj = current->pop();
MInstruction* ins = MGetIteratorCache::New(alloc(), obj);

Просмотреть файл

@ -578,7 +578,7 @@ class IonBuilder
AbortReasonOr<Ok> jsop_toasyncgen();
AbortReasonOr<Ok> jsop_toasynciter();
AbortReasonOr<Ok> jsop_toid();
AbortReasonOr<Ok> jsop_iter(uint8_t flags);
AbortReasonOr<Ok> jsop_iter();
AbortReasonOr<Ok> jsop_itermore();
AbortReasonOr<Ok> jsop_isnoiter();
AbortReasonOr<Ok> jsop_iterend();

Просмотреть файл

@ -402,7 +402,6 @@ IonGetIteratorIC::update(JSContext* cx, HandleScript outerScript, IonGetIterator
HandleValue value)
{
IonScript* ionScript = outerScript->ionScript();
jsbytecode* pc = ic->pc();
if (ic->state().maybeTransition())
ic->discardStubs(cx->zone());
@ -410,7 +409,7 @@ IonGetIteratorIC::update(JSContext* cx, HandleScript outerScript, IonGetIterator
if (ic->state().canAttachStub()) {
bool attached = false;
RootedScript script(cx, ic->script());
GetIteratorIRGenerator gen(cx, script, pc, ic->state().mode(), value);
GetIteratorIRGenerator gen(cx, script, ic->pc(), ic->state().mode(), value);
if (gen.tryAttachStub())
ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
@ -418,8 +417,7 @@ IonGetIteratorIC::update(JSContext* cx, HandleScript outerScript, IonGetIterator
ic->state().trackNotAttached();
}
uint8_t flags = GET_UINT8(pc);
return ValueToIterator(cx, flags, value);
return ValueToIterator(cx, value);
}
/* static */ bool

Просмотреть файл

@ -18,6 +18,7 @@
#include "js/Vector.h"
#include "threading/ProtectedData.h"
#include "vm/ErrorReporting.h"
#include "vm/MallocProvider.h"
#include "vm/Runtime.h"
#ifdef _MSC_VER

Просмотреть файл

@ -1000,9 +1000,8 @@ IsObjectInContextCompartment(JSObject* obj, const JSContext* cx);
/*
* NB: keep these in sync with the copy in builtin/SelfHostingDefines.h.
* The first two are omitted because they shouldn't be used in new code.
*/
#define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */
/* 0x1 is no longer used */
/* 0x2 is no longer used */
/* 0x4 is no longer used */
#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */

Просмотреть файл

@ -9047,3 +9047,29 @@ js::gc::detail::CellIsNotGray(const Cell* cell)
return false;
}
#endif
js::gc::ClearEdgesTracer::ClearEdgesTracer()
: CallbackTracer(TlsContext.get(), TraceWeakMapKeysValues)
{}
template <typename S>
inline void
js::gc::ClearEdgesTracer::clearEdge(S** thingp)
{
InternalBarrierMethods<S*>::preBarrier(*thingp);
InternalBarrierMethods<S*>::postBarrier(thingp, *thingp, nullptr);
*thingp = nullptr;
}
void js::gc::ClearEdgesTracer::onObjectEdge(JSObject** objp) { clearEdge(objp); }
void js::gc::ClearEdgesTracer::onStringEdge(JSString** strp) { clearEdge(strp); }
void js::gc::ClearEdgesTracer::onSymbolEdge(JS::Symbol** symp) { clearEdge(symp); }
void js::gc::ClearEdgesTracer::onScriptEdge(JSScript** scriptp) { clearEdge(scriptp); }
void js::gc::ClearEdgesTracer::onShapeEdge(js::Shape** shapep) { clearEdge(shapep); }
void js::gc::ClearEdgesTracer::onObjectGroupEdge(js::ObjectGroup** groupp) { clearEdge(groupp); }
void js::gc::ClearEdgesTracer::onBaseShapeEdge(js::BaseShape** basep) { clearEdge(basep); }
void js::gc::ClearEdgesTracer::onJitCodeEdge(js::jit::JitCode** codep) { clearEdge(codep); }
void js::gc::ClearEdgesTracer::onLazyScriptEdge(js::LazyScript** lazyp) { clearEdge(lazyp); }
void js::gc::ClearEdgesTracer::onScopeEdge(js::Scope** scopep) { clearEdge(scopep); }
void js::gc::ClearEdgesTracer::onRegExpSharedEdge(js::RegExpShared** sharedp) { clearEdge(sharedp); }
void js::gc::ClearEdgesTracer::onChild(const JS::GCCellPtr& thing) { MOZ_CRASH(); }

Просмотреть файл

@ -537,36 +537,32 @@ js::GetPropertyKeys(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto
}
static inline PropertyIteratorObject*
NewPropertyIteratorObject(JSContext* cx, unsigned flags)
NewPropertyIteratorObject(JSContext* cx)
{
if (flags & JSITER_ENUMERATE) {
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PropertyIteratorObject::class_,
TaggedProto(nullptr)));
if (!group)
return nullptr;
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &PropertyIteratorObject::class_,
TaggedProto(nullptr)));
if (!group)
return nullptr;
const Class* clasp = &PropertyIteratorObject::class_;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(nullptr),
ITERATOR_FINALIZE_KIND));
if (!shape)
return nullptr;
const Class* clasp = &PropertyIteratorObject::class_;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(nullptr),
ITERATOR_FINALIZE_KIND));
if (!shape)
return nullptr;
JSObject* obj;
JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, ITERATOR_FINALIZE_KIND,
GetInitialHeap(GenericObject, clasp),
shape, group));
JSObject* obj;
JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, ITERATOR_FINALIZE_KIND,
GetInitialHeap(GenericObject, clasp),
shape, group));
PropertyIteratorObject* res = &obj->as<PropertyIteratorObject>();
PropertyIteratorObject* res = &obj->as<PropertyIteratorObject>();
// CodeGenerator::visitIteratorStartO assumes the iterator object is not
// inside the nursery when deciding whether a barrier is necessary.
MOZ_ASSERT(!js::gc::IsInsideNursery(res));
// CodeGenerator::visitIteratorStartO assumes the iterator object is not
// inside the nursery when deciding whether a barrier is necessary.
MOZ_ASSERT(!js::gc::IsInsideNursery(res));
MOZ_ASSERT(res->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);
return res;
}
return NewBuiltinClassInstance<PropertyIteratorObject>(cx);
MOZ_ASSERT(res->numFixedSlots() == JSObject::ITER_CLASS_NFIXED_SLOTS);
return res;
}
NativeIterator*
@ -607,11 +603,11 @@ NativeIterator::allocateSentinel(JSContext* maybecx)
}
inline void
NativeIterator::init(JSObject* obj, JSObject* iterObj, unsigned flags, uint32_t numGuards, uint32_t key)
NativeIterator::init(JSObject* obj, JSObject* iterObj, uint32_t numGuards, uint32_t key)
{
this->obj.init(obj);
this->iterObj_ = iterObj;
this->flags = flags;
this->flags = 0;
this->guard_array = (HeapReceiverGuard*) this->props_end;
this->guard_length = numGuards;
this->guard_key = key;
@ -642,23 +638,20 @@ static inline void
RegisterEnumerator(JSContext* cx, PropertyIteratorObject* iterobj, NativeIterator* ni)
{
/* Register non-escaping native enumerators (for-in) with the current context. */
if (ni->flags & JSITER_ENUMERATE) {
ni->link(cx->compartment()->enumerators);
ni->link(cx->compartment()->enumerators);
MOZ_ASSERT(!(ni->flags & JSITER_ACTIVE));
ni->flags |= JSITER_ACTIVE;
}
MOZ_ASSERT(!(ni->flags & JSITER_ACTIVE));
ni->flags |= JSITER_ACTIVE;
}
static inline PropertyIteratorObject*
VectorToKeyIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector& keys,
uint32_t numGuards)
VectorToKeyIterator(JSContext* cx, HandleObject obj, AutoIdVector& keys, uint32_t numGuards)
{
if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj))
return nullptr;
MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx, flags));
Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx));
if (!iterobj)
return nullptr;
@ -667,7 +660,7 @@ VectorToKeyIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto
return nullptr;
iterobj->setNativeIterator(ni);
ni->init(obj, iterobj, flags, numGuards, 0);
ni->init(obj, iterobj, numGuards, 0);
if (!ni->initProperties(cx, iterobj, keys))
return nullptr;
@ -699,17 +692,16 @@ VectorToKeyIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto
JSObject*
js::EnumeratedIdVectorToIterator(JSContext* cx, HandleObject obj, unsigned flags,
AutoIdVector& props)
js::EnumeratedIdVectorToIterator(JSContext* cx, HandleObject obj, AutoIdVector& props)
{
return VectorToKeyIterator(cx, obj, flags, props, 0);
return VectorToKeyIterator(cx, obj, props, 0);
}
// Mainly used for .. in over null/undefined
JSObject*
js::NewEmptyPropertyIterator(JSContext* cx, unsigned flags)
js::NewEmptyPropertyIterator(JSContext* cx)
{
Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx, flags));
Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx));
if (!iterobj)
return nullptr;
@ -719,7 +711,7 @@ js::NewEmptyPropertyIterator(JSContext* cx, unsigned flags)
return nullptr;
iterobj->setNativeIterator(ni);
ni->init(nullptr, iterobj, flags, 0, 0);
ni->init(nullptr, iterobj, 0, 0);
if (!ni->initProperties(cx, iterobj, keys))
return nullptr;
@ -766,10 +758,6 @@ LookupInIteratorCache(JSContext* cx, JSObject* obj, uint32_t* numGuards)
{
MOZ_ASSERT(*numGuards == 0);
// The iterator object for JSITER_ENUMERATE never escapes, so we don't
// care that the "proper" prototype is set. This also lets us reuse an
// old, inactive iterator object.
ReceiverGuardVector guards(cx);
uint32_t key = 0;
JSObject* pobj = obj;
@ -861,39 +849,29 @@ StoreInIteratorCache(JSContext* cx, JSObject* obj, PropertyIteratorObject* itero
}
JSObject*
js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags)
js::GetIterator(JSContext* cx, HandleObject obj)
{
uint32_t numGuards = 0;
if (flags == JSITER_ENUMERATE) {
if (PropertyIteratorObject* iterobj = LookupInIteratorCache(cx, obj, &numGuards)) {
NativeIterator* ni = iterobj->getNativeIterator();
UpdateNativeIterator(ni, obj);
RegisterEnumerator(cx, iterobj, ni);
return iterobj;
}
if (numGuards > 0 && !CanStoreInIteratorCache(cx, obj))
numGuards = 0;
if (PropertyIteratorObject* iterobj = LookupInIteratorCache(cx, obj, &numGuards)) {
NativeIterator* ni = iterobj->getNativeIterator();
UpdateNativeIterator(ni, obj);
RegisterEnumerator(cx, iterobj, ni);
return iterobj;
}
if (MOZ_UNLIKELY(obj->is<PropertyIteratorObject>()))
return obj;
if (numGuards > 0 && !CanStoreInIteratorCache(cx, obj))
numGuards = 0;
// We should only call the enumerate trap for "for-in".
// Or when we call GetIterator from the Proxy [[Enumerate]] hook.
// JSITER_ENUMERATE is just an optimization and the same
// as flags == 0 otherwise.
if (flags == 0 || flags == JSITER_ENUMERATE) {
if (MOZ_UNLIKELY(obj->is<ProxyObject>()))
return Proxy::enumerate(cx, obj);
}
MOZ_ASSERT(!obj->is<PropertyIteratorObject>());
if (MOZ_UNLIKELY(obj->is<ProxyObject>()))
return Proxy::enumerate(cx, obj);
AutoIdVector keys(cx);
if (!Snapshot(cx, obj, flags, &keys))
if (!Snapshot(cx, obj, 0, &keys))
return nullptr;
JSObject* res = VectorToKeyIterator(cx, obj, flags, keys, numGuards);
JSObject* res = VectorToKeyIterator(cx, obj, keys, numGuards);
if (!res)
return nullptr;
@ -997,17 +975,15 @@ JSCompartment::getOrCreateIterResultTemplateObject(JSContext* cx)
/*** Iterator objects ****************************************************************************/
MOZ_ALWAYS_INLINE bool
NativeIteratorNext(JSContext* cx, NativeIterator* ni, MutableHandleValue rval)
MOZ_ALWAYS_INLINE void
NativeIteratorNext(NativeIterator* ni, MutableHandleValue rval)
{
if (ni->props_cursor >= ni->props_end) {
rval.setMagic(JS_NO_ITER_VALUE);
return true;
} else {
rval.setString(*ni->current());
ni->incCursor();
}
rval.setString(*ni->current());
ni->incCursor();
return true;
}
bool
@ -1122,26 +1098,26 @@ js::NewStringIteratorObject(JSContext* cx, NewObjectKind newKind)
}
JSObject*
js::ValueToIterator(JSContext* cx, unsigned flags, HandleValue vp)
js::ValueToIterator(JSContext* cx, HandleValue vp)
{
RootedObject obj(cx);
if (vp.isObject()) {
/* Common case. */
obj = &vp.toObject();
} else if ((flags & JSITER_ENUMERATE) && vp.isNullOrUndefined()) {
} else if (vp.isNullOrUndefined()) {
/*
* Enumerating over null and undefined gives an empty enumerator, so
* that |for (var p in <null or undefined>) <loop>;| never executes
* <loop>, per ES5 12.6.4.
*/
return NewEmptyPropertyIterator(cx, flags);
return NewEmptyPropertyIterator(cx);
} else {
obj = ToObject(cx, vp);
if (!obj)
return nullptr;
}
return GetIterator(cx, obj, flags);
return GetIterator(cx, obj);
}
void
@ -1151,18 +1127,16 @@ js::CloseIterator(JSObject* obj)
/* Remove enumerators from the active list, which is a stack. */
NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
if (ni->flags & JSITER_ENUMERATE) {
ni->unlink();
ni->unlink();
MOZ_ASSERT(ni->flags & JSITER_ACTIVE);
ni->flags &= ~JSITER_ACTIVE;
MOZ_ASSERT(ni->flags & JSITER_ACTIVE);
ni->flags &= ~JSITER_ACTIVE;
/*
* Reset the enumerator; it may still be in the cached iterators
* for this thread, and can be reused.
*/
ni->props_cursor = ni->props_array;
}
/*
* Reset the enumerator; it may still be in the cached iterators
* for this thread, and can be reused.
*/
ni->props_cursor = ni->props_array;
}
}
@ -1221,8 +1195,7 @@ js::UnwindIteratorForUncatchableException(JSContext* cx, JSObject* obj)
{
if (obj->is<PropertyIteratorObject>()) {
NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
if (ni->flags & JSITER_ENUMERATE)
ni->unlink();
ni->unlink();
}
}
@ -1371,7 +1344,8 @@ js::IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval)
// Fast path for native iterators.
if (MOZ_LIKELY(iterobj->is<PropertyIteratorObject>())) {
NativeIterator* ni = iterobj->as<PropertyIteratorObject>().getNativeIterator();
return NativeIteratorNext(cx, ni, rval);
NativeIteratorNext(ni, rval);
return true;
}
if (JS_IsDeadWrapper(iterobj)) {
@ -1389,8 +1363,7 @@ js::IteratorMore(JSContext* cx, HandleObject iterobj, MutableHandleValue rval)
{
AutoCompartment ac(cx, obj);
NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
if (!NativeIteratorNext(cx, ni, rval))
return false;
NativeIteratorNext(ni, rval);
}
return cx->compartment()->wrap(cx, rval);
}

Просмотреть файл

@ -85,7 +85,6 @@ struct NativeIterator
void link(NativeIterator* other) {
/* A NativeIterator cannot appear in the enumerator list twice. */
MOZ_ASSERT(!next_ && !prev_);
MOZ_ASSERT(flags & JSITER_ENUMERATE);
this->next_ = other;
this->prev_ = other->prev_;
@ -93,8 +92,6 @@ struct NativeIterator
other->prev_ = this;
}
void unlink() {
MOZ_ASSERT(flags & JSITER_ENUMERATE);
next_->prev_ = prev_;
prev_->next_ = next_;
next_ = nullptr;
@ -103,7 +100,7 @@ struct NativeIterator
static NativeIterator* allocateSentinel(JSContext* maybecx);
static NativeIterator* allocateIterator(JSContext* cx, uint32_t slength, uint32_t plength);
void init(JSObject* obj, JSObject* iterObj, unsigned flags, uint32_t slength, uint32_t key);
void init(JSObject* obj, JSObject* iterObj, uint32_t slength, uint32_t key);
bool initProperties(JSContext* cx, Handle<PropertyIteratorObject*> obj,
const js::AutoIdVector& props);
@ -154,29 +151,19 @@ StringIteratorObject*
NewStringIteratorObject(JSContext* cx, NewObjectKind newKind = GenericObject);
JSObject*
GetIterator(JSContext* cx, HandleObject obj, unsigned flags);
GetIterator(JSContext* cx, HandleObject obj);
PropertyIteratorObject*
LookupInIteratorCache(JSContext* cx, HandleObject obj);
/*
* Creates either a key or value iterator, depending on flags. For a value
* iterator, performs value-lookup to convert the given list of jsids.
*/
JSObject*
EnumeratedIdVectorToIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector& props);
EnumeratedIdVectorToIterator(JSContext* cx, HandleObject obj, AutoIdVector& props);
JSObject*
NewEmptyPropertyIterator(JSContext* cx, unsigned flags);
NewEmptyPropertyIterator(JSContext* cx);
/*
* Convert the value stored in *vp to its iteration object. The flags should
* contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating
* for-in semantics are required, and when the caller can guarantee that the
* iterator will never be exposed to scripts.
*/
JSObject*
ValueToIterator(JSContext* cx, unsigned flags, HandleValue vp);
ValueToIterator(JSContext* cx, HandleValue vp);
void
CloseIterator(JSObject* obj);

Просмотреть файл

@ -14,6 +14,7 @@
#include "jsfriendapi.h"
#include "jsobj.h"
#include "gc/DeletePolicy.h"
#include "gc/StoreBuffer.h"
#include "js/HashTable.h"

Просмотреть файл

@ -284,7 +284,7 @@ BaseProxyHandler::enumerate(JSContext* cx, HandleObject proxy) const
if (!GetPropertyKeys(cx, proxy, 0, &props))
return nullptr;
return EnumeratedIdVectorToIterator(cx, proxy, 0, props);
return EnumeratedIdVectorToIterator(cx, proxy, props);
}
bool

Просмотреть файл

@ -260,8 +260,7 @@ CrossCompartmentWrapper::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObjec
static bool
CanReify(HandleObject obj)
{
return obj->is<PropertyIteratorObject>() &&
(obj->as<PropertyIteratorObject>().getNativeIterator()->flags & JSITER_ENUMERATE);
return obj->is<PropertyIteratorObject>();
}
struct AutoCloseIterator
@ -303,11 +302,13 @@ Reify(JSContext* cx, JSCompartment* origin, HandleObject objp)
if (length > 0) {
if (!keys.reserve(length))
return nullptr;
RootedId id(cx);
RootedValue v(cx);
for (size_t i = 0; i < length; ++i) {
RootedId id(cx);
RootedValue v(cx, StringValue(ni->begin()[i]));
v.setString(ni->begin()[i]);
if (!ValueToId<CanGC>(cx, v, &id))
return nullptr;
cx->markId(id);
keys.infallibleAppend(id);
}
}
@ -315,7 +316,7 @@ Reify(JSContext* cx, JSCompartment* origin, HandleObject objp)
close.clear();
CloseIterator(iterObj);
obj = EnumeratedIdVectorToIterator(cx, obj, ni->flags, keys);
obj = EnumeratedIdVectorToIterator(cx, obj, keys);
}
return obj;
}

Просмотреть файл

@ -467,7 +467,7 @@ Proxy::enumerate(JSContext* cx, HandleObject proxy)
if (!GetPrototype(cx, proxy, &proto))
return nullptr;
if (!proto)
return EnumeratedIdVectorToIterator(cx, proxy, 0, props);
return EnumeratedIdVectorToIterator(cx, proxy, props);
assertSameCompartment(cx, proxy, proto);
AutoIdVector protoProps(cx);
@ -475,7 +475,7 @@ Proxy::enumerate(JSContext* cx, HandleObject proxy)
return nullptr;
if (!AppendUnique(cx, props, protoProps))
return nullptr;
return EnumeratedIdVectorToIterator(cx, proxy, 0, props);
return EnumeratedIdVectorToIterator(cx, proxy, props);
}
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
@ -486,7 +486,7 @@ Proxy::enumerate(JSContext* cx, HandleObject proxy)
if (!policy.allowed()) {
if (!policy.returnValue())
return nullptr;
return NewEmptyPropertyIterator(cx, 0);
return NewEmptyPropertyIterator(cx);
}
return handler->enumerate(cx, proxy);
}

Просмотреть файл

@ -86,7 +86,7 @@ ForwardingProxyHandler::enumerate(JSContext* cx, HandleObject proxy) const
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetIterator(cx, target, 0);
return GetIterator(cx, target);
}
bool

Просмотреть файл

@ -2276,10 +2276,8 @@ END_CASE(JSOP_HASOWN)
CASE(JSOP_ITER)
{
MOZ_ASSERT(REGS.stackDepth() >= 1);
uint8_t flags = GET_UINT8(REGS.pc);
HandleValue val = REGS.stackHandleAt(-1);
ReservedRooted<JSObject*> iter(&rootObject0);
iter.set(ValueToIterator(cx, flags, val));
JSObject* iter = ValueToIterator(cx, val);
if (!iter)
goto error;
REGS.sp[-1].setObject(*iter);

Просмотреть файл

@ -56,11 +56,11 @@ ShiftFromList(JSContext* cx, HandleNativeObject list)
Rooted<T*> entry(cx, &list->getDenseElement(0).toObject().as<T>());
if (!list->tryShiftDenseElements(1)) {
list->moveDenseElements(0, 1, length - 1);
list->setDenseInitializedLength(length - 1);
list->shrinkElements(cx, length - 1);
}
list->setDenseInitializedLength(length - 1);
MOZ_ASSERT(list->getDenseInitializedLength() == length - 1);
return entry;
}

Просмотреть файл

@ -997,6 +997,8 @@ void
NativeObject::shrinkElements(JSContext* cx, uint32_t reqCapacity)
{
MOZ_ASSERT(canHaveNonEmptyElements());
MOZ_ASSERT(reqCapacity >= getDenseInitializedLength());
if (denseElementsAreCopyOnWrite())
MOZ_CRASH();

Просмотреть файл

@ -698,15 +698,14 @@
macro(JSOP_THROWMSG, 74, "throwmsg", NULL, 3, 0, 0, JOF_UINT16) \
\
/*
* Sets up a for-in or for-each-in loop using the JSITER_* flag bits in
* this op's uint8_t immediate operand. It pops the top of stack value as
* 'val' and pushes 'iter' which is an iterator for 'val'.
* Sets up a for-in loop. It pops the top of stack value as 'val' and pushes
* 'iter' which is an iterator for 'val'.
* Category: Statements
* Type: For-In Statement
* Operands: uint8_t flags
* Operands:
* Stack: val => iter
*/ \
macro(JSOP_ITER, 75, "iter", NULL, 2, 1, 1, JOF_UINT8) \
macro(JSOP_ITER, 75, "iter", NULL, 1, 1, 1, JOF_BYTE) \
/*
* Pushes the next iterated value onto the stack. If no value is available,
* MagicValue(JS_NO_ITER_VALUE) is pushed.

Просмотреть файл

@ -13,6 +13,7 @@
#include "jsobj.h"
#include "jsopcode.h"
#include "gc/DeletePolicy.h"
#include "gc/Heap.h"
#include "gc/Policy.h"
#include "js/UbiNode.h"
@ -1538,6 +1539,23 @@ DEFINE_SCOPE_DATA_GCPOLICY(js::WasmFunctionScope::Data);
#undef DEFINE_SCOPE_DATA_GCPOLICY
// Scope data that contain GCPtrs must use the correct DeletePolicy.
template <>
struct DeletePolicy<js::FunctionScope::Data>
: public js::GCManagedDeletePolicy<js::FunctionScope::Data>
{};
template <>
struct DeletePolicy<js::ModuleScope::Data>
: public js::GCManagedDeletePolicy<js::ModuleScope::Data>
{};
template <>
struct DeletePolicy<js::WasmInstanceScope::Data>
: public js::GCManagedDeletePolicy<js::WasmInstanceScope::Data>
{ };
namespace ubi {
template <>

Просмотреть файл

@ -9,6 +9,7 @@
#include "jsobj.h"
#include "gc/DeletePolicy.h"
#include "gc/Zone.h"
#include "vm/Runtime.h"
#include "vm/TypeInference.h"

Просмотреть файл

@ -1729,6 +1729,20 @@ const JSPropertySpec WasmTableObject::properties[] =
JS_PS_END
};
static bool
ToTableIndex(JSContext* cx, HandleValue v, const Table& table, const char* noun, uint32_t* index)
{
if (!EnforceRangeU32(cx, v, UINT32_MAX, "Table", noun, index))
return false;
if (*index >= table.length()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, "Table", noun);
return false;
}
return true;
}
/* static */ bool
WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
{
@ -1736,7 +1750,7 @@ WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
const Table& table = tableObj->table();
uint32_t index;
if (!EnforceRangeU32(cx, args.get(0), table.length() - 1, "Table", "get index", &index))
if (!ToTableIndex(cx, args.get(0), table, "get index", &index))
return false;
ExternalTableElem& elem = table.externalArray()[index];
@ -1775,7 +1789,7 @@ WasmTableObject::setImpl(JSContext* cx, const CallArgs& args)
return false;
uint32_t index;
if (!EnforceRangeU32(cx, args.get(0), table.length() - 1, "Table", "set index", &index))
if (!ToTableIndex(cx, args.get(0), table, "set index", &index))
return false;
RootedFunction value(cx);

Просмотреть файл

@ -125,6 +125,7 @@
#include "mozilla/dom/ipc/IPCBlobInputStreamStorage.h"
#include "mozilla/dom/U2FTokenManager.h"
#include "mozilla/dom/PointerEventHandler.h"
#include "nsHostObjectProtocolHandler.h"
using namespace mozilla;
using namespace mozilla::net;
@ -433,4 +434,6 @@ nsLayoutStatics::Shutdown()
CacheObserver::Shutdown();
PromiseDebugging::Shutdown();
nsHostObjectProtocolHandler::RemoveDataEntries();
}

Просмотреть файл

@ -477,9 +477,6 @@ struct nsGridContainerFrame::LineRange
mEnd > mStart, "invalid line range");
mEnd -= aNumRemovedTracks[mEnd];
}
if (mStart == mEnd) {
mEnd = nsGridContainerFrame::kAutoLine;
}
}
/**
* Return the contribution of this line range for step 2 in
@ -4839,10 +4836,15 @@ nsGridContainerFrame::LineRange::ToPositionAndLengthForAbsPos(
: GridLineSide::eBeforeGridGap;
nscoord endPos = aTracks.GridLineEdge(mEnd, side);
*aLength = std::max(aGridOrigin + endPos, 0);
} else {
} else if (MOZ_LIKELY(mStart != mEnd)) {
nscoord pos;
ToPositionAndLength(aTracks.mSizes, &pos, aLength);
*aPos = aGridOrigin + pos;
} else {
// The grid area only covers removed 'auto-fit' tracks.
nscoord pos = aTracks.GridLineEdge(mStart, GridLineSide::eBeforeGridGap);
*aPos = aGridOrigin + pos;
*aLength = nscoord(0);
}
}
}

Просмотреть файл

@ -50,9 +50,6 @@ public:
NS_IMETHOD GetPrintRange(int32_t* aFromPage, int32_t* aToPage) = 0;
NS_IMETHOD DoPageEnd() = 0;
NS_IMETHOD SetSelectionHeight(nscoord aYOffset, nscoord aHeight) = 0;
NS_IMETHOD SetTotalNumPages(int32_t aTotal) = 0;
// For Shrink To Fit
NS_IMETHOD GetSTFPercent(float& aSTFPercent) = 0;

Просмотреть файл

@ -47,8 +47,6 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSimplePageSequenceFrame)
nsSimplePageSequenceFrame::nsSimplePageSequenceFrame(nsStyleContext* aContext)
: nsContainerFrame(aContext, kClassID)
, mTotalPages(-1)
, mSelectionHeight(-1)
, mYSelOffset(0)
, mCalledBeginPage(false)
, mCurrentCanvasListSetup(false)
{
@ -226,12 +224,6 @@ nsSimplePageSequenceFrame::Reflow(nsPresContext* aPresContext,
nsSize pageSize = aPresContext->GetPageSize();
mPageData->mReflowSize = pageSize;
// If we're printing a selection, we need to reflow with
// unconstrained height, to make sure we'll get to the selection
// even if it's beyond the first page of content.
if (nsIPrintSettings::kRangeSelection == mPrintRangeType) {
mPageData->mReflowSize.height = NS_UNCONSTRAINEDSIZE;
}
mPageData->mReflowMargin = mMargin;
// We use the CSS "margin" property on the -moz-page pseudoelement
@ -428,15 +420,14 @@ nsSimplePageSequenceFrame::StartPrint(nsPresContext* aPresContext,
aPrintSettings->GetEndPageRange(&mToPageNum);
aPrintSettings->GetPageRanges(mPageRanges);
mDoingPageRange = nsIPrintSettings::kRangeSpecifiedPageRange == mPrintRangeType ||
nsIPrintSettings::kRangeSelection == mPrintRangeType;
mDoingPageRange = nsIPrintSettings::kRangeSpecifiedPageRange == mPrintRangeType;
// If printing a range of pages make sure at least the starting page
// number is valid
int32_t totalPages = mFrames.GetLength();
mTotalPages = mFrames.GetLength();
if (mDoingPageRange) {
if (mFromPageNum > totalPages) {
if (mFromPageNum > mTotalPages) {
return NS_ERROR_INVALID_ARG;
}
}
@ -444,42 +435,8 @@ nsSimplePageSequenceFrame::StartPrint(nsPresContext* aPresContext,
// Begin printing of the document
nsresult rv = NS_OK;
// Determine if we are rendering only the selection
aPresContext->SetIsRenderingOnlySelection(nsIPrintSettings::kRangeSelection == mPrintRangeType);
if (mDoingPageRange) {
// XXX because of the hack for making the selection all print on one page
// we must make sure that the page is sized correctly before printing.
nscoord height = aPresContext->GetPageSize().height;
int32_t pageNum = 1;
nscoord y = 0;//mMargin.top;
for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
nsIFrame* page = e.get();
if (pageNum >= mFromPageNum && pageNum <= mToPageNum) {
nsRect rect = page->GetRect();
rect.y = y;
rect.height = height;
page->SetRect(rect);
y += rect.height + mMargin.top + mMargin.bottom;
}
pageNum++;
}
// adjust total number of pages
if (nsIPrintSettings::kRangeSelection != mPrintRangeType) {
totalPages = pageNum - 1;
}
}
mPageNum = 1;
if (mTotalPages == -1) {
mTotalPages = totalPages;
}
return rv;
}
@ -571,10 +528,6 @@ nsSimplePageSequenceFrame::DetermineWhetherToPrintPage()
mPrintThisPage = false; // don't print even numbered page
}
}
if (nsIPrintSettings::kRangeSelection == mPrintRangeType) {
mPrintThisPage = true;
}
}
nsIFrame*
@ -690,17 +643,6 @@ nsSimplePageSequenceFrame::ResetPrintCanvasList()
NS_IMETHODIMP
nsSimplePageSequenceFrame::PrintNextPage()
{
// This method would be very straightforward except that the
// "Print Selection Only" functionality (which is a broken mess) is
// integrated here. The thing to understand is that if we're printing a
// selection (which may contain multiple ranges) then we only enter this
// function once since the content to print is laid out as one arbitrarily
// long nsPageFrame instead of multiple nsPageFrames that are sized to fit
// the printer paper size(!). Each of the "pages" between the start and end
// of the selection are printed by offsetting the nsPageContentFrame by the
// index of the page being printed and then drawing the nsPageContentFrame.
// This does not work for IFrames.
//
// Note: When print al the pages or a page range the printed page shows the
// actual page number, when printing selection it prints the page number starting
// with the first page of the selection. For example if the user has a
@ -720,82 +662,30 @@ nsSimplePageSequenceFrame::PrintNextPage()
if (mPrintThisPage) {
nsDeviceContext* dc = PresContext()->DeviceContext();
nsPageFrame * pf = static_cast<nsPageFrame*>(currentPageFrame);
pf->SetPageNumInfo(mPageNum, mTotalPages);
pf->SetSharedPageData(mPageData);
// Only used if we're printing a selection:
nsIFrame* selectionContentFrame = nullptr;
nscoord pageContentHeight =
PresContext()->GetPageSize().height - (mMargin.top + mMargin.bottom);
nscoord selectionY = pageContentHeight;
int32_t selectionCurrentPageNum = 1;
bool haveUnfinishedSelectionToPrint = false;
if (mSelectionHeight >= 0) {
selectionContentFrame = currentPageFrame->PrincipalChildList().FirstChild();
MOZ_ASSERT(selectionContentFrame->IsPageContentFrame() &&
!selectionContentFrame->GetNextSibling(),
"Unexpected frame tree");
// To print a selection we reposition the page content frame for each
// page. We can do this (and not have to bother resetting the position
// after we're done) because we are printing from a static clone document
// that is thrown away after we finish printing.
selectionContentFrame->SetPosition(selectionContentFrame->GetPosition() +
nsPoint(0, -mYSelOffset));
nsContainerFrame::PositionChildViews(selectionContentFrame);
if (PresContext()->IsRootPaginatedDocument()) {
if (!mCalledBeginPage) {
// We must make sure BeginPage() has been called since some printing
// backends can't give us a valid rendering context for a [physical]
// page otherwise.
PR_PL(("\n"));
PR_PL(("***************** BeginPage *****************\n"));
rv = dc->BeginPage();
NS_ENSURE_SUCCESS(rv, rv);
}
}
do {
if (PresContext()->IsRootPaginatedDocument()) {
if (!mCalledBeginPage) {
// We must make sure BeginPage() has been called since some printing
// backends can't give us a valid rendering context for a [physical]
// page otherwise.
PR_PL(("\n"));
PR_PL(("***************** BeginPage *****************\n"));
rv = dc->BeginPage();
NS_ENSURE_SUCCESS(rv, rv);
}
PR_PL(("SeqFr::PrintNextPage -> %p PageNo: %d", currentPageFrame, mPageNum));
// Reset this flag. We reset it early here because if we loop around to
// print another page's worth of selection we need to call BeginPage
// again:
mCalledBeginPage = false;
}
// CreateRenderingContext can fail
RefPtr<gfxContext> gCtx = dc->CreateRenderingContext();
NS_ENSURE_TRUE(gCtx, NS_ERROR_OUT_OF_MEMORY);
PR_PL(("SeqFr::PrintNextPage -> %p PageNo: %d", pf, mPageNum));
// CreateRenderingContext can fail
RefPtr<gfxContext> gCtx = dc->CreateRenderingContext();
NS_ENSURE_TRUE(gCtx, NS_ERROR_OUT_OF_MEMORY);
nsRect drawingRect(nsPoint(0, 0), currentPageFrame->GetSize());
nsRegion drawingRegion(drawingRect);
nsLayoutUtils::PaintFrame(gCtx, currentPageFrame,
drawingRegion, NS_RGBA(0,0,0,0),
nsDisplayListBuilderMode::PAINTING,
nsLayoutUtils::PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES);
if (mSelectionHeight >= 0) {
haveUnfinishedSelectionToPrint = (selectionY < mSelectionHeight);
if (haveUnfinishedSelectionToPrint) {
selectionY += pageContentHeight;
selectionCurrentPageNum++;
pf->SetPageNumInfo(selectionCurrentPageNum, mTotalPages);
selectionContentFrame->SetPosition(selectionContentFrame->GetPosition() +
nsPoint(0, -pageContentHeight));
nsContainerFrame::PositionChildViews(selectionContentFrame);
// We're going to loop and call BeginPage to print another page's worth
// of selection so we need to call EndPage first. (Otherwise, EndPage
// is called in DoEndPage.)
PR_PL(("***************** End Page (PrintNextPage) *****************\n"));
rv = dc->EndPage();
NS_ENSURE_SUCCESS(rv, rv);
}
}
} while (haveUnfinishedSelectionToPrint);
nsRect drawingRect(nsPoint(0, 0), currentPageFrame->GetSize());
nsRegion drawingRegion(drawingRect);
nsLayoutUtils::PaintFrame(gCtx, currentPageFrame,
drawingRegion, NS_RGBA(0,0,0,0),
nsDisplayListBuilderMode::PAINTING,
nsLayoutUtils::PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES);
}
return rv;
}
@ -811,6 +701,7 @@ nsSimplePageSequenceFrame::DoPageEnd()
}
ResetPrintCanvasList();
mCalledBeginPage = false;
mPageNum++;

Просмотреть файл

@ -72,11 +72,6 @@ public:
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
// nsIPageSequenceFrame
NS_IMETHOD SetPageNo(int32_t aPageNo) { return NS_OK;}
NS_IMETHOD SetSelectionHeight(nscoord aYOffset, nscoord aHeight) override { mYSelOffset = aYOffset; mSelectionHeight = aHeight; return NS_OK; }
NS_IMETHOD SetTotalNumPages(int32_t aTotal) override { mTotalPages = aTotal; return NS_OK; }
// For Shrink To Fit
NS_IMETHOD GetSTFPercent(float& aSTFPercent) override;
@ -149,16 +144,10 @@ protected:
nsTArray<int32_t> mPageRanges;
nsTArray<RefPtr<mozilla::dom::HTMLCanvasElement> > mCurrentCanvasList;
// Selection Printing Info
nscoord mSelectionHeight;
nscoord mYSelOffset;
// Asynch Printing
bool mPrintThisPage;
bool mDoingPageRange;
bool mIsPrintingSelection;
bool mCalledBeginPage;
bool mCurrentCanvasListSetup;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше