Merge inbound to central, a=merge

This commit is contained in:
Wes Kocher 2016-08-26 16:20:50 -07:00
Родитель 44a1966767 3bef492837
Коммит f09e8fef1a
119 изменённых файлов: 3071 добавлений и 1745 удалений

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

@ -1392,6 +1392,10 @@ AccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
if (aVarChild.lVal > 0) {
// Gecko child indices are 0-based in contrast to indices used in MSAA.
if (IsProxy()) {
if (static_cast<uint32_t>(aVarChild.lVal) > Proxy()->ChildrenCount()) {
return nullptr;
}
return WrapperFor(Proxy()->ChildAt(aVarChild.lVal - 1));
} else {
return GetChildAt(aVarChild.lVal - 1);

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

@ -169,12 +169,12 @@ function* test_cache_cleared() {
yield OpenCacheEntry("http://" + TEST_HOST + "/",
"disk",
Ci.nsICacheStorage.OPEN_NORMALLY,
LoadContextInfo.custom(false, false, {userContextId}));
LoadContextInfo.custom(false, {userContextId}));
yield OpenCacheEntry("http://" + TEST_HOST + "/",
"memory",
Ci.nsICacheStorage.OPEN_NORMALLY,
LoadContextInfo.custom(false, false, {userContextId}));
LoadContextInfo.custom(false, {userContextId}));
}

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

@ -1156,11 +1156,6 @@ notification[value="translation"] menulist > .menulist-dropmarker {
max-width : 36px;
}
#PopupAutoCompleteRichResult {
/* The awesomebar popup should open just below the navbar bottom border. */
margin-top: 1px;
}
.autocomplete-richlistbox {
padding: 4px;
}

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

@ -11,7 +11,6 @@
* (eg. using ctrl+shift+X) */
margin-inline-start: -23px;
margin-inline-end: -16px;
padding: 1px;
}
.autocomplete-textbox-container {
@ -157,7 +156,7 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
}
.search-panel-one-offs {
margin: 0 -1px !important;
margin: 0 !important;
border-top: 1px solid #ccc;
}

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

@ -298,6 +298,17 @@ OriginAttributes::SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing)
mPrivateBrowsingId = aInPrivateBrowsing ? 1 : 0;
}
void
OriginAttributes::SetFromGenericAttributes(const GenericOriginAttributes& aAttrs)
{
mAppId = aAttrs.mAppId;
mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
mAddonId = aAttrs.mAddonId;
mUserContextId = aAttrs.mUserContextId;
mSignedPkg = aAttrs.mSignedPkg;
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
}
BasePrincipal::BasePrincipal()
{}

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

@ -23,6 +23,8 @@ class nsExpandedPrincipal;
namespace mozilla {
class GenericOriginAttributes;
// Base OriginAttributes class. This has several subclass flavors, and is not
// directly constructable itself.
class OriginAttributes : public dom::OriginAttributesDictionary
@ -57,6 +59,8 @@ public:
// flags. Once all other flags are removed, this can be removed too.
void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing);
void SetFromGenericAttributes(const GenericOriginAttributes& aAttrs);
protected:
OriginAttributes() {}
explicit OriginAttributes(const OriginAttributesDictionary& aOther)

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

@ -52,13 +52,11 @@ LoadContext::LoadContext(nsIPrincipal* aPrincipal,
{
PrincipalOriginAttributes poa = BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
mOriginAttributes.InheritFromDocToChildDocShell(poa);
mUsePrivateBrowsing = (poa.mPrivateBrowsingId != 0);
if (!aOptionalBase) {
return;
}
MOZ_ALWAYS_SUCCEEDS(aOptionalBase->GetIsContent(&mIsContent));
MOZ_ALWAYS_SUCCEEDS(aOptionalBase->GetUsePrivateBrowsing(&mUsePrivateBrowsing));
MOZ_ALWAYS_SUCCEEDS(aOptionalBase->GetUseRemoteTabs(&mUseRemoteTabs));
}
@ -127,7 +125,7 @@ LoadContext::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
*aUsePrivateBrowsing = mUsePrivateBrowsing;
*aUsePrivateBrowsing = mOriginAttributes.mPrivateBrowsingId > 0;
return NS_OK;
}
@ -209,7 +207,7 @@ LoadContext::IsTrackingProtectionOn(bool* aIsTrackingProtectionOn)
if (Preferences::GetBool("privacy.trackingprotection.enabled", false)) {
*aIsTrackingProtectionOn = true;
} else if (mUsePrivateBrowsing &&
} else if ((mOriginAttributes.mPrivateBrowsingId > 0) &&
Preferences::GetBool("privacy.trackingprotection.pbmode.enabled", false)) {
*aIsTrackingProtectionOn = true;
} else {

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

@ -47,14 +47,12 @@ public:
: mTopFrameElement(do_GetWeakReference(aTopFrameElement))
, mNestedFrameId(0)
, mIsContent(aToCopy.mIsContent)
, mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing)
, mUseRemoteTabs(aToCopy.mUseRemoteTabs)
, mOriginAttributes(aAttrs)
#ifdef DEBUG
, mIsNotNull(aToCopy.mIsNotNull)
#endif
{
MOZ_ASSERT(aToCopy.mUsePrivateBrowsing == (aAttrs.mPrivateBrowsingId != 0));
}
// appId/inIsolatedMozBrowser arguments override those in SerializedLoadContext
@ -65,14 +63,12 @@ public:
: mTopFrameElement(nullptr)
, mNestedFrameId(aNestedFrameId)
, mIsContent(aToCopy.mIsContent)
, mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing)
, mUseRemoteTabs(aToCopy.mUseRemoteTabs)
, mOriginAttributes(aAttrs)
#ifdef DEBUG
, mIsNotNull(aToCopy.mIsNotNull)
#endif
{
MOZ_ASSERT(aToCopy.mUsePrivateBrowsing == (aAttrs.mPrivateBrowsingId != 0));
}
LoadContext(dom::Element* aTopFrameElement,
@ -83,24 +79,21 @@ public:
: mTopFrameElement(do_GetWeakReference(aTopFrameElement))
, mNestedFrameId(0)
, mIsContent(aIsContent)
, mUsePrivateBrowsing(aUsePrivateBrowsing)
, mUseRemoteTabs(aUseRemoteTabs)
, mOriginAttributes(aAttrs)
#ifdef DEBUG
, mIsNotNull(true)
#endif
{
MOZ_ASSERT(aUsePrivateBrowsing == (aAttrs.mPrivateBrowsingId != 0));
}
// Constructor taking reserved appId for the safebrowsing cookie.
explicit LoadContext(uint32_t aAppId)
// Constructor taking reserved origin attributes.
explicit LoadContext(DocShellOriginAttributes& aAttrs)
: mTopFrameElement(nullptr)
, mNestedFrameId(0)
, mIsContent(false)
, mUsePrivateBrowsing(false)
, mUseRemoteTabs(false)
, mOriginAttributes(aAppId, false)
, mOriginAttributes(aAttrs)
#ifdef DEBUG
, mIsNotNull(true)
#endif
@ -118,7 +111,6 @@ private:
nsWeakPtr mTopFrameElement;
uint64_t mNestedFrameId;
bool mIsContent;
bool mUsePrivateBrowsing;
bool mUseRemoteTabs;
DocShellOriginAttributes mOriginAttributes;
#ifdef DEBUG

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

@ -38,10 +38,9 @@ SerializedLoadContext::SerializedLoadContext(nsIChannel* aChannel)
NS_SUCCEEDED(pbChannel->IsPrivateModeOverriden(&isPrivate,
&isOverriden)) &&
isOverriden) {
mUsePrivateBrowsing = isPrivate;
mIsPrivateBitValid = true;
}
mOriginAttributes.SyncAttributesWithPrivateBrowsing(mUsePrivateBrowsing);
mOriginAttributes.SyncAttributesWithPrivateBrowsing(isPrivate);
}
}
@ -61,8 +60,6 @@ SerializedLoadContext::Init(nsILoadContext* aLoadContext)
mIsNotNull = true;
mIsPrivateBitValid = true;
aLoadContext->GetIsContent(&mIsContent);
aLoadContext->GetUsePrivateBrowsing(&mUsePrivateBrowsing);
mOriginAttributes.SyncAttributesWithPrivateBrowsing(mUsePrivateBrowsing);
aLoadContext->GetUseRemoteTabs(&mUseRemoteTabs);
if (!aLoadContext->GetOriginAttributes(mOriginAttributes)) {
NS_WARNING("GetOriginAttributes failed");
@ -73,7 +70,6 @@ SerializedLoadContext::Init(nsILoadContext* aLoadContext)
// none of below values really matter when mIsNotNull == false:
// we won't be GetInterfaced to nsILoadContext
mIsContent = true;
mUsePrivateBrowsing = false;
mUseRemoteTabs = false;
}
}

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

@ -31,7 +31,6 @@ public:
: mIsNotNull(false)
, mIsPrivateBitValid(false)
, mIsContent(false)
, mUsePrivateBrowsing(false)
, mUseRemoteTabs(false)
{
Init(nullptr);
@ -52,7 +51,6 @@ public:
// mIsNotNull is false, i.e., child LoadContext was null.
bool mIsPrivateBitValid;
bool mIsContent;
bool mUsePrivateBrowsing;
bool mUseRemoteTabs;
mozilla::DocShellOriginAttributes mOriginAttributes;
};
@ -71,7 +69,6 @@ struct ParamTraits<SerializedLoadContext>
WriteParam(aMsg, aParam.mIsNotNull);
WriteParam(aMsg, aParam.mIsContent);
WriteParam(aMsg, aParam.mIsPrivateBitValid);
WriteParam(aMsg, aParam.mUsePrivateBrowsing);
WriteParam(aMsg, aParam.mUseRemoteTabs);
WriteParam(aMsg, suffix);
}
@ -82,7 +79,6 @@ struct ParamTraits<SerializedLoadContext>
if (!ReadParam(aMsg, aIter, &aResult->mIsNotNull) ||
!ReadParam(aMsg, aIter, &aResult->mIsContent) ||
!ReadParam(aMsg, aIter, &aResult->mIsPrivateBitValid) ||
!ReadParam(aMsg, aIter, &aResult->mUsePrivateBrowsing) ||
!ReadParam(aMsg, aIter, &aResult->mUseRemoteTabs) ||
!ReadParam(aMsg, aIter, &suffix)) {
return false;

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

@ -304,7 +304,6 @@ nsJSUtils::ModuleDeclarationInstantiation(JSContext* aCx, JS::Handle<JSObject*>
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(nsContentUtils::IsInMicroTask());
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);

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

@ -179,7 +179,7 @@ public:
RefPtr<nsModuleScript> mModuleScript;
// A promise that is completed on successful load of this module and all of
// its dependencies, indicating that the module is ready for instantitaion and
// its dependencies, indicating that the module is ready for instantiation and
// evaluation.
MozPromiseHolder<GenericPromise> mReady;
@ -261,6 +261,11 @@ nsModuleLoadRequest::DependenciesLoaded()
// The module and all of its dependencies have been successfully fetched and
// compiled.
if (!mLoader->InstantiateModuleTree(this)) {
LoadFailed();
return;
}
SetReady();
mLoader->ProcessLoadedModuleTree(this);
mLoader = nullptr;
@ -284,9 +289,17 @@ nsModuleLoadRequest::LoadFailed()
class nsModuleScript final : public nsISupports
{
enum InstantiationState {
Uninstantiated,
Instantiated,
Errored
};
RefPtr<nsScriptLoader> mLoader;
nsCOMPtr<nsIURI> mBaseURL;
JS::Heap<JSObject*> mModuleRecord;
JS::Heap<JS::Value> mException;
InstantiationState mInstantiationState;
~nsModuleScript();
@ -300,8 +313,20 @@ public:
nsScriptLoader* Loader() const { return mLoader; }
JSObject* ModuleRecord() const { return mModuleRecord; }
JS::Value Exception() const { return mException; }
nsIURI* BaseURL() const { return mBaseURL; }
void SetInstantiationResult(JS::Handle<JS::Value> aMaybeException);
bool IsUninstantiated() const {
return mInstantiationState == Uninstantiated;
}
bool IsInstantiated() const {
return mInstantiationState == Instantiated;
}
bool InstantiationFailed() const {
return mInstantiationState == Errored;
}
void UnlinkModuleRecord();
};
@ -323,6 +348,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsModuleScript)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mException)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsModuleScript)
@ -332,11 +358,13 @@ nsModuleScript::nsModuleScript(nsScriptLoader *aLoader, nsIURI* aBaseURL,
JS::Handle<JSObject*> aModuleRecord)
: mLoader(aLoader),
mBaseURL(aBaseURL),
mModuleRecord(aModuleRecord)
mModuleRecord(aModuleRecord),
mInstantiationState(Uninstantiated)
{
MOZ_ASSERT(mLoader);
MOZ_ASSERT(mBaseURL);
MOZ_ASSERT(mModuleRecord);
MOZ_ASSERT(mException.isUndefined());
// Make module's host defined field point to this module script object.
// This is cleared in the UnlinkModuleRecord().
@ -348,10 +376,13 @@ void
nsModuleScript::UnlinkModuleRecord()
{
// Remove module's back reference to this object request if present.
MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
this);
JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
if (mModuleRecord) {
MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
this);
JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
}
mModuleRecord = nullptr;
mException.setUndefined();
}
nsModuleScript::~nsModuleScript()
@ -363,7 +394,24 @@ nsModuleScript::~nsModuleScript()
DropJSObjects(this);
}
void
nsModuleScript::SetInstantiationResult(JS::Handle<JS::Value> aMaybeException)
{
MOZ_ASSERT(mInstantiationState == Uninstantiated);
MOZ_ASSERT(mModuleRecord);
MOZ_ASSERT(mException.isUndefined());
if (aMaybeException.isUndefined()) {
mInstantiationState = Instantiated;
} else {
mModuleRecord = nullptr;
mException = aMaybeException;
mInstantiationState = Errored;
}
}
//////////////////////////////////////////////////////////////
// nsScriptLoadRequestList
//////////////////////////////////////////////////////////////
@ -1021,12 +1069,18 @@ HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp)
return HandleModuleNotFound(aCx, script, string);
}
if (ms->InstantiationFailed()) {
JS::Rooted<JS::Value> exception(aCx, ms->Exception());
JS_SetPendingException(aCx, exception);
return false;
}
*vp = JS::ObjectValue(*ms->ModuleRecord());
return true;
}
static nsresult
EnsureModuleResolveHook(JSContext *aCx)
EnsureModuleResolveHook(JSContext* aCx)
{
if (JS::GetModuleResolveHook(aCx)) {
return NS_OK;
@ -1056,6 +1110,68 @@ nsScriptLoader::ProcessLoadedModuleTree(nsModuleLoadRequest* aRequest)
}
}
bool
nsScriptLoader::InstantiateModuleTree(nsModuleLoadRequest* aRequest)
{
// Perform eager instantiation of the loaded module tree.
MOZ_ASSERT(aRequest);
nsModuleScript* ms = aRequest->mModuleScript;
MOZ_ASSERT(ms);
if (!ms->ModuleRecord()) {
return false;
}
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(ms->ModuleRecord()))) {
return false;
}
nsresult rv = EnsureModuleResolveHook(jsapi.cx());
NS_ENSURE_SUCCESS(rv, false);
JS::Rooted<JSObject*> module(jsapi.cx(), ms->ModuleRecord());
bool ok = NS_SUCCEEDED(nsJSUtils::ModuleDeclarationInstantiation(jsapi.cx(), module));
JS::RootedValue exception(jsapi.cx());
if (!ok) {
MOZ_ASSERT(jsapi.HasException());
if (!jsapi.StealException(&exception)) {
return false;
}
MOZ_ASSERT(!exception.isUndefined());
}
// Mark this module and any uninstantiated dependencies found via depth-first
// search as instantiated and record any error.
mozilla::Vector<nsModuleLoadRequest*, 1> requests;
if (!requests.append(aRequest)) {
return false;
}
while (!requests.empty()) {
nsModuleLoadRequest* request = requests.popCopy();
nsModuleScript* ms = request->mModuleScript;
if (!ms->IsUninstantiated()) {
continue;
}
ms->SetInstantiationResult(exception);
for (auto import : request->mImports) {
if (import->mModuleScript->IsUninstantiated() &&
!requests.append(import))
{
return false;
}
}
}
return true;
}
nsresult
nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
bool aScriptFromHead)
@ -2018,17 +2134,18 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest)
}
if (aRequest->IsModuleRequest()) {
rv = EnsureModuleResolveHook(aes.cx());
NS_ENSURE_SUCCESS(rv, rv);
nsModuleLoadRequest* request = aRequest->AsModuleRequest();
MOZ_ASSERT(request->mModuleScript);
MOZ_ASSERT(!request->mOffThreadToken);
JS::Rooted<JSObject*> module(aes.cx(),
request->mModuleScript->ModuleRecord());
MOZ_ASSERT(module);
rv = nsJSUtils::ModuleDeclarationInstantiation(aes.cx(), module);
if (NS_SUCCEEDED(rv)) {
nsModuleScript* ms = request->mModuleScript;
MOZ_ASSERT(!ms->IsUninstantiated());
if (ms->InstantiationFailed()) {
JS::Rooted<JS::Value> exception(aes.cx(), ms->Exception());
JS_SetPendingException(aes.cx(), exception);
rv = NS_ERROR_FAILURE;
} else {
JS::Rooted<JSObject*> module(aes.cx(), ms->ModuleRecord());
MOZ_ASSERT(module);
rv = nsJSUtils::ModuleEvaluation(aes.cx(), module);
}
} else {

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

@ -584,6 +584,7 @@ private:
nsresult CreateModuleScript(nsModuleLoadRequest* aRequest);
nsresult ProcessFetchedModuleSource(nsModuleLoadRequest* aRequest);
void ProcessLoadedModuleTree(nsModuleLoadRequest* aRequest);
bool InstantiateModuleTree(nsModuleLoadRequest* aRequest);
void StartFetchingModuleDependencies(nsModuleLoadRequest* aRequest);
RefPtr<mozilla::GenericPromise>

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

@ -20,6 +20,7 @@ support-files =
module_large3.js
module_extractIntroType.js
iframe_extractIntroType.html
module_missingImport.js
[test_moduleScriptsRun.html]
[test_moduleParsedAsModule.html]
@ -44,5 +45,7 @@ support-files =
[test_multiModuleLargeImports.html]
[test_asyncInlineModules.html]
[test_scriptInsertedModule.html]
[test_linkErrorInCommon1.html]
[test_linkErrorInCommon2.html]
[test_topLevelIntroType.html]
[test_importIntroType.html]

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

@ -0,0 +1 @@
import { missing } from "./module_simple1.js";

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

@ -0,0 +1,32 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test handling of a link error in a common module</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script>
var runCount = 0;
var hadSyntaxError = false;
SimpleTest.waitForExplicitFinish();
window.onerror = handleError;
function handleError(message, url, line, column, error) {
if (error instanceof SyntaxError) {
hadSyntaxError = true;
}
}
function testError() {
ok(runCount == 0, 'Check no modules were executed');
ok(hadSyntaxError, 'Check that an error was reported');
SimpleTest.finish();
}
</script>
<script type="module">
import { missing } from "./module_simple1.js";
runCount++;
</script>
<script type="module">
import { missing } from "./module_simple1.js";
runCount++;
</script>
<body onload='testError()'></body>

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

@ -0,0 +1,32 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test handling of a link error in a common module</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script>
var runCount = 0;
var hadSyntaxError = false;
SimpleTest.waitForExplicitFinish();
window.onerror = handleError;
function handleError(message, url, line, column, error) {
if (error instanceof SyntaxError) {
hadSyntaxError = true;
}
}
function testError() {
ok(runCount == 0, 'Check no modules were executed');
ok(hadSyntaxError, 'Check that an error was reported');
SimpleTest.finish();
}
</script>
<script type="module">
import "./module_missingImport.js";
runCount++;
</script>
<script type="module">
import "./module_missingImport.js";
runCount++;
</script>
<body onload='testError()'></body>

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

@ -0,0 +1,50 @@
let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
Cu.import("resource://testing-common/httpd.js");
let server = new HttpServer();
server.start(-1);
let body = "<!DOCTYPE HTML><html><head><meta charset='utf-8'></head><body></body></html>";
function handler(request, response) {
response.setStatusLine(request.httpVersion, 200, "Ok");
response.setHeader("Content-Type", "text/html", false);
if (!request.hasHeader("Cookie")) {
response.setHeader("Set-Cookie", "test", false);
ok(true);
} else {
ok(false);
}
response.bodyOutputStream.write(body, body.length);
}
function run_test() {
do_test_pending();
server.registerPathHandler("/foo", handler);
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
xhr.open("GET", "http://localhost:" + server.identity.primaryPort + "/foo", true);
xhr.send(null);
xhr.onload = function() {
// We create another XHR to connect to the same site, but this time we
// specify with different origin attributes, which will make the XHR use a
// different cookie-jar than the previous one.
let xhr2 = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
xhr2.open("GET", "http://localhost:" + server.identity.primaryPort + "/foo", true);
xhr2.setOriginAttributes({userContextId: 1});
xhr2.send(null);
let loadInfo = xhr2.channel.loadInfo;
Assert.equal(loadInfo.originAttributes.userContextId, 1);
xhr2.onload = function() {
server.stop(do_test_finished);
}
};
}

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

@ -45,6 +45,7 @@ head = head_xml.js
head = head_xml.js
[test_xhr_document.js]
[test_xhr_standalone.js]
[test_xhr_origin_attributes.js]
[test_xml_parser.js]
head = head_xml.js
[test_xml_serializer.js]

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

@ -1505,6 +1505,33 @@ CanvasRenderingContext2D::OnStableState()
mHasPendingStableStateCallback = false;
}
void
CanvasRenderingContext2D::RestoreClipsAndTransformToTarget()
{
// Restore clips and transform.
mTarget->SetTransform(Matrix());
if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) {
// Cairo doesn't play well with huge clips. When given a very big clip it
// will try to allocate big mask surface without taking the target
// size into account which can cause OOM. See bug 1034593.
// This limits the clip extents to the size of the canvas.
// A fix in Cairo would probably be preferable, but requires somewhat
// invasive changes.
mTarget->PushClipRect(gfx::Rect(0, 0, mWidth, mHeight));
}
for (const auto& style : mStyleStack) {
for (const auto& clipOrTransform : style.clipsAndTransforms) {
if (clipOrTransform.IsClip()) {
mTarget->PushClip(clipOrTransform.clip);
} else {
mTarget->SetTransform(clipOrTransform.transform);
}
}
}
}
CanvasRenderingContext2D::RenderingMode
CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
RenderingMode aRenderingMode)
@ -1556,7 +1583,13 @@ CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
: IntRect(0, 0, mWidth, mHeight);
mTarget = mBufferProvider->BorrowDrawTarget(persistedRect);
mode = mRenderingMode;
if (mTarget && !mBufferProvider->PreservesDrawingState()) {
RestoreClipsAndTransformToTarget();
}
if (mTarget) {
return mode;
}
}
mIsSkiaGL = false;
@ -1649,28 +1682,7 @@ CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
if (mBufferProvider != oldBufferProvider || !mBufferProvider ||
!mBufferProvider->PreservesDrawingState()) {
// Restore clips and transform.
mTarget->SetTransform(Matrix());
if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) {
// Cairo doesn't play well with huge clips. When given a very big clip it
// will try to allocate big mask surface without taking the target
// size into account which can cause OOM. See bug 1034593.
// This limits the clip extents to the size of the canvas.
// A fix in Cairo would probably be preferable, but requires somewhat
// invasive changes.
mTarget->PushClipRect(canvasRect);
}
for (const auto& style : mStyleStack) {
for (const auto& clipOrTransform : style.clipsAndTransforms) {
if (clipOrTransform.IsClip()) {
mTarget->PushClip(clipOrTransform.clip);
} else {
mTarget->SetTransform(clipOrTransform.transform);
}
}
}
RestoreClipsAndTransformToTarget();
}
} else {
EnsureErrorTarget();
@ -1792,7 +1804,7 @@ CanvasRenderingContext2D::ReturnTarget(bool aForceReset)
if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) {
// With the cairo backend we pushed an extra clip rect which we have to
// balance out here. See the comment in EnsureDrawTarget.
// balance out here. See the comment in RestoreClipsAndTransformToTarget.
mTarget->PopClip();
}
}

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

@ -643,6 +643,8 @@ protected:
RenderingMode EnsureTarget(const gfx::Rect* aCoveredRect = nullptr,
RenderingMode aRenderMode = RenderingMode::DefaultBackendMode);
void RestoreClipsAndTransformToTarget();
/**
* This method is run at the end of the event-loop spin where
* ScheduleStableStateCallback was called.

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

@ -903,7 +903,7 @@ VideoStreamHelper.prototype = {
// ignore; stream might have shut down, and we don't bother clearing
// the setInterval.
}
}, 100);
}, 500);
},
waitForFrames: function(canvas, timeout_value) {

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

@ -152,6 +152,9 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget {
[Throws, ChromeOnly, Exposed=Window]
any getInterface(IID iid);
[ChromeOnly, Exposed=Window]
void setOriginAttributes(optional OriginAttributesDictionary originAttributes);
readonly attribute boolean mozAnon;
readonly attribute boolean mozSystem;
};

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

@ -165,6 +165,9 @@ public:
JS::MutableHandle<JS::Value> aRetval,
ErrorResult& aRv) = 0;
virtual void
SetOriginAttributes(const mozilla::dom::OriginAttributesDictionary& aAttrs) = 0;
virtual bool
MozAnon() const = 0;

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

@ -20,6 +20,7 @@
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/LoadContext.h"
#include "mozilla/MemoryReporting.h"
#include "nsIDOMDocument.h"
#include "mozilla/dom/ProgressEvent.h"
@ -1543,6 +1544,20 @@ XMLHttpRequestMainThread::OpenInternal(const nsACString& aMethod,
return NS_OK;
}
void
XMLHttpRequestMainThread::SetOriginAttributes(const OriginAttributesDictionary& aAttrs)
{
MOZ_ASSERT((mState == State::opened) && !mFlagSend);
GenericOriginAttributes attrs(aAttrs);
NeckoOriginAttributes neckoAttrs;
neckoAttrs.SetFromGenericAttributes(attrs);
nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
MOZ_ASSERT(loadInfo);
loadInfo->SetOriginAttributes(neckoAttrs);
}
void
XMLHttpRequestMainThread::PopulateNetworkInterfaceId()
{

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

@ -58,6 +58,7 @@ class BlobSet;
class FormData;
class URLSearchParams;
class XMLHttpRequestUpload;
struct OriginAttributesDictionary;
// A helper for building up an ArrayBuffer object's data
// before creating the ArrayBuffer itself. Will do doubling
@ -537,6 +538,10 @@ public:
{
return sDontWarnAboutSyncXHR;
}
virtual void
SetOriginAttributes(const mozilla::dom::OriginAttributesDictionary& aAttrs) override;
protected:
// XHR states are meant to mirror the XHR2 spec:
// https://xhr.spec.whatwg.org/#states

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

@ -248,6 +248,12 @@ public:
aRv.Throw(NS_ERROR_FAILURE);
}
virtual void
SetOriginAttributes(const mozilla::dom::OriginAttributesDictionary& aAttrs) override
{
MOZ_CRASH("This method cannot be called on workers.");
}
XMLHttpRequestUpload*
GetUploadObjectNoCreate() const
{

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

@ -33,4 +33,6 @@ LOCAL_INCLUDES += [
MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

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

@ -828,10 +828,10 @@ public:
{
Point4DTyped<TargetUnits, F> retPoint;
retPoint.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + _41;
retPoint.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + _42;
retPoint.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + _43;
retPoint.w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + _44;
retPoint.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + aPoint.w * _41;
retPoint.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + aPoint.w * _42;
retPoint.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + aPoint.w * _43;
retPoint.w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + aPoint.w * _44;
return retPoint;
}
@ -839,12 +839,14 @@ public:
template<class F>
Point3DTyped<TargetUnits, F> operator *(const Point3DTyped<SourceUnits, F>& aPoint) const
{
Point4DTyped<SourceUnits, F> temp(aPoint.x, aPoint.y, aPoint.z, 1);
Point3DTyped<TargetUnits, F> result;
result.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + _41;
result.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + _42;
result.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + _43;
Point4DTyped<TargetUnits, F> result = *this * temp;
result /= result.w;
result /= (aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + _44);
return Point3DTyped<TargetUnits, F>(result.x, result.y, result.z);
return result;
}
template<class F>

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

@ -386,6 +386,16 @@ using GCNurseryCollectionCallback = void(*)(JSContext* cx, GCNurseryProgress pro
extern JS_PUBLIC_API(GCNurseryCollectionCallback)
SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback);
typedef void
(* DoCycleCollectionCallback)(JSContext* cx);
/**
* The purge gray callback is called after any COMPARTMENT_REVIVED GC in which
* the majority of compartments have been marked gray.
*/
extern JS_PUBLIC_API(DoCycleCollectionCallback)
SetDoCycleCollectionCallback(JSContext* cx, DoCycleCollectionCallback callback);
/**
* Incremental GC defaults to enabled, but may be disabled for testing or in
* embeddings that have not yet implemented barriers on their native classes.

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

@ -22,25 +22,6 @@
using namespace js;
static const JSFunctionSpec promise_methods[] = {
JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0),
JS_SELF_HOSTED_FN("then", "Promise_then", 2, 0),
JS_FS_END
};
static const JSFunctionSpec promise_static_methods[] = {
JS_SELF_HOSTED_FN("all", "Promise_static_all", 1, 0),
JS_SELF_HOSTED_FN("race", "Promise_static_race", 1, 0),
JS_SELF_HOSTED_FN("reject", "Promise_static_reject", 1, 0),
JS_SELF_HOSTED_FN("resolve", "Promise_static_resolve", 1, 0),
JS_FS_END
};
static const JSPropertySpec promise_static_properties[] = {
JS_SELF_HOSTED_SYM_GET(species, "Promise_static_get_species", 0),
JS_PS_END
};
static double
MillisecondsSinceStartup()
{
@ -49,33 +30,664 @@ MillisecondsSinceStartup()
return (now - mozilla::TimeStamp::ProcessCreation(ignored)).ToMilliseconds();
}
static bool
CreateResolvingFunctions(JSContext* cx, HandleValue promise,
MutableHandleValue resolveVal,
MutableHandleValue rejectVal)
enum ResolutionFunctionSlots {
ResolutionFunctionSlot_Promise = 0,
ResolutionFunctionSlot_OtherFunction,
};
// ES2016, 25.4.1.8.
static MOZ_MUST_USE bool
TriggerPromiseReactions(JSContext* cx, HandleValue reactionsVal, JS::PromiseState state,
HandleValue valueOrReason)
{
FixedInvokeArgs<1> args(cx);
args[0].set(promise);
RootedObject reactions(cx, &reactionsVal.toObject());
RootedValue rval(cx);
if (!CallSelfHostedFunction(cx, cx->names().CreateResolvingFunctions, UndefinedHandleValue,
args, &rval))
{
AutoIdVector keys(cx);
if (!GetPropertyKeys(cx, reactions, JSITER_OWNONLY, &keys))
return false;
MOZ_ASSERT(keys.length() > 0, "Reactions list should be created lazily");
RootedPropertyName handlerName(cx);
handlerName = state == JS::PromiseState::Fulfilled
? cx->names().fulfillHandler
: cx->names().rejectHandler;
// Each reaction is an internally-created object with the structure:
// {
// promise: [the promise this reaction resolves],
// resolve: [the `resolve` callback content code provided],
// reject: [the `reject` callback content code provided],
// fulfillHandler: [the internal handler that fulfills the promise]
// rejectHandler: [the internal handler that rejects the promise]
// incumbentGlobal: [an object from the global that was incumbent when
// the reaction was created]
// }
RootedValue val(cx);
RootedObject reaction(cx);
RootedValue handler(cx);
RootedObject promise(cx);
RootedObject resolve(cx);
RootedObject reject(cx);
RootedObject objectFromIncumbentGlobal(cx);
for (size_t i = 0; i < keys.length(); i++) {
if (!GetProperty(cx, reactions, reactions, keys[i], &val))
return false;
reaction = &val.toObject();
if (!GetProperty(cx, reaction, reaction, cx->names().promise, &val))
return false;
// The jsapi function AddPromiseReactions can add reaction records
// without a `promise` object. See comment for EnqueuePromiseReactions
// in Promise.js.
promise = val.toObjectOrNull();
if (!GetProperty(cx, reaction, reaction, handlerName, &handler))
return false;
#ifdef DEBUG
if (handler.isNumber()) {
MOZ_ASSERT(handler.toNumber() == PROMISE_HANDLER_IDENTITY ||
handler.toNumber() == PROMISE_HANDLER_THROWER);
} else {
MOZ_ASSERT(handler.toObject().isCallable());
}
#endif
if (!GetProperty(cx, reaction, reaction, cx->names().resolve, &val))
return false;
resolve = &val.toObject();
MOZ_ASSERT(IsCallable(resolve));
if (!GetProperty(cx, reaction, reaction, cx->names().reject, &val))
return false;
reject = &val.toObject();
MOZ_ASSERT(IsCallable(reject));
if (!GetProperty(cx, reaction, reaction, cx->names().incumbentGlobal, &val))
return false;
objectFromIncumbentGlobal = val.toObjectOrNull();
if (!EnqueuePromiseReactionJob(cx, handler, valueOrReason, resolve, reject, promise,
objectFromIncumbentGlobal))
{
return false;
}
}
RootedArrayObject resolvingFunctions(cx, &args.rval().toObject().as<ArrayObject>());
resolveVal.set(resolvingFunctions->getDenseElement(0));
rejectVal.set(resolvingFunctions->getDenseElement(1));
MOZ_ASSERT(IsCallable(resolveVal));
MOZ_ASSERT(IsCallable(rejectVal));
return true;
}
// ES2016, Commoned-out implementation of 25.4.1.4. and 25.4.1.7.
static MOZ_MUST_USE bool
ResolvePromise(JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueOrReason,
JS::PromiseState state)
{
// Step 1.
MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
MOZ_ASSERT(state == JS::PromiseState::Fulfilled || state == JS::PromiseState::Rejected);
// Step 2.
// We only have one list of reactions for both resolution types. So
// instead of getting the right list of reactions, we determine the
// resolution type to retrieve the right information from the
// reaction records.
RootedValue reactionsVal(cx, promise->getFixedSlot(PROMISE_REACTIONS_OR_RESULT_SLOT));
// Step 3-5.
// The same slot is used for the reactions list and the result, so setting
// the result also removes the reactions list.
promise->setFixedSlot(PROMISE_REACTIONS_OR_RESULT_SLOT, valueOrReason);
// Step 6.
int32_t flags = promise->getFixedSlot(PROMISE_FLAGS_SLOT).toInt32();
flags |= PROMISE_FLAG_RESOLVED;
if (state == JS::PromiseState::Fulfilled)
flags |= PROMISE_FLAG_FULFILLED;
promise->setFixedSlot(PROMISE_FLAGS_SLOT, Int32Value(flags));
// Also null out the resolve/reject functions so they can be GC'd.
promise->setFixedSlot(PROMISE_RESOLVE_FUNCTION_SLOT, UndefinedValue());
// Now that everything else is done, do the things the debugger needs.
// Step 7 of RejectPromise implemented in onSettled.
promise->onSettled(cx);
// Step 7 of FulfillPromise.
// Step 8 of RejectPromise.
if (reactionsVal.isObject())
return TriggerPromiseReactions(cx, reactionsVal, state, valueOrReason);
return true;
}
// ES2016, 25.4.1.4.
static MOZ_MUST_USE bool
FulfillMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue value_) {
Rooted<PromiseObject*> promise(cx);
RootedValue value(cx, value_);
mozilla::Maybe<AutoCompartment> ac;
if (!IsWrapper(promiseObj)) {
promise = &promiseObj->as<PromiseObject>();
} else {
promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
ac.emplace(cx, promise);
if (!promise->compartment()->wrap(cx, &value))
return false;
}
MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
return ResolvePromise(cx, promise, value, JS::PromiseState::Fulfilled);
}
// ES2016, 25.4.1.7.
static MOZ_MUST_USE bool
RejectMaybeWrappedPromise(JSContext *cx, HandleObject promiseObj, HandleValue reason_) {
Rooted<PromiseObject*> promise(cx);
RootedValue reason(cx, reason_);
mozilla::Maybe<AutoCompartment> ac;
if (!IsWrapper(promiseObj)) {
promise = &promiseObj->as<PromiseObject>();
} else {
promise = &UncheckedUnwrap(promiseObj)->as<PromiseObject>();
ac.emplace(cx, promise);
// The rejection reason might've been created in a compartment with higher
// privileges than the Promise's. In that case, object-type rejection
// values might be wrapped into a wrapper that throws whenever the
// Promise's reaction handler wants to do anything useful with it. To
// avoid that situation, we synthesize a generic error that doesn't
// expose any privileged information but can safely be used in the
// rejection handler.
if (!promise->compartment()->wrap(cx, &reason))
return false;
if (reason.isObject() && !CheckedUnwrap(&reason.toObject())) {
// Async stacks are only properly adopted if there's at least one
// interpreter frame active right now. If a thenable job with a
// throwing `then` function got us here, that'll not be the case,
// so we add one by throwing the error from self-hosted code.
FixedInvokeArgs<1> getErrorArgs(cx);
getErrorArgs[0].set(Int32Value(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON));
if (!CallSelfHostedFunction(cx, "GetInternalError", reason, getErrorArgs, &reason))
return false;
}
}
MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
return ResolvePromise(cx, promise, reason, JS::PromiseState::Rejected);
}
static void
ClearResolutionFunctionSlots(JSFunction* resolutionFun)
{
JSFunction* otherFun = &resolutionFun->getExtendedSlot(ResolutionFunctionSlot_OtherFunction)
.toObject().as<JSFunction>();
resolutionFun->setExtendedSlot(ResolutionFunctionSlot_Promise, UndefinedValue());
otherFun->setExtendedSlot(ResolutionFunctionSlot_Promise, UndefinedValue());
// Also reset the reference to the resolve function so it can be collected.
resolutionFun->setExtendedSlot(ResolutionFunctionSlot_OtherFunction, UndefinedValue());
otherFun->setExtendedSlot(ResolutionFunctionSlot_OtherFunction, UndefinedValue());
}
// ES2016, 25.4.1.3.1.
static bool
RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction reject(cx, &args.callee().as<JSFunction>());
RootedValue reasonVal(cx, args.get(0));
// Steps 1-2.
RootedValue promiseVal(cx, reject->getExtendedSlot(ResolutionFunctionSlot_Promise));
// Steps 3-4.
// We use the existence of the Promise a a signal for whether it was
// already resolved. Upon resolution, it's reset to `undefined`.
if (promiseVal.isUndefined()) {
args.rval().setUndefined();
return true;
}
RootedObject promise(cx, &promiseVal.toObject());
// Step 5.
ClearResolutionFunctionSlots(reject);
// Step 6.
bool result = RejectMaybeWrappedPromise(cx, promise, reasonVal);
if (result)
args.rval().setUndefined();
return result;
}
// ES2016, 25.4.1.3.2, steps 7-13.
static bool
ResolvePromiseInternal(JSContext* cx, HandleObject promise, HandleValue resolutionVal)
{
// Step 7.
if (!resolutionVal.isObject())
return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
RootedObject resolution(cx, &resolutionVal.toObject());
// Step 8.
RootedValue thenVal(cx);
bool status = GetProperty(cx, resolution, resolution, cx->names().then, &thenVal);
// Step 9.
if (!status) {
RootedValue error(cx);
if (!GetAndClearException(cx, &error))
return false;
return RejectMaybeWrappedPromise(cx, promise, error);
}
// Step 10 (implicit).
// Step 11.
if (!IsCallable(thenVal)) {
return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
}
// Step 12.
RootedValue promiseVal(cx, ObjectValue(*promise));
if (!EnqueuePromiseResolveThenableJob(cx, promiseVal, resolutionVal, thenVal))
return false;
// Step 13.
return true;
}
// ES2016, 25.4.1.3.2.
static bool
ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction resolve(cx, &args.callee().as<JSFunction>());
RootedValue resolutionVal(cx, args.get(0));
// Steps 1-2.
RootedValue promiseVal(cx, resolve->getExtendedSlot(ResolutionFunctionSlot_Promise));
// Steps 3-4.
// We use the existence of the Promise a a signal for whether it was
// already resolved. Upon resolution, it's reset to `undefined`.
if (promiseVal.isUndefined()) {
args.rval().setUndefined();
return true;
}
RootedObject promise(cx, &promiseVal.toObject());
// Step 5.
ClearResolutionFunctionSlots(resolve);
// Step 6.
if (resolutionVal == promiseVal) {
// Step 6.a.
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF);
RootedValue selfResolutionError(cx);
bool status = GetAndClearException(cx, &selfResolutionError);
MOZ_ASSERT(status);
// Step 6.b.
status = RejectMaybeWrappedPromise(cx, promise, selfResolutionError);
if (status)
args.rval().setUndefined();
return status;
}
bool status = ResolvePromiseInternal(cx, promise, resolutionVal);
if (status)
args.rval().setUndefined();
return status;
}
// ES2016, 25.4.1.3.
static MOZ_MUST_USE bool
CreateResolvingFunctions(JSContext* cx, HandleValue promise,
MutableHandleValue resolveVal,
MutableHandleValue rejectVal)
{
RootedAtom funName(cx, cx->names().empty);
RootedFunction resolve(cx, NewNativeFunction(cx, ResolvePromiseFunction, 1, funName,
gc::AllocKind::FUNCTION_EXTENDED));
if (!resolve)
return false;
RootedFunction reject(cx, NewNativeFunction(cx, RejectPromiseFunction, 1, funName,
gc::AllocKind::FUNCTION_EXTENDED));
if (!reject)
return false;
// The resolving functions are trusted, so self-hosted code should be able
// to call them using callFunction instead of callContentFunction.
resolve->setFlags(resolve->flags() | JSFunction::SELF_HOSTED);
reject->setFlags(reject->flags() | JSFunction::SELF_HOSTED);
resolve->setExtendedSlot(ResolutionFunctionSlot_Promise, promise);
resolve->setExtendedSlot(ResolutionFunctionSlot_OtherFunction, ObjectValue(*reject));
reject->setExtendedSlot(ResolutionFunctionSlot_Promise, promise);
reject->setExtendedSlot(ResolutionFunctionSlot_OtherFunction, ObjectValue(*resolve));
resolveVal.setObject(*resolve);
rejectVal.setObject(*reject);
return true;
}
static PromiseObject*
CreatePromiseObjectInternal(JSContext* cx, HandleObject proto, bool protoIsWrapped)
{
// Step 3.
Rooted<PromiseObject*> promise(cx);
// Enter the unwrapped proto's compartment, if that's different from
// the current one.
// All state stored in a Promise's fixed slots must be created in the
// same compartment, so we get all of that out of the way here.
// (Except for the resolution functions, which are created below.)
mozilla::Maybe<AutoCompartment> ac;
if (protoIsWrapped)
ac.emplace(cx, proto);
promise = NewObjectWithClassProto<PromiseObject>(cx, proto);
if (!promise)
return nullptr;
// Step 4.
promise->setFixedSlot(PROMISE_FLAGS_SLOT, Int32Value(0));
// Steps 5-6.
// Omitted, we allocate our single list of reaction records lazily.
// Step 7.
// Implicit, the handled flag is unset by default.
// Store an allocation stack so we can later figure out what the
// control flow was for some unexpected results. Frightfully expensive,
// but oh well.
RootedObject stack(cx);
if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) {
if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames())))
return nullptr;
}
promise->setFixedSlot(PROMISE_ALLOCATION_SITE_SLOT, ObjectOrNullValue(stack));
promise->setFixedSlot(PROMISE_ALLOCATION_TIME_SLOT,
DoubleValue(MillisecondsSinceStartup()));
return promise;
}
/**
* Unforgeable version of ES2016, 25.4.4.4, Promise.reject.
*/
/* static */ JSObject*
PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
{
// Steps 1-2 (omitted).
// Roughly step 3.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx, nullptr, false));
if (!promise)
return nullptr;
// Let the Debugger know about this Promise.
JS::dbg::onNewPromise(cx, promise);
// Roughly step 4.
if (!ResolvePromise(cx, promise, value, JS::PromiseState::Rejected))
return nullptr;
// Step 5.
return promise;
}
/**
* Unforgeable version of ES2016, 25.4.4.5, Promise.resolve.
*/
/* static */ JSObject*
PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value)
{
// Steps 1-2 (omitted).
// Step 3.
if (value.isObject()) {
JSObject* obj = &value.toObject();
if (IsWrapper(obj))
obj = CheckedUnwrap(obj);
// Instead of getting the `constructor` property, do an unforgeable
// check.
if (obj && obj->is<PromiseObject>())
return obj;
}
// Step 4.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx, nullptr, false));
if (!promise)
return nullptr;
// Let the Debugger know about this Promise.
JS::dbg::onNewPromise(cx, promise);
// Steps 5.
if (!ResolvePromiseInternal(cx, promise, value))
return nullptr;
// Step 6.
return promise;
}
// ES6, 25.4.1.5.1.
/* static */ bool
GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction F(cx, &args.callee().as<JSFunction>());
// Steps 1-2 (implicit).
// Steps 3-4.
if (!F->getExtendedSlot(0).isUndefined() || !F->getExtendedSlot(1).isUndefined()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_PROMISE_CAPABILITY_HAS_SOMETHING_ALREADY);
return false;
}
// Step 5.
F->setExtendedSlot(0, args.get(0));
// Step 6.
F->setExtendedSlot(1, args.get(1));
// Step 7.
args.rval().setUndefined();
return true;
}
// ES2016, 25.4.1.5.
// Creates PromiseCapability records, see 25.4.1.1.
static bool
NewPromiseCapability(JSContext* cx, HandleObject C, MutableHandleObject promise,
MutableHandleObject resolve, MutableHandleObject reject)
{
RootedValue cVal(cx, ObjectValue(*C));
// Steps 1-2.
if (!IsConstructor(C)) {
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, -1, cVal, nullptr);
return false;
}
// Step 3 (omitted).
// Step 4.
RootedAtom funName(cx, cx->names().empty);
RootedFunction executor(cx, NewNativeFunction(cx, GetCapabilitiesExecutor, 2, funName,
gc::AllocKind::FUNCTION_EXTENDED));
if (!executor)
return false;
// Step 5 (omitted).
// Step 6.
FixedConstructArgs<1> cargs(cx);
cargs[0].setObject(*executor);
if (!Construct(cx, cVal, cargs, cVal, promise))
return false;
// Step 7.
RootedValue resolveVal(cx, executor->getExtendedSlot(0));
if (!IsCallable(resolveVal)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE);
return false;
}
// Step 8.
RootedValue rejectVal(cx, executor->getExtendedSlot(1));
if (!IsCallable(rejectVal)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE);
return false;
}
// Step 9 (well, the equivalent for all of promiseCapabilities' fields.)
resolve.set(&resolveVal.toObject());
reject.set(&rejectVal.toObject());
// Step 10.
return true;
}
enum ResolveOrRejectMode {
ResolveMode,
RejectMode
};
static bool
CommonStaticResolveRejectImpl(JSContext* cx, unsigned argc, Value* vp, ResolveOrRejectMode mode)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue x(cx, args.get(0));
// Steps 1-2.
if (!args.thisv().isObject()) {
const char* msg = mode == ResolveMode
? "Receiver of Promise.resolve call"
: "Receiver of Promise.reject call";
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, msg);
return false;
}
RootedValue cVal(cx, args.thisv());
RootedObject C(cx, &cVal.toObject());
// Step 3 of Resolve.
if (mode == ResolveMode && x.isObject()) {
RootedObject xObj(cx, &x.toObject());
bool isPromise = false;
if (xObj->is<PromiseObject>()) {
isPromise = true;
} else if (IsWrapper(xObj)) {
// Treat instances of Promise from other compartments as Promises
// here, too.
// It's important to do the GetProperty for the `constructor`
// below through the wrapper, because wrappers can change the
// outcome, so instead of unwrapping and then performing the
// GetProperty, just check here and then operate on the original
// object again.
RootedObject unwrappedObject(cx, CheckedUnwrap(xObj));
if (unwrappedObject && unwrappedObject->is<PromiseObject>())
isPromise = true;
}
if (isPromise) {
RootedValue ctorVal(cx);
if (!GetProperty(cx, xObj, xObj, cx->names().constructor, &ctorVal))
return false;
if (ctorVal == cVal) {
args.rval().set(x);
return true;
}
}
}
// Steps 4-5 of Resolve, 3-4 of Reject.
RootedObject promiseCtor(cx);
if (!GetBuiltinConstructor(cx, JSProto_Promise, &promiseCtor))
return false;
RootedObject promise(cx);
// If the current constructor is the original Promise constructor, we can
// optimize things by skipping the creation and invocation of the resolve
// and reject callbacks, directly creating and resolving the new Promise.
if (promiseCtor == C) {
// Roughly step 4 of Resolve, 3 of Reject.
promise = CreatePromiseObjectInternal(cx, nullptr, false);
if (!promise)
return false;
// Let the Debugger know about this Promise.
JS::dbg::onNewPromise(cx, promise);
// Roughly step 5 of Resolve.
if (mode == ResolveMode) {
if (!ResolvePromiseInternal(cx, promise, x))
return false;
} else {
// Roughly step 4 of Reject.
Rooted<PromiseObject*> promiseObj(cx, &promise->as<PromiseObject>());
if (!ResolvePromise(cx, promiseObj, x, JS::PromiseState::Rejected))
return false;
}
} else {
// Step 4 of Resolve, 3 of Reject.
RootedObject resolveFun(cx);
RootedObject rejectFun(cx);
if (!NewPromiseCapability(cx, C, &promise, &resolveFun, &rejectFun))
return false;
// Step 5 of Resolve, 4 of Reject.
FixedInvokeArgs<1> args2(cx);
args2[0].set(x);
RootedValue calleeOrRval(cx, ObjectValue(mode == ResolveMode ? *resolveFun : *rejectFun));
if (!Call(cx, calleeOrRval, UndefinedHandleValue, args2, &calleeOrRval))
return false;
}
// Step 6 of Resolve, 4 of Reject.
args.rval().setObject(*promise);
return true;
}
/**
* ES2016, 25.4.4.4, Promise.reject.
*/
static bool
Promise_reject(JSContext* cx, unsigned argc, Value* vp)
{
return CommonStaticResolveRejectImpl(cx, argc, vp, RejectMode);
}
/**
* ES2016, 25.4.4.5, Promise.resolve.
*/
static bool
Promise_resolve(JSContext* cx, unsigned argc, Value* vp)
{
return CommonStaticResolveRejectImpl(cx, argc, vp, ResolveMode);
}
// ES2016, February 12 draft, 25.4.3.1. steps 3-11.
/* static */
PromiseObject*
PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */)
{
@ -95,53 +707,8 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
}
// Step 3.
Rooted<PromiseObject*> promise(cx);
{
// Enter the unwrapped proto's compartment, if that's different from
// the current one.
// All state stored in a Promise's fixed slots must be created in the
// same compartment, so we get all of that out of the way here.
// (Except for the resolution functions, which are created below.)
mozilla::Maybe<AutoCompartment> ac;
if (wrappedProto)
ac.emplace(cx, usedProto);
promise = NewObjectWithClassProto<PromiseObject>(cx, usedProto);
if (!promise)
return nullptr;
// Step 4.
promise->setFixedSlot(PROMISE_STATE_SLOT, Int32Value(PROMISE_STATE_PENDING));
// Step 5.
RootedArrayObject reactions(cx, NewDenseEmptyArray(cx));
if (!reactions)
return nullptr;
promise->setFixedSlot(PROMISE_FULFILL_REACTIONS_SLOT, ObjectValue(*reactions));
// Step 6.
reactions = NewDenseEmptyArray(cx);
if (!reactions)
return nullptr;
promise->setFixedSlot(PROMISE_REJECT_REACTIONS_SLOT, ObjectValue(*reactions));
// Step 7.
promise->setFixedSlot(PROMISE_IS_HANDLED_SLOT,
Int32Value(PROMISE_IS_HANDLED_STATE_UNHANDLED));
// Store an allocation stack so we can later figure out what the
// control flow was for some unexpected results. Frightfully expensive,
// but oh well.
RootedObject stack(cx);
if (cx->options().asyncStack() || cx->compartment()->isDebuggee()) {
if (!JS::CaptureCurrentStack(cx, &stack, JS::StackCapture(JS::AllFrames())))
return nullptr;
}
promise->setFixedSlot(PROMISE_ALLOCATION_SITE_SLOT, ObjectOrNullValue(stack));
promise->setFixedSlot(PROMISE_ALLOCATION_TIME_SLOT,
DoubleValue(MillisecondsSinceStartup()));
}
// Steps 3-7.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx, usedProto, wrappedProto));
RootedValue promiseVal(cx, ObjectValue(*promise));
if (wrappedProto && !cx->compartment()->wrap(cx, &promiseVal))
@ -160,17 +727,11 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
if (wrappedProto) {
AutoCompartment ac(cx, promise);
RootedValue wrappedResolveVal(cx, resolveVal);
RootedValue wrappedRejectVal(cx, rejectVal);
if (!cx->compartment()->wrap(cx, &wrappedResolveVal) ||
!cx->compartment()->wrap(cx, &wrappedRejectVal))
{
if (!cx->compartment()->wrap(cx, &wrappedResolveVal))
return nullptr;
}
promise->setFixedSlot(PROMISE_RESOLVE_FUNCTION_SLOT, wrappedResolveVal);
promise->setFixedSlot(PROMISE_REJECT_FUNCTION_SLOT, wrappedRejectVal);
} else {
promise->setFixedSlot(PROMISE_RESOLVE_FUNCTION_SLOT, resolveVal);
promise->setFixedSlot(PROMISE_REJECT_FUNCTION_SLOT, rejectVal);
}
// Step 9.
@ -237,28 +798,24 @@ PromiseObject::getID()
* `Promise.all(iterable)` or `Promise.race(iterable)`, with this promise
* being a member of the passed-in `iterable`.
*
*
* For the then() case, we have both resolve and reject callbacks that know
* what the next promise is.
*
* For the race() case, likewise.
*
* For the all() case, our reject callback knows what the next promise is, but
* our resolve callback doesn't.
*
* So we walk over our _reject_ callbacks and ask each of them what promise
* its dependent promise is.
* Per spec, we should have separate lists of reaction records for the
* fulfill and reject cases. As an optimization, we have only one of those,
* containing the required data for both cases. So we just walk that list
* and extract the dependent promises from all reaction records.
*/
bool
PromiseObject::dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values)
{
RootedValue rejectReactionsVal(cx, getReservedSlot(PROMISE_REJECT_REACTIONS_SLOT));
RootedObject rejectReactions(cx, rejectReactionsVal.toObjectOrNull());
if (!rejectReactions)
if (state() != JS::PromiseState::Pending)
return true;
RootedValue reactionsVal(cx, getReservedSlot(PROMISE_REACTIONS_OR_RESULT_SLOT));
if (reactionsVal.isNullOrUndefined())
return true;
RootedObject reactions(cx, &reactionsVal.toObject());
AutoIdVector keys(cx);
if (!GetPropertyKeys(cx, rejectReactions, JSITER_OWNONLY, &keys))
if (!GetPropertyKeys(cx, reactions, JSITER_OWNONLY, &keys))
return false;
if (keys.length() == 0)
@ -267,32 +824,25 @@ PromiseObject::dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> v
if (!values.growBy(keys.length()))
return false;
RootedAtom capabilitiesAtom(cx, Atomize(cx, "capabilities", strlen("capabilities")));
if (!capabilitiesAtom)
return false;
RootedId capabilitiesId(cx, AtomToId(capabilitiesAtom));
// Each reaction is an internally-created object with the structure:
// {
// capabilities: {
// promise: [the promise this reaction resolves],
// resolve: [the `resolve` callback content code provided],
// reject: [the `reject` callback content code provided],
// },
// handler: [the internal handler that fulfills/rejects the promise]
// }
// promise: [the promise this reaction resolves],
// resolve: [the `resolve` callback content code provided],
// reject: [the `reject` callback content code provided],
// fulfillHandler: [the internal handler that fulfills the promise]
// rejectHandler: [the internal handler that rejects the promise]
// incumbentGlobal: [an object from the global that was incumbent when
// the reaction was created]
// }
//
// In the following loop we collect the `capabilities.promise` values for
// each reaction.
for (size_t i = 0; i < keys.length(); i++) {
MutableHandleValue val = values[i];
if (!GetProperty(cx, rejectReactions, rejectReactions, keys[i], val))
if (!GetProperty(cx, reactions, reactions, keys[i], val))
return false;
RootedObject reaction(cx, &val.toObject());
if (!GetProperty(cx, reaction, reaction, capabilitiesId, val))
return false;
RootedObject capabilities(cx, &val.toObject());
if (!GetProperty(cx, capabilities, capabilities, cx->runtime()->commonNames->promise, val))
if (!GetProperty(cx, reaction, reaction, cx->names().promise, val))
return false;
}
@ -388,10 +938,11 @@ PromiseConstructor(JSContext* cx, unsigned argc, Value* vp)
bool
PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue)
{
if (this->getFixedSlot(PROMISE_STATE_SLOT).toInt32() != unsigned(JS::PromiseState::Pending))
if (state() != JS::PromiseState::Pending)
return true;
RootedValue funVal(cx, this->getReservedSlot(PROMISE_RESOLVE_FUNCTION_SLOT));
// TODO: ensure that this holds for xray'd promises. (It probably doesn't)
MOZ_ASSERT(funVal.toObject().is<JSFunction>());
FixedInvokeArgs<1> args(cx);
@ -405,10 +956,12 @@ PromiseObject::resolve(JSContext* cx, HandleValue resolutionValue)
bool
PromiseObject::reject(JSContext* cx, HandleValue rejectionValue)
{
if (this->getFixedSlot(PROMISE_STATE_SLOT).toInt32() != unsigned(JS::PromiseState::Pending))
if (state() != JS::PromiseState::Pending)
return true;
RootedValue funVal(cx, this->getReservedSlot(PROMISE_REJECT_FUNCTION_SLOT));
RootedValue resolveVal(cx, this->getReservedSlot(PROMISE_RESOLVE_FUNCTION_SLOT));
RootedFunction resolve(cx, &resolveVal.toObject().as<JSFunction>());
RootedValue funVal(cx, resolve->getExtendedSlot(ResolutionFunctionSlot_OtherFunction));
MOZ_ASSERT(funVal.toObject().is<JSFunction>());
FixedInvokeArgs<1> args(cx);
@ -433,12 +986,8 @@ PromiseObject::onSettled(JSContext* cx)
promise->setFixedSlot(PROMISE_RESOLUTION_SITE_SLOT, ObjectOrNullValue(stack));
promise->setFixedSlot(PROMISE_RESOLUTION_TIME_SLOT, DoubleValue(MillisecondsSinceStartup()));
if (promise->state() == JS::PromiseState::Rejected &&
promise->getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() !=
PROMISE_IS_HANDLED_STATE_HANDLED)
{
if (promise->state() == JS::PromiseState::Rejected && promise->isUnhandled())
cx->runtime()->addUnhandledRejectedPromise(cx, promise);
}
JS::dbg::onPromiseSettled(cx, promise);
}
@ -763,8 +1312,6 @@ EnqueuePromiseResolveThenableJob(JSContext* cx, HandleValue promiseToResolve_,
AutoCompartment ac(cx, then);
RootedAtom funName(cx, cx->names().empty);
if (!funName)
return false;
RootedFunction job(cx, NewNativeFunction(cx, PromiseResolveThenableJob, 0, funName,
gc::AllocKind::FUNCTION_EXTENDED));
if (!job)
@ -844,6 +1391,25 @@ CreatePromisePrototype(JSContext* cx, JSProtoKey key)
return cx->global()->createBlankPrototype(cx, &PromiseObject::protoClass_);
}
static const JSFunctionSpec promise_methods[] = {
JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0),
JS_SELF_HOSTED_FN("then", "Promise_then", 2, 0),
JS_FS_END
};
static const JSFunctionSpec promise_static_methods[] = {
JS_SELF_HOSTED_FN("all", "Promise_static_all", 1, 0),
JS_SELF_HOSTED_FN("race", "Promise_static_race", 1, 0),
JS_FN("reject", Promise_reject, 1, 0),
JS_FN("resolve", Promise_resolve, 1, 0),
JS_FS_END
};
static const JSPropertySpec promise_static_properties[] = {
JS_SELF_HOSTED_SYM_GET(species, "Promise_static_get_species", 0),
JS_PS_END
};
static const ClassSpec PromiseObjectClassSpec = {
GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
CreatePromisePrototype,

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

@ -17,24 +17,32 @@ class AutoSetNewObjectMetadata;
class PromiseObject : public NativeObject
{
public:
static const unsigned RESERVED_SLOTS = 12;
static const unsigned RESERVED_SLOTS = 8;
static const Class class_;
static const Class protoClass_;
static PromiseObject* create(JSContext* cx, HandleObject executor,
HandleObject proto = nullptr);
static JSObject* unforgeableResolve(JSContext* cx, HandleValue value);
static JSObject* unforgeableReject(JSContext* cx, HandleValue value);
JS::PromiseState state() {
int32_t state = getFixedSlot(PROMISE_STATE_SLOT).toInt32();
MOZ_ASSERT(state >= 0 && state <= int32_t(JS::PromiseState::Rejected));
return JS::PromiseState(state);
int32_t flags = getFixedSlot(PROMISE_FLAGS_SLOT).toInt32();
if (!(flags & PROMISE_FLAG_RESOLVED)) {
MOZ_ASSERT(!(flags & PROMISE_FLAG_FULFILLED));
return JS::PromiseState::Pending;
}
if (flags & PROMISE_FLAG_FULFILLED)
return JS::PromiseState::Fulfilled;
return JS::PromiseState::Rejected;
}
Value value() {
MOZ_ASSERT(state() == JS::PromiseState::Fulfilled);
return getFixedSlot(PROMISE_RESULT_SLOT);
return getFixedSlot(PROMISE_REACTIONS_OR_RESULT_SLOT);
}
Value reason() {
MOZ_ASSERT(state() == JS::PromiseState::Rejected);
return getFixedSlot(PROMISE_RESULT_SLOT);
return getFixedSlot(PROMISE_REACTIONS_OR_RESULT_SLOT);
}
MOZ_MUST_USE bool resolve(JSContext* cx, HandleValue resolutionValue);
@ -57,13 +65,14 @@ class PromiseObject : public NativeObject
}
MOZ_MUST_USE bool dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values);
uint64_t getID();
bool markedAsUncaught() {
return getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() != PROMISE_IS_HANDLED_STATE_HANDLED;
bool isUnhandled() {
MOZ_ASSERT(state() == JS::PromiseState::Rejected);
return !(getFixedSlot(PROMISE_FLAGS_SLOT).toInt32() & PROMISE_FLAG_HANDLED);
}
void markAsReported() {
MOZ_ASSERT(getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() ==
PROMISE_IS_HANDLED_STATE_UNHANDLED);
setFixedSlot(PROMISE_IS_HANDLED_SLOT, Int32Value(PROMISE_IS_HANDLED_STATE_REPORTED));
MOZ_ASSERT(isUnhandled());
int32_t flags = getFixedSlot(PROMISE_FLAGS_SLOT).toInt32();
setFixedSlot(PROMISE_FLAGS_SLOT, Int32Value(flags | PROMISE_FLAG_REPORTED));
}
};

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

@ -5,165 +5,26 @@
// ES6, 25.4.1.2.
// This object is used to verify that an object is a PromiseReaction record.
var PromiseReactionRecordProto = {__proto__: null};
// ES6, 25.4.1.3.
function CreateResolvingFunctions(promise) {
// The callbacks created here can deal with Promises wrapped in cross-
// compartment wrappers. That's required because in some circumstances,
// they're created in a higher-privileged compartment from the Promise,
// so they can be invoked seamlessly by code in that compartment.
//
// See the comment in PromiseConstructor (in builtin/Promise.cpp) for more
// details.
let unwrap = false;
if (!IsPromise(promise)) {
assert(IsWrappedPromise(promise),
"CreateResolvingFunctions expects arg0 to be a - maybe wrapped - promise");
unwrap = true;
}
// Step 1.
let alreadyResolved = false;
// Steps 2-4.
// ES6, 25.4.1.3.2. Inlined here so we can use an upvar instead of a slot to
// store promise and alreadyResolved, and share the latter with reject below.
function resolve(resolution) {
// Steps 1-3 (implicit).
// Step 4.
if (alreadyResolved)
return undefined;
// Step 5.
alreadyResolved = true;
// Step 6.
// We know |promise| is an object, so using strict equality instead of
// SameValue is fine.
if (resolution === promise) {
// Step 6.a.
let selfResolutionError = GetTypeError(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF);
// Step 6.b.
if (unwrap) {
return RejectUnwrappedPromise(promise, selfResolutionError);
}
return RejectPromise(promise, selfResolutionError);
}
// Step 7.
if (!IsObject(resolution)) {
if (unwrap) {
return callFunction(CallPromiseMethodIfWrapped, promise, resolution,
"FulfillUnwrappedPromise");
}
return FulfillPromise(promise, resolution);
}
// Steps 8-9.
let then;
try {
then = resolution.then;
} catch (e) {
if (unwrap) {
return RejectUnwrappedPromise(promise, e);
}
return RejectPromise(promise, e);
}
// Step 10 (implicit).
// Step 11.
if (!IsCallable(then)) {
if (unwrap) {
return callFunction(CallPromiseMethodIfWrapped, promise, resolution,
"FulfillUnwrappedPromise");
}
return FulfillPromise(promise, resolution);
}
// Step 12.
_EnqueuePromiseResolveThenableJob(promise, resolution, then);
// Step 13.
return undefined;
}
// Steps 5-7.
// ES6, 25.4.1.3.2.
function reject(reason) {
// Steps 1-3 (implicit).
// Step 4.
if (alreadyResolved)
return undefined;
// Step 5.
alreadyResolved = true;
// Step 6.
if (unwrap) {
return RejectUnwrappedPromise(promise, reason);
}
return RejectPromise(promise, reason);
}
// Return an array instead of an object with resolve/reject properties
// to make value extraction from C++ easier.
return [resolve, reject];
function PromiseReactionRecord(promise, resolve, reject, fulfillHandler, rejectHandler,
incumbentGlobal) {
this.promise = promise;
this.resolve = resolve;
this.reject = reject;
this.fulfillHandler = fulfillHandler;
this.rejectHandler = rejectHandler;
this.incumbentGlobal = incumbentGlobal;
}
// ES6, 25.4.1.4.
function FulfillPromise(promise, value) {
return ResolvePromise(promise, value, PROMISE_FULFILL_REACTIONS_SLOT, PROMISE_STATE_FULFILLED);
}
function FulfillUnwrappedPromise(value) {
return ResolvePromise(this, value, PROMISE_FULFILL_REACTIONS_SLOT, PROMISE_STATE_FULFILLED);
}
// Commoned-out implementation of 25.4.1.4. and 25.4.1.7.
// ES2016 February 12 draft.
function ResolvePromise(promise, valueOrReason, reactionsSlot, state) {
// Step 1.
assert(GetPromiseState(promise) === PROMISE_STATE_PENDING,
"Can't resolve non-pending promise");
assert(state >= PROMISE_STATE_PENDING && state <= PROMISE_STATE_REJECTED,
`Invalid Promise state <${state}>`);
// Step 2.
var reactions = UnsafeGetObjectFromReservedSlot(promise, reactionsSlot);
// Step 3.
UnsafeSetReservedSlot(promise, PROMISE_RESULT_SLOT, valueOrReason);
// Step 4.
UnsafeSetReservedSlot(promise, PROMISE_FULFILL_REACTIONS_SLOT, null);
// Step 5.
UnsafeSetReservedSlot(promise, PROMISE_REJECT_REACTIONS_SLOT, null);
// Step 6.
UnsafeSetReservedSlot(promise, PROMISE_STATE_SLOT, state);
// Also null out the resolve/reject functions so they can be GC'd.
UnsafeSetReservedSlot(promise, PROMISE_RESOLVE_FUNCTION_SLOT, null);
UnsafeSetReservedSlot(promise, PROMISE_REJECT_FUNCTION_SLOT, null);
// Now that everything else is done, do the things the debugger needs.
// Step 7 of RejectPromise implemented in the debugger intrinsic.
_dbg_onPromiseSettled(promise);
// Step 7 of FulfillPromise.
// Step 8 of RejectPromise.
return TriggerPromiseReactions(reactions, valueOrReason);
}
MakeConstructible(PromiseReactionRecord, PromiseReactionRecordProto);
// Used to verify that an object is a PromiseCapability record.
var PromiseCapabilityRecordProto = {__proto__: null};
// ES6, 25.4.1.5.
// ES2016, 25.4.1.3, implemented in Promise.cpp.
// ES2016, 25.4.1.4, implemented in Promise.cpp.
// ES2016, 25.4.1.5.
// Creates PromiseCapability records, see 25.4.1.1.
function NewPromiseCapability(C) {
// Steps 1-2.
@ -207,31 +68,25 @@ function NewPromiseCapability(C) {
};
}
// ES6, 25.4.1.6. is implemented as an intrinsic in SelfHosting.cpp.
// ES2016, 25.4.1.6, implemented in SelfHosting.cpp.
// ES2016, February 12 draft, 25.4.1.7.
function RejectPromise(promise, reason) {
return ResolvePromise(promise, reason, PROMISE_REJECT_REACTIONS_SLOT, PROMISE_STATE_REJECTED);
}
// ES2016, 25.4.1.7, implemented in Promise.cpp.
// ES6, 25.4.1.8.
function TriggerPromiseReactions(reactions, argument) {
// Step 1.
for (var i = 0, len = reactions.length; i < len; i++)
EnqueuePromiseReactionJob(reactions[i], argument);
// Step 2 (implicit).
}
// ES2016, 25.4.1.8, implemented in Promise.cpp.
// ES2016, February 12 draft 25.4.1.9, implemented in SelfHosting.cpp.
// ES2016, 25.4.1.9, implemented in SelfHosting.cpp.
// ES6, 25.4.2.1.
function EnqueuePromiseReactionJob(reaction, argument) {
let capabilities = reaction.capabilities;
_EnqueuePromiseReactionJob(reaction.handler,
function EnqueuePromiseReactionJob(reaction, jobType, argument) {
// Reaction records contain handlers for both fulfillment and rejection.
// The `jobType` parameter allows us to retrieves the right one.
assert(jobType === PROMISE_JOB_TYPE_FULFILL || jobType === PROMISE_JOB_TYPE_REJECT,
"Invalid job type");
_EnqueuePromiseReactionJob(reaction[jobType],
argument,
capabilities.resolve,
capabilities.reject,
capabilities.promise,
reaction.resolve,
reaction.reject,
reaction.promise,
reaction.incumbentGlobal || null);
}
@ -239,7 +94,7 @@ function EnqueuePromiseReactionJob(reaction, argument) {
// ES6, 25.4.3.1. (Implemented in C++).
// ES7 2016-01-21 draft, 25.4.4.1.
// ES2016, 25.4.4.1.
function Promise_static_all(iterable) {
// Step 1.
let C = this;
@ -459,7 +314,7 @@ function CreatePromiseAllResolveElementFunction(index, values, promiseCapability
};
}
// ES7, 2016-01-21 draft, 25.4.4.3.
// ES2016, 25.4.4.3.
function Promise_static_race(iterable) {
// Step 1.
let C = this;
@ -497,7 +352,7 @@ function Promise_static_race(iterable) {
}
}
// ES7, 2016-01-21 draft, 25.4.4.3.1.
// ES2016, 25.4.4.3.1.
function PerformPromiseRace(iteratorRecord, resultCapability, C) {
assert(IsConstructor(C), "PerformPromiseRace called with non-constructor");
assert(IsPromiseCapability(resultCapability), "Invalid promise capability record");
@ -604,105 +459,47 @@ function BlockOnPromise(promise, blockedPromise, onResolve, onReject) {
// If the object isn't a maybe-wrapped instance of |Promise|, we ignore
// it. All this does is lose some small amount of debug information
// in scenarios that are highly unlikely to occur in useful code.
if (IsPromise(promise)) {
return callFunction(AddPromiseReaction, promise, PROMISE_REJECT_REACTIONS_SLOT,
blockedPromise);
}
if (IsPromise(promise))
return callFunction(AddDependentPromise, promise, blockedPromise);
if (IsWrappedPromise(promise)) {
callFunction(CallPromiseMethodIfWrapped, promise, PROMISE_REJECT_REACTIONS_SLOT,
blockedPromise, "AddPromiseReaction");
}
if (IsWrappedPromise(promise))
callFunction(CallPromiseMethodIfWrapped, promise, blockedPromise, "AddDependentPromise");
}
/**
* Invoked with a Promise as the receiver, AddPromiseReaction adds an entry to
* the reactions list in `slot`, using the other parameters as values for that
* reaction.
* Invoked with a Promise as the receiver, AddDependentPromise adds an entry
* to the reactions list.
*
* If any of the callback functions aren't specified, they're set to
* NullFunction. Doing that here is useful in case the call is performed on an
* unwrapped Promise. Passing in NullFunctions would cause useless compartment
* switches.
* This is only used to make dependent promises visible in the devtools, so no
* callbacks are provided. To make handling that case easier elsewhere,
* they're all set to NullFunction.
*
* The reason for the target Promise to be passed as the receiver is so the
* same function can be used for wrapped and unwrapped Promise objects.
*/
function AddPromiseReaction(slot, dependentPromise, onResolve, onReject, handler) {
assert(IsPromise(this), "AddPromiseReaction expects an unwrapped Promise as the receiver");
assert(slot === PROMISE_FULFILL_REACTIONS_SLOT || slot === PROMISE_REJECT_REACTIONS_SLOT,
"Invalid slot");
function AddDependentPromise(dependentPromise) {
assert(IsPromise(this), "AddDependentPromise expects an unwrapped Promise as the receiver");
if (!onResolve)
onResolve = NullFunction;
if (!onReject)
onReject = NullFunction;
if (!handler)
handler = NullFunction;
let reactions = UnsafeGetReservedSlot(this, slot);
// The reactions slot might've been reset because the Promise was resolved.
if (!reactions) {
assert(GetPromiseState(this) !== PROMISE_STATE_PENDING,
"Pending promises must have reactions lists.");
if (GetPromiseState(this) !== PROMISE_STATE_PENDING)
return;
}
_DefineDataProperty(reactions, reactions.length, {
__proto__: PromiseReactionRecordProto,
capabilities: {
__proto__: PromiseCapabilityRecordProto,
promise: dependentPromise,
reject: onReject,
resolve: onResolve
},
handler: handler
});
let reaction = new PromiseReactionRecord(dependentPromise, NullFunction, NullFunction,
NullFunction, NullFunction, null);
let reactions = UnsafeGetReservedSlot(this, PROMISE_REACTIONS_OR_RESULT_SLOT);
// The reactions list might not have been allocated yet.
if (!reactions)
UnsafeSetReservedSlot(dependentPromise, PROMISE_REACTIONS_OR_RESULT_SLOT, [reaction]);
else
_DefineDataProperty(reactions, reactions.length, reaction);
}
// ES6, 25.4.4.4.
function Promise_static_reject(r) {
// Step 1.
let C = this;
// ES2016, 25.4.4.4 (implemented in C++).
// Step 2.
if (!IsObject(C))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, "Receiver of Promise.reject call");
// ES2016, 25.4.4.5 (implemented in C++).
// Steps 3-4.
let promiseCapability = NewPromiseCapability(C);
// Steps 5-6.
callContentFunction(promiseCapability.reject, undefined, r);
// Step 7.
return promiseCapability.promise;
}
// ES6, 25.4.4.5.
function Promise_static_resolve(x) {
// Step 1.
let C = this;
// Step 2.
if (!IsObject(C))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, "Receiver of Promise.resolve call");
// Step 3.
if (IsObject(x) && (IsPromise(x) || IsWrappedPromise(x)) && x.constructor === C)
return x;
// Steps 4-5.
let promiseCapability = NewPromiseCapability(C);
// Steps 6-7.
callContentFunction(promiseCapability.resolve, undefined, x);
// Step 8.
return promiseCapability.promise;
}
//ES6, 25.4.4.6.
// ES6, 25.4.4.6.
function Promise_static_get_species() {
// Step 1.
return this;
@ -753,9 +550,9 @@ function Promise_then(onFulfilled, onRejected) {
*
* Used internally to implement DOM functionality.
*
* Note: the reactions pushed using this function contain a `capabilities`
* object whose `promise` field can contain null. That field is only ever used
* by devtools, which have to treat these reactions specially.
* Note: the reactions pushed using this function contain a `promise` field
* that can contain null. That field is only ever used by devtools, which have
* to treat these reactions specially.
*/
function EnqueuePromiseReactions(promise, dependentPromise, onFulfilled, onRejected) {
let isWrappedPromise = false;
@ -871,7 +668,7 @@ function UnwrappedPerformPromiseThen(fulfilledHandler, rejectedHandler, promise,
resultCapability);
}
// ES2016, March 1, 2016 draft, 25.4.5.3.1.
// ES2016, 25.4.5.3.1.
function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability) {
// Step 1.
assert(IsPromise(promise), "Can't call PerformPromiseThen on non-Promise objects");
@ -888,43 +685,37 @@ function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability)
onRejected = PROMISE_HANDLER_THROWER;
let incumbentGlobal = _GetObjectFromIncumbentGlobal();
// Step 5.
let fulfillReaction = {
__proto__: PromiseReactionRecordProto,
capabilities: resultCapability,
handler: onFulfilled,
incumbentGlobal
};
// Step 6.
let rejectReaction = {
__proto__: PromiseReactionRecordProto,
capabilities: resultCapability,
handler: onRejected,
incumbentGlobal
};
// Steps 5,6.
// Instead of creating separate reaction records for fulfillment and
// rejection, we create a combined record. All places we use the record
// can handle that.
let reaction = new PromiseReactionRecord(resultCapability.promise,
resultCapability.resolve,
resultCapability.reject,
onFulfilled,
onRejected,
incumbentGlobal);
// Step 7.
let state = GetPromiseState(promise);
let flags = UnsafeGetInt32FromReservedSlot(promise, PROMISE_FLAGS_SLOT);
if (state === PROMISE_STATE_PENDING) {
// Step 7.a.
let fulfillReactions = UnsafeGetObjectFromReservedSlot(promise,
PROMISE_FULFILL_REACTIONS_SLOT);
_DefineDataProperty(fulfillReactions, fulfillReactions.length, fulfillReaction);
// Step 7.b.
let rejectReactions = UnsafeGetObjectFromReservedSlot(promise,
PROMISE_REJECT_REACTIONS_SLOT);
_DefineDataProperty(rejectReactions, rejectReactions.length, rejectReaction);
// Steps 7.a,b.
// We only have a single list for fulfill and reject reactions.
let reactions = UnsafeGetReservedSlot(promise, PROMISE_REACTIONS_OR_RESULT_SLOT);
if (!reactions)
UnsafeSetReservedSlot(promise, PROMISE_REACTIONS_OR_RESULT_SLOT, [reaction]);
else
_DefineDataProperty(reactions, reactions.length, reaction);
}
// Step 8.
else if (state === PROMISE_STATE_FULFILLED) {
// Step 8.a.
let value = UnsafeGetReservedSlot(promise, PROMISE_RESULT_SLOT);
let value = UnsafeGetReservedSlot(promise, PROMISE_REACTIONS_OR_RESULT_SLOT);
// Step 8.b.
EnqueuePromiseReactionJob(fulfillReaction, value);
EnqueuePromiseReactionJob(reaction, PROMISE_JOB_TYPE_FULFILL, value);
}
// Step 9.
@ -933,21 +724,18 @@ function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability)
assert(state === PROMISE_STATE_REJECTED, "Invalid Promise state " + state);
// Step 9.b.
let reason = UnsafeGetReservedSlot(promise, PROMISE_RESULT_SLOT);
let reason = UnsafeGetReservedSlot(promise, PROMISE_REACTIONS_OR_RESULT_SLOT);
// Step 9.c.
if (UnsafeGetInt32FromReservedSlot(promise, PROMISE_IS_HANDLED_SLOT) !==
PROMISE_IS_HANDLED_STATE_HANDLED)
{
if (!(flags & PROMISE_FLAG_HANDLED))
HostPromiseRejectionTracker(promise, PROMISE_REJECTION_TRACKER_OPERATION_HANDLE);
}
// Step 9.d.
EnqueuePromiseReactionJob(rejectReaction, reason);
EnqueuePromiseReactionJob(reaction, PROMISE_JOB_TYPE_REJECT, reason);
}
// Step 10.
UnsafeSetReservedSlot(promise, PROMISE_IS_HANDLED_SLOT, PROMISE_IS_HANDLED_STATE_HANDLED);
UnsafeSetReservedSlot(promise, PROMISE_FLAGS_SLOT, flags | PROMISE_FLAG_HANDLED);
// Step 11.
return resultCapability.promise;
@ -963,5 +751,12 @@ function IsPromiseCapability(capability) {
}
function GetPromiseState(promise) {
return UnsafeGetInt32FromReservedSlot(promise, PROMISE_STATE_SLOT);
let flags = UnsafeGetInt32FromReservedSlot(promise, PROMISE_FLAGS_SLOT);
if (!(flags & PROMISE_FLAG_RESOLVED)) {
assert(!(flags & PROMISE_STATE_FULFILLED), "Fulfilled promises are resolved, too");
return PROMISE_STATE_PENDING;
}
if (flags & PROMISE_FLAG_FULFILLED)
return PROMISE_STATE_FULFILLED;
return PROMISE_STATE_REJECTED;
}

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

@ -57,26 +57,23 @@
#define ITEM_KIND_VALUE 1
#define ITEM_KIND_KEY_AND_VALUE 2
#define PROMISE_STATE_SLOT 0
#define PROMISE_RESULT_SLOT 1
#define PROMISE_FULFILL_REACTIONS_SLOT 2
#define PROMISE_REJECT_REACTIONS_SLOT 3
#define PROMISE_RESOLVE_FUNCTION_SLOT 4
#define PROMISE_REJECT_FUNCTION_SLOT 5
#define PROMISE_ALLOCATION_SITE_SLOT 6
#define PROMISE_RESOLUTION_SITE_SLOT 7
#define PROMISE_ALLOCATION_TIME_SLOT 8
#define PROMISE_RESOLUTION_TIME_SLOT 9
#define PROMISE_ID_SLOT 10
#define PROMISE_IS_HANDLED_SLOT 11
#define PROMISE_FLAGS_SLOT 0
#define PROMISE_REACTIONS_OR_RESULT_SLOT 1
#define PROMISE_RESOLVE_FUNCTION_SLOT 2
#define PROMISE_ALLOCATION_SITE_SLOT 3
#define PROMISE_RESOLUTION_SITE_SLOT 4
#define PROMISE_ALLOCATION_TIME_SLOT 5
#define PROMISE_RESOLUTION_TIME_SLOT 6
#define PROMISE_ID_SLOT 7
#define PROMISE_STATE_PENDING 0
#define PROMISE_STATE_FULFILLED 1
#define PROMISE_STATE_REJECTED 2
#define PROMISE_IS_HANDLED_STATE_HANDLED 0
#define PROMISE_IS_HANDLED_STATE_UNHANDLED 1
#define PROMISE_IS_HANDLED_STATE_REPORTED 2
#define PROMISE_FLAG_RESOLVED 0x1
#define PROMISE_FLAG_FULFILLED 0x2
#define PROMISE_FLAG_HANDLED 0x4
#define PROMISE_FLAG_REPORTED 0x8
#define PROMISE_HANDLER_IDENTITY 0
#define PROMISE_HANDLER_THROWER 1
@ -84,6 +81,9 @@
#define PROMISE_REJECTION_TRACKER_OPERATION_REJECT false
#define PROMISE_REJECTION_TRACKER_OPERATION_HANDLE true
#define PROMISE_JOB_TYPE_FULFILL "fulfillHandler"
#define PROMISE_JOB_TYPE_REJECT "rejectHandler"
// NB: keep these in sync with the copy in jsfriendapi.h.
#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */
#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */

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

@ -1444,8 +1444,10 @@ SettlePromiseNow(JSContext* cx, unsigned argc, Value* vp)
}
RootedNativeObject promise(cx, &args[0].toObject().as<NativeObject>());
promise->setReservedSlot(PROMISE_STATE_SLOT, Int32Value(PROMISE_STATE_FULFILLED));
promise->setReservedSlot(PROMISE_RESULT_SLOT, UndefinedValue());
int32_t flags = promise->getFixedSlot(PROMISE_FLAGS_SLOT).toInt32();
promise->setFixedSlot(PROMISE_FLAGS_SLOT,
Int32Value(flags | PROMISE_FLAG_RESOLVED | PROMISE_FLAG_FULFILLED));
promise->setFixedSlot(PROMISE_REACTIONS_OR_RESULT_SLOT, UndefinedValue());
JS::dbg::onPromiseSettled(cx, promise);
return true;

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

@ -207,6 +207,15 @@ function GetTypeError(msg) {
assert(false, "the catch block should've returned from this function.");
}
function GetInternalError(msg) {
try {
FUN_APPLY(ThrowInternalError, undefined, arguments);
} catch (e) {
return e;
}
assert(false, "the catch block should've returned from this function.");
}
// To be used when a function is required but calling it shouldn't do anything.
function NullFunction() {}

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

@ -778,6 +778,8 @@ class GCRuntime
JS::GCSliceCallback setSliceCallback(JS::GCSliceCallback callback);
JS::GCNurseryCollectionCallback setNurseryCollectionCallback(
JS::GCNurseryCollectionCallback callback);
JS::DoCycleCollectionCallback setDoCycleCollectionCallback(JS::DoCycleCollectionCallback callback);
void callDoCycleCollectionCallback(JSContext* cx);
void setFullCompartmentChecks(bool enable);
@ -947,6 +949,7 @@ class GCRuntime
void traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark,
AutoLockForExclusiveAccess& lock);
void bufferGrayRoots();
void maybeDoCycleCollection();
void markCompartments();
IncrementalProgress drainMarkStack(SliceBudget& sliceBudget, gcstats::Phase phase);
template <class CompartmentIterT> void markWeakReferences(gcstats::Phase phase);
@ -1305,6 +1308,7 @@ class GCRuntime
bool fullCompartmentChecks;
Callback<JSGCCallback> gcCallback;
Callback<JS::DoCycleCollectionCallback> gcDoCycleCollectionCallback;
Callback<JSObjectsTenuredCallback> tenuredCallback;
CallbackVector<JSFinalizeCallback> finalizeCallbacks;
CallbackVector<JSWeakPointerZoneGroupCallback> updateWeakPointerZoneGroupCallbacks;

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

@ -4725,26 +4725,9 @@ JS::CallOriginalPromiseResolve(JSContext* cx, JS::HandleValue resolutionValue)
CHECK_REQUEST(cx);
assertSameCompartment(cx, resolutionValue);
RootedObject promiseCtor(cx, GetPromiseConstructor(cx));
if (!promiseCtor)
return nullptr;
JSObject* obj;
{
FixedInvokeArgs<1> args(cx);
args[0].set(resolutionValue);
RootedValue thisvOrRval(cx, ObjectValue(*promiseCtor));
if (!CallSelfHostedFunction(cx, "Promise_static_resolve", thisvOrRval, args, &thisvOrRval))
return nullptr;
MOZ_ASSERT(thisvOrRval.isObject());
obj = &thisvOrRval.toObject();
}
MOZ_ASSERT(obj->is<PromiseObject>());
return obj;
RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, resolutionValue));
MOZ_ASSERT_IF(promise, promise->is<PromiseObject>());
return promise;
}
JS_PUBLIC_API(JSObject*)
@ -4754,26 +4737,9 @@ JS::CallOriginalPromiseReject(JSContext* cx, JS::HandleValue rejectionValue)
CHECK_REQUEST(cx);
assertSameCompartment(cx, rejectionValue);
RootedObject promiseCtor(cx, GetPromiseConstructor(cx));
if (!promiseCtor)
return nullptr;
JSObject* obj;
{
FixedInvokeArgs<1> args(cx);
args[0].set(rejectionValue);
RootedValue thisvOrRval(cx, ObjectValue(*promiseCtor));
if (!CallSelfHostedFunction(cx, "Promise_static_reject", thisvOrRval, args, &thisvOrRval))
return nullptr;
MOZ_ASSERT(thisvOrRval.isObject());
obj = &thisvOrRval.toObject();
}
MOZ_ASSERT(obj->is<PromiseObject>());
return obj;
RootedObject promise(cx, PromiseObject::unforgeableReject(cx, rejectionValue));
MOZ_ASSERT_IF(promise, promise->is<PromiseObject>());
return promise;
}
JS_PUBLIC_API(bool)

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

@ -1481,6 +1481,21 @@ GCRuntime::setNurseryCollectionCallback(JS::GCNurseryCollectionCallback callback
return stats.setNurseryCollectionCallback(callback);
}
JS::DoCycleCollectionCallback
GCRuntime::setDoCycleCollectionCallback(JS::DoCycleCollectionCallback callback)
{
auto prior = gcDoCycleCollectionCallback;
gcDoCycleCollectionCallback = Callback<JS::DoCycleCollectionCallback>(callback, nullptr);
return prior.op;
}
void
GCRuntime::callDoCycleCollectionCallback(JSContext* cx)
{
if (gcDoCycleCollectionCallback.op)
gcDoCycleCollectionCallback.op(cx);
}
bool
GCRuntime::addRoot(Value* vp, const char* name)
{
@ -6171,6 +6186,31 @@ GCRuntime::scanZonesBeforeGC()
return zoneStats;
}
// The GC can only clean up scheduledForDestruction compartments that were
// marked live by a barrier (e.g. by RemapWrappers from a navigation event).
// It is also common to have compartments held live because they are part of a
// cycle in gecko, e.g. involving the HTMLDocument wrapper. In this case, we
// need to run the CycleCollector in order to remove these edges before the
// compartment can be freed.
void
GCRuntime::maybeDoCycleCollection()
{
const static double ExcessiveGrayCompartments = 0.8;
const static size_t LimitGrayCompartments = 200;
size_t compartmentsTotal = 0;
size_t compartmentsGray = 0;
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
++compartmentsTotal;
GlobalObject* global = c->unsafeUnbarrieredMaybeGlobal();
if (global && global->asTenured().isMarked(GRAY))
++compartmentsGray;
}
double grayFraction = double(compartmentsGray) / double(compartmentsTotal);
if (grayFraction > ExcessiveGrayCompartments || compartmentsGray > LimitGrayCompartments)
callDoCycleCollectionCallback(rt->contextFromMainThread());
}
void
GCRuntime::checkCanCallAPI()
{
@ -6251,6 +6291,9 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
repeat = (poked && cleanUpEverything) || wasReset || repeatForDeadZone;
} while (repeat);
if (reason == JS::gcreason::COMPARTMENT_REVIVED)
maybeDoCycleCollection();
#ifdef JS_GC_ZEAL
if (shouldCompact() && rt->hasZealMode(ZealMode::CheckHeapOnMovingGC)) {
gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_TRACE_HEAP);
@ -7169,6 +7212,12 @@ JS::SetGCSliceCallback(JSContext* cx, GCSliceCallback callback)
return cx->gc.setSliceCallback(callback);
}
JS_PUBLIC_API(JS::DoCycleCollectionCallback)
JS::SetDoCycleCollectionCallback(JSContext* cx, JS::DoCycleCollectionCallback callback)
{
return cx->gc.setDoCycleCollectionCallback(callback);
}
JS_PUBLIC_API(JS::GCNurseryCollectionCallback)
JS::SetGCNurseryCollectionCallback(JSContext* cx, GCNurseryCollectionCallback callback)
{

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

@ -16,13 +16,41 @@ new Promise((res, rej)=>rej('rejection'))
.then(val=>results.push('then after catch with val: ' + val),
val=>{throw new Error("mustn't be called")});
new Promise((res, rej)=> {res('result'); rej('rejection'); })
.catch(val=>{throw new Error("mustn't be called");})
.then(val=>results.push('then after resolve+reject with val: ' + val),
val=>{throw new Error("mustn't be called")});
new Promise((res, rej)=> { rej('rejection'); res('result'); })
.catch(val=>{results.push('catch after reject+resolve with val: ' + val);})
drainJobQueue();
assertEq(results.length, 4);
assertEq(results.length, 6);
assertEq(results[0], 'then result');
assertEq(results[1], 'catch rejection');
assertEq(results[2], 'chained then with val: first then rval');
assertEq(results[3], 'then after catch with val: 2');
assertEq(results[2], 'catch after reject+resolve with val: rejection');
assertEq(results[3], 'chained then with val: first then rval');
assertEq(results[4], 'then after catch with val: 2');
assertEq(results[5], 'then after resolve+reject with val: result');
results = [];
Promise.resolve('resolution').then(res=>results.push(res),
rej=>{ throw new Error("mustn't be called"); });
let thenCalled = false;
Promise.reject('rejection').then(_=>{thenCalled = true},
rej=>results.push(rej));
drainJobQueue();
assertEq(thenCalled, false);
assertEq(results.length, 2);
assertEq(results[0], 'resolution');
assertEq(results[1], 'rejection');
function callback() {}
@ -32,17 +60,30 @@ Promise.reject.call(function(exec) { exec(callback, callback); });
Promise.all.call(function(exec) { exec(callback, callback); });
Promise.race.call(function(exec) { exec(callback, callback); });
let resolveResult = undefined;
function resolveFun() {resolveResult = "resolveCalled";}
Promise.resolve.call(function(exec) { exec(resolveFun, callback); });
assertEq(resolveResult, "resolveCalled");
let rejectResult = undefined;
function rejectFun() {rejectResult = "rejectCalled";}
Promise.reject.call(function(exec) { exec(callback, rejectFun); });
assertEq(rejectResult, "rejectCalled");
// These should throw:
var wasCalled = false;
var hasThrown = false;
try {
// Calling the executor function twice, providing a resolve callback both times.
Promise.resolve.call(function(executor) {
wasCalled = true;
executor(callback, undefined);
executor(callback, callback);
});
} catch (e) {
hasThrown = true;
}
assertEq(wasCalled, true);
assertEq(hasThrown, true);
var hasThrown = false;

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

@ -225,8 +225,13 @@
macro(promise, promise, "promise") \
macro(state, state, "state") \
macro(pending, pending, "pending") \
macro(fulfillHandler, fulfillHandler, "fulfillHandler") \
macro(fulfilled, fulfilled, "fulfilled") \
macro(reject, reject, "reject") \
macro(rejected, rejected, "rejected") \
macro(rejectHandler, rejectHandler, "rejectHandler") \
macro(resolve, resolve, "resolve") \
macro(incumbentGlobal, incumbentGlobal, "incumbentGlobal") \
macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \
macro(proto, proto, "__proto__") \
macro(prototype, prototype, "prototype") \

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

@ -8572,7 +8572,7 @@ DebuggerObject::proxyTargetGetter(JSContext* cx, unsigned argc, Value* vp)
}
Rooted<DebuggerObject*> result(cx);
if (!DebuggerObject::scriptedProxyTarget(cx, object, &result))
if (!DebuggerObject::getScriptedProxyTarget(cx, object, &result))
return false;
args.rval().setObjectOrNull(result);
@ -8589,7 +8589,7 @@ DebuggerObject::proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp)
return true;
}
Rooted<DebuggerObject*> result(cx);
if (!DebuggerObject::scriptedProxyHandler(cx, object, &result))
if (!DebuggerObject::getScriptedProxyHandler(cx, object, &result))
return false;
args.rval().setObjectOrNull(result);
@ -8603,7 +8603,7 @@ DebuggerObject::isPromiseGetter(JSContext* cx, unsigned argc, Value* vp)
THIS_DEBUGOBJECT(cx, argc, vp, "get isPromise", args, object)
bool result;
if (!DebuggerObject::isPromise(cx, object, result))
if (!DebuggerObject::getIsPromise(cx, object, result))
return false;
args.rval().setBoolean(result);
@ -9304,8 +9304,9 @@ DebuggerObject::isScriptedProxy() const
return js::IsScriptedProxy(referent());
}
#ifdef SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::isPromise(JSContext* cx, HandleDebuggerObject object,
DebuggerObject::getIsPromise(JSContext* cx, HandleDebuggerObject object,
bool& result)
{
JSObject* referent = object->referent();
@ -9321,6 +9322,7 @@ DebuggerObject::isPromise(JSContext* cx, HandleDebuggerObject object,
result = referent->is<PromiseObject>();
return true;
}
#endif // SPIDERMONKEY_PROMISE
/* static */ bool
DebuggerObject::getClassName(JSContext* cx, HandleDebuggerObject object,
@ -9978,8 +9980,8 @@ DebuggerObject::requireGlobal(JSContext* cx, HandleDebuggerObject object)
}
/* static */ bool
DebuggerObject::scriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result)
DebuggerObject::getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result)
{
MOZ_ASSERT(object->isScriptedProxy());
RootedObject referent(cx, object->referent());
@ -9993,8 +9995,8 @@ DebuggerObject::scriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
}
/* static */ bool
DebuggerObject::scriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result)
DebuggerObject::getScriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result)
{
MOZ_ASSERT(object->isScriptedProxy());
RootedObject referent(cx, object->referent());

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

@ -1252,10 +1252,14 @@ class DebuggerObject : public NativeObject
MutableHandleObject result);
static MOZ_MUST_USE bool getErrorMessageName(JSContext* cx, HandleDebuggerObject object,
MutableHandleString result);
static MOZ_MUST_USE bool scriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result);
static MOZ_MUST_USE bool scriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result);
static MOZ_MUST_USE bool getScriptedProxyTarget(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result);
static MOZ_MUST_USE bool getScriptedProxyHandler(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result);
#ifdef SPIDERMONKEY_PROMISE
static MOZ_MUST_USE bool getIsPromise(JSContext* cx, HandleDebuggerObject object,
bool& result);
#endif // SPIDERMONKEY_PROMISE
// Methods
static MOZ_MUST_USE bool isExtensible(JSContext* cx, HandleDebuggerObject object,
@ -1296,8 +1300,6 @@ class DebuggerObject : public NativeObject
MutableHandleObject result);
static MOZ_MUST_USE bool unwrap(JSContext* cx, HandleDebuggerObject object,
MutableHandleDebuggerObject result);
static MOZ_MUST_USE bool isPromise(JSContext* cx, HandleDebuggerObject object,
bool& result);
// Infallible properties
bool isCallable() const;

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

@ -210,7 +210,7 @@ intrinsic_UnsafeCallWrappedFunction(JSContext* cx, unsigned argc, Value* vp)
RootedObject wrappedFun(cx, &args[0].toObject());
RootedObject fun(cx, UncheckedUnwrap(wrappedFun));
MOZ_RELEASE_ASSERT(fun->is<JSFunction>());
MOZ_RELEASE_ASSERT(fun->as<JSFunction>().isSelfHostedBuiltin());
MOZ_RELEASE_ASSERT(fun->as<JSFunction>().isSelfHostedOrIntrinsic());
InvokeArgs args2(cx);
if (!args2.init(args.length() - 2))
@ -1835,25 +1835,6 @@ intrinsic_EnqueuePromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
intrinsic_EnqueuePromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 3);
MOZ_ASSERT(IsCallable(args[2]));
RootedValue promiseToResolve(cx, args[0]);
RootedValue thenable(cx, args[1]);
RootedValue then(cx, args[2]);
if (!EnqueuePromiseResolveThenableJob(cx, promiseToResolve, thenable, then))
return false;
args.rval().setUndefined();
return true;
}
// ES2016, February 12 draft, 25.4.1.9.
static bool
intrinsic_HostPromiseRejectionTracker(JSContext* cx, unsigned argc, Value* vp)
@ -1989,20 +1970,6 @@ intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
intrinsic_OriginalPromiseConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0);
JSObject* obj = GlobalObject::getOrCreatePromiseConstructor(cx, cx->global());
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
/**
* Returns an object created in the embedding-provided incumbent global.
*
@ -2045,47 +2012,6 @@ intrinsic_GetObjectFromIncumbentGlobal(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
intrinsic_RejectUnwrappedPromise(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
RootedObject obj(cx, &args[0].toObject());
MOZ_ASSERT(IsWrapper(obj));
Rooted<PromiseObject*> promise(cx, &UncheckedUnwrap(obj)->as<PromiseObject>());
AutoCompartment ac(cx, promise);
RootedValue reasonVal(cx, args[1]);
// The rejection reason might've been created in a compartment with higher
// privileges than the Promise's. In that case, object-type rejection
// values might be wrapped into a wrapper that throws whenever the
// Promise's reaction handler wants to do anything useful with it. To
// avoid that situation, we synthesize a generic error that doesn't
// expose any privileged information but can safely be used in the
// rejection handler.
if (!promise->compartment()->wrap(cx, &reasonVal))
return false;
if (reasonVal.isObject() && !CheckedUnwrap(&reasonVal.toObject())) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON);
if (!GetAndClearException(cx, &reasonVal))
return false;
}
RootedAtom atom(cx, Atomize(cx, "RejectPromise", strlen("RejectPromise")));
if (!atom)
return false;
RootedPropertyName name(cx, atom->asPropertyName());
FixedInvokeArgs<2> args2(cx);
args2[0].setObject(*promise);
args2[1].set(reasonVal);
return CallSelfHostedFunction(cx, name, UndefinedHandleValue, args2, args.rval());
}
static bool
intrinsic_IsWrappedPromiseObject(JSContext* cx, unsigned argc, Value* vp)
{
@ -2243,24 +2169,6 @@ intrinsic_ModuleNamespaceExports(JSContext* cx, unsigned argc, Value* vp)
return true;
}
/**
* Intrinsic used to tell the debugger about settled promises.
*
* This is invoked both when resolving and rejecting promises, after the
* resulting state has been set on the promise, and it's up to the debugger
* to act on this signal in whichever way it wants.
*/
static bool
intrinsic_onPromiseSettled(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
promise->onSettled(cx);
args.rval().setUndefined();
return true;
}
// The self-hosting global isn't initialized with the normal set of builtins.
// Instead, individual C++-implemented functions that're required by
// self-hosted code are defined as global functions. Accessing these
@ -2525,10 +2433,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("IsPromise", intrinsic_IsInstanceOfBuiltin<PromiseObject>, 1,0),
JS_FN("IsWrappedPromise", intrinsic_IsWrappedPromiseObject, 1, 0),
JS_FN("_EnqueuePromiseReactionJob", intrinsic_EnqueuePromiseReactionJob, 2, 0),
JS_FN("_EnqueuePromiseResolveThenableJob", intrinsic_EnqueuePromiseResolveThenableJob, 2, 0),
JS_FN("HostPromiseRejectionTracker", intrinsic_HostPromiseRejectionTracker,2, 0),
JS_FN("_GetOriginalPromiseConstructor", intrinsic_OriginalPromiseConstructor, 0, 0),
JS_FN("RejectUnwrappedPromise", intrinsic_RejectUnwrappedPromise, 2, 0),
JS_FN("CallPromiseMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<PromiseObject>>, 2,0),
@ -2638,8 +2543,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
JS_FN("_dbg_onPromiseSettled", intrinsic_onPromiseSettled, 1, 0),
JS_FS_END
};

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

@ -23,6 +23,7 @@
#include "nsIObserverService.h"
#include "nsIDebug2.h"
#include "nsIDocShell.h"
#include "nsIRunnable.h"
#include "amIAddonManager.h"
#include "nsPIDOMWindow.h"
#include "nsPrintfCString.h"
@ -720,6 +721,22 @@ XPCJSRuntime::GCSliceCallback(JSContext* cx,
(*self->mPrevGCSliceCallback)(cx, progress, desc);
}
/* static */ void
XPCJSRuntime::DoCycleCollectionCallback(JSContext* cx)
{
// The GC has detected that a CC at this point would collect a tremendous
// amount of garbage that is being revivified unnecessarily.
NS_DispatchToCurrentThread(
NS_NewRunnableFunction([](){nsJSContext::CycleCollectNow(nullptr);}));
XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
if (!self)
return;
if (self->mPrevDoCycleCollectionCallback)
(*self->mPrevDoCycleCollectionCallback)(cx);
}
void
XPCJSRuntime::CustomGCCallback(JSGCStatus status)
{
@ -3481,6 +3498,8 @@ XPCJSRuntime::Initialize()
JS_SetSizeOfIncludingThisCompartmentCallback(cx, CompartmentSizeOfIncludingThisCallback);
JS_SetCompartmentNameCallback(cx, CompartmentNameCallback);
mPrevGCSliceCallback = JS::SetGCSliceCallback(cx, GCSliceCallback);
mPrevDoCycleCollectionCallback = JS::SetDoCycleCollectionCallback(cx,
DoCycleCollectionCallback);
JS_AddFinalizeCallback(cx, FinalizeCallback, nullptr);
JS_AddWeakPointerZoneGroupCallback(cx, WeakPointerZoneGroupCallback, this);
JS_AddWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback, this);

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

@ -551,6 +551,7 @@ public:
static void GCSliceCallback(JSContext* cx,
JS::GCProgress progress,
const JS::GCDescription& desc);
static void DoCycleCollectionCallback(JSContext* cx);
static void FinalizeCallback(JSFreeOp* fop,
JSFinalizeStatus status,
bool isZoneGC,
@ -628,6 +629,7 @@ private:
nsTArray<xpcGCCallback> extraGCCallbacks;
RefPtr<WatchdogManager> mWatchdogManager;
JS::GCSliceCallback mPrevGCSliceCallback;
JS::DoCycleCollectionCallback mPrevDoCycleCollectionCallback;
JS::PersistentRootedObject mUnprivilegedJunkScope;
JS::PersistentRootedObject mPrivilegedJunkScope;
JS::PersistentRootedObject mCompilationScope;

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

@ -3589,6 +3589,9 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
nsBackgroundLayerState state(aForFrame, &aLayer.mImage, irFlags);
if (!state.mImageRenderer.PrepareImage()) {
// There's no image or it's not ready to be painted.
if (aOutIsTransformedFixed) {
*aOutIsTransformedFixed = false;
}
return state;
}

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

@ -2036,16 +2036,10 @@ nsPresContext::UpdateIsChrome()
nsIDocShellTreeItem::typeChrome == mContainer->ItemType();
}
/* virtual */ bool
bool
nsPresContext::HasAuthorSpecifiedRules(const nsIFrame *aFrame,
uint32_t ruleTypeMask) const
{
#ifdef MOZ_STYLO
if (!mShell || mShell->StyleSet()->IsServo()) {
NS_ERROR("stylo: nsPresContext::HasAuthorSpecifiedRules not implemented");
return true;
}
#endif
return
nsRuleNode::HasAuthorSpecifiedRules(aFrame->StyleContext(),
ruleTypeMask,

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

@ -895,8 +895,8 @@ public:
void UpdateIsChrome();
// Public API for native theme code to get style internals.
virtual bool HasAuthorSpecifiedRules(const nsIFrame *aFrame,
uint32_t ruleTypeMask) const;
bool HasAuthorSpecifiedRules(const nsIFrame *aFrame,
uint32_t ruleTypeMask) const;
// Is it OK to let the page specify colors and backgrounds?
bool UseDocumentColors() const {

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

@ -10,6 +10,7 @@
#include <algorithm> // for std::stable_sort
#include <limits>
#include "mozilla/Function.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h" // for PodZero
#include "nsAbsoluteContainingBlock.h"
@ -99,6 +100,23 @@ ClampToCSSMaxBSize(nscoord aSize, const ReflowInput* aReflowInput,
return aSize;
}
static bool
IsPercentOfIndefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis)
{
return aPercentBasis == NS_UNCONSTRAINEDSIZE && aCoord.HasPercent();
}
static nscoord
ResolveToDefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis)
{
MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit());
if (::IsPercentOfIndefiniteSize(aCoord, aPercentBasis)) {
return nscoord(0);
}
return std::max(nscoord(0),
nsRuleNode::ComputeCoordPercentCalc(aCoord, aPercentBasis));
}
enum class GridLineSide
{
eBeforeGridGap,
@ -132,6 +150,7 @@ struct nsGridContainerFrame::TrackSize
eSkipGrowUnlimited2 = 0x400,
eSkipGrowUnlimited = eSkipGrowUnlimited1 | eSkipGrowUnlimited2,
eBreakBefore = 0x800,
eFitContent = 0x1000,
};
static bool IsMinContent(const nsStyleCoord& aCoord)
@ -165,29 +184,35 @@ nsGridContainerFrame::TrackSize::Initialize(nscoord aPercentageBasis,
"track size data is expected to be initialized to zero");
auto minSizeUnit = aMinCoord.GetUnit();
auto maxSizeUnit = aMaxCoord.GetUnit();
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
if (minSizeUnit == eStyleUnit_None) {
// This track is sized using fit-content(size) (represented in style system
// with minCoord=None,maxCoord=size). In layout, fit-content(size) behaves
// as minmax(auto, max-content), with 'size' as an additional upper-bound.
mState = eFitContent;
minSizeUnit = eStyleUnit_Auto;
maxSizeUnit = eStyleUnit_Enumerated; // triggers max-content sizing below
}
if (::IsPercentOfIndefiniteSize(aMinCoord, aPercentageBasis)) {
// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-percentage
// "If the inline or block size of the grid container is indefinite,
// <percentage> values relative to that size are treated as 'auto'."
if (aMinCoord.HasPercent()) {
minSizeUnit = eStyleUnit_Auto;
}
if (aMaxCoord.HasPercent()) {
maxSizeUnit = eStyleUnit_Auto;
}
minSizeUnit = eStyleUnit_Auto;
}
if (::IsPercentOfIndefiniteSize(aMaxCoord, aPercentageBasis)) {
maxSizeUnit = eStyleUnit_Auto;
}
// http://dev.w3.org/csswg/css-grid/#algo-init
switch (minSizeUnit) {
case eStyleUnit_FlexFraction:
case eStyleUnit_Auto:
mState = eAutoMinSizing;
mState |= eAutoMinSizing;
break;
case eStyleUnit_Enumerated:
mState = IsMinContent(aMinCoord) ? eMinContentMinSizing
: eMaxContentMinSizing;
mState |= IsMinContent(aMinCoord) ? eMinContentMinSizing
: eMaxContentMinSizing;
break;
default:
mBase = nsRuleNode::ComputeCoordPercentCalc(aMinCoord, aPercentageBasis);
mBase = ::ResolveToDefiniteSize(aMinCoord, aPercentageBasis);
}
switch (maxSizeUnit) {
case eStyleUnit_Auto:
@ -204,7 +229,7 @@ nsGridContainerFrame::TrackSize::Initialize(nscoord aPercentageBasis,
mLimit = mBase;
break;
default:
mLimit = nsRuleNode::ComputeCoordPercentCalc(aMaxCoord, aPercentageBasis);
mLimit = ::ResolveToDefiniteSize(aMaxCoord, aPercentageBasis);
if (mLimit < mBase) {
mLimit = mBase;
}
@ -962,7 +987,7 @@ struct nsGridContainerFrame::TrackSizingFunctions
return 1;
}
}
nscoord trackSize = nsRuleNode::ComputeCoordPercentCalc(*coord, aSize);
nscoord trackSize = ::ResolveToDefiniteSize(*coord, aSize);
if (i == mRepeatAutoStart) {
// Use a minimum 1px for the repeat() track-size.
if (trackSize < AppUnitsPerCSSPixel()) {
@ -972,8 +997,7 @@ struct nsGridContainerFrame::TrackSizingFunctions
}
sum += trackSize;
}
nscoord gridGap =
std::max(nscoord(0), nsRuleNode::ComputeCoordPercentCalc(aGridGap, aSize));
nscoord gridGap = ::ResolveToDefiniteSize(aGridGap, aSize);
if (numTracks > 1) {
// Add grid-gaps for all the tracks including the repeat() track.
sum += gridGap * (numTracks - 1);
@ -1218,6 +1242,8 @@ struct nsGridContainerFrame::Tracks
}
}
using FitContentClamper =
function<bool(uint32_t aTrack, nscoord aMinSize, nscoord* aSize)>;
/**
* Grow the planned size for tracks in aGrowableTracks up to their limit
* and then freeze them (all aGrowableTracks must be unfrozen on entry).
@ -1225,7 +1251,8 @@ struct nsGridContainerFrame::Tracks
*/
nscoord GrowTracksToLimit(nscoord aAvailableSpace,
nsTArray<TrackSize>& aPlan,
const nsTArray<uint32_t>& aGrowableTracks) const
const nsTArray<uint32_t>& aGrowableTracks,
FitContentClamper aFitContentClamper) const
{
MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0);
nscoord space = aAvailableSpace;
@ -1238,11 +1265,17 @@ struct nsGridContainerFrame::Tracks
continue;
}
nscoord newBase = sz.mBase + spacePerTrack;
if (newBase > sz.mLimit) {
nscoord consumed = sz.mLimit - sz.mBase;
nscoord limit = sz.mLimit;
if (MOZ_UNLIKELY((sz.mState & TrackSize::eFitContent) &&
aFitContentClamper)) {
// Clamp the limit to the fit-content() size, for §12.5.2 step 5/6.
aFitContentClamper(track, sz.mBase, &limit);
}
if (newBase > limit) {
nscoord consumed = limit - sz.mBase;
if (consumed > 0) {
space -= consumed;
sz.mBase = sz.mLimit;
sz.mBase = limit;
}
sz.mState |= TrackSize::eFrozen;
if (--numGrowable == 0) {
@ -1313,7 +1346,8 @@ struct nsGridContainerFrame::Tracks
void GrowSelectedTracksUnlimited(nscoord aAvailableSpace,
nsTArray<TrackSize>& aPlan,
const nsTArray<uint32_t>& aGrowableTracks,
TrackSize::StateBits aSelector) const
TrackSize::StateBits aSelector,
FitContentClamper aFitContentClamper) const
{
MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0);
uint32_t numGrowable = aGrowableTracks.Length();
@ -1338,22 +1372,37 @@ struct nsGridContainerFrame::Tracks
}
}
nscoord space = aAvailableSpace;
while (true) {
DebugOnly<bool> didClamp = false;
while (numGrowable) {
nscoord spacePerTrack = std::max<nscoord>(space / numGrowable, 1);
for (uint32_t track : aGrowableTracks) {
TrackSize& sz = aPlan[track];
if (sz.mState & TrackSize::eSkipGrowUnlimited) {
continue; // an excluded track
}
sz.mBase += spacePerTrack;
space -= spacePerTrack;
nscoord delta = spacePerTrack;
nscoord newBase = sz.mBase + delta;
if (MOZ_UNLIKELY((sz.mState & TrackSize::eFitContent) &&
aFitContentClamper)) {
// Clamp newBase to the fit-content() size, for §12.5.2 step 5/6.
if (aFitContentClamper(track, sz.mBase, &newBase)) {
didClamp = true;
delta = newBase - sz.mBase;
MOZ_ASSERT(delta >= 0, "track size shouldn't shrink");
sz.mState |= TrackSize::eSkipGrowUnlimited1;
--numGrowable;
}
}
sz.mBase = newBase;
space -= delta;
MOZ_ASSERT(space >= 0);
if (space == 0) {
return;
}
}
}
MOZ_ASSERT_UNREACHABLE("we don't exit the loop above except by return");
MOZ_ASSERT(didClamp, "we don't exit the loop above except by return, "
"unless we clamped some track's size");
}
/**
@ -1366,9 +1415,9 @@ struct nsGridContainerFrame::Tracks
TrackSize::StateBits aSelector)
{
SetupGrowthPlan(aPlan, aGrowableTracks);
nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks);
nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks, nullptr);
if (space > 0) {
GrowSelectedTracksUnlimited(space, aPlan, aGrowableTracks, aSelector);
GrowSelectedTracksUnlimited(space, aPlan, aGrowableTracks, aSelector, nullptr);
}
CopyPlanToBase(aPlan, aGrowableTracks);
}
@ -1378,12 +1427,26 @@ struct nsGridContainerFrame::Tracks
*/
void DistributeToTrackLimits(nscoord aAvailableSpace,
nsTArray<TrackSize>& aPlan,
nsTArray<uint32_t>& aGrowableTracks)
nsTArray<uint32_t>& aGrowableTracks,
const TrackSizingFunctions& aFunctions,
nscoord aPercentageBasis)
{
nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks);
auto fitContentClamper = [&aFunctions, aPercentageBasis] (uint32_t aTrack,
nscoord aMinSize,
nscoord* aSize) {
nscoord fitContentLimit =
::ResolveToDefiniteSize(aFunctions.MaxSizingFor(aTrack), aPercentageBasis);
if (*aSize > fitContentLimit) {
*aSize = std::max(aMinSize, fitContentLimit);
return true;
}
return false;
};
nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks,
fitContentClamper);
if (space > 0) {
GrowSelectedTracksUnlimited(aAvailableSpace, aPlan, aGrowableTracks,
TrackSize::StateBits(0));
TrackSize::StateBits(0), fitContentClamper);
}
CopyPlanToLimit(aPlan, aGrowableTracks);
}
@ -3412,8 +3475,7 @@ nsGridContainerFrame::Tracks::Initialize(
aFunctions.MinSizingFor(i),
aFunctions.MaxSizingFor(i));
}
auto gap = nsRuleNode::ComputeCoordPercentCalc(aGridGap, aContentBoxSize);
mGridGap = std::max(nscoord(0), gap);
mGridGap = ::ResolveToDefiniteSize(aGridGap, aContentBoxSize);
mContentBoxSize = aContentBoxSize;
}
@ -3672,6 +3734,13 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1(
} else {
sz.mLimit = std::max(sz.mLimit, maxContentContribution.value());
}
if (MOZ_UNLIKELY(sz.mState & TrackSize::eFitContent)) {
// Clamp mLimit to the fit-content() size, for §12.5.1.
auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart);
nscoord fitContentClamp =
nsRuleNode::ComputeCoordPercentCalc(maxCoord, aPercentageBasis);
sz.mLimit = std::min(sz.mLimit, fitContentClamp);
}
}
if (sz.mLimit < sz.mBase) {
sz.mLimit = sz.mBase;
@ -4151,7 +4220,8 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
TrackSize::eIntrinsicMaxSizing,
tracks);
if (space > 0) {
DistributeToTrackLimits(space, plan, tracks);
DistributeToTrackLimits(space, plan, tracks, aFunctions,
aPercentageBasis);
}
}
for (size_t j = 0, len = mSizes.Length(); j < len; ++j) {
@ -4178,7 +4248,8 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
TrackSize::eAutoOrMaxContentMaxSizing,
tracks);
if (space > 0) {
DistributeToTrackLimits(space, plan, tracks);
DistributeToTrackLimits(space, plan, tracks, aFunctions,
aPercentageBasis);
}
}
}

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

@ -0,0 +1,135 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Reference: 'grid-column-gap' percentage</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1279182">
<style>
html,body {
color:black; background-color:white; font-size:1px; padding:0; margin:0;
}
.grid {
display: grid;
grid-template-columns: 30px 30px;
border: 1px solid;
}
.inline-grid {
display: inline-grid;
grid: 120px / 160px;
border: 1px solid;
}
.float { float:left; border: 2px solid blue; }
.percentgap {
grid-gap: 24px 32px;
}
span:nth-of-type(1) { background: magenta; }
span:nth-of-type(2) { background: cyan; }
span:nth-of-type(3) { background: yellow; }
span:nth-of-type(4) { background: lime; }
x {
display: inline-block;
width: 20px;
height: 30px;
}
br { clear: both; }
</style>
</head>
<body>
<div class="inline-grid">
<div class="grid percentgap">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<div class="inline-grid" style="grid: auto / auto">
<div class="grid percentgap" style="align-self:start; justify-self:start; width:160px; height:120px">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<div class="inline-grid">
<div class="grid" style="grid: min-content 20% min-content / min-content 20% min-content">
<span><x></x></span><z></z><span><x></x></span>
<z></z><z></z><z></z>
<span><x></x></span><z></z><span><x></x></span>
</div>
</div>
<br>
<div style="width:320px;height:200px">
<div class="grid percentgap" style="height:120px; grid-column-gap:64px">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<!-- TODO: fails on Windows 8 x64 Opt
<div class="inline-grid">
<div class="grid percentgap">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
-->
<div class="inline-grid" style="grid: auto / auto">
<div class="grid percentgap" style="align-self:start; justify-self:start; width:160px; height:120px">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<div class="inline-grid">
<div class="grid" style="grid: min-content 20% min-content / min-content 20% min-content">
<span><x></x></span><z></z><span><x></x></span>
<z></z><z></z><z></z>
<span><x></x></span><z></z><span><x></x></span>
</div>
</div>
<br>
<div style="width:320px;height:200px">
<div class="grid percentgap" style="height:120px; grid-column-gap:64px">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<div style="width:320px;height:200px">
<div class="grid calcgap" style="height:120px; grid-gap:0">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
</body>
</html>

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

@ -0,0 +1,142 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: 'grid-column-gap' percentage</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1279182">
<link rel="help" href="http://dev.w3.org/csswg/css-grid/#gutters">
<link rel="match" href="grid-percent-grid-gap-ref.html">
<style>
html,body {
color:black; background-color:white; font-size:1px; padding:0; margin:0;
}
.grid {
display: grid;
grid-template-columns: 30px 30px;
border: 1px solid;
}
.inline-grid {
display: inline-grid;
grid-auto-columns: 160px;
grid-auto-rows: 120px;
border: 1px solid;
}
.float { float:left; border: 2px solid blue; }
.percentgap {
grid-gap: 20%;
}
.calcgap {
grid-gap: calc(12px + 10%) calc(16px + 10%);
}
span:nth-of-type(1) { background: magenta; }
span:nth-of-type(2) { background: cyan; }
span:nth-of-type(3) { background: yellow; }
span:nth-of-type(4) { background: lime; }
x {
display: inline-block;
width: 20px;
height: 30px;
}
br { clear: both; }
</style>
</head>
<body>
<div class="inline-grid">
<div class="grid percentgap">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<div class="inline-grid" style="grid: auto / auto">
<div class="grid percentgap" style="align-self:start; justify-self:start; width:160px; height:120px">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<div class="inline-grid">
<div class="grid" style="grid: min-content 20% min-content / min-content 20% min-content">
<span><x></x></span><z></z><span><x></x></span>
<z></z><z></z><z></z>
<span><x></x></span><z></z><span><x></x></span>
</div>
</div>
<br>
<div style="width:320px;height:200px">
<div class="grid percentgap" style="height:120px">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<!-- TODO: fails on Windows 8 x64 Opt
<div class="inline-grid">
<div class="grid calcgap">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
-->
<div class="inline-grid" style="grid: auto / auto">
<div class="grid calcgap" style="align-self:start; justify-self:start; width:160px; height:120px">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<div class="inline-grid">
<div class="grid" style="grid: min-content calc(12px + 10%) min-content / min-content calc(16px + 10%) min-content">
<span><x></x></span><z></z><span><x></x></span>
<z></z><z></z><z></z>
<span><x></x></span><z></z><span><x></x></span>
</div>
</div>
<br>
<div style="width:320px;height:200px">
<div class="grid calcgap" style="height:120px; grid-column-gap:calc(32px + 10%)">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
<div style="width:320px;height:200px">
<div class="grid calcgap" style="height:120px; grid-gap:calc(32px - 30%)">
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
<span><x></x></span>
</div>
</div>
</body>
</html>

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

@ -0,0 +1,178 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>Reference: fit-content() track sizing</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281320">
<style type="text/css">
body,html { color:black; background:white; font-size:1px; padding:0; margin:0; }
.grid {
display: grid;
grid-template-rows: auto auto;
position: relative;
border: 1px solid;
}
.c1 { grid-template-columns: max-content minmax(100px, 1fr); }
.c2 { grid: auto 10px / 200px 0 minmax(100px, 1fr); }
.c3 { grid: auto 10px / 100px 100px minmax(0px, 1fr); }
.c4 { grid: auto 10px / 100px 100px minmax(100px, 1fr); }
.c5 { grid: auto 10px / 0px minmax(0, 1fr) minmax(100px, 1fr); }
.c6 { grid: auto 10px / fit-content(0px) minmax(0, 1fr) minmax(100px, 1fr); }
.c7 { grid: auto 10px / fit-content(40%) fit-content(40%); }
span { line-height:0; grid-column:span 2; background: lime; }
.c1 span { grid-column:span 1; }
a {
display: inline-block;
width: 50px;
height: 1px;
}
y {
position: absolute;
left:0; right:0; top:0; bottom:0;
grid-area: 2/2/3/3;
height: 1px;
background: grey;
}
.w3 .c1 { grid-template-columns: 176px minmax(0px, 1fr); }
.w3 .c2 { grid-template-columns: 176px 0 minmax(0px, 1fr); }
.w4 .c1 { grid-template-columns: 152px minmax(0px, 1fr); }
.w4 .c2 { grid-template-columns: 152px 0 minmax(0px, 1fr); }
.w5 .c1 { grid-template-columns: 128px minmax(0px, 1fr); }
.w5 .c2 { grid-template-columns: 128px 0 minmax(0px, 1fr); }
.w6 .c1 { grid-template-columns: 104px minmax(0px, 1fr); }
.w6 .c2 { grid-template-columns: 104px 0 minmax(0px, 1fr); }
.w6 .c4 { grid-template-columns: 60px 100px minmax(0px, 1fr); }
.w7 .c1 { grid-template-columns: 80px minmax(0px, 1fr); }
.w7 .c2 { grid-template-columns: 80px 0 minmax(0px, 1fr); }
.w7 .c3 { grid-template-columns: 80px 80px minmax(0px, 1fr); }
.w7 .c4 { grid-template-columns: 0px 100px minmax(0px, 1fr); }
.w8 .c1 { grid-template-columns: 50px minmax(100px, 1fr); }
.w8 .c2 { grid-template-columns: 50px 0 minmax(100px, 1fr); }
.w8 .c3 { grid-template-columns: 56px 56px minmax(0, 1fr); }
.w8 .c4 { grid-template-columns: 0px 100px minmax(100px, 1fr); }
.w9 .c1 { grid-template-columns: 50px minmax(100px, 1fr); }
.w9 .c2 { grid-template-columns: 50px 0 minmax(100px, 1fr); }
.w9 .c3 { grid-template-columns: 32px 32px minmax(0, 1fr); }
.w9 .c4 { grid-template-columns: 0px 100px minmax(100px, 1fr); }
.wA .c1 { grid-template-columns: 50px minmax(100px, 1fr); }
.wA .c2 { grid-template-columns: 50px 0 minmax(100px, 1fr); }
.wA .c3 { grid-template-columns: 25px 25px minmax(0, 1fr); }
.wA .c4 { grid-template-columns: 0px 100px minmax(100px, 1fr); }
.wB .c1 { grid-template-columns: 50px minmax(100px, 1fr); }
.wB .c2 { grid-template-columns: 50px 0 minmax(100px, 1fr); }
.wB .c3 { grid-template-columns: 25px 25px minmax(0, 1fr); }
.wB .c4 { grid-template-columns: 0px 100px minmax(100px, 1fr); }
</style>
</head>
<body>
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c6"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="w2" style="width:502px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c6"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div class="w3" style="width:442px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div class="w4" style="width:382px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div class="w5" style="width:322px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div class="w6" style="width:262px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div class="w7" style="width:202px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c7"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div class="w8" style="width:142px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div class="w9" style="width:82px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div class="wA" style="width:22px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c6"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div class="wB" style="width:2px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
</body>
</html>

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

@ -0,0 +1,141 @@
<!DOCTYPE HTML>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html><head>
<meta charset="utf-8">
<title>CSS Grid Test: fit-content() track sizing</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281320">
<link rel="help" href="https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content">
<link rel="match" href="grid-track-fit-content-sizing-001-ref.html">
<style type="text/css">
body,html { color:black; background:white; font-size:1px; padding:0; margin:0; }
.grid {
display: grid;
grid-template-rows: auto auto;
position: relative;
border: 1px solid;
}
.c1 { grid-template-columns: fit-content(40%) minmax(100px, 1fr); }
.c2 { grid: auto 10px / fit-content(40%) 0 minmax(100px, 1fr); }
.c3 { grid: auto 10px / fit-content(40%) fit-content(40%) minmax(0px, 1fr); }
.c4 { grid: auto 10px / fit-content(40%) 100px minmax(100px, 1fr); }
.c5 { grid: auto 10px / fit-content(40%) minmax(0, 1fr) minmax(100px, 1fr); }
.c6 { grid: auto 10px / fit-content(calc(1px - 99%)) minmax(0, 1fr) minmax(100px, 1fr); }
.c7 { grid: auto 10px / none; grid-auto-columns: fit-content(40%); }
span { line-height:0; grid-column:span 2; background: lime; }
.c1 span { grid-column:span 1; }
a {
display: inline-block;
width: 50px;
height: 1px;
}
y {
position: absolute;
left:0; right:0; top:0; bottom:0;
grid-area: 2/2/3/3;
height: 1px;
background: grey;
}
</style>
</head>
<body>
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c6"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div style="width:502px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c6"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div style="width:442px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div style="width:382px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div style="width:322px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div style="width:262px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div style="width:202px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c7"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div style="width:142px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div style="width:82px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div style="width:22px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c6"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
<div style="width:2px">
<div class="grid c1"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c2"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c3"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c4"><span><a></a><a></a><a></a><a></a></span><y></y></div>
<div class="grid c5"><span><a></a><a></a><a></a><a></a></span><y></y></div>
</div>
</body>
</html>

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

@ -75,6 +75,14 @@ x {
.sz.t5 x { width: 10px }
.sz.tA x { width: 160px }
.tC {
grid-template-columns: 5px;
grid-template-rows: 5px;
}
.tD {
grid-template-columns: 0;
grid-template-rows: 0;
}
</style>
</head>
<body>
@ -106,7 +114,9 @@ x {
<div class="grid sz t9"><span><t></t></span><x></x></div>
<div class="grid sz tA"><span><t></t></span><x></x></div>
<div class="grid sz tB"><span><t></t></span><x></x></div>
<div class="grid sz tC"><span><t></t></span><x style="grid-area:2/1;height:10px; width:5px"></x></div>
<div class="grid sz tD"><span><t></t></span><x style="grid-area:1/1;height:10px; width:100px"></x></div>
<div class="grid sz tD"><span><t></t></span><x style="grid-area:1/1;height:10px; width:100px"></x></div>
</body>
</html>

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

@ -70,6 +70,15 @@ body,html { color:black; background:white; font-family:monospace; font-size:32px
grid-template-columns: minmax(60%, 0);
grid-template-rows: minmax(40%, 0);
}
.tC {
grid-template-columns: calc(10px - 5%);
grid-template-rows: calc(10px - 5%);
}
.tD {
grid-template-columns: calc(10px - 40%);
grid-template-rows: calc(10px - 40%);
}
span {
background: grey;
@ -121,6 +130,9 @@ x {
<div class="grid sz t9"><span><t></t></span><x></x></div>
<div class="grid sz tA"><span><t></t></span><x></x></div>
<div class="grid sz tB"><span><t></t></span><x></x></div>
<div class="grid sz tC"><span><t></t></span><x></x></div>
<div class="grid sz tD"><span><t></t></span><x style="grid-area:1/2;height:10px"></x></div>
<div class="grid sz tD"><span><t></t></span><x style="grid-area:2/2;height:10px"></x></div>
</body>

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

@ -62,6 +62,7 @@ fuzzy-if(winWidget,1,36) == grid-auto-min-sizing-definite-001.html grid-auto-min
== grid-track-intrinsic-sizing-003.html grid-track-intrinsic-sizing-003-ref.html
== grid-track-intrinsic-sizing-004.html grid-track-intrinsic-sizing-004-ref.html
== grid-track-percent-sizing-001.html grid-track-percent-sizing-001-ref.html
== grid-track-fit-content-sizing-001.html grid-track-fit-content-sizing-001-ref.html
== grid-max-sizing-flex-001.html grid-max-sizing-flex-001-ref.html
== grid-max-sizing-flex-002.html grid-max-sizing-flex-002-ref.html
== grid-max-sizing-flex-003.html grid-max-sizing-flex-003-ref.html
@ -92,6 +93,7 @@ skip-if(Android&&isDebugBuild) == grid-column-gap-001.html grid-column-gap-001-r
== grid-column-gap-003.html grid-column-gap-003-ref.html
== grid-column-gap-004.html grid-column-gap-004-ref.html
== grid-row-gap-001.html grid-row-gap-001-ref.html
== grid-percent-grid-gap-001.html grid-percent-grid-gap-001-ref.html
skip-if(Android&&isDebugBuild) == grid-row-gap-002.html grid-row-gap-002-ref.html # Bug 1245884 - slow
skip-if(Android&&isDebugBuild) == grid-row-gap-003.html grid-row-gap-003-ref.html # Bug 1245884 - slow
skip-if(Android&&isDebugBuild) == grid-row-gap-004.html grid-row-gap-004-ref.html # Bug 1245884 - slow

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

@ -1212,8 +1212,10 @@ Declaration::GetValue(nsCSSPropertyID aProperty, nsAString& aValue,
break;
}
// This can express either grid-template-{areas,columns,rows}
// or grid-auto-{flow,columns,rows}, but not both.
// The 'grid' shorthand has 3 different possibilities for syntax:
// #1 <'grid-template'>
// #2 <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>?
// #3 [ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'>
case eCSSProperty_grid: {
const nsCSSValue& columnGapValue =
*data->ValueFor(eCSSProperty_grid_column_gap);
@ -1241,26 +1243,60 @@ Declaration::GetValue(nsCSSPropertyID aProperty, nsAString& aValue,
const nsCSSValue& autoRowsValue =
*data->ValueFor(eCSSProperty_grid_auto_rows);
if (areasValue.GetUnit() == eCSSUnit_None &&
columnsValue.GetUnit() == eCSSUnit_None &&
rowsValue.GetUnit() == eCSSUnit_None) {
AppendValueToString(eCSSProperty_grid_auto_flow,
aValue, aSerialization);
aValue.Append(char16_t(' '));
AppendValueToString(eCSSProperty_grid_auto_rows,
aValue, aSerialization);
// grid-template-rows/areas:none + default grid-auto-columns +
// non-default row grid-auto-flow or grid-auto-rows.
// --> serialize as 'grid' syntax #3.
// (for default grid-auto-flow/rows we prefer to serialize to
// "none ['/' ...]" instead using syntax #2 or #1 below)
if (rowsValue.GetUnit() == eCSSUnit_None &&
areasValue.GetUnit() == eCSSUnit_None &&
autoColumnsValue.GetUnit() == eCSSUnit_Auto &&
autoFlowValue.GetUnit() == eCSSUnit_Enumerated &&
(autoFlowValue.GetIntValue() & NS_STYLE_GRID_AUTO_FLOW_ROW) &&
(autoFlowValue.GetIntValue() != NS_STYLE_GRID_AUTO_FLOW_ROW ||
autoRowsValue.GetUnit() != eCSSUnit_Auto)) {
aValue.AppendLiteral("auto-flow");
if (autoFlowValue.GetIntValue() & NS_STYLE_GRID_AUTO_FLOW_DENSE) {
aValue.AppendLiteral(" dense");
}
if (autoRowsValue.GetUnit() != eCSSUnit_Auto) {
aValue.Append(' ');
AppendValueToString(eCSSProperty_grid_auto_rows,
aValue, aSerialization);
}
aValue.AppendLiteral(" / ");
AppendValueToString(eCSSProperty_grid_template_columns,
aValue, aSerialization);
break;
}
// grid-template-columns/areas:none + column grid-auto-flow +
// default grid-auto-rows.
// --> serialize as 'grid' syntax #2.
if (columnsValue.GetUnit() == eCSSUnit_None &&
areasValue.GetUnit() == eCSSUnit_None &&
autoRowsValue.GetUnit() == eCSSUnit_Auto &&
autoFlowValue.GetUnit() == eCSSUnit_Enumerated &&
(autoFlowValue.GetIntValue() & NS_STYLE_GRID_AUTO_FLOW_COLUMN)) {
AppendValueToString(eCSSProperty_grid_template_rows,
aValue, aSerialization);
aValue.AppendLiteral(" / auto-flow ");
if (autoFlowValue.GetIntValue() & NS_STYLE_GRID_AUTO_FLOW_DENSE) {
aValue.AppendLiteral("dense ");
}
AppendValueToString(eCSSProperty_grid_auto_columns,
aValue, aSerialization);
break;
} else if (!(autoFlowValue.GetUnit() == eCSSUnit_Enumerated &&
autoFlowValue.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_ROW &&
autoColumnsValue.GetUnit() == eCSSUnit_Auto &&
autoRowsValue.GetUnit() == eCSSUnit_Auto)) {
}
if (!(autoFlowValue.GetUnit() == eCSSUnit_Enumerated &&
autoFlowValue.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_ROW &&
autoColumnsValue.GetUnit() == eCSSUnit_Auto &&
autoRowsValue.GetUnit() == eCSSUnit_Auto)) {
// Not serializable, bail.
return;
}
// Fall through to eCSSProperty_grid_template
// Fall through to eCSSProperty_grid_template (syntax #1)
MOZ_FALLTHROUGH;
}
case eCSSProperty_grid_template: {
@ -1334,6 +1370,11 @@ Declaration::GetValue(nsCSSPropertyID aProperty, nsAString& aValue,
aValue.Append(char16_t(' '));
// <track-size>
if (unit == eCSSUnit_Pair) {
// 'repeat()' isn't allowed with non-default 'grid-template-areas'.
aValue.Truncate();
return;
}
rowsItem->mValue.AppendToString(eCSSProperty_grid_template_rows,
aValue, aSerialization);
if (rowsItem->mNext &&
@ -1354,6 +1395,16 @@ Declaration::GetValue(nsCSSPropertyID aProperty, nsAString& aValue,
}
}
if (columnsValue.GetUnit() != eCSSUnit_None) {
const nsCSSValueList* colsItem = columnsValue.GetListValue();
colsItem = colsItem->mNext; // first value is <line-names>
for (; colsItem; colsItem = colsItem->mNext) {
if (colsItem->mValue.GetUnit() == eCSSUnit_Pair) {
// 'repeat()' isn't allowed with non-default 'grid-template-areas'.
aValue.Truncate();
return;
}
colsItem = colsItem->mNext; // skip <line-names>
}
aValue.AppendLiteral(" / ");
AppendValueToString(eCSSProperty_grid_template_columns,
aValue, aSerialization);

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

@ -149,6 +149,7 @@ CSS_KEY(appworkspace, appworkspace)
CSS_KEY(auto, auto)
CSS_KEY(auto-fill, auto_fill)
CSS_KEY(auto-fit, auto_fit)
CSS_KEY(auto-flow, auto_flow)
CSS_KEY(avoid, avoid)
CSS_KEY(background, background)
CSS_KEY(backwards, backwards)
@ -276,6 +277,7 @@ CSS_KEY(farthest-corner, farthest_corner)
CSS_KEY(fill, fill)
CSS_KEY(filled, filled)
CSS_KEY(fill-box, fill_box)
CSS_KEY(fit-content, fit_content)
CSS_KEY(fixed, fixed)
CSS_KEY(flat, flat)
CSS_KEY(flex, flex)

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

@ -109,6 +109,12 @@ enum class GridTrackSizeFlags {
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(GridTrackSizeFlags)
enum class GridTrackListFlags {
eDefaultTrackList = 0x0, // parse a <track-list>
eExplicitTrackList = 0x1, // parse an <explicit-track-list> instead
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(GridTrackListFlags)
namespace {
// Rule processing function
@ -981,9 +987,11 @@ protected:
// starting with a <line-names> (which is itself a list)
// and alternating between that and <track-size>.
bool ParseGridTrackListWithFirstLineNames(nsCSSValue& aValue,
const nsCSSValue& aFirstLineNames);
const nsCSSValue& aFirstLineNames,
GridTrackListFlags aFlags = GridTrackListFlags::eDefaultTrackList);
bool ParseGridTrackList(nsCSSPropertyID aPropID);
bool ParseGridTrackList(nsCSSPropertyID aPropID,
GridTrackListFlags aFlags = GridTrackListFlags::eDefaultTrackList);
bool ParseGridTemplateColumnsRows(nsCSSPropertyID aPropID);
// |aAreaIndices| is a lookup table to help us parse faster,
@ -992,10 +1000,11 @@ protected:
css::GridTemplateAreasValue* aResult,
nsDataHashtable<nsStringHashKey, uint32_t>& aAreaIndices);
bool ParseGridTemplateAreas();
bool ParseGridTemplate();
bool ParseGridTemplateColumnsOrAutoFlow(bool aForGridShorthand);
bool ParseGridTemplate(bool aForGridShorthand = false);
bool ParseGridTemplateAfterString(const nsCSSValue& aFirstLineNames);
bool ParseGrid();
bool ParseGridShorthandAutoProps();
CSSParseResult ParseGridShorthandAutoProps(int32_t aAutoFlowAxis);
bool ParseGridLine(nsCSSValue& aValue);
bool ParseGridColumnRowStartEnd(nsCSSPropertyID aPropID);
bool ParseGridColumnRow(nsCSSPropertyID aStartPropID,
@ -8749,12 +8758,25 @@ CSSParserImpl::ParseGridTrackSize(nsCSSValue& aValue,
return result;
}
// Attempt to parse a minmax() function.
// Attempt to parse a minmax() or fit-content() function.
if (!GetToken(true)) {
return CSSParseResult::NotFound;
}
if (!(eCSSToken_Function == mToken.mType &&
mToken.mIdent.LowerCaseEqualsLiteral("minmax"))) {
if (eCSSToken_Function != mToken.mType) {
UngetToken();
return CSSParseResult::NotFound;
}
if (mToken.mIdent.LowerCaseEqualsLiteral("fit-content")) {
nsCSSValue::Array* func = aValue.InitFunction(eCSSKeyword_fit_content, 1);
if (ParseGridTrackBreadth(func->Item(1)) == CSSParseResult::Ok &&
func->Item(1).IsLengthPercentCalcUnit() &&
ExpectSymbol(')', true)) {
return CSSParseResult::Ok;
}
SkipUntil(')');
return CSSParseResult::Error;
}
if (!mToken.mIdent.LowerCaseEqualsLiteral("minmax")) {
UngetToken();
return CSSParseResult::NotFound;
}
@ -8792,7 +8814,8 @@ CSSParserImpl::ParseGridAutoColumnsRows(nsCSSPropertyID aPropID)
bool
CSSParserImpl::ParseGridTrackListWithFirstLineNames(nsCSSValue& aValue,
const nsCSSValue& aFirstLineNames)
const nsCSSValue& aFirstLineNames,
GridTrackListFlags aFlags)
{
nsCSSValueList* firstLineNamesItem = aValue.SetListValue();
firstLineNamesItem->mValue = aFirstLineNames;
@ -8800,6 +8823,7 @@ CSSParserImpl::ParseGridTrackListWithFirstLineNames(nsCSSValue& aValue,
// This function is trying to parse <track-list>, which is
// [ <line-names>? [ <track-size> | <repeat()> ] ]+ <line-names>?
// and we're already past the first "<line-names>?".
// If aFlags contains eExplicitTrackList then <repeat()> is disallowed.
//
// Each iteration of the following loop attempts to parse either a
// repeat() or a <track-size> expression, and then an (optional)
@ -8815,7 +8839,8 @@ CSSParserImpl::ParseGridTrackListWithFirstLineNames(nsCSSValue& aValue,
if (!GetToken(true)) {
break;
}
if (mToken.mType == eCSSToken_Function &&
if (!(aFlags & GridTrackListFlags::eExplicitTrackList) &&
mToken.mType == eCSSToken_Function &&
mToken.mIdent.LowerCaseEqualsLiteral("repeat")) {
nsCSSValueList* startOfRepeat = item;
if (!ParseGridTrackListRepeat(&item)) {
@ -8835,11 +8860,16 @@ CSSParserImpl::ParseGridTrackListWithFirstLineNames(nsCSSValue& aValue,
list != firstRepeat; list = list->mNext) {
if (list->mValue.GetUnit() == eCSSUnit_Function) {
nsCSSValue::Array* func = list->mValue.GetArrayValue();
NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_minmax,
"Expected minmax(), got another function name");
if (!func->Item(1).IsLengthPercentCalcUnit() &&
!func->Item(2).IsLengthPercentCalcUnit()) {
return false;
auto funcName = func->Item(0).GetKeywordValue();
if (funcName == eCSSKeyword_minmax) {
if (!func->Item(1).IsLengthPercentCalcUnit() &&
!func->Item(2).IsLengthPercentCalcUnit()) {
return false;
}
} else {
MOZ_ASSERT(funcName == eCSSKeyword_fit_content,
"Expected minmax() or fit-content() function");
return false; // fit-content() is not a <fixed-size>
}
} else if (!list->mValue.IsLengthPercentCalcUnit()) {
return false;
@ -9155,12 +9185,13 @@ CSSParserImpl::ParseGridTrackListRepeat(nsCSSValueList** aTailPtr)
}
bool
CSSParserImpl::ParseGridTrackList(nsCSSPropertyID aPropID)
CSSParserImpl::ParseGridTrackList(nsCSSPropertyID aPropID,
GridTrackListFlags aFlags)
{
nsCSSValue value;
nsCSSValue firstLineNames;
if (ParseGridLineNames(firstLineNames) == CSSParseResult::Error ||
!ParseGridTrackListWithFirstLineNames(value, firstLineNames)) {
!ParseGridTrackListWithFirstLineNames(value, firstLineNames, aFlags)) {
return false;
}
AppendValue(aPropID, value);
@ -9314,13 +9345,34 @@ CSSParserImpl::ParseGridTemplateAreas()
return true;
}
// [ auto-flow && dense? ] <'grid-auto-columns'>? |
// <'grid-template-columns'>
bool
CSSParserImpl::ParseGridTemplate()
CSSParserImpl::ParseGridTemplateColumnsOrAutoFlow(bool aForGridShorthand)
{
if (aForGridShorthand) {
auto res = ParseGridShorthandAutoProps(NS_STYLE_GRID_AUTO_FLOW_COLUMN);
if (res == CSSParseResult::Error) {
return false;
}
if (res == CSSParseResult::Ok) {
nsCSSValue value(eCSSUnit_None);
AppendValue(eCSSProperty_grid_template_columns, value);
return true;
}
}
return ParseGridTemplateColumnsRows(eCSSProperty_grid_template_columns);
}
bool
CSSParserImpl::ParseGridTemplate(bool aForGridShorthand)
{
// none |
// subgrid |
// <'grid-template-rows'> / <'grid-template-columns'> |
// [ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <track-list>]?
// [ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <explicit-track-list>]?
// or additionally when aForGridShorthand is true:
// <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>?
nsCSSValue value;
if (ParseSingleTokenVariant(value, VARIANT_INHERIT, nullptr)) {
AppendValue(eCSSProperty_grid_template_areas, value);
@ -9335,7 +9387,7 @@ CSSParserImpl::ParseGridTemplate()
AppendValue(eCSSProperty_grid_template_rows, value);
AppendValue(eCSSProperty_grid_template_areas, value);
if (ExpectSymbol('/', true)) {
return ParseGridTemplateColumnsRows(eCSSProperty_grid_template_columns);
return ParseGridTemplateColumnsOrAutoFlow(aForGridShorthand);
}
AppendValue(eCSSProperty_grid_template_columns, value);
return true;
@ -9356,7 +9408,7 @@ CSSParserImpl::ParseGridTemplate()
AppendValue(eCSSProperty_grid_template_rows, value);
AppendValue(eCSSProperty_grid_template_areas, nsCSSValue(eCSSUnit_None));
if (ExpectSymbol('/', true)) {
return ParseGridTemplateColumnsRows(eCSSProperty_grid_template_columns);
return ParseGridTemplateColumnsOrAutoFlow(aForGridShorthand);
}
if (value.GetListValue()->mNext) {
// Non-empty <line-name-list> after 'subgrid'.
@ -9384,9 +9436,10 @@ CSSParserImpl::ParseGridTemplate()
if (!ParseGridTemplateAfterString(firstLineNames)) {
return false;
}
// Parse an optional [ / <track-list> ] as the columns value.
// Parse an optional [ / <explicit-track-list> ] as the columns value.
if (ExpectSymbol('/', true)) {
return ParseGridTrackList(eCSSProperty_grid_template_columns);
return ParseGridTrackList(eCSSProperty_grid_template_columns,
GridTrackListFlags::eExplicitTrackList);
}
value.SetNoneValue(); // absent means 'none'
AppendValue(eCSSProperty_grid_template_columns, value);
@ -9403,7 +9456,7 @@ CSSParserImpl::ParseGridTemplate()
AppendValue(eCSSProperty_grid_template_rows, value);
value.SetNoneValue();
AppendValue(eCSSProperty_grid_template_areas, value);
return ParseGridTemplateColumnsRows(eCSSProperty_grid_template_columns);
return ParseGridTemplateColumnsOrAutoFlow(aForGridShorthand);
}
// Helper for parsing the 'grid-template' shorthand:
@ -9481,7 +9534,8 @@ CSSParserImpl::ParseGridTemplateAfterString(const nsCSSValue& aFirstLineNames)
}
// <'grid-template'> |
// [ <'grid-auto-flow'> [ <'grid-auto-rows'> [ / <'grid-auto-columns'> ]? ]? ]
// <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>? |
// [ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'>
bool
CSSParserImpl::ParseGrid()
{
@ -9495,11 +9549,6 @@ CSSParserImpl::ParseGrid()
return true;
}
// An empty value is always invalid.
if (!GetToken(true)) {
return false;
}
// https://drafts.csswg.org/css-grid/#grid-shorthand
// "Also, the gutter properties are reset by this shorthand,
// even though they can't be set by it."
@ -9507,58 +9556,93 @@ CSSParserImpl::ParseGrid()
AppendValue(eCSSProperty_grid_row_gap, value);
AppendValue(eCSSProperty_grid_column_gap, value);
// The values starts with a <'grid-auto-flow'> if and only if
// it starts with a 'dense', 'column' or 'row' keyword.
if (mToken.mType == eCSSToken_Ident) {
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
if (keyword == eCSSKeyword_dense ||
keyword == eCSSKeyword_column ||
keyword == eCSSKeyword_row) {
UngetToken();
return ParseGridAutoFlow() && ParseGridShorthandAutoProps();
}
// [ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'>
auto res = ParseGridShorthandAutoProps(NS_STYLE_GRID_AUTO_FLOW_ROW);
if (res == CSSParseResult::Error) {
return false;
}
if (res == CSSParseResult::Ok) {
value.SetAutoValue();
AppendValue(eCSSProperty_grid_auto_columns, value);
nsCSSValue none(eCSSUnit_None);
AppendValue(eCSSProperty_grid_template_areas, none);
AppendValue(eCSSProperty_grid_template_rows, none);
if (!ExpectSymbol('/', true)) {
return false;
}
return ParseGridTemplateColumnsRows(eCSSProperty_grid_template_columns);
}
UngetToken();
// Set other subproperties to their initial values
// and parse <'grid-template'>.
// Set remaining subproperties that might not be set by ParseGridTemplate to
// their initial values and then parse <'grid-template'> |
// <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>? .
value.SetIntValue(NS_STYLE_GRID_AUTO_FLOW_ROW, eCSSUnit_Enumerated);
AppendValue(eCSSProperty_grid_auto_flow, value);
value.SetAutoValue();
AppendValue(eCSSProperty_grid_auto_rows, value);
AppendValue(eCSSProperty_grid_auto_columns, value);
return ParseGridTemplate();
return ParseGridTemplate(true);
}
// Parse [ <'grid-auto-rows'> [ / <'grid-auto-columns'> ]? ]?
// for the 'grid' shorthand.
// Assumes that <'grid-auto-flow'> was already parsed by the caller.
bool
CSSParserImpl::ParseGridShorthandAutoProps()
// Parse [ auto-flow && dense? ] <'grid-auto-[rows|columns]'>? for the 'grid'
// shorthand. If aAutoFlowAxis == NS_STYLE_GRID_AUTO_FLOW_ROW then we're
// parsing row values, otherwise column values.
CSSParseResult
CSSParserImpl::ParseGridShorthandAutoProps(int32_t aAutoFlowAxis)
{
nsCSSValue autoColumnsValue;
nsCSSValue autoRowsValue;
CSSParseResult result = ParseGridTrackSize(autoRowsValue);
if (result == CSSParseResult::Error) {
return false;
MOZ_ASSERT(aAutoFlowAxis == NS_STYLE_GRID_AUTO_FLOW_ROW ||
aAutoFlowAxis == NS_STYLE_GRID_AUTO_FLOW_COLUMN);
if (!GetToken(true)) {
return CSSParseResult::NotFound;
}
if (result == CSSParseResult::NotFound) {
autoRowsValue.SetAutoValue();
autoColumnsValue.SetAutoValue();
} else {
if (!ExpectSymbol('/', true)) {
autoColumnsValue.SetAutoValue();
} else if (ParseGridTrackSize(autoColumnsValue) != CSSParseResult::Ok) {
return false;
// [ auto-flow && dense? ]
int32_t autoFlowValue = 0;
if (mToken.mType == eCSSToken_Ident) {
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
if (keyword == eCSSKeyword_auto_flow) {
autoFlowValue = aAutoFlowAxis;
if (GetToken(true)) {
if (mToken.mType == eCSSToken_Ident &&
nsCSSKeywords::LookupKeyword(mToken.mIdent) == eCSSKeyword_dense) {
autoFlowValue |= NS_STYLE_GRID_AUTO_FLOW_DENSE;
} else {
UngetToken();
}
}
} else if (keyword == eCSSKeyword_dense) {
if (!GetToken(true)) {
return CSSParseResult::Error;
}
if (mToken.mType != eCSSToken_Ident ||
nsCSSKeywords::LookupKeyword(mToken.mIdent) != eCSSKeyword_auto_flow) {
UngetToken();
return CSSParseResult::Error;
}
autoFlowValue = aAutoFlowAxis | NS_STYLE_GRID_AUTO_FLOW_DENSE;
}
}
AppendValue(eCSSProperty_grid_auto_rows, autoRowsValue);
AppendValue(eCSSProperty_grid_auto_columns, autoColumnsValue);
nsCSSValue templateValue(eCSSUnit_None); // Initial values
AppendValue(eCSSProperty_grid_template_areas, templateValue);
AppendValue(eCSSProperty_grid_template_rows, templateValue);
AppendValue(eCSSProperty_grid_template_columns, templateValue);
return true;
if (autoFlowValue) {
nsCSSValue value;
value.SetIntValue(autoFlowValue, eCSSUnit_Enumerated);
AppendValue(eCSSProperty_grid_auto_flow, value);
} else {
UngetToken();
return CSSParseResult::NotFound;
}
// <'grid-auto-[rows|columns]'>?
nsCSSValue autoTrackValue;
CSSParseResult result = ParseGridTrackSize(autoTrackValue);
if (result == CSSParseResult::Error) {
return result;
}
if (result == CSSParseResult::NotFound) {
autoTrackValue.SetAutoValue();
}
AppendValue(aAutoFlowAxis == NS_STYLE_GRID_AUTO_FLOW_ROW ?
eCSSProperty_grid_auto_rows : eCSSProperty_grid_auto_columns,
autoTrackValue);
return CSSParseResult::Ok;
}
// Parse a <grid-line>.

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

@ -2531,6 +2531,21 @@ already_AddRefed<CSSValue>
nsComputedDOMStyle::GetGridTrackSize(const nsStyleCoord& aMinValue,
const nsStyleCoord& aMaxValue)
{
if (aMinValue.GetUnit() == eStyleUnit_None) {
// A fit-content() function.
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
nsAutoString argumentStr, fitContentStr;
fitContentStr.AppendLiteral("fit-content(");
MOZ_ASSERT(aMaxValue.IsCoordPercentCalcUnit(),
"unexpected unit for fit-content() argument value");
SetValueToCoord(val, aMaxValue, true);
val->GetCssText(argumentStr);
fitContentStr.Append(argumentStr);
fitContentStr.Append(char16_t(')'));
val->SetString(fitContentStr);
return val.forget();
}
if (aMinValue == aMaxValue) {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
SetValueToCoord(val, aMinValue, true,

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

@ -8118,6 +8118,9 @@ SetGridTrackBreadth(const nsCSSValue& aValue,
aResult.SetFlexFractionValue(aValue.GetFloatValue());
} else if (unit == eCSSUnit_Auto) {
aResult.SetAutoValue();
} else if (unit == eCSSUnit_None) {
// For fit-content().
aResult.SetNoneValue();
} else {
MOZ_ASSERT(unit != eCSSUnit_Inherit && unit != eCSSUnit_Unset,
"Unexpected value that would use dummyParentCoord");
@ -8139,14 +8142,22 @@ SetGridTrackSize(const nsCSSValue& aValue,
RuleNodeCacheConditions& aConditions)
{
if (aValue.GetUnit() == eCSSUnit_Function) {
// A minmax() function.
nsCSSValue::Array* func = aValue.GetArrayValue();
NS_ASSERTION(func->Item(0).GetKeywordValue() == eCSSKeyword_minmax,
"Expected minmax(), got another function name");
SetGridTrackBreadth(func->Item(1), aResultMin,
aStyleContext, aPresContext, aConditions);
SetGridTrackBreadth(func->Item(2), aResultMax,
aStyleContext, aPresContext, aConditions);
auto funcName = func->Item(0).GetKeywordValue();
if (funcName == eCSSKeyword_minmax) {
SetGridTrackBreadth(func->Item(1), aResultMin,
aStyleContext, aPresContext, aConditions);
SetGridTrackBreadth(func->Item(2), aResultMax,
aStyleContext, aPresContext, aConditions);
} else if (funcName == eCSSKeyword_fit_content) {
// We represent fit-content(L) as 'none' min-sizing and L max-sizing.
SetGridTrackBreadth(nsCSSValue(eCSSUnit_None), aResultMin,
aStyleContext, aPresContext, aConditions);
SetGridTrackBreadth(func->Item(1), aResultMax,
aStyleContext, aPresContext, aConditions);
} else {
NS_ERROR("Expected minmax() or fit-content(), got another function name");
}
} else {
// A single <track-breadth>,
// specifies identical min and max sizing functions.
@ -10404,6 +10415,13 @@ nsRuleNode::HasAuthorSpecifiedRules(nsStyleContext* aStyleContext,
uint32_t ruleTypeMask,
bool aAuthorColorsAllowed)
{
#ifdef MOZ_STYLO
if (aStyleContext->StyleSource().IsServoComputedValues()) {
NS_WARNING("stylo: nsRuleNode::HasAuthorSpecifiedRules not implemented");
return true;
}
#endif
uint32_t inheritBits = 0;
if (ruleTypeMask & NS_AUTHOR_SPECIFIED_BACKGROUND)
inheritBits |= NS_STYLE_INHERIT_BIT(Background);

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

@ -992,11 +992,17 @@ public:
// Compute the value of an nsStyleCoord that IsCalcUnit().
// (Values that don't require aPercentageBasis should be handled
// inside nsRuleNode rather than through this API.)
// @note the caller is expected to handle percentage of an indefinite size
// and NOT call this method with aPercentageBasis == NS_UNCONSTRAINEDSIZE.
// @note the return value may be negative, e.g. for "calc(a - b%)"
static nscoord ComputeComputedCalc(const nsStyleCoord& aCoord,
nscoord aPercentageBasis);
// Compute the value of an nsStyleCoord that is either a coord, a
// percent, or a calc expression.
// @note the caller is expected to handle percentage of an indefinite size
// and NOT call this method with aPercentageBasis == NS_UNCONSTRAINEDSIZE.
// @note the return value may be negative, e.g. for "calc(a - b%)"
static nscoord ComputeCoordPercentCalc(const nsStyleCoord& aCoord,
nscoord aPercentageBasis);

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

@ -1653,6 +1653,8 @@ struct nsStyleGridLine
//
// A <track-size> specified as a single <track-breadth> is represented
// as identical min and max sizing functions.
// A 'fit-content(size)' <track-size> is represented as eStyleUnit_None
// in the min sizing function and 'size' in the max sizing function.
//
// The units for nsStyleCoord are:
// * eStyleUnit_Percent represents a <percentage>

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

@ -6080,12 +6080,15 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
"12%",
"min-content",
"max-content",
"calc(20px + 10%)",
"calc(2px - 99%)",
"minmax(20px, max-content)",
"minmax(min-content, auto)",
"minmax(auto, max-content)",
"m\\69nmax(20px, 4Fr)",
"MinMax(min-content, calc(20px + 10%))",
"fit-content(1px)",
"fit-content(calc(1px - 99%))",
"fit-content(10%)",
],
invalid_values: [
"",
@ -6101,6 +6104,9 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
"minmax(20px, 100px, 200px)",
"maxmin(100px, 20px)",
"minmax(min-content, minmax(30px, max-content))",
"fit-content(-1px)",
"fit-content(auto)",
"fit-content(min-content)",
]
};
gCSSProperties["grid-auto-rows"] = {
@ -6122,7 +6128,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
"40px",
"2.5fr",
"[normal] 40px [] auto [ ] 12%",
"[foo] 40px min-content [ bar ] calc(20px + 10%) max-content",
"[foo] 40px min-content [ bar ] calc(2px - 99%) max-content",
"40px min-content calc(20px + 10%) max-content",
"minmax(min-content, auto)",
"minmax(auto, max-content)",
@ -6145,10 +6151,13 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
"minmax(calc(1% + 1px),auto) repeat(Auto-fit,[] 1%) minmax(auto,1%)",
"[a] repeat( auto-fit,[a b] minmax(0,0) )",
"[a] 40px repeat(auto-fit,[a b] minmax(1px, 0) [])",
"[a] calc(1%) [b] repeat(auto-fit,[a b] minmax(1mm, 1%) [c]) [c]",
"[a] calc(1px - 99%) [b] repeat(auto-fit,[a b] minmax(1mm, 1%) [c]) [c]",
"repeat(auto-fill,minmax(1%,auto))",
"repeat(auto-fill,minmax(1em,min-content)) minmax(min-content,0)",
"repeat(auto-fill,minmax(max-content,1mm))",
"fit-content(1px) 1fr",
"[a] fit-content(calc(1px - 99%)) [b]",
"[a] fit-content(10%) [b c] fit-content(1em)",
],
invalid_values: [
"",
@ -6208,6 +6217,9 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
"auto repeat(auto-fit, 10px)",
"minmax(min-content,max-content) repeat(auto-fit, 0)",
"10px [a] 10px [b a] 1fr [b] repeat(auto-fill, 0)",
"fit-content(-1px)",
"fit-content(auto)",
"fit-content(min-content)",
],
unbalanced_values: [
"(foo] 40px",
@ -6306,10 +6318,10 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
other_values: [
// <'grid-template-rows'> / <'grid-template-columns'>
"40px / 100px",
"[foo] 40px [bar] / [baz] 100px [fizz]",
"[foo] 40px [bar] / [baz] repeat(auto-fill,100px) [fizz]",
" none/100px",
"40px/none",
// [ <track-list> / ]? [ <line-names>? <string> <track-size>? <line-names>? ]+
// [ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <explicit-track-list> ]?
"'fizz'",
"[bar] 'fizz'",
"'fizz' / [foo] 40px",
@ -6320,6 +6332,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
"[bar] 'fizz' 100px [buzz] \n [a] '.' 200px [b] / [foo] 40px",
],
invalid_values: [
"'fizz' / repeat(1, 100px)",
"'fizz' repeat(1, 100px) / 0px",
"[foo] [bar] 40px / 100px",
"[fizz] [buzz] 100px / 40px",
"[fizz] [buzz] 'foo' / 40px",
@ -6362,21 +6376,32 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
"none / none",
],
other_values: [
"column 40px",
"column dense auto",
"dense row minmax(min-content, 2fr)",
"row 40px / 100px",
"auto-flow 40px / none",
"auto-flow / 40px",
"auto-flow dense auto / auto",
"dense auto-flow minmax(min-content, 2fr) / auto",
"dense auto-flow / 100px",
"none / auto-flow 40px",
"40px / auto-flow",
"none / dense auto-flow auto",
].concat(
gCSSProperties["grid-template"].other_values,
gCSSProperties["grid-auto-flow"].other_values
gCSSProperties["grid-template"].other_values
),
invalid_values: [
"row column 40px",
"row -20px",
"row 200ms",
"row 40px 100px",
"auto-flow",
" / auto-flow",
"dense 0 / 0",
"dense dense 40px / 0",
"auto-flow / auto-flow",
"auto-flow / dense",
"auto-flow [a] 0 / 0",
"0 / auto-flow [a] 0",
"auto-flow -20px / 0",
"auto-flow 200ms / 0",
"auto-flow 40px 100px / 0",
].concat(
gCSSProperties["grid-template"].invalid_values,
gCSSProperties["grid-auto-flow"].other_values,
gCSSProperties["grid-auto-flow"].invalid_values
.filter((v) => v != 'none')
)
@ -6542,8 +6567,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0" ],
other_values: [ "2px", "2%", "1em", "calc(1px + 1em)", "calc(1%)",
"calc(1% + 1ch)" ],
invalid_values: [ "-1px", "auto", "none", "1px 1px", "-1%" ],
"calc(1% + 1ch)" , "calc(1px - 99%)" ],
invalid_values: [ "-1px", "auto", "none", "1px 1px", "-1%", "fit-content(1px)" ],
};
gCSSProperties["grid-row-gap"] = {
domProp: "gridRowGap",
@ -6551,8 +6576,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.grid.enabled")) {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0" ],
other_values: [ "2px", "2%", "1em", "calc(1px + 1em)", "calc(1%)",
"calc(1% + 1ch)" ],
invalid_values: [ "-1px", "auto", "none", "1px 1px", "-1%" ],
"calc(1% + 1ch)" , "calc(1px - 99%)" ],
invalid_values: [ "-1px", "auto", "none", "1px 1px", "-1%", "min-content" ],
};
gCSSProperties["grid-gap"] = {
domProp: "gridGap",

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

@ -175,42 +175,64 @@ var grid_template_test_cases = [
gridTemplateColumns: isGridTemplateSubgridValueEnabled ? "subgrid [] [foo]" : "none",
gridTemplateRows: isGridTemplateSubgridValueEnabled ? "subgrid [bar]" : "none",
},
{
specified: "'fizz' repeat(1, 100px)",
},
{
specified: "'fizz' repeat(auto-fill, 100px)",
},
{
specified: "'fizz' / repeat(1, 100px)",
},
{
specified: "'fizz' / repeat(auto-fill, 100px)",
},
];
grid_test_cases = grid_template_test_cases.concat([
{
specified: "row",
specified: "auto-flow / 0",
gridAutoFlow: "row",
gridAutoRows: "auto",
gridTemplateColumns: "0px",
},
{
specified: "dense",
specified: "auto-flow dense / 0",
gridAutoFlow: "row dense",
gridAutoRows: "auto",
gridTemplateColumns: "0px",
},
{
specified: "row 40px",
specified: "auto-flow 40px / none",
gridAutoFlow: "row",
gridAutoRows: "40px",
},
{
specified: "column 40px",
specified: "none / auto-flow 40px",
gridAutoFlow: "column",
gridAutoRows: "40px",
gridAutoRows: "auto",
gridAutoColumns: "40px",
},
{
specified: "column dense auto",
specified: "0 / auto-flow dense auto",
gridAutoFlow: "column dense",
gridAutoRows: "auto",
gridAutoColumns: "auto",
gridTemplateRows: "0px",
},
{
specified: "dense row minmax(min-content, 2fr)",
specified: "dense auto-flow minmax(min-content, 2fr) / 0",
gridAutoFlow: "row dense",
gridAutoRows: "minmax(min-content, 2fr)",
gridAutoColumns: "auto",
gridTemplateColumns: "0px",
},
{
specified: "row 40px / 100px",
specified: "auto-flow 40px / 100px",
gridAutoFlow: "row",
gridAutoRows: "40px",
gridAutoColumns: "100px",
gridAutoColumns: "auto",
gridTemplateColumns: "100px",
},
]);

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

@ -57,6 +57,17 @@ var grid_template_test_cases = [
gridTemplateRows: "[foo] 20px [bar]",
shorthand: "[foo] \"a\" 20px [bar]",
},
{
gridTemplateAreas: "\"a\"",
gridTemplateRows: "[foo] repeat(1, 20px) [bar]",
shorthand: "[foo] \"a\" 20px [bar]",
},
{
gridTemplateAreas: "\"a a\"",
gridTemplateColumns: "repeat(2, 100px)",
gridTemplateRows: "auto",
shorthand: "\"a a\" auto / 100px 100px",
},
// Combinations of longhands that make the shorthand non-serializable:
{
gridTemplateAreas: "\"a\"",
@ -84,37 +95,58 @@ var grid_template_test_cases = [
gridTemplateColumns: "subgrid",
shorthand: "",
},
{
gridTemplateAreas: "\"a\"",
gridTemplateRows: "repeat(auto-fill, 20px)",
shorthand: "",
},
{
gridTemplateAreas: "\"a\"",
gridTemplateColumns: "repeat(auto-fill, 100px)",
gridTemplateRows: "auto",
shorthand: "",
},
];
grid_test_cases = grid_template_test_cases.concat([
{
gridAutoFlow: "row",
shorthand: "row auto / auto",
shorthand: "none / none",
},
{
gridAutoRows: "40px",
shorthand: "row 40px / auto",
shorthand: "auto-flow 40px / none",
},
{
gridAutoFlow: "column dense",
gridAutoRows: "minmax(min-content, max-content)",
shorthand: "column dense minmax(min-content, max-content) / auto",
shorthand: "",
},
{
gridAutoFlow: "column dense",
gridAutoColumns: "minmax(min-content, max-content)",
shorthand: "none / auto-flow dense minmax(min-content, max-content)",
},
{
gridAutoFlow: "row dense",
gridAutoColumns: "minmax(min-content, 2fr)",
shorthand: "row dense auto / minmax(min-content, 2fr)",
shorthand: "",
},
{
gridAutoFlow: "row dense",
gridAutoRows: "minmax(min-content, 2fr)",
shorthand: "auto-flow dense minmax(min-content, 2fr) / none",
},
{
gridAutoFlow: "row",
gridAutoRows: "40px",
gridAutoColumns: "100px",
shorthand: "row 40px / 100px",
gridTemplateColumns: "100px",
shorthand: "auto-flow 40px / 100px",
},
{
gridAutoFlow: "row",
gridRowGap: "0px",
shorthand: "row auto / auto",
shorthand: "none / none",
},
{
gridAutoFlow: "row",

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

@ -37,8 +37,6 @@ GARBAGE += \
res/raw/browsersearch.json \
res/raw/suggestedsites.json \
.aapt.deps \
javah.out \
jni-stubs.inc \
GeneratedJNINatives.h \
GeneratedJNIWrappers.cpp \
GeneratedJNIWrappers.h \
@ -291,16 +289,6 @@ classycle_jar := $(topsrcdir)/mobile/android/build/classycle/classycle-1.4.1.jar
-outjars jars-proguarded \
-libraryjars $(library_jars)
CLASSES_WITH_JNI= \
org.mozilla.gecko.GeckoAppShell \
org.mozilla.gecko.GeckoJavaSampler \
org.mozilla.gecko.GeckoSmsManager \
$(NULL)
jni-stubs.inc: gecko-browser.jar constants.jar gecko-mozglue.jar gecko-util.jar sync-thirdparty.jar
$(JAVAH) -o javah.out -bootclasspath $(JAVA_BOOTCLASSPATH) -classpath $(subst $(NULL) $(NULL),:,$^) $(CLASSES_WITH_JNI)
$(PYTHON) $(topsrcdir)/mobile/android/base/jni-generator.py javah.out $@
ANNOTATION_PROCESSOR_JAR_FILES := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar
# This annotation processing step also generates
@ -487,7 +475,6 @@ endif
include $(topsrcdir)/config/android-common.mk
update-generated-wrappers:
@cp $(CURDIR)/jni-stubs.inc $(topsrcdir)/mozglue/android
@cp $(CURDIR)/GeneratedJNIWrappers.cpp $(CURDIR)/GeneratedJNIWrappers.h $(CURDIR)/GeneratedJNINatives.h $(topsrcdir)/widget/android
@echo Updated generated JNI code
@ -525,9 +512,8 @@ endif
# GeneratedJNIWrappers.cpp target also generates
# GeneratedJNIWrappers.h and GeneratedJNINatives.h
ifndef MOZ_BUILD_MOBILE_ANDROID_WITH_GRADLE
libs:: jni-stubs.inc GeneratedJNIWrappers.cpp
@(diff jni-stubs.inc $(topsrcdir)/mozglue/android/jni-stubs.inc >/dev/null && \
diff GeneratedJNIWrappers.cpp $(topsrcdir)/widget/android/GeneratedJNIWrappers.cpp >/dev/null && \
libs:: GeneratedJNIWrappers.cpp
@(diff GeneratedJNIWrappers.cpp $(topsrcdir)/widget/android/GeneratedJNIWrappers.cpp >/dev/null && \
diff GeneratedJNIWrappers.h $(topsrcdir)/widget/android/GeneratedJNIWrappers.h >/dev/null && \
diff GeneratedJNINatives.h $(topsrcdir)/widget/android/GeneratedJNINatives.h >/dev/null) || \
(echo '*****************************************************' && \

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

@ -68,6 +68,12 @@ public class ReferrerReceiver extends BroadcastReceiver {
if (TextUtils.equals(referrer.campaign, DISTRIBUTION_UTM_CAMPAIGN)) {
Distribution.onReceivedReferrer(context, referrer);
// We want Adjust information for OTA distributions as well
try {
AdjustConstants.getAdjustHelper().onReceive(context, intent);
} catch (Exception e) {
Log.e(LOGTAG, "Got exception in Adjust's onReceive for distribution.", e);
}
} else {
Log.d(LOGTAG, "Not downloading distribution: non-matching campaign.");
// If this is a Mozilla campaign, pass the campaign along to Gecko.

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

@ -1,109 +0,0 @@
# 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/.
import argparse
import re
STUB_TEMPLATE = '''
typedef %(returnType)s (*%(functionName)s_t)(%(paramTypes)s);
static %(functionName)s_t f_%(functionName)s;
extern "C" NS_EXPORT %(returnType)s MOZ_JNICALL
%(functionName)s(%(parameterList)s) {
if (!f_%(functionName)s) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return %(returnValue)s;
}
%(returnKeyword)s f_%(functionName)s(%(arguments)s);
}
'''
BINDING_TEMPLATE = ' xul_dlsym("%(functionName)s", &f_%(functionName)s);\n'
class Generator:
"""
Class to convert a javah-produced JNI stub file into stubs/bindings files
for inclusion into mozglue.
"""
def __init__(self, outputfile):
self.outputfile = outputfile
def write(self, guard, stuff):
self.outputfile.write('#ifdef %s\n' % guard)
self.outputfile.write(stuff)
self.outputfile.write('#endif\n\n')
def process(self, inputfile):
self.outputfile.write('/* WARNING - This file is autogenerated by '
+ 'mobile/android/base/jni-generator.py. '
+ 'Do not edit manually! */\n')
# this matches lines such as:
# JNIEXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume
# and extracts the return type and the function name
nameRegex = re.compile('''JNIEXPORT \s+
(?P<returnType>\S+) \s+
JNICALL \s+
(?P<functionName>\S+)''', re.VERBOSE)
# this matches lines such as:
# (JNIEnv *, jclass);
# and extracts everything within the parens; this will be split
# on commas to get the argument types.
paramsRegex = re.compile('\((.*)\);')
for line in inputfile:
line = line.strip()
match = re.match(nameRegex, line)
if match:
returnType = match.group('returnType')
functionName = match.group('functionName')
match = re.match(paramsRegex, line)
if match:
paramTypes = re.split('\s*,\s*', match.group(1))
paramNames = ['arg%d' % i for i in range(0, len(paramTypes))]
if returnType == 'void':
returnValue = ''
elif returnType in ('jobject', 'jstring') or returnType.endswith('Array'):
returnValue = 'nullptr'
elif returnType in ('jint', 'jfloat', 'jdouble', 'jlong'):
returnValue = '0'
elif returnType == 'jboolean':
returnValue = 'false'
else:
raise Exception(('Unsupported JNI return type %s found; '
+ 'please update mobile/android/base/'
+ 'jni-generator.py to handle this case!')
% returnType)
self.write('JNI_STUBS', STUB_TEMPLATE % {
'returnType': returnType,
'functionName': functionName,
'paramTypes': ', '.join(paramTypes),
'parameterList': ', '.join('%s %s' % param
for param in zip(paramTypes, paramNames)),
'arguments': ', '.join(paramNames),
'returnValue': returnValue,
'returnKeyword': 'return' if returnType != 'void' else ''})
self.write('JNI_BINDINGS', BINDING_TEMPLATE % {
'functionName': functionName})
def main():
parser = argparse.ArgumentParser(
description='Generate mozglue bindings for JNI functions.')
parser.add_argument('inputfile', type=argparse.FileType('r'))
parser.add_argument('outputfile', type=argparse.FileType('w'))
args = parser.parse_args()
gen = Generator(args.outputfile)
try:
gen.process(args.inputfile)
finally:
args.outputfile.close()
args.inputfile.close()
if __name__ == '__main__':
main()

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

@ -70,6 +70,7 @@ import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@ -159,7 +160,7 @@ public class GeckoAppShell
editor.commit();
}
reportJavaCrash(getExceptionStackTrace(exc));
reportJavaCrash(exc, getExceptionStackTrace(exc));
} catch (final Throwable e) {
}
@ -239,7 +240,7 @@ public class GeckoAppShell
// helper methods
@WrapForJNI
private static native void reportJavaCrash(String stackTrace);
/* package */ static native void reportJavaCrash(Throwable exc, String stackTrace);
@WrapForJNI(dispatchTo = "gecko")
public static native void notifyUriVisited(String uri);
@ -315,20 +316,13 @@ public class GeckoAppShell
*/
@WrapForJNI(exceptionMode = "ignore")
public static String handleUncaughtException(Throwable e) {
if (AppConstants.MOZ_CRASHREPORTER) {
final Throwable exc = CrashHandler.getRootException(e);
final StackTraceElement[] stack = exc.getStackTrace();
if (stack.length >= 1 && stack[0].isNativeMethod()) {
// The exception occurred when running native code. Return an exception
// string and trigger the crash reporter inside the caller so that we get
// a better native stack in Socorro.
CrashHandler.logException(Thread.currentThread(), exc);
return CrashHandler.getExceptionStackTrace(exc);
}
}
private static String getExceptionStackTrace(Throwable e) {
return CrashHandler.getExceptionStackTrace(CrashHandler.getRootException(e));
}
@WrapForJNI(exceptionMode = "ignore")
private static void handleUncaughtException(Throwable e) {
CRASH_HANDLER.uncaughtException(null, e);
return null;
}
private static float getLocationAccuracy(Location location) {
@ -1833,13 +1827,30 @@ public class GeckoAppShell
sGeckoInterface = aGeckoInterface;
}
public static android.hardware.Camera sCamera;
/* package */ static Camera sCamera;
static native void cameraCallbackBridge(byte[] data);
private static final int kPreferredFPS = 25;
private static byte[] sCameraBuffer;
static final int kPreferredFPS = 25;
static byte[] sCameraBuffer;
private static class CameraCallback implements Camera.PreviewCallback {
@WrapForJNI(calledFrom = "gecko")
private static native void onFrameData(int camera, byte[] data);
private final int mCamera;
public CameraCallback(int camera) {
mCamera = camera;
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
onFrameData(mCamera, data);
if (sCamera != null) {
sCamera.addCallbackBuffer(sCameraBuffer);
}
}
}
@WrapForJNI(calledFrom = "gecko")
static int[] initCamera(String aContentType, int aCamera, int aWidth, int aHeight) {
@ -1860,14 +1871,14 @@ public class GeckoAppShell
int[] result = new int[4];
result[0] = 0;
if (android.hardware.Camera.getNumberOfCameras() == 0) {
if (Camera.getNumberOfCameras() == 0) {
return result;
}
try {
sCamera = android.hardware.Camera.open(aCamera);
sCamera = Camera.open(aCamera);
android.hardware.Camera.Parameters params = sCamera.getParameters();
Camera.Parameters params = sCamera.getParameters();
params.setPreviewFormat(ImageFormat.NV21);
// use the preview fps closest to 25 fps.
@ -1886,11 +1897,11 @@ public class GeckoAppShell
}
// set up the closest preview size available
Iterator<android.hardware.Camera.Size> sit = params.getSupportedPreviewSizes().iterator();
Iterator<Camera.Size> sit = params.getSupportedPreviewSizes().iterator();
int sizeDelta = 10000000;
int bufferSize = 0;
while (sit.hasNext()) {
android.hardware.Camera.Size size = sit.next();
Camera.Size size = sit.next();
if (Math.abs(size.width * size.height - aWidth * aHeight) < sizeDelta) {
sizeDelta = Math.abs(size.width * size.height - aWidth * aHeight);
params.setPreviewSize(size.width, size.height);
@ -1914,14 +1925,7 @@ public class GeckoAppShell
sCamera.setParameters(params);
sCameraBuffer = new byte[(bufferSize * 12) / 8];
sCamera.addCallbackBuffer(sCameraBuffer);
sCamera.setPreviewCallbackWithBuffer(new android.hardware.Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
cameraCallbackBridge(data);
if (sCamera != null)
sCamera.addCallbackBuffer(sCameraBuffer);
}
});
sCamera.setPreviewCallbackWithBuffer(new CameraCallback(aCamera));
sCamera.startPreview();
params = sCamera.getParameters();
result[0] = 1;

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

@ -79,43 +79,33 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener
public Compositor() {
}
@WrapForJNI(calledFrom = "ui", dispatchTo = "proxy")
@WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
@Override protected native void disposeNative();
// Gecko thread sets its Java instances; does not block UI thread.
@WrapForJNI(calledFrom = "any", dispatchTo = "proxy")
@WrapForJNI(calledFrom = "any", dispatchTo = "gecko")
/* package */ native void attachToJava(GeckoLayerClient layerClient,
NativePanZoomController npzc);
@WrapForJNI(calledFrom = "any", dispatchTo = "proxy")
@WrapForJNI(calledFrom = "any", dispatchTo = "gecko")
/* package */ native void onSizeChanged(int windowWidth, int windowHeight,
int screenWidth, int screenHeight);
// Gecko thread creates compositor; blocks UI thread.
@WrapForJNI(calledFrom = "ui", dispatchTo = "proxy")
/* package */ native void createCompositor(int width, int height);
/* package */ native void createCompositor(int width, int height, Object surface);
// Gecko thread pauses compositor; blocks UI thread.
@WrapForJNI(calledFrom = "ui", dispatchTo = "current")
/* package */ native void syncPauseCompositor();
// UI thread resumes compositor and notifies Gecko thread; does not block UI thread.
@WrapForJNI(calledFrom = "ui", dispatchTo = "proxy")
/* package */ native void syncResumeResizeCompositor(int width, int height);
@WrapForJNI(calledFrom = "ui", dispatchTo = "current")
/* package */ native void syncResumeResizeCompositor(int width, int height, Object surface);
@WrapForJNI(calledFrom = "any", dispatchTo = "current")
/* package */ native void syncInvalidateAndScheduleComposite();
@WrapForJNI
private Object getSurface() {
synchronized (LayerView.this) {
if (LayerView.this.mServerSurfaceValid) {
return LayerView.this.getSurface();
}
}
return null;
}
@WrapForJNI(calledFrom = "gecko")
private void reattach() {
mCompositorCreated = true;
@ -459,11 +449,9 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener
void serverSurfaceChanged(int newWidth, int newHeight) {
ThreadUtils.assertOnUiThread();
synchronized (this) {
mWidth = newWidth;
mHeight = newHeight;
mServerSurfaceValid = true;
}
mWidth = newWidth;
mHeight = newHeight;
mServerSurfaceValid = true;
updateCompositor();
}
@ -484,7 +472,7 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener
// the compositor resuming, so that Gecko knows that it can now draw.
// It is important to not notify Gecko until after the compositor has
// been resumed, otherwise Gecko may send updates that get dropped.
mCompositor.syncResumeResizeCompositor(mWidth, mHeight);
mCompositor.syncResumeResizeCompositor(mWidth, mHeight, getSurface());
return;
}
@ -493,7 +481,7 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener
// happen without needing to block anywhere.
if (mServerSurfaceValid && getLayerClient().isGeckoReady()) {
mCompositorCreated = true;
mCompositor.createCompositor(mWidth, mHeight);
mCompositor.createCompositor(mWidth, mHeight, getSurface());
}
}
@ -522,7 +510,7 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener
}
if (mCompositorCreated) {
mCompositor.syncResumeResizeCompositor(width, height);
mCompositor.syncResumeResizeCompositor(width, height, getSurface());
}
if (mOverscroll != null) {
@ -561,9 +549,7 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener
mCompositor.syncPauseCompositor();
}
synchronized (this) {
mServerSurfaceValid = false;
}
mServerSurfaceValid = false;
}
private void onDestroyed() {

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

@ -165,10 +165,6 @@ Java_org_mozilla_gecko_GeckoThread_registerUiThread(JNIEnv*, jclass)
sJavaUiThread = pthread_self();
}
#define JNI_STUBS
#include "jni-stubs.inc"
#undef JNI_STUBS
static void * xul_handle = nullptr;
#ifndef MOZ_FOLD_LIBS
static void * sqlite_handle = nullptr;
@ -231,10 +227,6 @@ loadGeckoLibs(const char *apkName)
return FAILURE;
}
#define JNI_BINDINGS
#include "jni-stubs.inc"
#undef JNI_BINDINGS
void (*XRE_StartupTimelineRecord)(int, TimeStamp);
xul_dlsym("XRE_StartupTimelineRecord", &XRE_StartupTimelineRecord);

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

@ -1,457 +0,0 @@
/* WARNING - This file is autogenerated by mobile/android/base/jni-generator.py. Do not edit manually! */
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash_t)(JNIEnv *, jclass, jstring);
static Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash_t f_Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv * arg0, jclass arg1, jstring arg2) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(arg0, arg1, arg2);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash", &f_Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited_t)(JNIEnv *, jclass, jstring);
static Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited_t f_Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited(JNIEnv * arg0, jclass arg1, jstring arg2) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited(arg0, arg1, arg2);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited", &f_Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_syncNotifyObservers_t)(JNIEnv *, jclass, jstring, jstring);
static Java_org_mozilla_gecko_GeckoAppShell_syncNotifyObservers_t f_Java_org_mozilla_gecko_GeckoAppShell_syncNotifyObservers;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoAppShell_syncNotifyObservers(JNIEnv * arg0, jclass arg1, jstring arg2, jstring arg3) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_syncNotifyObservers) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_syncNotifyObservers(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_syncNotifyObservers", &f_Java_org_mozilla_gecko_GeckoAppShell_syncNotifyObservers);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_nativeNotifyObservers_t)(JNIEnv *, jclass, jstring, jstring);
static Java_org_mozilla_gecko_GeckoAppShell_nativeNotifyObservers_t f_Java_org_mozilla_gecko_GeckoAppShell_nativeNotifyObservers;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoAppShell_nativeNotifyObservers(JNIEnv * arg0, jclass arg1, jstring arg2, jstring arg3) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_nativeNotifyObservers) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_nativeNotifyObservers(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_nativeNotifyObservers", &f_Java_org_mozilla_gecko_GeckoAppShell_nativeNotifyObservers);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onSensorChanged_t)(JNIEnv *, jclass, jint, jfloat, jfloat, jfloat, jfloat, jint, jlong);
static Java_org_mozilla_gecko_GeckoAppShell_onSensorChanged_t f_Java_org_mozilla_gecko_GeckoAppShell_onSensorChanged;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoAppShell_onSensorChanged(JNIEnv * arg0, jclass arg1, jint arg2, jfloat arg3, jfloat arg4, jfloat arg5, jfloat arg6, jint arg7, jlong arg8) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_onSensorChanged) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_onSensorChanged(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_onSensorChanged", &f_Java_org_mozilla_gecko_GeckoAppShell_onSensorChanged);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onLocationChanged_t)(JNIEnv *, jclass, jdouble, jdouble, jdouble, jfloat, jfloat, jfloat, jlong);
static Java_org_mozilla_gecko_GeckoAppShell_onLocationChanged_t f_Java_org_mozilla_gecko_GeckoAppShell_onLocationChanged;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoAppShell_onLocationChanged(JNIEnv * arg0, jclass arg1, jdouble arg2, jdouble arg3, jdouble arg4, jfloat arg5, jfloat arg6, jfloat arg7, jlong arg8) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_onLocationChanged) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_onLocationChanged(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_onLocationChanged", &f_Java_org_mozilla_gecko_GeckoAppShell_onLocationChanged);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_notifyAlertListener_t)(JNIEnv *, jclass, jstring, jstring);
static Java_org_mozilla_gecko_GeckoAppShell_notifyAlertListener_t f_Java_org_mozilla_gecko_GeckoAppShell_notifyAlertListener;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoAppShell_notifyAlertListener(JNIEnv * arg0, jclass arg1, jstring arg2, jstring arg3) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_notifyAlertListener) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_notifyAlertListener(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_notifyAlertListener", &f_Java_org_mozilla_gecko_GeckoAppShell_notifyAlertListener);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden_t)(JNIEnv *, jclass, jobject);
static Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden_t f_Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden(JNIEnv * arg0, jclass arg1, jobject arg2) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden(arg0, arg1, arg2);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden", &f_Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge_t)(JNIEnv *, jclass, jbyteArray);
static Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge_t f_Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge(JNIEnv * arg0, jclass arg1, jbyteArray arg2) {
if (!f_Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge(arg0, arg1, arg2);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge", &f_Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge);
#endif
#ifdef JNI_STUBS
typedef jdouble (*Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime_t)(JNIEnv *, jclass);
static Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime_t f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime;
extern "C" NS_EXPORT jdouble MOZ_JNICALL
Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv * arg0, jclass arg1) {
if (!f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return 0;
}
return f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(arg0, arg1);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime", &f_Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived_t)(JNIEnv *, jclass, jint, jstring, jstring, jint, jlong, jlong);
static Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived(JNIEnv * arg0, jclass arg1, jint arg2, jstring arg3, jstring arg4, jint arg5, jlong arg6, jlong arg7) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent_t)(JNIEnv *, jclass, jint, jstring, jstring, jlong, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent(JNIEnv * arg0, jclass arg1, jint arg2, jstring arg3, jstring arg4, jlong arg5, jint arg6) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery_t)(JNIEnv *, jclass, jint, jint, jstring, jstring, jlong);
static Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery(JNIEnv * arg0, jclass arg1, jint arg2, jint arg3, jstring arg4, jstring arg5, jlong arg6) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed_t)(JNIEnv *, jclass, jint, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed(JNIEnv * arg0, jclass arg1, jint arg2, jint arg3) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms_t)(JNIEnv *, jclass, jint, jint, jstring, jstring, jstring, jlong, jboolean, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms(JNIEnv * arg0, jclass arg1, jint arg2, jint arg3, jstring arg4, jstring arg5, jstring arg6, jlong arg7, jboolean arg8, jint arg9) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed_t)(JNIEnv *, jclass, jint, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed(JNIEnv * arg0, jclass arg1, jint arg2, jint arg3) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted_t)(JNIEnv *, jclass, jboolean, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted(JNIEnv * arg0, jclass arg1, jboolean arg2, jint arg3) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed_t)(JNIEnv *, jclass, jint, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed(JNIEnv * arg0, jclass arg1, jint arg2, jint arg3) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkedAsRead_t)(JNIEnv *, jclass, jboolean, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkedAsRead_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkedAsRead;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkedAsRead(JNIEnv * arg0, jclass arg1, jboolean arg2, jint arg3) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkedAsRead) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkedAsRead(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkedAsRead", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkedAsRead);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkAsReadFailed_t)(JNIEnv *, jclass, jint, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkAsReadFailed_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkAsReadFailed;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkAsReadFailed(JNIEnv * arg0, jclass arg1, jint arg2, jint arg3) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkAsReadFailed) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkAsReadFailed(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkAsReadFailed", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifySmsMarkAsReadFailed);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorError_t)(JNIEnv *, jclass, jint, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorError_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorError;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorError(JNIEnv * arg0, jclass arg1, jint arg2, jint arg3) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorError) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorError(arg0, arg1, arg2, arg3);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorError", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorError);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifyThreadCursorResult_t)(JNIEnv *, jclass, jlong, jstring, jstring, jlong, jobjectArray, jlong, jstring, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifyThreadCursorResult_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifyThreadCursorResult;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifyThreadCursorResult(JNIEnv * arg0, jclass arg1, jlong arg2, jstring arg3, jstring arg4, jlong arg5, jobjectArray arg6, jlong arg7, jstring arg8, jint arg9) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifyThreadCursorResult) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifyThreadCursorResult(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifyThreadCursorResult", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifyThreadCursorResult);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifyMessageCursorResult_t)(JNIEnv *, jclass, jint, jint, jstring, jstring, jstring, jlong, jlong, jboolean, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifyMessageCursorResult_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifyMessageCursorResult;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifyMessageCursorResult(JNIEnv * arg0, jclass arg1, jint arg2, jint arg3, jstring arg4, jstring arg5, jstring arg6, jlong arg7, jlong arg8, jboolean arg9, jint arg10) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifyMessageCursorResult) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifyMessageCursorResult(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifyMessageCursorResult", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifyMessageCursorResult);
#endif
#ifdef JNI_STUBS
typedef void (*Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorDone_t)(JNIEnv *, jclass, jint);
static Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorDone_t f_Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorDone;
extern "C" NS_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorDone(JNIEnv * arg0, jclass arg1, jint arg2) {
if (!f_Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorDone) {
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
"JNI Function called before it was loaded");
return ;
}
f_Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorDone(arg0, arg1, arg2);
}
#endif
#ifdef JNI_BINDINGS
xul_dlsym("Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorDone", &f_Java_org_mozilla_gecko_GeckoSmsManager_notifyCursorDone);
#endif

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

@ -18,12 +18,10 @@ namespace net {
NS_IMPL_ISUPPORTS(LoadContextInfo, nsILoadContextInfo)
LoadContextInfo::LoadContextInfo(bool aIsPrivate, bool aIsAnonymous, NeckoOriginAttributes aOriginAttributes)
: mIsPrivate(aIsPrivate)
, mIsAnonymous(aIsAnonymous)
LoadContextInfo::LoadContextInfo(bool aIsAnonymous, NeckoOriginAttributes aOriginAttributes)
: mIsAnonymous(aIsAnonymous)
, mOriginAttributes(aOriginAttributes)
{
mOriginAttributes.SyncAttributesWithPrivateBrowsing(mIsPrivate);
}
LoadContextInfo::~LoadContextInfo()
@ -32,7 +30,7 @@ LoadContextInfo::~LoadContextInfo()
NS_IMETHODIMP LoadContextInfo::GetIsPrivate(bool *aIsPrivate)
{
*aIsPrivate = mIsPrivate;
*aIsPrivate = mOriginAttributes.mPrivateBrowsingId > 0;
return NS_OK;
}
@ -62,7 +60,7 @@ NS_IMPL_ISUPPORTS(LoadContextInfoFactory, nsILoadContextInfoFactory)
NS_IMETHODIMP LoadContextInfoFactory::GetDefault(nsILoadContextInfo * *aDefault)
{
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(false, false, NeckoOriginAttributes());
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(false, NeckoOriginAttributes());
info.forget(aDefault);
return NS_OK;
}
@ -70,20 +68,20 @@ NS_IMETHODIMP LoadContextInfoFactory::GetDefault(nsILoadContextInfo * *aDefault)
NS_IMETHODIMP LoadContextInfoFactory::GetPrivate(nsILoadContextInfo * *aPrivate)
{
NeckoOriginAttributes attrs;
attrs.SyncAttributesWithPrivateBrowsing(aPrivate);
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(true, false, attrs);
attrs.SyncAttributesWithPrivateBrowsing(true);
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(false, attrs);
info.forget(aPrivate);
return NS_OK;
}
NS_IMETHODIMP LoadContextInfoFactory::GetAnonymous(nsILoadContextInfo * *aAnonymous)
{
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(false, true, NeckoOriginAttributes());
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(true, NeckoOriginAttributes());
info.forget(aAnonymous);
return NS_OK;
}
NS_IMETHODIMP LoadContextInfoFactory::Custom(bool aPrivate, bool aAnonymous,
NS_IMETHODIMP LoadContextInfoFactory::Custom(bool aAnonymous,
JS::HandleValue aOriginAttributes, JSContext *cx,
nsILoadContextInfo * *_retval)
{
@ -91,7 +89,7 @@ NS_IMETHODIMP LoadContextInfoFactory::Custom(bool aPrivate, bool aAnonymous,
bool status = attrs.Init(cx, aOriginAttributes);
NS_ENSURE_TRUE(status, NS_ERROR_FAILURE);
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(aPrivate, aAnonymous, attrs);
nsCOMPtr<nsILoadContextInfo> info = GetLoadContextInfo(aAnonymous, attrs);
info.forget(_retval);
return NS_OK;
}
@ -119,7 +117,7 @@ GetLoadContextInfo(nsIChannel * aChannel)
{
nsresult rv;
bool pb = NS_UsePrivateBrowsing(aChannel);
DebugOnly<bool> pb = NS_UsePrivateBrowsing(aChannel);
bool anon = false;
nsLoadFlags loadFlags;
@ -130,28 +128,28 @@ GetLoadContextInfo(nsIChannel * aChannel)
NeckoOriginAttributes oa;
NS_GetOriginAttributes(aChannel, oa);
MOZ_ASSERT(pb == (oa.mPrivateBrowsingId > 0));
return new LoadContextInfo(pb, anon, oa);
return new LoadContextInfo(anon, oa);
}
LoadContextInfo *
GetLoadContextInfo(nsILoadContext *aLoadContext, bool aIsAnonymous)
{
if (!aLoadContext) {
return new LoadContextInfo(false, aIsAnonymous,
return new LoadContextInfo(aIsAnonymous,
NeckoOriginAttributes(nsILoadContextInfo::NO_APP_ID, false));
}
bool pb = aLoadContext->UsePrivateBrowsing();
DebugOnly<bool> pb = aLoadContext->UsePrivateBrowsing();
DocShellOriginAttributes doa;
aLoadContext->GetOriginAttributes(doa);
doa.SyncAttributesWithPrivateBrowsing(pb);
MOZ_ASSERT(pb == (doa.mPrivateBrowsingId > 0));
NeckoOriginAttributes noa;
noa.InheritFromDocShellToNecko(doa);
return new LoadContextInfo(pb, aIsAnonymous, noa);
return new LoadContextInfo(aIsAnonymous, noa);
}
LoadContextInfo*
@ -167,18 +165,15 @@ GetLoadContextInfo(nsIDOMWindow *aWindow,
LoadContextInfo *
GetLoadContextInfo(nsILoadContextInfo *aInfo)
{
return new LoadContextInfo(aInfo->IsPrivate(),
aInfo->IsAnonymous(),
return new LoadContextInfo(aInfo->IsAnonymous(),
*aInfo->OriginAttributesPtr());
}
LoadContextInfo *
GetLoadContextInfo(bool const aIsPrivate,
bool const aIsAnonymous,
GetLoadContextInfo(bool const aIsAnonymous,
NeckoOriginAttributes const &aOriginAttributes)
{
return new LoadContextInfo(aIsPrivate,
aIsAnonymous,
return new LoadContextInfo(aIsAnonymous,
aOriginAttributes);
}

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

@ -19,13 +19,12 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSILOADCONTEXTINFO
LoadContextInfo(bool aIsPrivate, bool aIsAnonymous, NeckoOriginAttributes aOriginAttributes);
LoadContextInfo(bool aIsAnonymous, NeckoOriginAttributes aOriginAttributes);
private:
virtual ~LoadContextInfo();
protected:
bool mIsPrivate : 1;
bool mIsAnonymous : 1;
NeckoOriginAttributes mOriginAttributes;
};
@ -53,8 +52,7 @@ LoadContextInfo*
GetLoadContextInfo(nsILoadContextInfo *aInfo);
LoadContextInfo*
GetLoadContextInfo(bool const aIsPrivate,
bool const aIsAnonymous,
GetLoadContextInfo(bool const aIsAnonymous,
NeckoOriginAttributes const &aOriginAttributes);
} // namespace net

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

@ -620,7 +620,7 @@ Predictor::Init()
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<LoadContextInfo> lci =
new LoadContextInfo(false, false, NeckoOriginAttributes());
new LoadContextInfo(false, NeckoOriginAttributes());
rv = cacheStorageService->DiskCacheStorage(lci, false,
getter_AddRefs(mCacheDiskStorage));

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

@ -64,8 +64,7 @@ interface nsILoadContextInfo : nsISupports
bool Equals(nsILoadContextInfo *aOther)
{
return IsPrivate() == aOther->IsPrivate() &&
IsAnonymous() == aOther->IsAnonymous() &&
return IsAnonymous() == aOther->IsAnonymous() &&
*OriginAttributesPtr() == *aOther->OriginAttributesPtr();
}
%}
@ -84,7 +83,7 @@ interface nsILoadContextInfoFactory : nsISupports
readonly attribute nsILoadContextInfo private;
readonly attribute nsILoadContextInfo anonymous;
[implicit_jscontext]
nsILoadContextInfo custom(in boolean aPrivate, in boolean aAnonymous, in jsval aOriginAttributes);
nsILoadContextInfo custom(in boolean aAnonymous, in jsval aOriginAttributes);
nsILoadContextInfo fromLoadContext(in nsILoadContext aLoadContext, in boolean aAnonymous);
nsILoadContextInfo fromWindow(in nsIDOMWindow aWindow, in boolean aAnonymous);
};

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

@ -36,7 +36,6 @@ public:
: Tokenizer(aInput)
// Initialize attributes to their default values
, originAttribs(0, false)
, isPrivate(false)
, isAnonymous(false)
// Initialize the cache key to a zero length by default
, lastTag(0)
@ -46,7 +45,6 @@ public:
private:
// Results
NeckoOriginAttributes originAttribs;
bool isPrivate;
bool isAnonymous;
nsCString idEnhance;
nsDependentCSubstring cacheKey;
@ -92,7 +90,7 @@ private:
break;
}
case 'p':
isPrivate = true;
originAttribs.SyncAttributesWithPrivateBrowsing(true);
break;
case 'b':
// Leaving to be able to read and understand oldformatted entries
@ -166,7 +164,7 @@ public:
{
RefPtr<LoadContextInfo> info;
if (ParseTags()) {
info = GetLoadContextInfo(isPrivate, isAnonymous, originAttribs);
info = GetLoadContextInfo(isAnonymous, originAttribs);
}
return info.forget();

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

@ -410,11 +410,12 @@ namespace CacheStorageEvictHelper {
nsresult ClearStorage(bool const aPrivate,
bool const aAnonymous,
NeckoOriginAttributes const &aOa)
NeckoOriginAttributes &aOa)
{
nsresult rv;
RefPtr<LoadContextInfo> info = GetLoadContextInfo(aPrivate, aAnonymous, aOa);
aOa.SyncAttributesWithPrivateBrowsing(aPrivate);
RefPtr<LoadContextInfo> info = GetLoadContextInfo(aAnonymous, aOa);
nsCOMPtr<nsICacheStorage> storage;
RefPtr<CacheStorageService> service = CacheStorageService::Self();
@ -435,7 +436,7 @@ nsresult ClearStorage(bool const aPrivate,
return NS_OK;
}
nsresult Run(NeckoOriginAttributes const &aOa)
nsresult Run(NeckoOriginAttributes &aOa)
{
nsresult rv;

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

@ -90,7 +90,7 @@ CookieServiceParent::GetOriginAttributesFromParams(const IPC::SerializedLoadCont
}
if (aLoadContext.IsPrivateBitValid()) {
aIsPrivate = aLoadContext.mUsePrivateBrowsing;
aIsPrivate = aLoadContext.mOriginAttributes.mPrivateBrowsingId > 0;
}
aAttrs.InheritFromDocShellToNecko(docShellAttrs);

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

@ -99,7 +99,7 @@ static PBOverrideStatus
PBOverrideStatusFromLoadContext(const SerializedLoadContext& aSerialized)
{
if (!aSerialized.IsNotNull() && aSerialized.IsPrivateBitValid()) {
return aSerialized.mUsePrivateBrowsing ?
return (aSerialized.mOriginAttributes.mPrivateBrowsingId > 0) ?
kPBOverride_Private :
kPBOverride_NotPrivate;
}
@ -184,7 +184,7 @@ NeckoParent::CreateChannelLoadContext(const PBrowserOrId& aBrowser,
// if !UsingNeckoIPCSecurity(), we may not have a LoadContext to set. This is
// the common case for most xpcshell tests.
if (aSerialized.IsNotNull()) {
attrs.SyncAttributesWithPrivateBrowsing(aSerialized.mUsePrivateBrowsing);
attrs.SyncAttributesWithPrivateBrowsing(aSerialized.mOriginAttributes.mPrivateBrowsingId > 0);
switch (aBrowser.type()) {
case PBrowserOrId::TPBrowserParent:
{
@ -825,7 +825,7 @@ NeckoParent::RecvPredPredict(const ipc::OptionalURIParams& aTargetURI,
DocShellOriginAttributes attrs(NECKO_UNKNOWN_APP_ID, false);
nsCOMPtr<nsILoadContext> loadContext;
if (aLoadContext.IsNotNull()) {
attrs.SyncAttributesWithPrivateBrowsing(aLoadContext.mUsePrivateBrowsing);
attrs.SyncAttributesWithPrivateBrowsing(aLoadContext.mOriginAttributes.mPrivateBrowsingId > 0);
loadContext = new LoadContext(aLoadContext, nestedFrameId, attrs);
}
@ -858,7 +858,7 @@ NeckoParent::RecvPredLearn(const ipc::URIParams& aTargetURI,
DocShellOriginAttributes attrs(NECKO_UNKNOWN_APP_ID, false);
nsCOMPtr<nsILoadContext> loadContext;
if (aLoadContext.IsNotNull()) {
attrs.SyncAttributesWithPrivateBrowsing(aLoadContext.mUsePrivateBrowsing);
attrs.SyncAttributesWithPrivateBrowsing(aLoadContext.mOriginAttributes.mPrivateBrowsingId > 0);
loadContext = new LoadContext(aLoadContext, nestedFrameId, attrs);
}

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

@ -3,26 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CameraStreamImpl.h"
#include "GeneratedJNINatives.h"
#include "nsCRTGlue.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
#include "mozilla/Monitor.h"
/**
* JNI part & helper runnable
*/
extern "C" {
NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge(JNIEnv *, jclass, jbyteArray data);
}
NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge(JNIEnv *env, jclass, jbyteArray data) {
mozilla::net::CameraStreamImpl* impl = mozilla::net::CameraStreamImpl::GetInstance(0);
impl->transmitFrame(env, &data);
}
using namespace mozilla;
namespace mozilla {
@ -31,20 +17,40 @@ namespace net {
static CameraStreamImpl* mCamera0 = nullptr;
static CameraStreamImpl* mCamera1 = nullptr;
class CameraStreamImpl::Callback
: public java::GeckoAppShell::CameraCallback::Natives<Callback>
{
public:
static void OnFrameData(int32_t aCamera, jni::ByteArray::Param aData)
{
MOZ_ASSERT(NS_IsMainThread());
CameraStreamImpl* impl = GetInstance(uint32_t(aCamera));
if (impl) {
impl->TransmitFrame(aData);
}
}
};
/**
* CameraStreamImpl
*/
void CameraStreamImpl::transmitFrame(JNIEnv *env, jbyteArray *data) {
if (!mCallback)
return;
jboolean isCopy;
jbyte* jFrame = env->GetByteArrayElements(*data, &isCopy);
uint32_t length = env->GetArrayLength(*data);
if (length > 0) {
mCallback->ReceiveFrame((char*)jFrame, length);
void CameraStreamImpl::TransmitFrame(jni::ByteArray::Param aData) {
if (!mCallback) {
return;
}
env->ReleaseByteArrayElements(*data, jFrame, 0);
JNIEnv* const env = jni::GetGeckoThreadEnv();
const size_t length = size_t(env->GetArrayLength(aData.Get()));
if (!length) {
return;
}
jbyte* const data = env->GetByteArrayElements(aData.Get(), nullptr);
mCallback->ReceiveFrame(reinterpret_cast<char*>(data), length);
env->ReleaseByteArrayElements(aData.Get(), data, JNI_ABORT);
}
CameraStreamImpl* CameraStreamImpl::GetInstance(uint32_t aCamera) {
@ -86,7 +92,17 @@ bool CameraStreamImpl::Init(const nsCString& contentType, const uint32_t& camera
mCallback = aCallback;
mWidth = width;
mHeight = height;
return AndroidBridge::Bridge()->InitCamera(contentType, camera, &mWidth, &mHeight, &mFps);
Callback::Init();
jni::IntArray::LocalRef retArray = java::GeckoAppShell::InitCamera(
contentType, int32_t(camera), int32_t(width), int32_t(height));
nsTArray<int32_t> ret = retArray->GetElements();
mWidth = uint32_t(ret[1]);
mHeight = uint32_t(ret[2]);
mFps = uint32_t(ret[3]);
return !!ret[0];
}
void CameraStreamImpl::Close() {

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

@ -5,8 +5,9 @@
#ifndef __CAMERASTREAMIMPL_H__
#define __CAMERASTREAMIMPL_H__
#include "mozilla/jni/Refs.h"
#include "nsString.h"
#include "AndroidBridge.h"
/**
* This singleton class handles communication with the Android camera
@ -15,45 +16,47 @@
namespace mozilla {
namespace net {
class CameraStreamImpl {
public:
class FrameCallback {
public:
virtual void ReceiveFrame(char* frame, uint32_t length) = 0;
};
/**
* instance bound to a given camera
*/
static CameraStreamImpl* GetInstance(uint32_t aCamera);
bool initNeeded() {
return !mInit;
}
FrameCallback* GetFrameCallback() {
return mCallback;
}
bool Init(const nsCString& contentType, const uint32_t& camera, const uint32_t& width, const uint32_t& height, FrameCallback* callback);
void Close();
uint32_t GetWidth() { return mWidth; }
uint32_t GetHeight() { return mHeight; }
uint32_t GetFps() { return mFps; }
void takePicture(const nsAString& aFileName);
void transmitFrame(JNIEnv *env, jbyteArray *data);
private:
class Callback;
CameraStreamImpl(uint32_t aCamera);
CameraStreamImpl(const CameraStreamImpl&);
CameraStreamImpl& operator=(const CameraStreamImpl&);
~CameraStreamImpl();
void TransmitFrame(jni::ByteArray::Param aData);
bool mInit;
uint32_t mCamera;
uint32_t mWidth;

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

@ -144,7 +144,7 @@ WyciwygChannelParent::SetupAppData(const IPC::SerializedLoadContext& loadContext
if (!mLoadContext && loadContext.IsPrivateBitValid()) {
nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(mChannel);
if (pbChannel)
pbChannel->SetPrivate(loadContext.mUsePrivateBrowsing);
pbChannel->SetPrivate(loadContext.mOriginAttributes.mPrivateBrowsingId > 0);
}
mReceivedAppData = true;

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

@ -788,8 +788,8 @@ nsWyciwygChannel::OpenCacheEntry(nsIURI *aURI,
NS_ENSURE_SUCCESS(rv, rv);
bool anonymous = mLoadFlags & LOAD_ANONYMOUS;
RefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo(
mPrivateBrowsing, anonymous, mOriginAttributes);
mOriginAttributes.SyncAttributesWithPrivateBrowsing(mPrivateBrowsing);
RefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo(anonymous, mOriginAttributes);
nsCOMPtr<nsICacheStorage> cacheStorage;
if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)

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

@ -43,7 +43,7 @@ CacheCallback.prototype = {
};
function checkCacheEntry(url, exists, appId) {
var loadContext = appId ? LoadContextInfo.custom(false, false, {appId: appId}) : LoadContextInfo.default;
var loadContext = appId ? LoadContextInfo.custom(false, {appId: appId}) : LoadContextInfo.default;
var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
.getService(Ci.nsICacheStorageService);
var cache = cacheService.diskCacheStorage(loadContext, false);

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

@ -47,7 +47,8 @@ function store_entries(cb)
asyncOpenCacheEntry(entries[store_idx][0],
entries[store_idx][2],
Ci.nsICacheStorage.OPEN_TRUNCATE,
LoadContextInfo.custom(!entries[store_idx][3], false, {}),
LoadContextInfo.custom(false,
{privateBrowsingId : entries[store_idx][3] ? 0 : 1}),
store_data,
appCache);
}
@ -87,7 +88,8 @@ function check_entries(cb, pbExited)
asyncOpenCacheEntry(entries[check_idx][0],
entries[check_idx][2],
Ci.nsICacheStorage.OPEN_READONLY,
LoadContextInfo.custom(!entries[check_idx][3], false, {}),
LoadContextInfo.custom(false,
{privateBrowsingId : entries[check_idx][3] ? 0 : 1}),
check_data,
appCache);
}

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

@ -115,8 +115,9 @@ nsHTMLEntities::AddRefTable(void)
void
nsHTMLEntities::ReleaseTable(void)
{
if (--gTableRefCnt != 0)
if (--gTableRefCnt != 0) {
return;
}
delete gEntityToUnicode;
delete gUnicodeToEntity;
@ -128,17 +129,18 @@ int32_t
nsHTMLEntities::EntityToUnicode(const nsCString& aEntity)
{
NS_ASSERTION(gEntityToUnicode, "no lookup table, needs addref");
if (!gEntityToUnicode)
if (!gEntityToUnicode) {
return -1;
}
//this little piece of code exists because entities may or may not have the terminating ';'.
//if we see it, strip if off for this test...
//this little piece of code exists because entities may or may not have the terminating ';'.
//if we see it, strip if off for this test...
if(';'==aEntity.Last()) {
nsAutoCString temp(aEntity);
temp.Truncate(aEntity.Length()-1);
return EntityToUnicode(temp);
}
if(';'==aEntity.Last()) {
nsAutoCString temp(aEntity);
temp.Truncate(aEntity.Length()-1);
return EntityToUnicode(temp);
}
auto entry =
static_cast<EntityNodeEntry*>(gEntityToUnicode->Search(aEntity.get()));

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

@ -14,4 +14,6 @@ config = {
"ignore_no_changes": True,
"ssh_user": "ffxbld",
"ssh_key": "~/.ssh/ffxbld_rsa",
"ship_it_root": "https://ship-it-dev.allizom.org",
"ship_it_username": "stage-ffxbld",
}

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

@ -16,4 +16,6 @@ config = {
"ignore_no_changes": True,
"ssh_user": "ffxbld",
"ssh_key": "~/.ssh/ffxbld_rsa",
"ship_it_root": "https://ship-it-dev.allizom.org",
"ship_it_username": "stage-ffxbld",
}

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

@ -12,4 +12,6 @@ config = {
"ignore_no_changes": True,
"ssh_user": "ffxbld",
"ssh_key": "~/.ssh/ffxbld_rsa",
"ship_it_root": "https://ship-it.mozilla.org",
"ship_it_username": "ffxbld",
}

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

@ -16,4 +16,6 @@ config = {
"ignore_no_changes": True,
"ssh_user": "ffxbld",
"ssh_key": "~/.ssh/ffxbld_rsa",
"ship_it_root": "https://ship-it.mozilla.org",
"ship_it_username": "ffxbld",
}

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

@ -16,4 +16,6 @@ config = {
"ignore_no_changes": True,
"ssh_user": "ffxbld",
"ssh_key": "~/.ssh/ffxbld_rsa",
"ship_it_root": "https://ship-it.mozilla.org",
"ship_it_username": "ffxbld",
}

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

@ -0,0 +1,110 @@
#!/usr/bin/env python
# lint_ignore=E501
# ***** BEGIN LICENSE BLOCK *****
# 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/.
# ***** END LICENSE BLOCK *****
""" postrelease_mark_as_shipped.py
A script to automate the manual way of updating a release as shipped in Ship-it
following its successful ship-to-the-door opertion.
"""
import os
import sys
from datetime import datetime
sys.path.insert(1, os.path.dirname(os.path.dirname(sys.path[0])))
from mozharness.base.python import VirtualenvMixin, virtualenv_config_options
from mozharness.base.script import BaseScript
from mozharness.mozilla.buildbot import BuildbotMixin
def build_release_name(product, version, buildno):
"""Function to reconstruct the name of the release based on product,
version and buildnumber
"""
return "{}-{}-build{}".format(product.capitalize(),
str(version), str(buildno))
class MarkReleaseAsShipped(BaseScript, VirtualenvMixin, BuildbotMixin):
config_options = virtualenv_config_options
def __init__(self, require_config_file=True):
super(MarkReleaseAsShipped, self).__init__(
config_options=self.config_options,
require_config_file=require_config_file,
config={
"virtualenv_modules": [
"shipitapi",
],
"virtualenv_path": "venv",
"credentials_file": "oauth.txt",
"buildbot_json_path": "buildprops.json",
"timeout": 60,
},
all_actions=[
"create-virtualenv",
"activate-virtualenv",
"mark-as-shipped",
],
default_actions=[
"create-virtualenv",
"activate-virtualenv",
"mark-as-shipped",
],
)
def _pre_config_lock(self, rw_config):
super(MarkReleaseAsShipped, self)._pre_config_lock(rw_config)
# override properties from buildbot properties here as defined by
# taskcluster properties
self.read_buildbot_config()
if not self.buildbot_config:
self.warning("Skipping buildbot properties overrides")
return
props = self.buildbot_config['properties']
mandatory_props = ['product', 'version', 'buildnumber']
missing_props = []
for prop in mandatory_props:
if props.get(prop):
self.info("Overriding %s with %s" % (prop, props[prop]))
self.config[prop] = props.get(prop)
else:
self.warning("%s could not be found within buildprops" % prop)
missing_props.append(prop)
if missing_props:
raise Exception("%s not found in configs" % missing_props)
self.config['name'] = build_release_name(self.config['product'],
self.config['version'],
self.config['buildnumber'])
def mark_as_shipped(self):
"""Method to make a simple call to Ship-it API to change a release
status to 'shipped'
"""
credentials_file = os.path.join(os.getcwd(),
self.config["credentials_file"])
credentials = {}
execfile(credentials_file, credentials)
ship_it_credentials = credentials["ship_it_credentials"]
auth = (self.config["ship_it_username"],
ship_it_credentials.get(self.config["ship_it_username"]))
api_root = self.config['ship_it_root']
from shipitapi import Release
release_api = Release(auth, api_root=api_root,
timeout=self.config['timeout'])
shipped_at = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
self.info("Mark the release as shipped with %s timestamp" % shipped_at)
release_api.update(self.config['name'],
status='shipped', shippedAt=shipped_at)
if __name__ == '__main__':
MarkReleaseAsShipped().run_and_exit()

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

@ -13,6 +13,7 @@
#include "nsIServiceManager.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsITreeBoxObject.h"
#include "nsITreeColumns.h"
#include "nsIObserverService.h"
@ -1201,6 +1202,14 @@ nsAutoCompleteController::StartSearch(uint16_t aSearchType)
searchParam.AppendLiteral(" prohibit-autofill");
}
uint32_t userContextId;
rv = input->GetUserContextId(&userContextId);
if (NS_SUCCEEDED(rv) &&
userContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
searchParam.AppendLiteral(" user-context-id:");
searchParam.AppendInt(userContextId, 10);
}
rv = search->StartSearch(mSearchString, searchParam, result, static_cast<nsIAutoCompleteObserver *>(this));
if (NS_FAILED(rv)) {
++mSearchesFailed;

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

@ -154,4 +154,9 @@ interface nsIAutoCompleteInput : nsISupports
* Don't rollup the popup when the caret is moved.
*/
readonly attribute boolean noRollupOnCaretMove;
/**
* The userContextId of the current browser.
*/
readonly attribute unsigned long userContextId;
};

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

@ -5,6 +5,7 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
/**
* Dummy nsIAutoCompleteInput source that returns

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

@ -0,0 +1,45 @@
"use strict";
Cu.import("resource://gre/modules/Promise.jsm");
function AutoCompleteInput(aSearches, aUserContextId) {
this.searches = aSearches;
this.userContextId = aUserContextId;
this.popup.selectedIndex = -1;
}
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
function AutoCompleteSearch(aName) {
this.name = aName;
}
AutoCompleteSearch.prototype = Object.create(AutoCompleteSearchBase.prototype);
add_task(function *test_userContextId() {
let searchParam = yield doSearch("test", 1);
Assert.equal(searchParam, " user-context-id:1");
});
function doSearch(aString, aUserContextId) {
let deferred = Promise.defer();
let search = new AutoCompleteSearch("test");
search.startSearch = function (aSearchString,
aSearchParam,
aPreviousResult,
aListener) {
unregisterAutoCompleteSearch(search);
deferred.resolve(aSearchParam);
};
registerAutoCompleteSearch(search);
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
getService(Ci.nsIAutoCompleteController);
let input = new AutoCompleteInput([ search.name ], aUserContextId);
controller.input = input;
controller.startSearch(aString);
return deferred.promise;
}

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

@ -10,6 +10,7 @@ skip-if = toolkit == 'gonk'
[test_463023.js]
[test_660156.js]
[test_autocomplete_multiple.js]
[test_autocomplete_userContextId.js]
[test_autofillSelectedPopupIndex.js]
[test_badDefaultIndex.js]
[test_completeDefaultIndex_casing.js]

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