зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
a1c780edbb
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1289951 maybe needed a clobber to fix xpcshell tests?
|
||||
Bug 1287426 - Clobber required because of Linux Chromium sandbox file moves.
|
||||
|
|
|
@ -526,6 +526,8 @@ pref("privacy.sanitize.migrateFx3Prefs", false);
|
|||
|
||||
pref("privacy.panicButton.enabled", true);
|
||||
|
||||
pref("privacy.firstparty.isolate", false);
|
||||
|
||||
pref("network.proxy.share_proxy_settings", false); // use the same proxy settings for all protocols
|
||||
|
||||
// simple gestures support
|
||||
|
|
|
@ -2,9 +2,23 @@
|
|||
skip-if = buildapp == "mulet"
|
||||
tags = usercontextid firstpartyisolation originattributes
|
||||
support-files =
|
||||
dummy.html
|
||||
file_firstPartyBasic.html
|
||||
head.js
|
||||
test.js
|
||||
test.js^headers^
|
||||
test.html
|
||||
test2.html
|
||||
test2.js
|
||||
test2.js^headers^
|
||||
test_firstParty.html
|
||||
test_firstParty_cookie.html
|
||||
test_firstParty_html_redirect.html
|
||||
test_firstParty_http_redirect.html
|
||||
test_firstParty_http_redirect.html^headers^
|
||||
test_firstParty_iframe_http_redirect.html
|
||||
test_firstParty_postMessage.html
|
||||
window.html
|
||||
|
||||
[browser_dummy.js]
|
||||
skip-if = true
|
||||
[browser_firstPartyIsolation.js]
|
||||
[browser_localStorageIsolation.js]
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* This is a dummy test case which makes this could be built.
|
||||
* Should be removed after actual tests landed.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
ok(true, "Make this test pass anyway.");
|
||||
});
|
|
@ -0,0 +1,174 @@
|
|||
const BASE_URL = "http://mochi.test:8888/browser/browser/components/originattributes/test/browser/";
|
||||
const BASE_DOMAIN = "mochi.test";
|
||||
|
||||
add_task(function* setup() {
|
||||
Services.prefs.setBoolPref("privacy.firstparty.isolate", true);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("privacy.firstparty.isolate");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for the top-level document and child iframes should have the
|
||||
* firstPartyDomain attribute.
|
||||
*/
|
||||
add_task(function* principal_test() {
|
||||
let tab = gBrowser.addTab(BASE_URL + "test_firstParty.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser, true, function (url) {
|
||||
return url == BASE_URL + "test_firstParty.html";
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, { firstPartyDomain: BASE_DOMAIN }, function* (attrs) {
|
||||
info("document principal: " + content.document.nodePrincipal.origin);
|
||||
Assert.equal(docShell.getOriginAttributes().firstPartyDomain, "",
|
||||
"top-level docShell shouldn't have firstPartyDomain attribute.");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The document should have firstPartyDomain");
|
||||
|
||||
for (let i = 1; i < 4; i++) {
|
||||
let iframe = content.document.getElementById("iframe" + i);
|
||||
info("iframe principal: " + iframe.contentDocument.nodePrincipal.origin);
|
||||
Assert.equal(iframe.frameLoader.docShell.getOriginAttributes().firstPartyDomain,
|
||||
attrs.firstPartyDomain, "iframe's docshell should have firstPartyDomain");
|
||||
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "iframe should have firstPartyDomain");
|
||||
}
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for the cookie jars of the top-level document and child iframe should be
|
||||
* isolated by firstPartyDomain.
|
||||
*/
|
||||
add_task(function* cookie_test() {
|
||||
let tab = gBrowser.addTab(BASE_URL + "test_firstParty_cookie.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser, true);
|
||||
|
||||
let iter = Services.cookies.enumerator;
|
||||
let count = 0;
|
||||
while (iter.hasMoreElements()) {
|
||||
count++;
|
||||
let cookie = iter.getNext().QueryInterface(Ci.nsICookie2);
|
||||
Assert.equal(cookie.value, "foo", "Cookie value should be foo");
|
||||
Assert.equal(cookie.originAttributes.firstPartyDomain, BASE_DOMAIN, "Cookie's origin attributes should be " + BASE_DOMAIN);
|
||||
}
|
||||
|
||||
// one cookie is from requesting test.js from top-level doc, and the other from
|
||||
// requesting test2.js from iframe test2.html.
|
||||
Assert.equal(count, 2, "Should have two cookies");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for after redirect, the top-level document should update the firstPartyDomain
|
||||
* attribute. However if the redirect is happening on the iframe, the attribute
|
||||
* should remain the same.
|
||||
*/
|
||||
add_task(function* redirect_test() {
|
||||
let tab = gBrowser.addTab(BASE_URL + "test_firstParty_http_redirect.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
yield ContentTask.spawn(tab.linkedBrowser, { firstPartyDomain: "example.com" }, function* (attrs) {
|
||||
info("document principal: " + content.document.nodePrincipal.origin);
|
||||
info("document uri: " + content.document.documentURI);
|
||||
|
||||
Assert.equal(content.document.documentURI, "http://example.com/browser/browser/components/originattributes/test/browser/dummy.html",
|
||||
"The page should have been redirected to http://example.com/browser/browser/components/originattributes/test/browser/dummy.html");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The document should have firstPartyDomain");
|
||||
});
|
||||
|
||||
// Since this is a HTML redirect, we wait until the final page is loaded.
|
||||
let tab2 = gBrowser.addTab(BASE_URL + "test_firstParty_html_redirect.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser, false, function(url) {
|
||||
return url == "http://example.com/";
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(tab2.linkedBrowser, { firstPartyDomain: "example.com" }, function* (attrs) {
|
||||
info("2nd tab document principal: " + content.document.nodePrincipal.origin);
|
||||
info("2nd tab document uri: " + content.document.documentURI);
|
||||
Assert.equal(content.document.documentURI, "http://example.com/",
|
||||
"The page should have been redirected to http://example.com");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The document should have firstPartyDomain");
|
||||
});
|
||||
|
||||
let tab3 = gBrowser.addTab(BASE_URL + "test_firstParty_iframe_http_redirect.html");
|
||||
yield BrowserTestUtils.browserLoaded(tab3.linkedBrowser, true, function(url) {
|
||||
return url == (BASE_URL + "test_firstParty_iframe_http_redirect.html");
|
||||
});
|
||||
|
||||
// This redirect happens on the iframe, so unlike the two redirect tests above,
|
||||
// the firstPartyDomain should still stick to the current top-level document,
|
||||
// which is mochi.test.
|
||||
yield ContentTask.spawn(tab3.linkedBrowser, { firstPartyDomain: "mochi.test" }, function* (attrs) {
|
||||
let iframe = content.document.getElementById("iframe1");
|
||||
info("iframe document principal: " + iframe.contentDocument.nodePrincipal.origin);
|
||||
info("iframe document uri: " + iframe.contentDocument.documentURI);
|
||||
|
||||
Assert.equal(iframe.contentDocument.documentURI, "http://example.com/browser/browser/components/originattributes/test/browser/dummy.html",
|
||||
"The page should have been redirected to http://example.com/browser/browser/components/originattributes/test/browser/dummy.html");
|
||||
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The iframe should have firstPartyDomain: " + attrs.firstPartyDomain);
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab3);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test for postMessage between document and iframe.
|
||||
*/
|
||||
add_task(function* postMessage_test() {
|
||||
let tab = gBrowser.addTab(BASE_URL + "test_firstParty_postMessage.html");
|
||||
|
||||
// The top-level page will post a message to its child iframe, and wait for
|
||||
// another message from the iframe, once it receives the message, it will
|
||||
// create another iframe, dummy.html.
|
||||
// So we wait until dummy.html is loaded
|
||||
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser, true, function (url) {
|
||||
return url == BASE_URL + "dummy.html";
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
|
||||
info("document principal: " + content.document.nodePrincipal.origin);
|
||||
let value = content.document.getElementById("message").textContent;
|
||||
Assert.equal(value, "OK");
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* When the web page calls window.open, the new window should have the same
|
||||
* firstPartyDomain attribute.
|
||||
*/
|
||||
add_task(function* openWindow_test() {
|
||||
Services.prefs.setIntPref("browser.link.open_newwindow", 2);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("browser.link.open_newwindow");
|
||||
});
|
||||
|
||||
let tab = gBrowser.addTab(BASE_URL + "window.html");
|
||||
let win = yield BrowserTestUtils.waitForNewWindow();
|
||||
|
||||
yield ContentTask.spawn(win.gBrowser.selectedBrowser, { firstPartyDomain: "mochi.test" }, function* (attrs) {
|
||||
Assert.equal(docShell.getOriginAttributes().firstPartyDomain, attrs.firstPartyDomain,
|
||||
"window.open() should have firstPartyDomain attribute");
|
||||
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "The document should have firstPartyDomain");
|
||||
|
||||
let iframe = content.document.getElementById("iframe1");
|
||||
Assert.equal(iframe.frameLoader.docShell.getOriginAttributes().firstPartyDomain,
|
||||
attrs.firstPartyDomain, "iframe's docshell should have firstPartyDomain");
|
||||
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
|
||||
attrs.firstPartyDomain, "iframe should have firstPartyDomain");
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
yield BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Dummy test page</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
||||
</head>
|
||||
<body>
|
||||
<p>Dummy test page</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script>
|
||||
window.onmessage = function (evt) {
|
||||
if (evt.data != "HI") {
|
||||
return;
|
||||
}
|
||||
|
||||
window.parent.postMessage("OK", "http://mochi.test:8888");
|
||||
};
|
||||
|
||||
setTimeout(function() {
|
||||
window.parent.postMessage("KO", "http://mochi.test:8888");
|
||||
}, 1000);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
Hello World.
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
var i = 1;
|
|
@ -0,0 +1 @@
|
|||
Set-Cookie: test=foo
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script src="test2.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
Hello World.
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
var i = 1;
|
|
@ -0,0 +1 @@
|
|||
Set-Cookie: test2=foo
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<iframe id="iframe1" src="http://example.com"></iframe>
|
||||
<iframe id="iframe2" sandbox="" src="http://example.com"></iframe>
|
||||
<iframe id="iframe3" sandbox="allow-same-origin" src="http://example.com"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script src="test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
Hello World.
|
||||
<iframe id="iframe1" src="test2.html"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8" http-equiv="refresh" content="0; url=http://example.com/"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,2 @@
|
|||
HTTP 302 Found
|
||||
Location: http://example.com/browser/browser/components/originattributes/test/browser/dummy.html
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<iframe id="iframe1" src="test_firstParty_http_redirect.html"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test for Bug 1260931</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<script>
|
||||
function onload() {
|
||||
let iframe1 = document.getElementById("iframe1");
|
||||
iframe1.contentWindow.postMessage("HI", "http://mochi.test:8888");
|
||||
}
|
||||
|
||||
window.onmessage = function (evt) {
|
||||
document.getElementById("message").textContent = evt.data;
|
||||
|
||||
let iframe2 = document.createElement("iframe");
|
||||
iframe2.src = "dummy.html";
|
||||
document.body.appendChild(iframe2);
|
||||
};
|
||||
</script>
|
||||
<body onload="onload()">
|
||||
<div>
|
||||
<iframe id="iframe1" src="test.html"></iframe>
|
||||
<span id="message"></span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Page creating a popup</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var w = window.open();
|
||||
w.document.body.innerHTML = "<iframe id='iframe1' src='data:text/plain,test2'></iframe>";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -269,6 +269,11 @@ bool isIgnoredPathForImplicitConversion(const Decl *Declaration) {
|
|||
if (Begin->compare_lower(StringRef("graphite2")) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (Begin->compare_lower(StringRef("chromium")) == 0) {
|
||||
// Ignore security/sandbox/chromium but not ipc/chromium.
|
||||
++Begin;
|
||||
return Begin != End && Begin->compare_lower(StringRef("sandbox")) == 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#endif
|
||||
#include "nsIAddonPolicyService.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
|
||||
|
@ -47,6 +48,7 @@ PrincipalOriginAttributes::InheritFromDocShellToDoc(const DocShellOriginAttribut
|
|||
mSignedPkg = aAttrs.mSignedPkg;
|
||||
|
||||
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
|
||||
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -60,6 +62,7 @@ PrincipalOriginAttributes::InheritFromNecko(const NeckoOriginAttributes& aAttrs)
|
|||
mSignedPkg = aAttrs.mSignedPkg;
|
||||
|
||||
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
|
||||
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -77,6 +80,7 @@ DocShellOriginAttributes::InheritFromDocToChildDocShell(const PrincipalOriginAtt
|
|||
mSignedPkg = aAttrs.mSignedPkg;
|
||||
|
||||
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
|
||||
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -93,10 +97,13 @@ NeckoOriginAttributes::InheritFromDocToNecko(const PrincipalOriginAttributes& aA
|
|||
// mSignedPkg accordingly by mSignedPkgInBrowser
|
||||
|
||||
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
|
||||
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
|
||||
}
|
||||
|
||||
void
|
||||
NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs)
|
||||
NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs,
|
||||
const bool aIsTopLevelDocument,
|
||||
nsIURI* aURI)
|
||||
{
|
||||
mAppId = aAttrs.mAppId;
|
||||
mInIsolatedMozBrowser = aAttrs.mInIsolatedMozBrowser;
|
||||
|
@ -109,6 +116,24 @@ NeckoOriginAttributes::InheritFromDocShellToNecko(const DocShellOriginAttributes
|
|||
// mSignedPkg accordingly by mSignedPkgInBrowser
|
||||
|
||||
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
|
||||
|
||||
bool isFirstPartyEnabled = IsFirstPartyEnabled();
|
||||
|
||||
// When the pref is on, we also compute the firstPartyDomain attribute
|
||||
// if this is for top-level document.
|
||||
if (isFirstPartyEnabled && aIsTopLevelDocument) {
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(tldService);
|
||||
if (!tldService) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString baseDomain;
|
||||
tldService->GetBaseDomain(aURI, 0, baseDomain);
|
||||
mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
|
||||
} else {
|
||||
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -161,6 +186,11 @@ OriginAttributes::CreateSuffix(nsACString& aStr) const
|
|||
params->Set(NS_LITERAL_STRING("privateBrowsingId"), value);
|
||||
}
|
||||
|
||||
if (!mFirstPartyDomain.IsEmpty()) {
|
||||
MOZ_RELEASE_ASSERT(mFirstPartyDomain.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound);
|
||||
params->Set(NS_LITERAL_STRING("firstPartyDomain"), mFirstPartyDomain);
|
||||
}
|
||||
|
||||
aStr.Truncate();
|
||||
|
||||
params->Serialize(value);
|
||||
|
@ -247,6 +277,12 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
if (aName.EqualsLiteral("firstPartyDomain")) {
|
||||
MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty());
|
||||
mOriginAttributes->mFirstPartyDomain.Assign(aValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
// No other attributes are supported.
|
||||
return false;
|
||||
}
|
||||
|
@ -307,6 +343,21 @@ OriginAttributes::SetFromGenericAttributes(const GenericOriginAttributes& aAttrs
|
|||
mUserContextId = aAttrs.mUserContextId;
|
||||
mSignedPkg = aAttrs.mSignedPkg;
|
||||
mPrivateBrowsingId = aAttrs.mPrivateBrowsingId;
|
||||
mFirstPartyDomain = aAttrs.mFirstPartyDomain;
|
||||
}
|
||||
|
||||
bool
|
||||
OriginAttributes::IsFirstPartyEnabled()
|
||||
{
|
||||
// Cache the privacy.firstparty.isolate pref.
|
||||
static bool sFirstPartyIsolation = false;
|
||||
static bool sCachedFirstPartyPref = false;
|
||||
if (!sCachedFirstPartyPref) {
|
||||
sCachedFirstPartyPref = true;
|
||||
Preferences::AddBoolVarCache(&sFirstPartyIsolation, "privacy.firstparty.isolate");
|
||||
}
|
||||
|
||||
return sFirstPartyIsolation;
|
||||
}
|
||||
|
||||
BasePrincipal::BasePrincipal()
|
||||
|
|
|
@ -37,7 +37,8 @@ public:
|
|||
mAddonId == aOther.mAddonId &&
|
||||
mUserContextId == aOther.mUserContextId &&
|
||||
mSignedPkg == aOther.mSignedPkg &&
|
||||
mPrivateBrowsingId == aOther.mPrivateBrowsingId;
|
||||
mPrivateBrowsingId == aOther.mPrivateBrowsingId &&
|
||||
mFirstPartyDomain == aOther.mFirstPartyDomain;
|
||||
}
|
||||
bool operator!=(const OriginAttributes& aOther) const
|
||||
{
|
||||
|
@ -65,6 +66,9 @@ protected:
|
|||
OriginAttributes() {}
|
||||
explicit OriginAttributes(const OriginAttributesDictionary& aOther)
|
||||
: OriginAttributesDictionary(aOther) {}
|
||||
|
||||
// check if "privacy.firstparty.isolate" is enabled.
|
||||
bool IsFirstPartyEnabled();
|
||||
};
|
||||
|
||||
class PrincipalOriginAttributes;
|
||||
|
@ -136,7 +140,11 @@ public:
|
|||
// is made.
|
||||
void InheritFromDocToNecko(const PrincipalOriginAttributes& aAttrs);
|
||||
|
||||
void InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs);
|
||||
// Inheriting OriginAttributes from a docshell when loading a top-level
|
||||
// document.
|
||||
void InheritFromDocShellToNecko(const DocShellOriginAttributes& aAttrs,
|
||||
const bool aIsTopLevelDocument = false,
|
||||
nsIURI* aURI = nullptr);
|
||||
};
|
||||
|
||||
// For operating on OriginAttributes not associated with any data structure.
|
||||
|
@ -189,6 +197,10 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
if (mFirstPartyDomain.WasPassed() && mFirstPartyDomain.Value() != aAttrs.mFirstPartyDomain) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -225,6 +237,11 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
if (mFirstPartyDomain.WasPassed() && aOther.mFirstPartyDomain.WasPassed() &&
|
||||
mFirstPartyDomain.Value() != aOther.mFirstPartyDomain.Value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -436,37 +436,20 @@ nsScriptSecurityManager::GetChannelURIPrincipal(nsIChannel* aChannel,
|
|||
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(aChannel, loadContext);
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||
nsContentPolicyType contentPolicyType = nsIContentPolicy::TYPE_INVALID;
|
||||
if (loadInfo) {
|
||||
contentPolicyType = loadInfo->GetExternalContentPolicyType();
|
||||
}
|
||||
|
||||
// Inherit the origin attributes from loadInfo.
|
||||
// If this is a top-level document load, the origin attributes of the
|
||||
// loadInfo will be set from nsDocShell::DoURILoad.
|
||||
// For subresource loading, the origin attributes of the loadInfo is from
|
||||
// its loadingPrincipal.
|
||||
PrincipalOriginAttributes attrs;
|
||||
if (nsIContentPolicy::TYPE_DOCUMENT == contentPolicyType ||
|
||||
nsIContentPolicy::TYPE_SUBDOCUMENT == contentPolicyType) {
|
||||
// If it's document or sub-document, inherit originAttributes from
|
||||
// the document.
|
||||
if (loadContext) {
|
||||
DocShellOriginAttributes docShellAttrs;
|
||||
loadContext->GetOriginAttributes(docShellAttrs);
|
||||
attrs.InheritFromDocShellToDoc(docShellAttrs, uri);
|
||||
}
|
||||
} else {
|
||||
// Inherit origin attributes from loading principal if any.
|
||||
nsCOMPtr<nsIPrincipal> loadingPrincipal;
|
||||
if (loadInfo) {
|
||||
loadInfo->GetLoadingPrincipal(getter_AddRefs(loadingPrincipal));
|
||||
}
|
||||
if (loadingPrincipal) {
|
||||
attrs = BasePrincipal::Cast(loadingPrincipal)->OriginAttributesRef();
|
||||
}
|
||||
}
|
||||
|
||||
// For addons loadInfo might be null.
|
||||
if (loadInfo) {
|
||||
attrs.InheritFromNecko(loadInfo->GetOriginAttributes());
|
||||
}
|
||||
rv = MaybeSetAddonIdFromURI(attrs, uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrincipal> prin = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
|
||||
|
|
|
@ -42,7 +42,9 @@ function printAttrs(name, attrs) {
|
|||
"\tuserContextId: " + attrs.userContextId + ",\n" +
|
||||
"\tinIsolatedMozBrowser: " + attrs.inIsolatedMozBrowser + ",\n" +
|
||||
"\taddonId: '" + attrs.addonId + "',\n" +
|
||||
"\tsignedPkg: '" + attrs.signedPkg + "'\n}");
|
||||
"\tsignedPkg: '" + attrs.signedPkg + "',\n" +
|
||||
"\tprivateBrowsingId: '" + attrs.privateBrowsingId + "',\n" +
|
||||
"\tfirstPartyDomain: '" + attrs.firstPartyDomain + "'\n}");
|
||||
}
|
||||
|
||||
|
||||
|
@ -55,6 +57,8 @@ function checkValues(attrs, values) {
|
|||
do_check_eq(attrs.inIsolatedMozBrowser, values.inIsolatedMozBrowser || false);
|
||||
do_check_eq(attrs.addonId, values.addonId || '');
|
||||
do_check_eq(attrs.signedPkg, values.signedPkg || '');
|
||||
do_check_eq(attrs.privateBrowsingId, values.privateBrowsingId || '');
|
||||
do_check_eq(attrs.firstPartyDomain, values.firstPartyDomain || '');
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
@ -122,6 +126,11 @@ function run_test() {
|
|||
checkOriginAttributes(exampleOrg_addon, { addonId: "dummy" }, '^addonId=dummy');
|
||||
do_check_eq(exampleOrg_addon.origin, 'http://example.org^addonId=dummy');
|
||||
|
||||
// First party Uri
|
||||
var exampleOrg_firstPartyDomain = ssm.createCodebasePrincipal(makeURI('http://example.org'), {firstPartyDomain: 'example.org'});
|
||||
checkOriginAttributes(exampleOrg_firstPartyDomain, { firstPartyDomain: "example.org" }, '^firstPartyDomain=example.org');
|
||||
do_check_eq(exampleOrg_firstPartyDomain.origin, 'http://example.org^firstPartyDomain=example.org');
|
||||
|
||||
// Make sure we don't crash when serializing principals with UNKNOWN_APP_ID.
|
||||
try {
|
||||
let binaryStream = Cc["@mozilla.org/binaryoutputstream;1"].
|
||||
|
@ -177,6 +186,7 @@ function run_test() {
|
|||
checkCrossOrigin(exampleOrg_appBrowser, nullPrin_appBrowser);
|
||||
checkCrossOrigin(exampleOrg_appBrowser, exampleCom_appBrowser);
|
||||
checkCrossOrigin(exampleOrg_addon, exampleOrg);
|
||||
checkCrossOrigin(exampleOrg_firstPartyDomain, exampleOrg);
|
||||
checkCrossOrigin(exampleOrg_userContext, exampleOrg);
|
||||
checkCrossOrigin(exampleOrg_userContextAddon, exampleOrg);
|
||||
checkCrossOrigin(exampleOrg_userContext, exampleOrg_userContextAddon);
|
||||
|
@ -203,7 +213,7 @@ function run_test() {
|
|||
|
||||
// check that we can create an empty origin attributes dict with default
|
||||
// members and values.
|
||||
emptyAttrs = ChromeUtils.fillNonDefaultOriginAttributes({});
|
||||
var emptyAttrs = ChromeUtils.fillNonDefaultOriginAttributes({});
|
||||
checkValues(emptyAttrs);
|
||||
|
||||
var uri = "http://example.org";
|
||||
|
@ -213,19 +223,20 @@ function run_test() {
|
|||
[ "^userContextId=3", {userContextId: 3} ],
|
||||
[ "^addonId=fooBar", {addonId: "fooBar"} ],
|
||||
[ "^inBrowser=1", {inIsolatedMozBrowser: true} ],
|
||||
[ "^firstPartyDomain=example.org", {firstPartyDomain: "example.org"} ],
|
||||
[ "^signedPkg=bazQux", {signedPkg: "bazQux"} ],
|
||||
[ "^appId=3&inBrowser=1&userContextId=6",
|
||||
{appId: 3, userContextId: 6, inIsolatedMozBrowser: true} ] ];
|
||||
|
||||
// check that we can create an origin attributes from an origin properly
|
||||
tests.forEach(function(t) {
|
||||
tests.forEach(t => {
|
||||
let attrs = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]);
|
||||
checkValues(attrs, t[1]);
|
||||
do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), t[0]);
|
||||
});
|
||||
|
||||
// check that we can create an origin attributes from a dict properly
|
||||
tests.forEach(function(t) {
|
||||
tests.forEach(t => {
|
||||
let attrs = ChromeUtils.fillNonDefaultOriginAttributes(t[1]);
|
||||
checkValues(attrs, t[1]);
|
||||
do_check_eq(ChromeUtils.originAttributesToSuffix(attrs), t[0]);
|
||||
|
@ -244,7 +255,7 @@ function run_test() {
|
|||
[ "^appId=5", {appId: 5}, {appId: 3, userContextId: 7}, {appId: 3, userContextId: 7}, "^appId=3&userContextId=7" ] ];
|
||||
|
||||
// check that we can set origin attributes values properly
|
||||
set_tests.forEach(function(t) {
|
||||
set_tests.forEach(t => {
|
||||
let orig = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]);
|
||||
checkValues(orig, t[1]);
|
||||
let mod = orig;
|
||||
|
@ -267,7 +278,7 @@ function run_test() {
|
|||
[ "^appId=5&userContextId=3", {appId: 5, userContextId: 3}, {appId: 5}, "^appId=5" ] ];
|
||||
|
||||
// check that we can set the userContextId to default properly
|
||||
dflt_tests.forEach(function(t) {
|
||||
dflt_tests.forEach(t => {
|
||||
let orig = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]);
|
||||
checkValues(orig, t[1]);
|
||||
let mod = orig;
|
||||
|
@ -275,4 +286,26 @@ function run_test() {
|
|||
checkValues(mod, t[2]);
|
||||
do_check_eq(ChromeUtils.originAttributesToSuffix(mod), t[3]);
|
||||
});
|
||||
|
||||
// each row in the dflt2_tests array has these values:
|
||||
// [0] - the suffix used to create an origin attribute from
|
||||
// [1] - the expected result of creating an origin attributes from [0]
|
||||
// [2] - the expected result after setting firstPartyUri to the default
|
||||
// [3] - the expected result of creating a suffix from [2]
|
||||
var dflt2_tests = [
|
||||
[ "", {}, {}, "" ],
|
||||
[ "^firstPartyDomain=foo.com", {firstPartyDomain: "foo.com"}, {}, "" ],
|
||||
[ "^appId=5", {appId: 5}, {appId: 5}, "^appId=5" ],
|
||||
[ "^appId=5&firstPartyDomain=foo.com", {appId: 5, firstPartyDomain: "foo.com"}, {appId: 5}, "^appId=5" ] ];
|
||||
|
||||
// check that we can set the userContextId to default properly
|
||||
dflt2_tests.forEach(t => {
|
||||
let orig = ChromeUtils.createOriginAttributesFromOrigin(uri + t[0]);
|
||||
checkValues(orig, t[1]);
|
||||
let mod = orig;
|
||||
mod['firstPartyDomain'] = "";
|
||||
checkValues(mod, t[2]);
|
||||
do_check_eq(ChromeUtils.originAttributesToSuffix(mod), t[3]);
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -10812,7 +10812,10 @@ nsDocShell::DoURILoad(nsIURI* aURI,
|
|||
// OriginAttributes of the parent document. Or in case there isn't a
|
||||
// parent document.
|
||||
NeckoOriginAttributes neckoAttrs;
|
||||
neckoAttrs.InheritFromDocShellToNecko(GetOriginAttributes());
|
||||
bool isTopLevelDoc = aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT &&
|
||||
mItemType == typeContent &&
|
||||
!GetIsMozBrowserOrApp();
|
||||
neckoAttrs.InheritFromDocShellToNecko(GetOriginAttributes(), isTopLevelDoc, aURI);
|
||||
rv = loadInfo->SetOriginAttributes(neckoAttrs);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
|
|
|
@ -2098,6 +2098,38 @@ nsFrameLoader::MaybeCreateDocShell()
|
|||
attrs = nsDocShell::Cast(docShell)->GetOriginAttributes();
|
||||
}
|
||||
|
||||
// Inherit origin attributes from parent document if
|
||||
// 1. It's in a content docshell.
|
||||
// 2. its nodePrincipal is not a SystemPrincipal.
|
||||
// 3. It's not a mozbrowser nor mozapp frame.
|
||||
//
|
||||
// For example, firstPartyDomain is computed from top-level document, it
|
||||
// doesn't exist in the top-level docshell.
|
||||
if (parentType == nsIDocShellTreeItem::typeContent &&
|
||||
!nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()) &&
|
||||
!OwnerIsMozBrowserOrAppFrame()) {
|
||||
PrincipalOriginAttributes poa = BasePrincipal::Cast(doc->NodePrincipal())->OriginAttributesRef();
|
||||
|
||||
// Assert on the firstPartyDomain from top-level docshell should be empty
|
||||
if (mIsTopLevelContent) {
|
||||
MOZ_ASSERT(attrs.mFirstPartyDomain.IsEmpty(),
|
||||
"top-level docshell shouldn't have firstPartyDomain attribute.");
|
||||
}
|
||||
|
||||
// So far we want to make sure InheritFromDocToChildDocShell doesn't override
|
||||
// any other origin attribute than firstPartyDomain.
|
||||
MOZ_ASSERT(attrs.mAppId == poa.mAppId,
|
||||
"docshell and document should have the same appId attribute.");
|
||||
MOZ_ASSERT(attrs.mUserContextId == poa.mUserContextId,
|
||||
"docshell and document should have the same userContextId attribute.");
|
||||
MOZ_ASSERT(attrs.mInIsolatedMozBrowser == poa.mInIsolatedMozBrowser,
|
||||
"docshell and document should have the same inIsolatedMozBrowser attribute.");
|
||||
MOZ_ASSERT(attrs.mPrivateBrowsingId == poa.mPrivateBrowsingId,
|
||||
"docshell and document should have the same privateBrowsingId attribute.");
|
||||
|
||||
attrs.InheritFromDocToChildDocShell(poa);
|
||||
}
|
||||
|
||||
if (OwnerIsAppFrame()) {
|
||||
// You can't be both an app and a browser frame.
|
||||
MOZ_ASSERT(!OwnerIsMozBrowserFrame());
|
||||
|
|
|
@ -543,11 +543,7 @@ skip-if = buildapp == 'b2g'
|
|||
[test_bug698381.html]
|
||||
[test_bug698384.html]
|
||||
[test_bug704063.html]
|
||||
[test_bug704320_http_http.html]
|
||||
[test_bug704320_http_https.html]
|
||||
[test_bug704320_https_http.html]
|
||||
skip-if = buildapp == 'b2g' # b2g (https://example.com not working bug 1162353)
|
||||
[test_bug704320_https_https.html]
|
||||
[test_bug704320.html]
|
||||
skip-if = buildapp == 'b2g' # b2g (https://example.com not working bug 1162353)
|
||||
[test_bug704320_policyset.html]
|
||||
[test_bug704320_policyset2.html]
|
||||
|
|
|
@ -5,21 +5,31 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
|||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 704320 - HTTPS to HTTPS</title>
|
||||
<title>Test for Bug 704320</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="referrerHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var testIframeUrls = [
|
||||
// HTTPS to HTTPS
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer-when-downgrade',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=no-referrer',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=unsafe-url',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=origin',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=https&policy=origin-when-cross-origin'
|
||||
];
|
||||
//generates URLs to test
|
||||
var generateURLArray = (function(from, to){
|
||||
const baseURL = '://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=';
|
||||
const schemeTo = '&scheme-to=';
|
||||
|
||||
return [
|
||||
from + baseURL + from + schemeTo + to + '&policy=no-referrer-when-downgrade',
|
||||
from + baseURL + from + schemeTo + to + '&policy=no-referrer',
|
||||
from + baseURL + from + schemeTo + to + '&policy=unsafe-url',
|
||||
from + baseURL + from + schemeTo + to + '&policy=origin',
|
||||
from + baseURL + from + schemeTo + to + '&policy=origin-when-cross-origin',
|
||||
];
|
||||
});
|
||||
|
||||
var testIframeUrls = generateURLArray('http', 'http');
|
||||
testIframeUrls = testIframeUrls.concat(generateURLArray('https', 'https'));
|
||||
testIframeUrls = testIframeUrls.concat(generateURLArray('http', 'https'));
|
||||
testIframeUrls = testIframeUrls.concat(generateURLArray('https', 'http'));
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
@ -51,12 +61,11 @@ var tests = (function() {
|
|||
</head>
|
||||
|
||||
<body onload="tests.next();">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTPS to HTTPS</a>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP/HTTPS to HTTPS/HTTP</a>
|
||||
<p id="display"></p>
|
||||
<pre id="content">
|
||||
</pre>
|
||||
<iframe id="testframe"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
|
@ -1,62 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 704320 - HTTP to HTTP</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="referrerHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var testIframeUrls = [
|
||||
// HTTP to HTTP
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer-when-downgrade',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=no-referrer',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=unsafe-url',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=origin',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=http&policy=origin-when-cross-origin',
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
||||
/**
|
||||
* This is the main test routine -- serialized by use of a generator.
|
||||
* It performs all tests in sequence using in the same iframe.
|
||||
*/
|
||||
var tests = (function() {
|
||||
var iframe = document.getElementById("testframe");
|
||||
iframe.onload = function() {
|
||||
advance();
|
||||
}
|
||||
|
||||
// load the test frame from testIframeUrls[url]
|
||||
// it will call back into this function via postMessage when it finishes loading.
|
||||
// and continue beyond the yield.
|
||||
for(url in testIframeUrls) {
|
||||
yield iframe.src = testIframeUrls[url];
|
||||
// run test and check result for loaded test URL
|
||||
yield checkExpectedGlobalResults();
|
||||
}
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="tests.next();">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP to HTTP</a>
|
||||
<p id="display"></p>
|
||||
<pre id="content">
|
||||
</pre>
|
||||
<iframe id="testframe"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 704320 - HTTP to HTTPS</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="referrerHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var testIframeUrls = [
|
||||
// HTTP to HTTPS
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer-when-downgrade',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=no-referrer',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=unsafe-url',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=origin',
|
||||
'http://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=http&scheme-to=https&policy=origin-when-cross-origin',
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
||||
/**
|
||||
* This is the main test routine -- serialized by use of a generator.
|
||||
* It performs all tests in sequence using in the same iframe.
|
||||
*/
|
||||
var tests = (function() {
|
||||
var iframe = document.getElementById("testframe");
|
||||
iframe.onload = function() {
|
||||
advance();
|
||||
}
|
||||
|
||||
// load the test frame from testIframeUrls[url]
|
||||
// it will call back into this function via postMessage when it finishes loading.
|
||||
// and continue beyond the yield.
|
||||
for(url in testIframeUrls) {
|
||||
yield iframe.src = testIframeUrls[url];
|
||||
// run test and check result for loaded test URL
|
||||
yield checkExpectedGlobalResults();
|
||||
}
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="tests.next();">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP to HTTPS</a>
|
||||
<p id="display"></p>
|
||||
<pre id="content">
|
||||
</pre>
|
||||
<iframe id="testframe"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=704320
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 704320 - HTTPS to HTTP</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="referrerHelper.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var testIframeUrls = [
|
||||
// HTTPS to HTTP
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=no-referrer-when-downgrade',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=no-referrer',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=unsafe-url',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=origin',
|
||||
'https://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=https&scheme-to=http&policy=origin-when-cross-origin',
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var advance = function() { tests.next(); };
|
||||
|
||||
/**
|
||||
* This is the main test routine -- serialized by use of a generator.
|
||||
* It performs all tests in sequence using in the same iframe.
|
||||
*/
|
||||
var tests = (function() {
|
||||
var iframe = document.getElementById("testframe");
|
||||
iframe.onload = function() {
|
||||
advance();
|
||||
}
|
||||
|
||||
// load the test frame from testIframeUrls[url]
|
||||
// it will call back into this function via postMessage when it finishes loading.
|
||||
// and continue beyond the yield.
|
||||
for(url in testIframeUrls) {
|
||||
yield iframe.src = testIframeUrls[url];
|
||||
// run test and check result for loaded test URL
|
||||
yield checkExpectedGlobalResults();
|
||||
}
|
||||
|
||||
// complete. Be sure to yield so we don't call this twice.
|
||||
yield SimpleTest.finish();
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="tests.next();">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTPS to HTTP</a>
|
||||
<p id="display"></p>
|
||||
<pre id="content">
|
||||
</pre>
|
||||
<iframe id="testframe"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -509,7 +509,7 @@ TabChild::Create(nsIContentChild* aManager,
|
|||
child->mManager = aManager;
|
||||
child->SetTabId(aTabId);
|
||||
child->SetTabContext(aContext);
|
||||
child->NotifyTabContextUpdated();
|
||||
child->NotifyTabContextUpdated(true);
|
||||
return child.forget();
|
||||
}
|
||||
|
||||
|
@ -727,6 +727,7 @@ TabChild::Init()
|
|||
}
|
||||
|
||||
webBrowser->SetContainerWindow(this);
|
||||
webBrowser->SetOriginAttributes(OriginAttributesRef());
|
||||
mWebNav = do_QueryInterface(webBrowser);
|
||||
NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
|
||||
|
||||
|
@ -755,7 +756,7 @@ TabChild::Init()
|
|||
baseWindow->Create();
|
||||
|
||||
// Set the tab context attributes then pass to docShell
|
||||
NotifyTabContextUpdated();
|
||||
NotifyTabContextUpdated(false);
|
||||
|
||||
// IPC uses a WebBrowser object for which DNS prefetching is turned off
|
||||
// by default. But here we really want it, so enable it explicitly
|
||||
|
@ -825,7 +826,7 @@ TabChild::Init()
|
|||
}
|
||||
|
||||
void
|
||||
TabChild::NotifyTabContextUpdated()
|
||||
TabChild::NotifyTabContextUpdated(bool aIsPreallocated)
|
||||
{
|
||||
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(WebNavigation());
|
||||
MOZ_ASSERT(docShell);
|
||||
|
@ -835,7 +836,10 @@ TabChild::NotifyTabContextUpdated()
|
|||
}
|
||||
|
||||
UpdateFrameType();
|
||||
nsDocShell::Cast(docShell)->SetOriginAttributes(OriginAttributesRef());
|
||||
|
||||
if (aIsPreallocated) {
|
||||
nsDocShell::Cast(docShell)->SetOriginAttributes(OriginAttributesRef());
|
||||
}
|
||||
|
||||
// Set SANDBOXED_AUXILIARY_NAVIGATION flag if this is a receiver page.
|
||||
if (!PresentationURL().IsEmpty()) {
|
||||
|
|
|
@ -687,12 +687,13 @@ private:
|
|||
void HandleDoubleTap(const CSSPoint& aPoint, const Modifiers& aModifiers,
|
||||
const ScrollableLayerGuid& aGuid);
|
||||
|
||||
// Notify others that our TabContext has been updated. (At the moment, this
|
||||
// sets the appropriate origin attributes on our docshell.)
|
||||
// Notify others that our TabContext has been updated.
|
||||
//
|
||||
// You should call this after calling TabContext::SetTabContext(). We also
|
||||
// call this during Init().
|
||||
void NotifyTabContextUpdated();
|
||||
//
|
||||
// @param aIsPreallocated true if this is called for Preallocated Tab.
|
||||
void NotifyTabContextUpdated(bool aIsPreallocated);
|
||||
|
||||
// Update the frameType on our docshell.
|
||||
void UpdateFrameType();
|
||||
|
|
|
@ -81,6 +81,7 @@ dictionary OriginAttributesDictionary {
|
|||
DOMString addonId = "";
|
||||
DOMString signedPkg = "";
|
||||
unsigned long privateBrowsingId = 0;
|
||||
DOMString firstPartyDomain = "";
|
||||
};
|
||||
dictionary OriginAttributesPatternDictionary {
|
||||
unsigned long appId;
|
||||
|
@ -89,4 +90,5 @@ dictionary OriginAttributesPatternDictionary {
|
|||
DOMString addonId;
|
||||
DOMString signedPkg;
|
||||
unsigned long privateBrowsingId;
|
||||
DOMString firstPartyDomain;
|
||||
};
|
||||
|
|
|
@ -716,12 +716,12 @@ WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread()
|
|||
MOZ_ASSERT(aRunnable);
|
||||
}
|
||||
|
||||
// We must call RunBackOnWorkerThread() also if the runnable is cancelled.
|
||||
// We must call RunBackOnWorkerThread() also if the runnable is canceled.
|
||||
nsresult
|
||||
Cancel() override
|
||||
{
|
||||
WorkerRun(nullptr, mWorkerPrivate);
|
||||
return NS_OK;
|
||||
return MainThreadWorkerControlRunnable::Cancel();
|
||||
}
|
||||
|
||||
virtual bool
|
||||
|
@ -730,10 +730,14 @@ WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread()
|
|||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
mRunnable->RunBackOnWorkerThread();
|
||||
if (mRunnable) {
|
||||
mRunnable->RunBackOnWorkerThread();
|
||||
|
||||
// Let's release the worker thread.
|
||||
mRunnable->ReleaseWorker();
|
||||
mRunnable = nullptr;
|
||||
}
|
||||
|
||||
// Let's release the worker thread.
|
||||
mRunnable->ReleaseWorker();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ UNIFIED_SOURCES += [
|
|||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
LOCAL_INCLUDES += [
|
||||
'/docshell/base',
|
||||
'/dom/base',
|
||||
'/dom/svg',
|
||||
'/layout/style',
|
||||
|
|
|
@ -13,6 +13,14 @@ interface nsIDOMWindow;
|
|||
interface mozIDOMWindowProxy;
|
||||
interface nsIWeakReference;
|
||||
|
||||
%{C++
|
||||
namespace mozilla {
|
||||
class DocShellOriginAttributes;
|
||||
}
|
||||
%}
|
||||
|
||||
[ref] native const_OriginAttributesRef(const mozilla::DocShellOriginAttributes);
|
||||
|
||||
/**
|
||||
* The nsIWebBrowser interface is implemented by web browser objects.
|
||||
* Embedders use this interface during initialisation to associate
|
||||
|
@ -144,4 +152,12 @@ interface nsIWebBrowser : nsISupports
|
|||
* appropriate.
|
||||
*/
|
||||
attribute boolean isActive;
|
||||
|
||||
/**
|
||||
* Set Origin Attributes on the nsIWebBrowser.
|
||||
* The Origin Attributes will be passed to the docshell once it has been
|
||||
* created
|
||||
*/
|
||||
[noscript, notxpcom, nostdcall, binaryname(SetOriginAttributes)]
|
||||
void binarySetOriginAttributes(in const_OriginAttributesRef aOriginAttrs);
|
||||
};
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "Layers.h"
|
||||
#include "gfxContext.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsDocShell.h"
|
||||
|
||||
// for painting the background window
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
|
@ -388,6 +389,12 @@ nsWebBrowser::SetIsActive(bool aIsActive)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsWebBrowser::SetOriginAttributes(const DocShellOriginAttributes& aAttrs)
|
||||
{
|
||||
mOriginAttributes = aAttrs;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// nsWebBrowser::nsIDocShellTreeItem
|
||||
//*****************************************************************************
|
||||
|
@ -1193,6 +1200,7 @@ nsWebBrowser::Create()
|
|||
nsCOMPtr<nsIDocShell> docShell(
|
||||
do_CreateInstance("@mozilla.org/docshell;1", &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsDocShell::Cast(docShell)->SetOriginAttributes(mOriginAttributes);
|
||||
rv = SetDocShell(docShell);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "nsEmbedStream.h"
|
||||
#include "nsIWidgetListener.h"
|
||||
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsWeakPtr.h"
|
||||
|
||||
|
@ -132,6 +133,7 @@ protected:
|
|||
nsCOMPtr<nsIWebNavigation> mDocShellAsNav;
|
||||
nsCOMPtr<nsIScrollable> mDocShellAsScrollable;
|
||||
nsCOMPtr<nsITextScroll> mDocShellAsTextScroll;
|
||||
mozilla::DocShellOriginAttributes mOriginAttributes;
|
||||
|
||||
nsCOMPtr<nsIWidget> mInternalWidget;
|
||||
nsCOMPtr<nsIWindowWatcher> mWWatch;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* 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/. */
|
||||
|
||||
#include "libyuv.h"
|
||||
#include "MacIOSurfaceHelpers.h"
|
||||
#include "mozilla/gfx/MacIOSurface.h"
|
||||
#include "YCbCrUtils.h"
|
||||
|
@ -84,58 +85,13 @@ CreateSourceSurfaceFromLockedMacIOSurface(MacIOSurface* aSurface)
|
|||
|
||||
ConvertYCbCrToRGB(data, SurfaceFormat::B8G8R8X8, IntSize::Truncate(ioWidth, ioHeight), mappedSurface.mData, mappedSurface.mStride);
|
||||
} else if (ioFormat == SurfaceFormat::YUV422) {
|
||||
/* Convert to YV16 */
|
||||
size_t cbCrWidth = (ioWidth+1)>>1;
|
||||
size_t cbCrHeight = ioHeight;
|
||||
// Ensure our stride is a multiple of 32 to allow for memory aligned rows.
|
||||
size_t cbCrStride = ALIGNED_32(cbCrWidth);
|
||||
size_t strideDelta = cbCrStride - cbCrWidth;
|
||||
MOZ_ASSERT(strideDelta <= 31);
|
||||
|
||||
auto yPlane = MakeUnique<uint8_t[]>(cbCrStride * 2 * ioHeight + 31);
|
||||
auto cbPlane = MakeUnique<uint8_t[]>(cbCrStride * cbCrHeight + 31);
|
||||
auto crPlane = MakeUnique<uint8_t[]>(cbCrStride * cbCrHeight + 31);
|
||||
|
||||
uint8_t* src = (uint8_t*)aSurface->GetBaseAddress();
|
||||
uint8_t* yDest = ALIGNEDPTR_32(yPlane.get());
|
||||
uint8_t* cbDest = ALIGNEDPTR_32(cbPlane.get());
|
||||
uint8_t* crDest = ALIGNEDPTR_32(crPlane.get());
|
||||
|
||||
for (size_t i = 0; i < ioHeight; i++) {
|
||||
uint8_t* rowSrc = src + bytesPerRow * i;
|
||||
for (size_t j = 0; j < cbCrWidth; j++) {
|
||||
*cbDest = *rowSrc;
|
||||
cbDest++;
|
||||
rowSrc++;
|
||||
*yDest = *rowSrc;
|
||||
yDest++;
|
||||
rowSrc++;
|
||||
*crDest = *rowSrc;
|
||||
crDest++;
|
||||
rowSrc++;
|
||||
*yDest = *rowSrc;
|
||||
yDest++;
|
||||
rowSrc++;
|
||||
}
|
||||
if (strideDelta) {
|
||||
cbDest += strideDelta;
|
||||
crDest += strideDelta;
|
||||
yDest += strideDelta << 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert to RGB */
|
||||
PlanarYCbCrData data;
|
||||
data.mYChannel = ALIGNEDPTR_32(yPlane.get());
|
||||
data.mYStride = cbCrStride * 2;
|
||||
data.mYSize = IntSize::Truncate(ioWidth, ioHeight);
|
||||
data.mCbChannel = ALIGNEDPTR_32(cbPlane.get());
|
||||
data.mCrChannel = ALIGNEDPTR_32(crPlane.get());
|
||||
data.mCbCrStride = cbCrStride;
|
||||
data.mCbCrSize = IntSize::Truncate(cbCrWidth, cbCrHeight);
|
||||
data.mPicSize = data.mYSize;
|
||||
|
||||
ConvertYCbCrToRGB(data, SurfaceFormat::B8G8R8X8, IntSize::Truncate(ioWidth, ioHeight), mappedSurface.mData, mappedSurface.mStride);
|
||||
IntSize size = IntSize::Truncate(ioWidth, ioHeight);
|
||||
libyuv::ConvertToARGB((uint8_t*)aSurface->GetBaseAddress(), 0 /* not used */,
|
||||
mappedSurface.mData, mappedSurface.mStride,
|
||||
0, 0,
|
||||
size.width, size.height,
|
||||
size.width, size.height,
|
||||
libyuv::kRotate0, libyuv::FOURCC_UYVY);
|
||||
} else {
|
||||
unsigned char* ioData = (unsigned char*)aSurface->GetBaseAddress();
|
||||
|
||||
|
|
|
@ -394,12 +394,21 @@ public:
|
|||
* Lock the texture host for compositing.
|
||||
*/
|
||||
virtual bool Lock() { return true; }
|
||||
|
||||
/**
|
||||
* Unlock the texture host after compositing.
|
||||
* Unlock the texture host after compositing. Lock() and Unlock() should be
|
||||
* called in pair.
|
||||
*/
|
||||
virtual void Unlock() {}
|
||||
|
||||
/**
|
||||
* Lock the texture host for compositing without using compositor.
|
||||
*/
|
||||
virtual bool LockWithoutCompositor() { return true; }
|
||||
/**
|
||||
* Similar to Unlock(), but it should be called with LockWithoutCompositor().
|
||||
*/
|
||||
virtual void UnlockWithoutCompositor() {}
|
||||
|
||||
/**
|
||||
* Note that the texture host format can be different from its corresponding
|
||||
* texture source's. For example a ShmemTextureHost can have the ycbcr
|
||||
|
@ -811,6 +820,29 @@ private:
|
|||
bool mLocked;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoLockTextureHostWithoutCompositor
|
||||
{
|
||||
public:
|
||||
explicit AutoLockTextureHostWithoutCompositor(TextureHost* aTexture)
|
||||
: mTexture(aTexture)
|
||||
{
|
||||
mLocked = mTexture ? mTexture->LockWithoutCompositor() : false;
|
||||
}
|
||||
|
||||
~AutoLockTextureHostWithoutCompositor()
|
||||
{
|
||||
if (mTexture && mLocked) {
|
||||
mTexture->UnlockWithoutCompositor();
|
||||
}
|
||||
}
|
||||
|
||||
bool Failed() { return mTexture && !mLocked; }
|
||||
|
||||
private:
|
||||
RefPtr<TextureHost> mTexture;
|
||||
bool mLocked;
|
||||
};
|
||||
|
||||
/**
|
||||
* This can be used as an offscreen rendering target by the compositor, and
|
||||
* subsequently can be used as a source by the compositor.
|
||||
|
|
|
@ -733,11 +733,40 @@ DXGITextureHostD3D11::GetCompositor()
|
|||
bool
|
||||
DXGITextureHostD3D11::Lock()
|
||||
{
|
||||
/**
|
||||
* Note: This function may be called when mCompositor is null
|
||||
* such as during WebVR frame submission.
|
||||
**/
|
||||
if (!mCompositor) {
|
||||
// Make an early return here if we call SetCompositor() with an incompatible
|
||||
// compositor. This check tries to prevent the problem where we use that
|
||||
// incompatible compositor to compose this texture.
|
||||
return false;
|
||||
}
|
||||
|
||||
return LockInternal();
|
||||
}
|
||||
|
||||
bool
|
||||
DXGITextureHostD3D11::LockWithoutCompositor()
|
||||
{
|
||||
// Unlike the normal Lock() function, this function may be called when
|
||||
// mCompositor is nullptr such as during WebVR frame submission. So, there is
|
||||
// no 'mCompositor' checking here.
|
||||
return LockInternal();
|
||||
}
|
||||
|
||||
void
|
||||
DXGITextureHostD3D11::Unlock()
|
||||
{
|
||||
UnlockInternal();
|
||||
}
|
||||
|
||||
void
|
||||
DXGITextureHostD3D11::UnlockWithoutCompositor()
|
||||
{
|
||||
UnlockInternal();
|
||||
}
|
||||
|
||||
bool
|
||||
DXGITextureHostD3D11::LockInternal()
|
||||
{
|
||||
if (!GetDevice()) {
|
||||
NS_WARNING("trying to lock a TextureHost without a D3D device");
|
||||
return false;
|
||||
|
@ -758,7 +787,7 @@ DXGITextureHostD3D11::Lock()
|
|||
}
|
||||
|
||||
void
|
||||
DXGITextureHostD3D11::Unlock()
|
||||
DXGITextureHostD3D11::UnlockInternal()
|
||||
{
|
||||
UnlockD3DTexture(mTextureSource->GetD3D11Texture());
|
||||
}
|
||||
|
|
|
@ -296,9 +296,11 @@ public:
|
|||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
virtual bool Lock() override;
|
||||
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual bool LockWithoutCompositor() override;
|
||||
virtual void UnlockWithoutCompositor() override;
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
|
||||
|
@ -307,6 +309,9 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
bool LockInternal();
|
||||
void UnlockInternal();
|
||||
|
||||
RefPtr<ID3D11Device> GetDevice();
|
||||
|
||||
bool OpenSharedHandle();
|
||||
|
|
|
@ -83,7 +83,9 @@ VRDisplayHost::SubmitFrame(VRLayerParent* aLayer, const int32_t& aInputFrameID,
|
|||
// compensate.
|
||||
|
||||
TextureHost* th = TextureHost::AsTextureHost(aTexture);
|
||||
AutoLockTextureHost autoLock(th);
|
||||
// WebVR doesn't use the compositor to compose the frame, so use
|
||||
// AutoLockTextureHostWithoutCompositor here.
|
||||
AutoLockTextureHostWithoutCompositor autoLock(th);
|
||||
if (autoLock.Failed()) {
|
||||
NS_WARNING("Failed to lock the VR layer texture");
|
||||
return;
|
||||
|
|
|
@ -350,6 +350,20 @@ SVGDocumentWrapper::SetupViewer(nsIRequest* aRequest,
|
|||
|
||||
NS_ENSURE_TRUE(viewer, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Create a navigation time object and pass it to the SVG document through
|
||||
// the viewer.
|
||||
// The timeline(DocumentTimeline, used in CSS animation) of this SVG
|
||||
// document needs this navigation timing object for time computation, such
|
||||
// as to calculate current time stamp based on the start time of navigation
|
||||
// time object.
|
||||
//
|
||||
// For a root document, DocShell would do these sort of things
|
||||
// automatically. Since there is no DocShell for this wrapped SVG document,
|
||||
// we must set it up manually.
|
||||
RefPtr<nsDOMNavigationTiming> timing = new nsDOMNavigationTiming();
|
||||
timing->NotifyNavigationStart();
|
||||
viewer->SetNavigationTiming(timing);
|
||||
|
||||
nsCOMPtr<nsIParser> parser = do_QueryInterface(listener);
|
||||
NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
|
||||
|
||||
|
|
|
@ -525,6 +525,12 @@ VectorImage::RequestRefresh(const TimeStamp& aTime)
|
|||
return;
|
||||
}
|
||||
|
||||
PendingAnimationTracker* tracker =
|
||||
mSVGDocumentWrapper->GetDocument()->GetPendingAnimationTracker();
|
||||
if (tracker && ShouldAnimate()) {
|
||||
tracker->TriggerPendingAnimationsOnNextTick(aTime);
|
||||
}
|
||||
|
||||
EvaluateAnimation();
|
||||
|
||||
mSVGDocumentWrapper->TickRefreshDriver();
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
|
||||
width="100" height="100">
|
||||
<defs>
|
||||
<style>
|
||||
#myRect {
|
||||
animation-duration: 0.1s;
|
||||
animation-name: fade;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes fade {
|
||||
0% { fill-opacity: 0 }
|
||||
100% { fill-opacity: 1 }
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="red"/>
|
||||
<rect id="myRect" width="100%" height="100%" fill="lime" fill-opacity="0"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 490 B |
|
@ -62,6 +62,7 @@ support-files =
|
|||
lime100x100.svg
|
||||
lime-anim-100x100.svg
|
||||
lime-anim-100x100-2.svg
|
||||
lime-css-anim-100x100.svg
|
||||
opaque.bmp
|
||||
purple.gif
|
||||
red.gif
|
||||
|
|
|
@ -33,7 +33,11 @@ var gMyDecoderObserver; // value will be set in main()
|
|||
var gReferenceSnapshot; // value will be set in takeReferenceSnapshot()
|
||||
var gPollCounter = 0;
|
||||
var gIsTestFinished = false;
|
||||
|
||||
var gSVGImages = [
|
||||
"lime-anim-100x100.svg", // SMIL animation
|
||||
"lime-css-anim-100x100.svg" // CSS animation
|
||||
]
|
||||
var gSVGCurrentImage = 0;
|
||||
|
||||
function takeReferenceSnapshot() {
|
||||
// Take a snapshot of the initial (essentially blank) page
|
||||
|
@ -53,6 +57,13 @@ function takeReferenceSnapshot() {
|
|||
"reference div should disappear when it becomes display:none");
|
||||
}
|
||||
|
||||
function loadNextImageAndPoll()
|
||||
{
|
||||
setTimeout(myPoll, 1);
|
||||
// kick off image-loading! myPoll handles the rest.
|
||||
gImg.setAttribute("src", gSVGImages[gSVGCurrentImage]);
|
||||
}
|
||||
|
||||
function myPoll() {
|
||||
gPollCounter++;
|
||||
ok(true, "myPoll called");
|
||||
|
@ -61,7 +72,12 @@ function myPoll() {
|
|||
// SUCCESS!
|
||||
ok(true, "Animated image looks correct, " +
|
||||
"at call #" + gPollCounter + " to myPoll");
|
||||
cleanUpAndFinish();
|
||||
|
||||
if (++gSVGCurrentImage > gSVGImages.length) {
|
||||
cleanUpAndFinish();
|
||||
} else {
|
||||
loadNextImageAndPoll();
|
||||
}
|
||||
}
|
||||
else
|
||||
setTimeout(myPoll, 1);
|
||||
|
@ -91,10 +107,7 @@ function main() {
|
|||
// earlier test got our image in there already.
|
||||
clearAllImageCaches();
|
||||
|
||||
setTimeout(myPoll, 1);
|
||||
|
||||
// kick off image-loading! myPoll handles the rest.
|
||||
gImg.setAttribute("src", "lime-anim-100x100.svg");
|
||||
loadNextImageAndPoll();
|
||||
|
||||
// In case something goes wrong, fail earlier than mochitest timeout,
|
||||
// and with more information.
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
// This file is only meant to compile on windows
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -3,6 +3,7 @@ asm.js/testParallelCompile.js
|
|||
auto-regress/bug653395.js
|
||||
auto-regress/bug654392.js
|
||||
auto-regress/bug675251.js
|
||||
auto-regress/bug729797.js
|
||||
baseline/bug847446.js
|
||||
baseline/bug852175.js
|
||||
basic/bug632964-regexp.js
|
||||
|
|
|
@ -51,6 +51,7 @@ js1_5/GC/regress-203278-2.js
|
|||
js1_5/GC/regress-203278-3.js
|
||||
js1_5/GC/regress-278725.js
|
||||
js1_5/Regress/regress-312588.js
|
||||
js1_5/Regress/regress-321971.js
|
||||
js1_5/Regress/regress-360969-01.js
|
||||
js1_5/Regress/regress-360969-02.js
|
||||
js1_5/Regress/regress-360969-03.js
|
||||
|
|
|
@ -1782,7 +1782,7 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
|
|||
|
||||
nsIFrame* frame = aBuilder->RootReferenceFrame();
|
||||
nsPresContext* presContext = frame->PresContext();
|
||||
nsIPresShell* presShell = presContext->GetPresShell();
|
||||
nsIPresShell* presShell = presContext->PresShell();
|
||||
nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
|
||||
|
||||
NotifySubDocInvalidationFunc computeInvalidFunc =
|
||||
|
@ -1809,10 +1809,7 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
|
|||
BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this,
|
||||
containerParameters, nullptr);
|
||||
|
||||
nsIDocument* document = nullptr;
|
||||
if (presShell) {
|
||||
document = presShell->GetDocument();
|
||||
}
|
||||
nsIDocument* document = presShell->GetDocument();
|
||||
|
||||
if (!root) {
|
||||
layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
|
||||
|
|
|
@ -148,6 +148,7 @@ NeckoParent::GetValidatedAppInfo(const SerializedLoadContext& aSerialized,
|
|||
aAttrs.mSignedPkg = aSerialized.mOriginAttributes.mSignedPkg;
|
||||
aAttrs.mUserContextId = aSerialized.mOriginAttributes.mUserContextId;
|
||||
aAttrs.mPrivateBrowsingId = aSerialized.mOriginAttributes.mPrivateBrowsingId;
|
||||
aAttrs.mFirstPartyDomain = aSerialized.mOriginAttributes.mFirstPartyDomain;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -2901,6 +2901,36 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
|
|||
if (mLoadInfo) {
|
||||
nsCOMPtr<nsILoadInfo> newLoadInfo =
|
||||
static_cast<mozilla::LoadInfo*>(mLoadInfo.get())->Clone();
|
||||
|
||||
// re-compute the origin attributes of the loadInfo if it's top-level load.
|
||||
bool isTopLevelDoc =
|
||||
newLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT;
|
||||
|
||||
if (isTopLevelDoc) {
|
||||
nsCOMPtr<nsILoadContext> loadContext;
|
||||
NS_QueryNotificationCallbacks(this, loadContext);
|
||||
DocShellOriginAttributes docShellAttrs;
|
||||
if (loadContext) {
|
||||
loadContext->GetOriginAttributes(docShellAttrs);
|
||||
}
|
||||
MOZ_ASSERT(docShellAttrs.mFirstPartyDomain.IsEmpty(),
|
||||
"top-level docshell shouldn't have firstPartyDomain attribute.");
|
||||
|
||||
NeckoOriginAttributes attrs = newLoadInfo->GetOriginAttributes();
|
||||
|
||||
MOZ_ASSERT(docShellAttrs.mAppId == attrs.mAppId,
|
||||
"docshell and necko should have the same appId attribute.");
|
||||
MOZ_ASSERT(docShellAttrs.mUserContextId == attrs.mUserContextId,
|
||||
"docshell and necko should have the same userContextId attribute.");
|
||||
MOZ_ASSERT(docShellAttrs.mInIsolatedMozBrowser == attrs.mInIsolatedMozBrowser,
|
||||
"docshell and necko should have the same inIsolatedMozBrowser attribute.");
|
||||
MOZ_ASSERT(docShellAttrs.mPrivateBrowsingId == attrs.mPrivateBrowsingId,
|
||||
"docshell and necko should have the same privateBrowsingId attribute.");
|
||||
|
||||
attrs.InheritFromDocShellToNecko(docShellAttrs, true, newURI);
|
||||
newLoadInfo->SetOriginAttributes(attrs);
|
||||
}
|
||||
|
||||
bool isInternalRedirect =
|
||||
(redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
|
||||
nsIChannelEventSink::REDIRECT_STS_UPGRADE));
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a copy of a file that is generated by the chromium build.
|
||||
|
||||
// Generated by build/write_buildflag_header.py
|
||||
// From "//base:debugging_flags"
|
||||
|
||||
#ifndef BASE_DEBUG_DEBUGGING_FLAGS_H_
|
||||
#define BASE_DEBUG_DEBUGGING_FLAGS_H_
|
||||
|
||||
#include "build/buildflag.h"
|
||||
|
||||
#define BUILDFLAG_INTERNAL_ENABLE_PROFILING() (0)
|
||||
|
||||
#endif // BASE_DEBUG_DEBUGGING_FLAGS_H_
|
|
@ -0,0 +1,29 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a dummy version of Chromium source file base/file_version_info_win.h
|
||||
// Within our copy of Chromium files FileVersionInfoWin is only used in
|
||||
// base/win/windows_version.cc in GetVersionFromKernel32, which we don't use.
|
||||
|
||||
#ifndef BASE_FILE_VERSION_INFO_WIN_H_
|
||||
#define BASE_FILE_VERSION_INFO_WIN_H_
|
||||
|
||||
struct tagVS_FIXEDFILEINFO;
|
||||
typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
class FileVersionInfoWin {
|
||||
public:
|
||||
static FileVersionInfoWin*
|
||||
CreateFileVersionInfo(const base::FilePath& file_path) { return nullptr; }
|
||||
|
||||
VS_FIXEDFILEINFO* fixed_file_info() { return nullptr; }
|
||||
};
|
||||
|
||||
#endif // BASE_FILE_VERSION_INFO_WIN_H_
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This is a dummy version of Chromium source file base/file/file_path.cc.
|
||||
// To provide the functions required in base/win/windows_version.cc
|
||||
// GetVersionFromKernel32, which we don't use.
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
FilePath::FilePath(FilePath::StringPieceType path) {
|
||||
}
|
||||
|
||||
FilePath::~FilePath() {
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -26,16 +26,41 @@
|
|||
#include "base/strings/utf_string_conversions.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace logging {
|
||||
|
||||
namespace {
|
||||
|
||||
int min_log_level = 0;
|
||||
int g_min_log_level = 0;
|
||||
|
||||
LoggingDestination g_logging_destination = LOG_DEFAULT;
|
||||
|
||||
// For LOG_ERROR and above, always print to stderr.
|
||||
const int kAlwaysPrintErrorLevel = LOG_ERROR;
|
||||
|
||||
// A log message handler that gets notified of every log message we process.
|
||||
LogMessageHandlerFunction log_message_handler = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
void SetMinLogLevel(int level) {
|
||||
g_min_log_level = std::min(LOG_FATAL, level);
|
||||
}
|
||||
|
||||
int GetMinLogLevel() {
|
||||
return min_log_level;
|
||||
return g_min_log_level;
|
||||
}
|
||||
|
||||
bool ShouldCreateLogMessage(int severity) {
|
||||
if (severity < g_min_log_level)
|
||||
return false;
|
||||
|
||||
// Return true here unless we know ~LogMessage won't do anything. Note that
|
||||
// ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even
|
||||
// when g_logging_destination is LOG_NONE.
|
||||
return g_logging_destination != LOG_NONE || log_message_handler ||
|
||||
severity >= kAlwaysPrintErrorLevel;
|
||||
}
|
||||
|
||||
int GetVlogLevelHelper(const char* file, size_t N) {
|
||||
|
@ -67,6 +92,10 @@ LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
|
|||
: severity_(severity), file_(file), line_(line) {
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, const char* condition)
|
||||
: severity_(LOG_FATAL), file_(file), line_(line) {
|
||||
}
|
||||
|
||||
LogMessage::LogMessage(const char* file, int line, std::string* result)
|
||||
: severity_(LOG_FATAL), file_(file), line_(line) {
|
||||
delete result;
|
||||
|
|
|
@ -48,6 +48,24 @@ typedef LPSTARTUPINFOEXA LPSTARTUPINFOEX;
|
|||
#define PROCESS_DEP_ENABLE 0x00000001
|
||||
#define PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION 0x00000002
|
||||
|
||||
// They dynamically load these, but they still use the functions to describe the
|
||||
// function pointers!
|
||||
WINBASEAPI
|
||||
int
|
||||
WINAPI
|
||||
GetUserDefaultLocaleName(
|
||||
_Out_writes_(cchLocaleName) LPWSTR lpLocaleName,
|
||||
_In_ int cchLocaleName
|
||||
);
|
||||
|
||||
WINBASEAPI
|
||||
BOOL
|
||||
WINAPI
|
||||
QueryThreadCycleTime(
|
||||
_In_ HANDLE ThreadHandle,
|
||||
_Out_ PULONG64 CycleTime
|
||||
);
|
||||
|
||||
#endif // (_WIN32_WINNT >= 0x0600)
|
||||
|
||||
#if (_WIN32_WINNT < 0x0601)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#include <stack>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
|
||||
namespace base {
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
|
||||
// This is a low level implementation of atomic semantics for reference
|
||||
// counting. Please use base/memory/ref_counted.h directly instead.
|
||||
//
|
||||
// The implementation includes annotations to avoid some false positives
|
||||
// when using data race detection tools.
|
||||
|
||||
#ifndef BASE_ATOMIC_REF_COUNT_H_
|
||||
#define BASE_ATOMIC_REF_COUNT_H_
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#define BASE_ATOMIC_SEQUENCE_NUM_H_
|
||||
|
||||
#include "base/atomicops.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/macros.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
|
|
|
@ -28,10 +28,14 @@
|
|||
#ifndef BASE_ATOMICOPS_H_
|
||||
#define BASE_ATOMICOPS_H_
|
||||
|
||||
#include <cassert> // Small C++ header which defines implementation specific
|
||||
// macros used to identify the STL implementation.
|
||||
#include <stdint.h>
|
||||
|
||||
// Small C++ header which defines implementation specific macros used to
|
||||
// identify the STL implementation.
|
||||
// - libc++: captures __config for _LIBCPP_VERSION
|
||||
// - libstdc++: captures bits/c++config.h for __GLIBCXX__
|
||||
#include <cstddef>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
|
@ -140,65 +144,13 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
|
|||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
// The following x86 CPU features are used in atomicops_internals_x86_gcc.h, but
|
||||
// this file is duplicated inside of Chrome: protobuf and tcmalloc rely on the
|
||||
// struct being present at link time. Some parts of Chrome can currently use the
|
||||
// portable interface whereas others still use GCC one. The include guards are
|
||||
// the same as in atomicops_internals_x86_gcc.cc.
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
// This struct is not part of the public API of this module; clients may not
|
||||
// use it. (However, it's exported via BASE_EXPORT because clients implicitly
|
||||
// do use it at link time by inlining these functions.)
|
||||
// Features of this x86. Values may not be correct before main() is run,
|
||||
// but are set conservatively.
|
||||
struct AtomicOps_x86CPUFeatureStruct {
|
||||
bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
|
||||
// after acquire compare-and-swap.
|
||||
// The following fields are unused by Chrome's base implementation but are
|
||||
// still used by copies of the same code in other parts of the code base. This
|
||||
// causes an ODR violation, and the other code is likely reading invalid
|
||||
// memory.
|
||||
// TODO(jfb) Delete these fields once the rest of the Chrome code base doesn't
|
||||
// depend on them.
|
||||
bool has_sse2; // Processor has SSE2.
|
||||
bool has_cmpxchg16b; // Processor supports cmpxchg16b instruction.
|
||||
};
|
||||
BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
|
||||
AtomicOps_Internalx86CPUFeatures;
|
||||
#endif
|
||||
|
||||
// Try to use a portable implementation based on C++11 atomics.
|
||||
//
|
||||
// Some toolchains support C++11 language features without supporting library
|
||||
// features (recent compiler, older STL). Whitelist libstdc++ and libc++ that we
|
||||
// know will have <atomic> when compiling C++11.
|
||||
#if ((__cplusplus >= 201103L) && \
|
||||
((defined(__GLIBCXX__) && (__GLIBCXX__ > 20110216)) || \
|
||||
(defined(_LIBCPP_VERSION) && (_LIBCPP_STD_VER >= 11))))
|
||||
#if defined(OS_WIN)
|
||||
// TODO(jfb): The MSVC header includes windows.h, which other files end up
|
||||
// relying on. Fix this as part of crbug.com/559247.
|
||||
# include "base/atomicops_internals_x86_msvc.h"
|
||||
#else
|
||||
# include "base/atomicops_internals_portable.h"
|
||||
#else // Otherwise use a platform specific implementation.
|
||||
# if defined(THREAD_SANITIZER)
|
||||
# error "Thread sanitizer must use the portable atomic operations"
|
||||
# elif (defined(OS_WIN) && defined(COMPILER_MSVC) && \
|
||||
defined(ARCH_CPU_X86_FAMILY))
|
||||
# include "base/atomicops_internals_x86_msvc.h"
|
||||
# elif defined(OS_MACOSX)
|
||||
# include "base/atomicops_internals_mac.h"
|
||||
# elif defined(OS_NACL)
|
||||
# include "base/atomicops_internals_gcc.h"
|
||||
# elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARMEL)
|
||||
# include "base/atomicops_internals_arm_gcc.h"
|
||||
# elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM64)
|
||||
# include "base/atomicops_internals_arm64_gcc.h"
|
||||
# elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
|
||||
# include "base/atomicops_internals_x86_gcc.h"
|
||||
# elif (defined(COMPILER_GCC) && \
|
||||
(defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY)))
|
||||
# include "base/atomicops_internals_mips_gcc.h"
|
||||
# else
|
||||
# error "Atomic operations are not supported on your platform"
|
||||
# endif
|
||||
#endif // Portable / non-portable includes.
|
||||
#endif
|
||||
|
||||
// On some platforms we need additional declarations to make
|
||||
// AtomicWord compatible with our other Atomic* types.
|
||||
|
|
|
@ -1,294 +0,0 @@
|
|||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file is an internal atomic implementation, use base/atomicops.h instead.
|
||||
//
|
||||
// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
|
||||
|
||||
#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
||||
#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
||||
|
||||
#if defined(OS_QNX)
|
||||
#include <sys/cpuinline.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
// Memory barriers on ARM are funky, but the kernel is here to help:
|
||||
//
|
||||
// * ARMv5 didn't support SMP, there is no memory barrier instruction at
|
||||
// all on this architecture, or when targeting its machine code.
|
||||
//
|
||||
// * Some ARMv6 CPUs support SMP. A full memory barrier can be produced by
|
||||
// writing a random value to a very specific coprocessor register.
|
||||
//
|
||||
// * On ARMv7, the "dmb" instruction is used to perform a full memory
|
||||
// barrier (though writing to the co-processor will still work).
|
||||
// However, on single core devices (e.g. Nexus One, or Nexus S),
|
||||
// this instruction will take up to 200 ns, which is huge, even though
|
||||
// it's completely un-needed on these devices.
|
||||
//
|
||||
// * There is no easy way to determine at runtime if the device is
|
||||
// single or multi-core. However, the kernel provides a useful helper
|
||||
// function at a fixed memory address (0xffff0fa0), which will always
|
||||
// perform a memory barrier in the most efficient way. I.e. on single
|
||||
// core devices, this is an empty function that exits immediately.
|
||||
// On multi-core devices, it implements a full memory barrier.
|
||||
//
|
||||
// * This source could be compiled to ARMv5 machine code that runs on a
|
||||
// multi-core ARMv6 or ARMv7 device. In this case, memory barriers
|
||||
// are needed for correct execution. Always call the kernel helper, even
|
||||
// when targeting ARMv5TE.
|
||||
//
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
// Note: This is a function call, which is also an implicit compiler barrier.
|
||||
typedef void (*KernelMemoryBarrierFunc)();
|
||||
((KernelMemoryBarrierFunc)0xffff0fa0)();
|
||||
#elif defined(OS_QNX)
|
||||
__cpu_membarrier();
|
||||
#else
|
||||
#error MemoryBarrier() is not implemented on this platform.
|
||||
#endif
|
||||
}
|
||||
|
||||
// An ARM toolchain would only define one of these depending on which
|
||||
// variant of the target architecture is being used. This tests against
|
||||
// any known ARMv6 or ARMv7 variant, where it is possible to directly
|
||||
// use ldrex/strex instructions to implement fast atomic operations.
|
||||
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
|
||||
defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || \
|
||||
defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
|
||||
defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
|
||||
defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value;
|
||||
int reloop;
|
||||
do {
|
||||
// The following is equivalent to:
|
||||
//
|
||||
// prev_value = LDREX(ptr)
|
||||
// reloop = 0
|
||||
// if (prev_value != old_value)
|
||||
// reloop = STREX(ptr, new_value)
|
||||
__asm__ __volatile__(" ldrex %0, [%3]\n"
|
||||
" mov %1, #0\n"
|
||||
" cmp %0, %4\n"
|
||||
#ifdef __thumb2__
|
||||
" it eq\n"
|
||||
#endif
|
||||
" strexeq %1, %5, [%3]\n"
|
||||
: "=&r"(prev_value), "=&r"(reloop), "+m"(*ptr)
|
||||
: "r"(ptr), "r"(old_value), "r"(new_value)
|
||||
: "cc", "memory");
|
||||
} while (reloop != 0);
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 result = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
MemoryBarrier();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
MemoryBarrier();
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 value;
|
||||
int reloop;
|
||||
do {
|
||||
// Equivalent to:
|
||||
//
|
||||
// value = LDREX(ptr)
|
||||
// value += increment
|
||||
// reloop = STREX(ptr, value)
|
||||
//
|
||||
__asm__ __volatile__(" ldrex %0, [%3]\n"
|
||||
" add %0, %0, %4\n"
|
||||
" strex %1, %0, [%3]\n"
|
||||
: "=&r"(value), "=&r"(reloop), "+m"(*ptr)
|
||||
: "r"(ptr), "r"(increment)
|
||||
: "cc", "memory");
|
||||
} while (reloop);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
// TODO(digit): Investigate if it's possible to implement this with
|
||||
// a single MemoryBarrier() operation between the LDREX and STREX.
|
||||
// See http://crbug.com/246514
|
||||
MemoryBarrier();
|
||||
Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
|
||||
MemoryBarrier();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 old_value;
|
||||
int reloop;
|
||||
do {
|
||||
// old_value = LDREX(ptr)
|
||||
// reloop = STREX(ptr, new_value)
|
||||
__asm__ __volatile__(" ldrex %0, [%3]\n"
|
||||
" strex %1, %4, [%3]\n"
|
||||
: "=&r"(old_value), "=&r"(reloop), "+m"(*ptr)
|
||||
: "r"(ptr), "r"(new_value)
|
||||
: "cc", "memory");
|
||||
} while (reloop != 0);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
// This tests against any known ARMv5 variant.
|
||||
#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
|
||||
defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
|
||||
|
||||
// The kernel also provides a helper function to perform an atomic
|
||||
// compare-and-swap operation at the hard-wired address 0xffff0fc0.
|
||||
// On ARMv5, this is implemented by a special code path that the kernel
|
||||
// detects and treats specially when thread pre-emption happens.
|
||||
// On ARMv6 and higher, it uses LDREX/STREX instructions instead.
|
||||
//
|
||||
// Note that this always perform a full memory barrier, there is no
|
||||
// need to add calls MemoryBarrier() before or after it. It also
|
||||
// returns 0 on success, and 1 on exit.
|
||||
//
|
||||
// Available and reliable since Linux 2.6.24. Both Android and ChromeOS
|
||||
// use newer kernel revisions, so this should not be a concern.
|
||||
namespace {
|
||||
|
||||
inline int LinuxKernelCmpxchg(Atomic32 old_value,
|
||||
Atomic32 new_value,
|
||||
volatile Atomic32* ptr) {
|
||||
typedef int (*KernelCmpxchgFunc)(Atomic32, Atomic32, volatile Atomic32*);
|
||||
return ((KernelCmpxchgFunc)0xffff0fc0)(old_value, new_value, ptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value;
|
||||
for (;;) {
|
||||
prev_value = *ptr;
|
||||
if (prev_value != old_value)
|
||||
return prev_value;
|
||||
if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
|
||||
return old_value;
|
||||
}
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 old_value;
|
||||
do {
|
||||
old_value = *ptr;
|
||||
} while (LinuxKernelCmpxchg(old_value, new_value, ptr));
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
for (;;) {
|
||||
// Atomic exchange the old value with an incremented one.
|
||||
Atomic32 old_value = *ptr;
|
||||
Atomic32 new_value = old_value + increment;
|
||||
if (!LinuxKernelCmpxchg(old_value, new_value, ptr)) {
|
||||
// The exchange took place as expected.
|
||||
return new_value;
|
||||
}
|
||||
// Otherwise, *ptr changed mid-loop and we need to retry.
|
||||
}
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value;
|
||||
for (;;) {
|
||||
prev_value = *ptr;
|
||||
if (prev_value != old_value) {
|
||||
// Always ensure acquire semantics.
|
||||
MemoryBarrier();
|
||||
return prev_value;
|
||||
}
|
||||
if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
|
||||
return old_value;
|
||||
}
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
// This could be implemented as:
|
||||
// MemoryBarrier();
|
||||
// return NoBarrier_CompareAndSwap();
|
||||
//
|
||||
// But would use 3 barriers per succesful CAS. To save performance,
|
||||
// use Acquire_CompareAndSwap(). Its implementation guarantees that:
|
||||
// - A succesful swap uses only 2 barriers (in the kernel helper).
|
||||
// - An early return due to (prev_value != old_value) performs
|
||||
// a memory barrier with no store, which is equivalent to the
|
||||
// generic implementation above.
|
||||
return Acquire_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
#else
|
||||
# error "Your CPU's ARM architecture is not supported yet"
|
||||
#endif
|
||||
|
||||
// NOTE: Atomicity of the following load and store operations is only
|
||||
// guaranteed in case of 32-bit alignement of |ptr| values.
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; }
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
} // namespace base::subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
#include <atomic>
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
|
@ -221,7 +223,7 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
|||
}
|
||||
|
||||
#endif // defined(ARCH_CPU_64_BITS)
|
||||
}
|
||||
} // namespace base::subtle
|
||||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
|
||||
|
|
|
@ -1,228 +0,0 @@
|
|||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file is an internal atomic implementation, use base/atomicops.h instead.
|
||||
|
||||
#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|
||||
#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|
||||
|
||||
#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
// 32-bit low-level operations on any platform.
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev;
|
||||
__asm__ __volatile__("lock; cmpxchgl %1,%2"
|
||||
: "=a" (prev)
|
||||
: "q" (new_value), "m" (*ptr), "0" (old_value)
|
||||
: "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
__asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg.
|
||||
: "=r" (new_value)
|
||||
: "m" (*ptr), "0" (new_value)
|
||||
: "memory");
|
||||
return new_value; // Now it's the previous value.
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddl %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now holds the old value of *ptr
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddl %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now holds the old value of *ptr
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
__asm__ __volatile__("mfence" : : : "memory");
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
*ptr = value; // An x86 store acts as a release barrier.
|
||||
// See comments in Atomic64 version of Release_Store(), below.
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
|
||||
// See comments in Atomic64 version of Release_Store(), below.
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
// 64-bit low-level operations on 64-bit platform.
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 prev;
|
||||
__asm__ __volatile__("lock; cmpxchgq %1,%2"
|
||||
: "=a" (prev)
|
||||
: "q" (new_value), "m" (*ptr), "0" (old_value)
|
||||
: "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
|
||||
Atomic64 new_value) {
|
||||
__asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg.
|
||||
: "=r" (new_value)
|
||||
: "m" (*ptr), "0" (new_value)
|
||||
: "memory");
|
||||
return new_value; // Now it's the previous value.
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
Atomic64 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddq %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now contains the previous value of *ptr
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
Atomic64 temp = increment;
|
||||
__asm__ __volatile__("lock; xaddq %0,%1"
|
||||
: "+r" (temp), "+m" (*ptr)
|
||||
: : "memory");
|
||||
// temp now contains the previous value of *ptr
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return temp + increment;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
|
||||
*ptr = value; // An x86 store acts as a release barrier
|
||||
// for current AMD/Intel chips as of Jan 2008.
|
||||
// See also Acquire_Load(), below.
|
||||
|
||||
// When new chips come out, check:
|
||||
// IA-32 Intel Architecture Software Developer's Manual, Volume 3:
|
||||
// System Programming Guide, Chatper 7: Multiple-processor management,
|
||||
// Section 7.2, Memory Ordering.
|
||||
// Last seen at:
|
||||
// http://developer.intel.com/design/pentium4/manuals/index_new.htm
|
||||
//
|
||||
// x86 stores/loads fail to act as barriers for a few instructions (clflush
|
||||
// maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
|
||||
// not generated by the compiler, and are rare. Users of these instructions
|
||||
// need to know about cache behaviour in any case since all of these involve
|
||||
// either flushing cache lines or non-temporal cache hints.
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
|
||||
// for current AMD/Intel chips as of Jan 2008.
|
||||
// See also Release_Store(), above.
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
|
||||
__asm__ __volatile__("lfence" : : : "memory");
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
#endif // defined(__x86_64__)
|
||||
|
||||
} // namespace base::subtle
|
||||
} // namespace base
|
||||
|
||||
#undef ATOMICOPS_COMPILER_BARRIER
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|
|
@ -12,6 +12,7 @@
|
|||
#include <intrin.h>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
// windows.h #defines this (only on x64). This causes problems because the
|
||||
|
@ -55,9 +56,6 @@ inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
|||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
|
||||
#error "We require at least vs2005 for MemoryBarrier"
|
||||
#endif
|
||||
inline void MemoryBarrier() {
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
// See #undef and note at the top of this file.
|
||||
|
@ -112,7 +110,7 @@ inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
|||
|
||||
// 64-bit low-level operations on 64-bit platform.
|
||||
|
||||
COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
|
||||
static_assert(sizeof(Atomic64) == sizeof(PVOID), "atomic word is atomic");
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
|
@ -192,7 +190,7 @@ inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
|||
|
||||
#endif // defined(_WIN64)
|
||||
|
||||
} // namespace base::subtle
|
||||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
|
||||
|
|
|
@ -10,25 +10,20 @@
|
|||
|
||||
#if defined(BASE_IMPLEMENTATION)
|
||||
#define BASE_EXPORT __declspec(dllexport)
|
||||
#define BASE_EXPORT_PRIVATE __declspec(dllexport)
|
||||
#else
|
||||
#define BASE_EXPORT __declspec(dllimport)
|
||||
#define BASE_EXPORT_PRIVATE __declspec(dllimport)
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
|
||||
#else // defined(WIN32)
|
||||
#if defined(BASE_IMPLEMENTATION)
|
||||
#define BASE_EXPORT __attribute__((visibility("default")))
|
||||
#define BASE_EXPORT_PRIVATE __attribute__((visibility("default")))
|
||||
#else
|
||||
#define BASE_EXPORT
|
||||
#define BASE_EXPORT_PRIVATE
|
||||
#endif // defined(BASE_IMPLEMENTATION)
|
||||
#endif
|
||||
|
||||
#else // defined(COMPONENT_BUILD)
|
||||
#define BASE_EXPORT
|
||||
#define BASE_EXPORT_PRIVATE
|
||||
#endif
|
||||
|
||||
#endif // BASE_BASE_EXPORT_H_
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_BASE_PATHS_WIN_H__
|
||||
#define BASE_BASE_PATHS_WIN_H__
|
||||
#ifndef BASE_BASE_PATHS_WIN_H_
|
||||
#define BASE_BASE_PATHS_WIN_H_
|
||||
|
||||
// This file declares windows-specific path keys for the base module.
|
||||
// These can be used with the PathService to access various special
|
||||
|
@ -16,8 +16,14 @@ enum {
|
|||
|
||||
DIR_WINDOWS, // Windows directory, usually "c:\windows"
|
||||
DIR_SYSTEM, // Usually c:\windows\system32"
|
||||
DIR_PROGRAM_FILES, // Usually c:\program files
|
||||
DIR_PROGRAM_FILESX86, // Usually c:\program files or c:\program files (x86)
|
||||
// 32-bit 32-bit on 64-bit 64-bit on 64-bit
|
||||
// DIR_PROGRAM_FILES 1 2 1
|
||||
// DIR_PROGRAM_FILESX86 1 2 2
|
||||
// DIR_PROGRAM_FILES6432 1 1 1
|
||||
// 1 - C:\Program Files 2 - C:\Program Files (x86)
|
||||
DIR_PROGRAM_FILES, // See table above.
|
||||
DIR_PROGRAM_FILESX86, // See table above.
|
||||
DIR_PROGRAM_FILES6432, // See table above.
|
||||
|
||||
DIR_IE_INTERNET_CACHE, // Temporary Internet Files directory.
|
||||
DIR_COMMON_START_MENU, // Usually "C:\Documents and Settings\All Users\
|
||||
|
@ -36,8 +42,8 @@ enum {
|
|||
DIR_COMMON_DESKTOP, // Directory for the common desktop (visible
|
||||
// on all user's Desktop).
|
||||
DIR_USER_QUICK_LAUNCH, // Directory for the quick launch shortcuts.
|
||||
DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar via
|
||||
// base::win::TaskbarPinShortcutLink().
|
||||
DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar
|
||||
// (Win7-8) via base::win::PinShortcutToTaskbar().
|
||||
DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts.
|
||||
|
||||
PATH_WIN_END
|
||||
|
@ -45,4 +51,4 @@ enum {
|
|||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BASE_PATHS_WIN_H__
|
||||
#endif // BASE_BASE_PATHS_WIN_H_
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
#include "base/base_switches.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace switches {
|
||||
|
||||
|
@ -14,13 +15,29 @@ const char kDisableBreakpad[] = "disable-breakpad";
|
|||
// generated internally.
|
||||
const char kEnableCrashReporter[] = "enable-crash-reporter";
|
||||
|
||||
// Makes memory allocators keep track of their allocations and context, so a
|
||||
// detailed breakdown of memory usage can be presented in chrome://tracing when
|
||||
// the memory-infra category is enabled.
|
||||
const char kEnableHeapProfiling[] = "enable-heap-profiling";
|
||||
|
||||
// Generates full memory crash dump.
|
||||
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
|
||||
|
||||
// Force low-end device when set to 1;
|
||||
// Auto-detect low-end device when set to 2;
|
||||
// Force non-low-end device when set to other values or empty;
|
||||
const char kLowEndDeviceMode[] = "low-end-device-mode";
|
||||
// Force low-end device mode when set.
|
||||
const char kEnableLowEndDeviceMode[] = "enable-low-end-device-mode";
|
||||
|
||||
// Force disabling of low-end device mode when set.
|
||||
const char kDisableLowEndDeviceMode[] = "disable-low-end-device-mode";
|
||||
|
||||
// This option can be used to force field trials when testing changes locally.
|
||||
// The argument is a list of name and value pairs, separated by slashes. If a
|
||||
// trial name is prefixed with an asterisk, that trial will start activated.
|
||||
// For example, the following argument defines two trials, with the second one
|
||||
// activated: "GoogleNow/Enable/*MaterialDesignNTP/Default/" This option can
|
||||
// also be used by the browser process to send the list of trials to a
|
||||
// non-browser process, using the same format. See
|
||||
// FieldTrialList::CreateTrialsFromString() in field_trial.h for details.
|
||||
const char kForceFieldTrials[] = "force-fieldtrials";
|
||||
|
||||
// Suppresses all error dialogs when present.
|
||||
const char kNoErrorDialogs[] = "noerrdialogs";
|
||||
|
@ -47,9 +64,6 @@ const char kVModule[] = "vmodule";
|
|||
// Will wait for 60 seconds for a debugger to come to attach to the process.
|
||||
const char kWaitForDebugger[] = "wait-for-debugger";
|
||||
|
||||
// Sends a pretty-printed version of tracing info to the console.
|
||||
const char kTraceToConsole[] = "trace-to-console";
|
||||
|
||||
// Sends trace events from these categories to a file.
|
||||
// --trace-to-file on its own sends to default categories.
|
||||
const char kTraceToFile[] = "trace-to-file";
|
||||
|
@ -66,6 +80,11 @@ const char kProfilerTiming[] = "profiler-timing";
|
|||
// chrome://profiler.
|
||||
const char kProfilerTimingDisabledValue[] = "0";
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Disables the USB keyboard detection for blocking the OSK on Win8+.
|
||||
const char kDisableUsbKeyboardDetect[] = "disable-usb-keyboard-detect";
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// Used for turning on Breakpad crash reporting in a debug environment where
|
||||
// crash reporting is typically compiled but disabled.
|
||||
|
|
|
@ -12,20 +12,26 @@
|
|||
namespace switches {
|
||||
|
||||
extern const char kDisableBreakpad[];
|
||||
extern const char kDisableLowEndDeviceMode[];
|
||||
extern const char kEnableCrashReporter[];
|
||||
extern const char kEnableHeapProfiling[];
|
||||
extern const char kEnableLowEndDeviceMode[];
|
||||
extern const char kForceFieldTrials[];
|
||||
extern const char kFullMemoryCrashReport[];
|
||||
extern const char kLowEndDeviceMode[];
|
||||
extern const char kNoErrorDialogs[];
|
||||
extern const char kProfilerTiming[];
|
||||
extern const char kProfilerTimingDisabledValue[];
|
||||
extern const char kTestChildProcess[];
|
||||
extern const char kTraceToConsole[];
|
||||
extern const char kTraceToFile[];
|
||||
extern const char kTraceToFileName[];
|
||||
extern const char kV[];
|
||||
extern const char kVModule[];
|
||||
extern const char kWaitForDebugger[];
|
||||
|
||||
#if defined(OS_WIN)
|
||||
extern const char kDisableUsbKeyboardDetect[];
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
extern const char kEnableCrashReporterForTesting[];
|
||||
#endif
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file contains definitions of our old basic integral types
|
||||
// ((u)int{8,16,32,64}) and further includes. I recommend that you use the C99
|
||||
// standard types instead, and include <stdint.h>/<stddef.h>/etc. as needed.
|
||||
// Note that the macros and macro-like constructs that were formerly defined in
|
||||
// this file are now available separately in base/macros.h.
|
||||
|
||||
#ifndef BASE_BASICTYPES_H_
|
||||
#define BASE_BASICTYPES_H_
|
||||
|
||||
#include <limits.h> // So we can set the bounds of our types.
|
||||
#include <stddef.h> // For size_t.
|
||||
#include <stdint.h> // For intptr_t.
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/port.h" // Types that only need exist on certain systems.
|
||||
|
||||
// DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
|
||||
typedef int8_t int8;
|
||||
typedef uint8_t uint8;
|
||||
typedef int16_t int16;
|
||||
typedef uint16_t uint16;
|
||||
typedef int32_t int32;
|
||||
typedef uint32_t uint32;
|
||||
typedef int64_t int64;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
// DEPRECATED: Please use std::numeric_limits (from <limits>) instead.
|
||||
const uint8 kuint8max = 0xFF;
|
||||
const uint16 kuint16max = 0xFFFF;
|
||||
const uint32 kuint32max = 0xFFFFFFFF;
|
||||
const uint64 kuint64max = 0xFFFFFFFFFFFFFFFFULL;
|
||||
const int8 kint8min = -0x7F - 1;
|
||||
const int8 kint8max = 0x7F;
|
||||
const int16 kint16min = -0x7FFF - 1;
|
||||
const int16 kint16max = 0x7FFF;
|
||||
const int32 kint32min = -0x7FFFFFFF - 1;
|
||||
const int32 kint32max = 0x7FFFFFFF;
|
||||
const int64 kint64min = -0x7FFFFFFFFFFFFFFFLL - 1;
|
||||
const int64 kint64max = 0x7FFFFFFFFFFFFFFFLL;
|
||||
|
||||
#endif // BASE_BASICTYPES_H_
|
|
@ -1,8 +1,3 @@
|
|||
// This file was GENERATED by command:
|
||||
// pump.py bind.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
@ -46,464 +41,59 @@
|
|||
//
|
||||
// TODO(ajwong): We might be able to avoid this now, but need to test.
|
||||
//
|
||||
// It is possible to move most of the COMPILE_ASSERT asserts into BindState<>,
|
||||
// but it feels a little nicer to have the asserts here so people do not
|
||||
// need to crack open bind_internal.h. On the other hand, it makes Bind()
|
||||
// harder to read.
|
||||
// It is possible to move most of the static_assert into BindState<>, but it
|
||||
// feels a little nicer to have the asserts here so people do not need to crack
|
||||
// open bind_internal.h. On the other hand, it makes Bind() harder to read.
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Functor>
|
||||
template <typename Functor, typename... Args>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void()>
|
||||
typename internal::CallbackParamTraits<Args>::StorageType...>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
typedef internal::BindState<RunnableType, RunType, void()> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor)));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
Bind(Functor functor, const Args&... args) {
|
||||
// Type aliases for how to store and run the functor.
|
||||
using RunnableType = typename internal::FunctorTraits<Functor>::RunnableType;
|
||||
using RunType = typename internal::FunctorTraits<Functor>::RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// checks below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
using BoundRunType = typename RunnableType::RunType;
|
||||
|
||||
using BoundArgs =
|
||||
internal::TakeTypeListItem<sizeof...(Args),
|
||||
internal::ExtractArgs<BoundRunType>>;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
static_assert(!internal::HasNonConstReferenceItem<BoundArgs>::value,
|
||||
"do not bind functions with nonconst ref");
|
||||
|
||||
const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType)> BindState;
|
||||
static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value,
|
||||
"first bound argument to method cannot be array");
|
||||
static_assert(
|
||||
!internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value,
|
||||
"a parameter is a refcounted type and needs scoped_refptr");
|
||||
|
||||
using BindState = internal::BindState<
|
||||
RunnableType, RunType,
|
||||
typename internal::CallbackParamTraits<Args>::StorageType...>;
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
|
||||
typename P5>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
|
||||
const P5& p5) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
|
||||
p5_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
|
||||
typename P5, typename P6>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
|
||||
const P5& p5, const P6& p6) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
|
||||
p5_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
|
||||
p6_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6));
|
||||
}
|
||||
|
||||
template <typename Functor, typename P1, typename P2, typename P3, typename P4,
|
||||
typename P5, typename P6, typename P7>
|
||||
base::Callback<
|
||||
typename internal::BindState<
|
||||
typename internal::FunctorTraits<Functor>::RunnableType,
|
||||
typename internal::FunctorTraits<Functor>::RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType,
|
||||
typename internal::CallbackParamTraits<P7>::StorageType)>
|
||||
::UnboundRunType>
|
||||
Bind(Functor functor, const P1& p1, const P2& p2, const P3& p3, const P4& p4,
|
||||
const P5& p5, const P6& p6, const P7& p7) {
|
||||
// Typedefs for how to store and run the functor.
|
||||
typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
|
||||
typedef typename internal::FunctorTraits<Functor>::RunType RunType;
|
||||
|
||||
// Use RunnableType::RunType instead of RunType above because our
|
||||
// checks should below for bound references need to know what the actual
|
||||
// functor is going to interpret the argument as.
|
||||
typedef internal::FunctionTraits<typename RunnableType::RunType>
|
||||
BoundFunctorTraits;
|
||||
|
||||
// Do not allow binding a non-const reference parameter. Non-const reference
|
||||
// parameters are disallowed by the Google style guide. Also, binding a
|
||||
// non-const reference parameter can make for subtle bugs because the
|
||||
// invoked function will receive a reference to the stored copy of the
|
||||
// argument and not the original.
|
||||
COMPILE_ASSERT(
|
||||
!(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A2Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A3Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A4Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A5Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A6Type>::value ||
|
||||
is_non_const_reference<typename BoundFunctorTraits::A7Type>::value ),
|
||||
do_not_bind_functions_with_nonconst_ref);
|
||||
|
||||
// For methods, we need to be careful for parameter 1. We do not require
|
||||
// a scoped_refptr because BindState<> itself takes care of AddRef() for
|
||||
// methods. We also disallow binding of an array as the method's target
|
||||
// object.
|
||||
COMPILE_ASSERT(
|
||||
internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!internal::NeedsScopedRefptrButGetsRawPtr<P1>::value,
|
||||
p1_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value ||
|
||||
!is_array<P1>::value,
|
||||
first_bound_argument_to_method_cannot_be_array);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P2>::value,
|
||||
p2_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P3>::value,
|
||||
p3_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P4>::value,
|
||||
p4_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P5>::value,
|
||||
p5_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P6>::value,
|
||||
p6_is_refcounted_type_and_needs_scoped_refptr);
|
||||
COMPILE_ASSERT(!internal::NeedsScopedRefptrButGetsRawPtr<P7>::value,
|
||||
p7_is_refcounted_type_and_needs_scoped_refptr);
|
||||
typedef internal::BindState<RunnableType, RunType,
|
||||
void(typename internal::CallbackParamTraits<P1>::StorageType,
|
||||
typename internal::CallbackParamTraits<P2>::StorageType,
|
||||
typename internal::CallbackParamTraits<P3>::StorageType,
|
||||
typename internal::CallbackParamTraits<P4>::StorageType,
|
||||
typename internal::CallbackParamTraits<P5>::StorageType,
|
||||
typename internal::CallbackParamTraits<P6>::StorageType,
|
||||
typename internal::CallbackParamTraits<P7>::StorageType)> BindState;
|
||||
|
||||
|
||||
return Callback<typename BindState::UnboundRunType>(
|
||||
new BindState(internal::MakeRunnable(functor), p1, p2, p3, p4, p5, p6,
|
||||
p7));
|
||||
new BindState(internal::MakeRunnable(functor), args...));
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
// scoped_ptr<Foo> f(new Foo());
|
||||
//
|
||||
// // |cb| is given ownership of Foo(). |f| is now NULL.
|
||||
// // You can use f.Pass() in place of &f, but it's more verbose.
|
||||
// // You can use std::move(f) in place of &f, but it's more verbose.
|
||||
// Closure cb = Bind(&TakesOwnership, Passed(&f));
|
||||
//
|
||||
// // Run was never called so |cb| still owns Foo() and deletes
|
||||
|
@ -129,7 +129,7 @@
|
|||
// Passed() is particularly useful with PostTask() when you are transferring
|
||||
// ownership of an argument into a task, but don't necessarily know if the
|
||||
// task will always be executed. This can happen if the task is cancellable
|
||||
// or if it is posted to a MessageLoopProxy.
|
||||
// or if it is posted to a TaskRunner.
|
||||
//
|
||||
//
|
||||
// SIMPLE FUNCTIONS AND UTILITIES.
|
||||
|
@ -143,10 +143,15 @@
|
|||
#ifndef BASE_BIND_HELPERS_H_
|
||||
#define BASE_BIND_HELPERS_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/template_util.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
|
@ -185,7 +190,7 @@ namespace internal {
|
|||
// want to probe for. Then we create a class Base that inherits from both T
|
||||
// (the class we wish to probe) and BaseMixin. Note that the function
|
||||
// signature in BaseMixin does not need to match the signature of the function
|
||||
// we are probing for; thus it's easiest to just use void(void).
|
||||
// we are probing for; thus it's easiest to just use void().
|
||||
//
|
||||
// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
|
||||
// ambiguous resolution between BaseMixin and T. This lets us write the
|
||||
|
@ -222,8 +227,8 @@ namespace internal {
|
|||
// See http://crbug.com/82038.
|
||||
template <typename T>
|
||||
class SupportsAddRefAndRelease {
|
||||
typedef char Yes[1];
|
||||
typedef char No[2];
|
||||
using Yes = char[1];
|
||||
using No = char[2];
|
||||
|
||||
struct BaseMixin {
|
||||
void AddRef();
|
||||
|
@ -242,7 +247,7 @@ class SupportsAddRefAndRelease {
|
|||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <void(BaseMixin::*)(void)> struct Helper {};
|
||||
template <void(BaseMixin::*)()> struct Helper {};
|
||||
|
||||
template <typename C>
|
||||
static No& Check(Helper<&C::AddRef>*);
|
||||
|
@ -276,8 +281,8 @@ struct UnsafeBindtoRefCountedArg<T*>
|
|||
|
||||
template <typename T>
|
||||
class HasIsMethodTag {
|
||||
typedef char Yes[1];
|
||||
typedef char No[2];
|
||||
using Yes = char[1];
|
||||
using No = char[2];
|
||||
|
||||
template <typename U>
|
||||
static Yes& Check(typename U::IsMethod*);
|
||||
|
@ -359,22 +364,24 @@ class OwnedWrapper {
|
|||
// created when we are explicitly trying to do a destructive move.
|
||||
//
|
||||
// Two notes:
|
||||
// 1) PassedWrapper supports any type that has a "Pass()" function.
|
||||
// This is intentional. The whitelisting of which specific types we
|
||||
// support is maintained by CallbackParamTraits<>.
|
||||
// 1) PassedWrapper supports any type that has a move constructor, however
|
||||
// the type will need to be specifically whitelisted in order for it to be
|
||||
// bound to a Callback. We guard this explicitly at the call of Passed()
|
||||
// to make for clear errors. Things not given to Passed() will be forwarded
|
||||
// and stored by value which will not work for general move-only types.
|
||||
// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
|
||||
// scoper to a Callback and allow the Callback to execute once.
|
||||
template <typename T>
|
||||
class PassedWrapper {
|
||||
public:
|
||||
explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
|
||||
explicit PassedWrapper(T&& scoper)
|
||||
: is_valid_(true), scoper_(std::move(scoper)) {}
|
||||
PassedWrapper(const PassedWrapper& other)
|
||||
: is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
|
||||
}
|
||||
: is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
|
||||
T Pass() const {
|
||||
CHECK(is_valid_);
|
||||
is_valid_ = false;
|
||||
return scoper_.Pass();
|
||||
return std::move(scoper_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -385,13 +392,13 @@ class PassedWrapper {
|
|||
// Unwrap the stored parameters for the wrappers above.
|
||||
template <typename T>
|
||||
struct UnwrapTraits {
|
||||
typedef const T& ForwardType;
|
||||
using ForwardType = const T&;
|
||||
static ForwardType Unwrap(const T& o) { return o; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<UnretainedWrapper<T> > {
|
||||
typedef T* ForwardType;
|
||||
using ForwardType = T*;
|
||||
static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
|
||||
return unretained.get();
|
||||
}
|
||||
|
@ -399,7 +406,7 @@ struct UnwrapTraits<UnretainedWrapper<T> > {
|
|||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<ConstRefWrapper<T> > {
|
||||
typedef const T& ForwardType;
|
||||
using ForwardType = const T&;
|
||||
static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
|
||||
return const_ref.get();
|
||||
}
|
||||
|
@ -407,19 +414,19 @@ struct UnwrapTraits<ConstRefWrapper<T> > {
|
|||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<scoped_refptr<T> > {
|
||||
typedef T* ForwardType;
|
||||
using ForwardType = T*;
|
||||
static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<WeakPtr<T> > {
|
||||
typedef const WeakPtr<T>& ForwardType;
|
||||
using ForwardType = const WeakPtr<T>&;
|
||||
static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<OwnedWrapper<T> > {
|
||||
typedef T* ForwardType;
|
||||
using ForwardType = T*;
|
||||
static ForwardType Unwrap(const OwnedWrapper<T>& o) {
|
||||
return o.get();
|
||||
}
|
||||
|
@ -427,7 +434,7 @@ struct UnwrapTraits<OwnedWrapper<T> > {
|
|||
|
||||
template <typename T>
|
||||
struct UnwrapTraits<PassedWrapper<T> > {
|
||||
typedef T ForwardType;
|
||||
using ForwardType = T;
|
||||
static T Unwrap(PassedWrapper<T>& o) {
|
||||
return o.Pass();
|
||||
}
|
||||
|
@ -435,45 +442,46 @@ struct UnwrapTraits<PassedWrapper<T> > {
|
|||
|
||||
// Utility for handling different refcounting semantics in the Bind()
|
||||
// function.
|
||||
template <bool is_method, typename T>
|
||||
struct MaybeRefcount;
|
||||
template <bool is_method, typename... T>
|
||||
struct MaybeScopedRefPtr;
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<false, T> {
|
||||
static void AddRef(const T&) {}
|
||||
static void Release(const T&) {}
|
||||
template <bool is_method>
|
||||
struct MaybeScopedRefPtr<is_method> {
|
||||
MaybeScopedRefPtr() {}
|
||||
};
|
||||
|
||||
template <typename T, size_t n>
|
||||
struct MaybeRefcount<false, T[n]> {
|
||||
static void AddRef(const T*) {}
|
||||
static void Release(const T*) {}
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<false, T, Rest...> {
|
||||
MaybeScopedRefPtr(const T&, const Rest&...) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, T> {
|
||||
static void AddRef(const T&) {}
|
||||
static void Release(const T&) {}
|
||||
template <typename T, size_t n, typename... Rest>
|
||||
struct MaybeScopedRefPtr<false, T[n], Rest...> {
|
||||
MaybeScopedRefPtr(const T*, const Rest&...) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, T*> {
|
||||
static void AddRef(T* o) { o->AddRef(); }
|
||||
static void Release(T* o) { o->Release(); }
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<true, T, Rest...> {
|
||||
MaybeScopedRefPtr(const T& o, const Rest&...) {}
|
||||
};
|
||||
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<true, T*, Rest...> {
|
||||
MaybeScopedRefPtr(T* o, const Rest&...) : ref_(o) {}
|
||||
scoped_refptr<T> ref_;
|
||||
};
|
||||
|
||||
// No need to additionally AddRef() and Release() since we are storing a
|
||||
// scoped_refptr<> inside the storage object already.
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, scoped_refptr<T> > {
|
||||
static void AddRef(const scoped_refptr<T>& o) {}
|
||||
static void Release(const scoped_refptr<T>& o) {}
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<true, scoped_refptr<T>, Rest...> {
|
||||
MaybeScopedRefPtr(const scoped_refptr<T>&, const Rest&...) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MaybeRefcount<true, const T*> {
|
||||
static void AddRef(const T* o) { o->AddRef(); }
|
||||
static void Release(const T* o) { o->Release(); }
|
||||
template <typename T, typename... Rest>
|
||||
struct MaybeScopedRefPtr<true, const T*, Rest...> {
|
||||
MaybeScopedRefPtr(const T* o, const Rest&...) : ref_(o) {}
|
||||
scoped_refptr<const T> ref_;
|
||||
};
|
||||
|
||||
// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
|
||||
|
@ -481,15 +489,113 @@ struct MaybeRefcount<true, const T*> {
|
|||
// InvokeHelper that will no-op itself in the event the WeakPtr<> for
|
||||
// the target object is invalidated.
|
||||
//
|
||||
// P1 should be the type of the object that will be received of the method.
|
||||
template <bool IsMethod, typename P1>
|
||||
// The first argument should be the type of the object that will be received by
|
||||
// the method.
|
||||
template <bool IsMethod, typename... Args>
|
||||
struct IsWeakMethod : public false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsWeakMethod<true, WeakPtr<T> > : public true_type {};
|
||||
template <typename T, typename... Args>
|
||||
struct IsWeakMethod<true, WeakPtr<T>, Args...> : public true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T> > > : public true_type {};
|
||||
template <typename T, typename... Args>
|
||||
struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T>>, Args...>
|
||||
: public true_type {};
|
||||
|
||||
|
||||
// Packs a list of types to hold them in a single type.
|
||||
template <typename... Types>
|
||||
struct TypeList {};
|
||||
|
||||
// Used for DropTypeListItem implementation.
|
||||
template <size_t n, typename List>
|
||||
struct DropTypeListItemImpl;
|
||||
|
||||
// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
|
||||
template <size_t n, typename T, typename... List>
|
||||
struct DropTypeListItemImpl<n, TypeList<T, List...>>
|
||||
: DropTypeListItemImpl<n - 1, TypeList<List...>> {};
|
||||
|
||||
template <typename T, typename... List>
|
||||
struct DropTypeListItemImpl<0, TypeList<T, List...>> {
|
||||
using Type = TypeList<T, List...>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DropTypeListItemImpl<0, TypeList<>> {
|
||||
using Type = TypeList<>;
|
||||
};
|
||||
|
||||
// A type-level function that drops |n| list item from given TypeList.
|
||||
template <size_t n, typename List>
|
||||
using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
|
||||
|
||||
// Used for TakeTypeListItem implementation.
|
||||
template <size_t n, typename List, typename... Accum>
|
||||
struct TakeTypeListItemImpl;
|
||||
|
||||
// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
|
||||
template <size_t n, typename T, typename... List, typename... Accum>
|
||||
struct TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>
|
||||
: TakeTypeListItemImpl<n - 1, TypeList<List...>, Accum..., T> {};
|
||||
|
||||
template <typename T, typename... List, typename... Accum>
|
||||
struct TakeTypeListItemImpl<0, TypeList<T, List...>, Accum...> {
|
||||
using Type = TypeList<Accum...>;
|
||||
};
|
||||
|
||||
template <typename... Accum>
|
||||
struct TakeTypeListItemImpl<0, TypeList<>, Accum...> {
|
||||
using Type = TypeList<Accum...>;
|
||||
};
|
||||
|
||||
// A type-level function that takes first |n| list item from given TypeList.
|
||||
// E.g. TakeTypeListItem<3, TypeList<A, B, C, D>> is evaluated to
|
||||
// TypeList<A, B, C>.
|
||||
template <size_t n, typename List>
|
||||
using TakeTypeListItem = typename TakeTypeListItemImpl<n, List>::Type;
|
||||
|
||||
// Used for ConcatTypeLists implementation.
|
||||
template <typename List1, typename List2>
|
||||
struct ConcatTypeListsImpl;
|
||||
|
||||
template <typename... Types1, typename... Types2>
|
||||
struct ConcatTypeListsImpl<TypeList<Types1...>, TypeList<Types2...>> {
|
||||
using Type = TypeList<Types1..., Types2...>;
|
||||
};
|
||||
|
||||
// A type-level function that concats two TypeLists.
|
||||
template <typename List1, typename List2>
|
||||
using ConcatTypeLists = typename ConcatTypeListsImpl<List1, List2>::Type;
|
||||
|
||||
// Used for MakeFunctionType implementation.
|
||||
template <typename R, typename ArgList>
|
||||
struct MakeFunctionTypeImpl;
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef R Type(Args...);
|
||||
};
|
||||
|
||||
// A type-level function that constructs a function type that has |R| as its
|
||||
// return type and has TypeLists items as its arguments.
|
||||
template <typename R, typename ArgList>
|
||||
using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
|
||||
|
||||
// Used for ExtractArgs.
|
||||
template <typename Signature>
|
||||
struct ExtractArgsImpl;
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct ExtractArgsImpl<R(Args...)> {
|
||||
using Type = TypeList<Args...>;
|
||||
};
|
||||
|
||||
// A type-level function that extracts function arguments into a TypeList.
|
||||
// E.g. ExtractArgs<R(A, B, C)> is evaluated to TypeList<A, B, C>.
|
||||
template <typename Signature>
|
||||
using ExtractArgs = typename ExtractArgsImpl<Signature>::Type;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
|
@ -508,17 +614,25 @@ static inline internal::OwnedWrapper<T> Owned(T* o) {
|
|||
return internal::OwnedWrapper<T>(o);
|
||||
}
|
||||
|
||||
// We offer 2 syntaxes for calling Passed(). The first takes a temporary and
|
||||
// is best suited for use with the return value of a function. The second
|
||||
// takes a pointer to the scoper and is just syntactic sugar to avoid having
|
||||
// to write Passed(scoper.Pass()).
|
||||
template <typename T>
|
||||
static inline internal::PassedWrapper<T> Passed(T scoper) {
|
||||
return internal::PassedWrapper<T>(scoper.Pass());
|
||||
// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and
|
||||
// is best suited for use with the return value of a function or other temporary
|
||||
// rvalues. The second takes a pointer to the scoper and is just syntactic sugar
|
||||
// to avoid having to write Passed(std::move(scoper)).
|
||||
//
|
||||
// Both versions of Passed() prevent T from being an lvalue reference. The first
|
||||
// via use of enable_if, and the second takes a T* which will not bind to T&.
|
||||
template <typename T,
|
||||
typename std::enable_if<internal::IsMoveOnlyType<T>::value &&
|
||||
!std::is_lvalue_reference<T>::value>::type* =
|
||||
nullptr>
|
||||
static inline internal::PassedWrapper<T> Passed(T&& scoper) {
|
||||
return internal::PassedWrapper<T>(std::move(scoper));
|
||||
}
|
||||
template <typename T>
|
||||
template <typename T,
|
||||
typename std::enable_if<internal::IsMoveOnlyType<T>::value>::type* =
|
||||
nullptr>
|
||||
static inline internal::PassedWrapper<T> Passed(T* scoper) {
|
||||
return internal::PassedWrapper<T>(scoper->Pass());
|
||||
return internal::PassedWrapper<T>(std::move(*scoper));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,6 +8,8 @@
|
|||
#ifndef BASE_BIND_INTERNAL_WIN_H_
|
||||
#define BASE_BIND_INTERNAL_WIN_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
|
||||
// the same as __cdecl which would turn the following specializations into
|
||||
// multiple definitions.
|
||||
|
@ -23,7 +25,9 @@ class RunnableAdapter;
|
|||
template <typename R, typename... Args>
|
||||
class RunnableAdapter<R(__stdcall *)(Args...)> {
|
||||
public:
|
||||
typedef R (RunType)(Args...);
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef R RunType(Args...);
|
||||
|
||||
explicit RunnableAdapter(R(__stdcall *function)(Args...))
|
||||
: function_(function) {
|
||||
|
@ -41,7 +45,9 @@ class RunnableAdapter<R(__stdcall *)(Args...)> {
|
|||
template <typename R, typename... Args>
|
||||
class RunnableAdapter<R(__fastcall *)(Args...)> {
|
||||
public:
|
||||
typedef R (RunType)(Args...);
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef R RunType(Args...);
|
||||
|
||||
explicit RunnableAdapter(R(__fastcall *function)(Args...))
|
||||
: function_(function) {
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_BIT_CAST_H_
|
||||
#define BASE_BIT_CAST_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// bit_cast<Dest,Source> is a template function that implements the equivalent
|
||||
// of "*reinterpret_cast<Dest*>(&source)". We need this in very low-level
|
||||
// functions like the protobuf library and fast math support.
|
||||
//
|
||||
// float f = 3.14159265358979;
|
||||
// int i = bit_cast<int32_t>(f);
|
||||
// // i = 0x40490fdb
|
||||
//
|
||||
// The classical address-casting method is:
|
||||
//
|
||||
// // WRONG
|
||||
// float f = 3.14159265358979; // WRONG
|
||||
// int i = * reinterpret_cast<int*>(&f); // WRONG
|
||||
//
|
||||
// The address-casting method actually produces undefined behavior according to
|
||||
// the ISO C++98 specification, section 3.10 ("basic.lval"), paragraph 15.
|
||||
// (This did not substantially change in C++11.) Roughly, this section says: if
|
||||
// an object in memory has one type, and a program accesses it with a different
|
||||
// type, then the result is undefined behavior for most values of "different
|
||||
// type".
|
||||
//
|
||||
// This is true for any cast syntax, either *(int*)&f or
|
||||
// *reinterpret_cast<int*>(&f). And it is particularly true for conversions
|
||||
// between integral lvalues and floating-point lvalues.
|
||||
//
|
||||
// The purpose of this paragraph is to allow optimizing compilers to assume that
|
||||
// expressions with different types refer to different memory. Compilers are
|
||||
// known to take advantage of this. So a non-conforming program quietly
|
||||
// produces wildly incorrect output.
|
||||
//
|
||||
// The problem is not the use of reinterpret_cast. The problem is type punning:
|
||||
// holding an object in memory of one type and reading its bits back using a
|
||||
// different type.
|
||||
//
|
||||
// The C++ standard is more subtle and complex than this, but that is the basic
|
||||
// idea.
|
||||
//
|
||||
// Anyways ...
|
||||
//
|
||||
// bit_cast<> calls memcpy() which is blessed by the standard, especially by the
|
||||
// example in section 3.9 . Also, of course, bit_cast<> wraps up the nasty
|
||||
// logic in one place.
|
||||
//
|
||||
// Fortunately memcpy() is very fast. In optimized mode, compilers replace
|
||||
// calls to memcpy() with inline object code when the size argument is a
|
||||
// compile-time constant. On a 32-bit system, memcpy(d,s,4) compiles to one
|
||||
// load and one store, and memcpy(d,s,8) compiles to two loads and two stores.
|
||||
//
|
||||
// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
|
||||
// is likely to surprise you.
|
||||
|
||||
template <class Dest, class Source>
|
||||
inline Dest bit_cast(const Source& source) {
|
||||
static_assert(sizeof(Dest) == sizeof(Source),
|
||||
"bit_cast requires source and destination to be the same size");
|
||||
|
||||
Dest dest;
|
||||
memcpy(&dest, &source, sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
|
||||
#endif // BASE_BIT_CAST_H_
|
|
@ -1,8 +1,3 @@
|
|||
// This file was GENERATED by command:
|
||||
// pump.py callback.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
@ -31,7 +26,7 @@
|
|||
// much like lexical closures are used in other languages. For example, it
|
||||
// is used in Chromium code to schedule tasks on different MessageLoops.
|
||||
//
|
||||
// A callback with no unbound input parameters (base::Callback<void(void)>)
|
||||
// A callback with no unbound input parameters (base::Callback<void()>)
|
||||
// is called a base::Closure. Note that this is NOT the same as what other
|
||||
// languages refer to as a closure -- it does not retain a reference to its
|
||||
// enclosing environment.
|
||||
|
@ -53,7 +48,7 @@
|
|||
// BINDING A BARE FUNCTION
|
||||
//
|
||||
// int Return5() { return 5; }
|
||||
// base::Callback<int(void)> func_cb = base::Bind(&Return5);
|
||||
// base::Callback<int()> func_cb = base::Bind(&Return5);
|
||||
// LOG(INFO) << func_cb.Run(); // Prints 5.
|
||||
//
|
||||
// BINDING A CLASS METHOD
|
||||
|
@ -67,7 +62,7 @@
|
|||
// void PrintBye() { LOG(INFO) << "bye."; }
|
||||
// };
|
||||
// scoped_refptr<Ref> ref = new Ref();
|
||||
// base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
|
||||
// base::Callback<void()> ref_cb = base::Bind(&Ref::Foo, ref);
|
||||
// LOG(INFO) << ref_cb.Run(); // Prints out 3.
|
||||
//
|
||||
// By default the object must support RefCounted or you will get a compiler
|
||||
|
@ -109,10 +104,10 @@
|
|||
// calling.
|
||||
//
|
||||
// void MyFunc(int i, const std::string& str) {}
|
||||
// base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
|
||||
// base::Callback<void()> cb = base::Bind(&MyFunc, 23, "hello world");
|
||||
// cb.Run();
|
||||
//
|
||||
// A callback with no unbound input parameters (base::Callback<void(void)>)
|
||||
// A callback with no unbound input parameters (base::Callback<void()>)
|
||||
// is called a base::Closure. So we could have also written:
|
||||
//
|
||||
// base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
|
||||
|
@ -170,7 +165,7 @@
|
|||
// that doesn't expect a return value.
|
||||
//
|
||||
// int DoSomething(int arg) { cout << arg << endl; }
|
||||
// base::Callback<void<int>) cb =
|
||||
// base::Callback<void(int)> cb =
|
||||
// base::Bind(base::IgnoreResult(&DoSomething));
|
||||
//
|
||||
//
|
||||
|
@ -180,7 +175,7 @@
|
|||
//
|
||||
// Bound parameters are specified as arguments to Bind() and are passed to the
|
||||
// function. A callback with no parameters or no unbound parameters is called a
|
||||
// Closure (base::Callback<void(void)> and base::Closure are the same thing).
|
||||
// Closure (base::Callback<void()> and base::Closure are the same thing).
|
||||
//
|
||||
// PASSING PARAMETERS OWNED BY THE CALLBACK
|
||||
//
|
||||
|
@ -359,33 +354,30 @@ namespace base {
|
|||
//
|
||||
// If you are thinking of forward declaring Callback in your own header file,
|
||||
// please include "base/callback_forward.h" instead.
|
||||
template <typename Sig>
|
||||
class Callback;
|
||||
|
||||
namespace internal {
|
||||
template <typename Runnable, typename RunType, typename BoundArgsType>
|
||||
template <typename Runnable, typename RunType, typename... BoundArgsType>
|
||||
struct BindState;
|
||||
} // namespace internal
|
||||
|
||||
template <typename R>
|
||||
class Callback<R(void)> : public internal::CallbackBase {
|
||||
template <typename R, typename... Args>
|
||||
class Callback<R(Args...)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)();
|
||||
// MSVC 2013 doesn't support Type Alias of function types.
|
||||
// Revisit this after we update it to newer version.
|
||||
typedef R RunType(Args...);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
Callback() : CallbackBase(nullptr) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
template <typename Runnable, typename BindRunType, typename... BoundArgsType>
|
||||
explicit Callback(
|
||||
internal::BindState<Runnable, BindRunType, BoundArgsType...>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType...>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
@ -394,377 +386,20 @@ class Callback<R(void)> : public internal::CallbackBase {
|
|||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run() const {
|
||||
R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args)
|
||||
const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get());
|
||||
return f(bind_state_.get(), internal::CallbackForward(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*);
|
||||
|
||||
using PolymorphicInvoke =
|
||||
R(*)(internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<Args>::ForwardType...);
|
||||
};
|
||||
|
||||
template <typename R, typename A1>
|
||||
class Callback<R(A1)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2>
|
||||
class Callback<R(A1, A2)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3>
|
||||
class Callback<R(A1, A2, A3)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4>
|
||||
class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5>
|
||||
class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4, A5);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType a5) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4),
|
||||
internal::CallbackForward(a5));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6>
|
||||
class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4, A5, A6);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType a6) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4),
|
||||
internal::CallbackForward(a5),
|
||||
internal::CallbackForward(a6));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
template <typename R, typename A1, typename A2, typename A3, typename A4,
|
||||
typename A5, typename A6, typename A7>
|
||||
class Callback<R(A1, A2, A3, A4, A5, A6, A7)> : public internal::CallbackBase {
|
||||
public:
|
||||
typedef R(RunType)(A1, A2, A3, A4, A5, A6, A7);
|
||||
|
||||
Callback() : CallbackBase(NULL) { }
|
||||
|
||||
// Note that this constructor CANNOT be explicit, and that Bind() CANNOT
|
||||
// return the exact Callback<> type. See base/bind.h for details.
|
||||
template <typename Runnable, typename BindRunType, typename BoundArgsType>
|
||||
Callback(internal::BindState<Runnable, BindRunType,
|
||||
BoundArgsType>* bind_state)
|
||||
: CallbackBase(bind_state) {
|
||||
|
||||
// Force the assignment to a local variable of PolymorphicInvoke
|
||||
// so the compiler will typecheck that the passed in Run() method has
|
||||
// the correct type.
|
||||
PolymorphicInvoke invoke_func =
|
||||
&internal::BindState<Runnable, BindRunType, BoundArgsType>
|
||||
::InvokerType::Run;
|
||||
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
|
||||
}
|
||||
|
||||
bool Equals(const Callback& other) const {
|
||||
return CallbackBase::Equals(other);
|
||||
}
|
||||
|
||||
R Run(typename internal::CallbackParamTraits<A1>::ForwardType a1,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType a2,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType a3,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType a4,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType a5,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType a6,
|
||||
typename internal::CallbackParamTraits<A7>::ForwardType a7) const {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
|
||||
|
||||
return f(bind_state_.get(), internal::CallbackForward(a1),
|
||||
internal::CallbackForward(a2),
|
||||
internal::CallbackForward(a3),
|
||||
internal::CallbackForward(a4),
|
||||
internal::CallbackForward(a5),
|
||||
internal::CallbackForward(a6),
|
||||
internal::CallbackForward(a7));
|
||||
}
|
||||
|
||||
private:
|
||||
typedef R(*PolymorphicInvoke)(
|
||||
internal::BindStateBase*,
|
||||
typename internal::CallbackParamTraits<A1>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A2>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A3>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A4>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A5>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A6>::ForwardType,
|
||||
typename internal::CallbackParamTraits<A7>::ForwardType);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Syntactic sugar to make Callback<void(void)> easier to declare since it
|
||||
// will be used in a lot of APIs with delayed execution.
|
||||
typedef Callback<void(void)> Closure;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CALLBACK_H
|
||||
#endif // BASE_CALLBACK_H_
|
||||
|
|
|
@ -10,8 +10,10 @@ namespace base {
|
|||
template <typename Sig>
|
||||
class Callback;
|
||||
|
||||
typedef Callback<void(void)> Closure;
|
||||
// Syntactic sugar to make Callback<void()> easier to declare since it
|
||||
// will be used in a lot of APIs with delayed execution.
|
||||
using Closure = Callback<void()>;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CALLBACK_FORWARD_H
|
||||
#endif // BASE_CALLBACK_FORWARD_H_
|
||||
|
|
|
@ -9,6 +9,18 @@
|
|||
namespace base {
|
||||
namespace internal {
|
||||
|
||||
void BindStateBase::AddRef() {
|
||||
AtomicRefCountInc(&ref_count_);
|
||||
}
|
||||
|
||||
void BindStateBase::Release() {
|
||||
if (!AtomicRefCountDec(&ref_count_))
|
||||
destructor_(this);
|
||||
}
|
||||
|
||||
CallbackBase::CallbackBase(const CallbackBase& c) = default;
|
||||
CallbackBase& CallbackBase::operator=(const CallbackBase& c) = default;
|
||||
|
||||
void CallbackBase::Reset() {
|
||||
polymorphic_invoke_ = NULL;
|
||||
// NULL the bind_state_ last, since it may be holding the last ref to whatever
|
||||
|
@ -24,7 +36,7 @@ bool CallbackBase::Equals(const CallbackBase& other) const {
|
|||
CallbackBase::CallbackBase(BindStateBase* bind_state)
|
||||
: bind_state_(bind_state),
|
||||
polymorphic_invoke_(NULL) {
|
||||
DCHECK(!bind_state_.get() || bind_state_->HasOneRef());
|
||||
DCHECK(!bind_state_.get() || bind_state_->ref_count_ == 1);
|
||||
}
|
||||
|
||||
CallbackBase::~CallbackBase() {
|
||||
|
|
|
@ -9,16 +9,19 @@
|
|||
#define BASE_CALLBACK_INTERNAL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/atomic_ref_count.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
|
||||
template <typename T>
|
||||
class ScopedVector;
|
||||
#include "base/template_util.h"
|
||||
|
||||
namespace base {
|
||||
namespace internal {
|
||||
class CallbackBase;
|
||||
|
||||
// BindStateBase is used to provide an opaque handle that the Callback
|
||||
// class can use to represent a function object with bound arguments. It
|
||||
|
@ -26,16 +29,39 @@ namespace internal {
|
|||
// DoInvoke function to perform the function execution. This allows
|
||||
// us to shield the Callback class from the types of the bound argument via
|
||||
// "type erasure."
|
||||
class BindStateBase : public RefCountedThreadSafe<BindStateBase> {
|
||||
// At the base level, the only task is to add reference counting data. Don't use
|
||||
// RefCountedThreadSafe since it requires the destructor to be a virtual method.
|
||||
// Creating a vtable for every BindState template instantiation results in a lot
|
||||
// of bloat. Its only task is to call the destructor which can be done with a
|
||||
// function pointer.
|
||||
class BindStateBase {
|
||||
protected:
|
||||
friend class RefCountedThreadSafe<BindStateBase>;
|
||||
virtual ~BindStateBase() {}
|
||||
explicit BindStateBase(void (*destructor)(BindStateBase*))
|
||||
: ref_count_(0), destructor_(destructor) {}
|
||||
~BindStateBase() = default;
|
||||
|
||||
private:
|
||||
friend class scoped_refptr<BindStateBase>;
|
||||
friend class CallbackBase;
|
||||
|
||||
void AddRef();
|
||||
void Release();
|
||||
|
||||
AtomicRefCount ref_count_;
|
||||
|
||||
// Pointer to a function that will properly destroy |this|.
|
||||
void (*destructor_)(BindStateBase*);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BindStateBase);
|
||||
};
|
||||
|
||||
// Holds the Callback methods that don't require specialization to reduce
|
||||
// template bloat.
|
||||
class BASE_EXPORT CallbackBase {
|
||||
public:
|
||||
CallbackBase(const CallbackBase& c);
|
||||
CallbackBase& operator=(const CallbackBase& c);
|
||||
|
||||
// Returns true if Callback is null (doesn't refer to anything).
|
||||
bool is_null() const { return bind_state_.get() == NULL; }
|
||||
|
||||
|
@ -47,7 +73,7 @@ class BASE_EXPORT CallbackBase {
|
|||
// another type. It is not okay to use void*. We create a InvokeFuncStorage
|
||||
// that that can store our function pointer, and then cast it back to
|
||||
// the original type on usage.
|
||||
typedef void(*InvokeFuncStorage)(void);
|
||||
using InvokeFuncStorage = void(*)();
|
||||
|
||||
// Returns true if this callback equals |other|. |other| may be null.
|
||||
bool Equals(const CallbackBase& other) const;
|
||||
|
@ -68,8 +94,14 @@ class BASE_EXPORT CallbackBase {
|
|||
};
|
||||
|
||||
// A helper template to determine if given type is non-const move-only-type,
|
||||
// i.e. if a value of the given type should be passed via .Pass() in a
|
||||
// destructive way.
|
||||
// i.e. if a value of the given type should be passed via std::move() in a
|
||||
// destructive way. Types are considered to be move-only if they have a
|
||||
// sentinel MoveOnlyTypeForCPP03 member: a class typically gets this from using
|
||||
// the DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND macro.
|
||||
// It would be easy to generalize this trait to all move-only types... but this
|
||||
// confuses template deduction in VS2013 with certain types such as
|
||||
// std::unique_ptr.
|
||||
// TODO(dcheng): Revisit this when Windows switches to VS2015 by default.
|
||||
template <typename T> struct IsMoveOnlyType {
|
||||
template <typename U>
|
||||
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
|
||||
|
@ -81,6 +113,21 @@ template <typename T> struct IsMoveOnlyType {
|
|||
!is_const<T>::value;
|
||||
};
|
||||
|
||||
// Specialization of IsMoveOnlyType so that std::unique_ptr is still considered
|
||||
// move-only, even without the sentinel member.
|
||||
template <typename T>
|
||||
struct IsMoveOnlyType<std::unique_ptr<T>> : std::true_type {};
|
||||
|
||||
template <typename>
|
||||
struct CallbackParamTraitsForMoveOnlyType;
|
||||
|
||||
template <typename>
|
||||
struct CallbackParamTraitsForNonMoveOnlyType;
|
||||
|
||||
// TODO(tzik): Use a default parameter once MSVS supports variadic templates
|
||||
// with default values.
|
||||
// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates
|
||||
//
|
||||
// This is a typetraits object that's used to take an argument type, and
|
||||
// extract a suitable type for storing and forwarding arguments.
|
||||
//
|
||||
|
@ -92,10 +139,17 @@ template <typename T> struct IsMoveOnlyType {
|
|||
// parameters by const reference. In this case, we end up passing an actual
|
||||
// array type in the initializer list which C++ does not allow. This will
|
||||
// break passing of C-string literals.
|
||||
template <typename T, bool is_move_only = IsMoveOnlyType<T>::value>
|
||||
struct CallbackParamTraits {
|
||||
typedef const T& ForwardType;
|
||||
typedef T StorageType;
|
||||
template <typename T>
|
||||
struct CallbackParamTraits
|
||||
: std::conditional<IsMoveOnlyType<T>::value,
|
||||
CallbackParamTraitsForMoveOnlyType<T>,
|
||||
CallbackParamTraitsForNonMoveOnlyType<T>>::type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CallbackParamTraitsForNonMoveOnlyType {
|
||||
using ForwardType = const T&;
|
||||
using StorageType = T;
|
||||
};
|
||||
|
||||
// The Storage should almost be impossible to trigger unless someone manually
|
||||
|
@ -104,9 +158,9 @@ struct CallbackParamTraits {
|
|||
//
|
||||
// The ForwardType should only be used for unbound arguments.
|
||||
template <typename T>
|
||||
struct CallbackParamTraits<T&, false> {
|
||||
typedef T& ForwardType;
|
||||
typedef T StorageType;
|
||||
struct CallbackParamTraitsForNonMoveOnlyType<T&> {
|
||||
using ForwardType = T&;
|
||||
using StorageType = T;
|
||||
};
|
||||
|
||||
// Note that for array types, we implicitly add a const in the conversion. This
|
||||
|
@ -115,16 +169,16 @@ struct CallbackParamTraits<T&, false> {
|
|||
// T[n]" does not seem to match correctly, so we are stuck with this
|
||||
// restriction.
|
||||
template <typename T, size_t n>
|
||||
struct CallbackParamTraits<T[n], false> {
|
||||
typedef const T* ForwardType;
|
||||
typedef const T* StorageType;
|
||||
struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
|
||||
using ForwardType = const T*;
|
||||
using StorageType = const T*;
|
||||
};
|
||||
|
||||
// See comment for CallbackParamTraits<T[n]>.
|
||||
template <typename T>
|
||||
struct CallbackParamTraits<T[], false> {
|
||||
typedef const T* ForwardType;
|
||||
typedef const T* StorageType;
|
||||
struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
|
||||
using ForwardType = const T*;
|
||||
using StorageType = const T*;
|
||||
};
|
||||
|
||||
// Parameter traits for movable-but-not-copyable scopers.
|
||||
|
@ -141,9 +195,9 @@ struct CallbackParamTraits<T[], false> {
|
|||
// reference cannot be used with temporaries which means the result of a
|
||||
// function or a cast would not be usable with Callback<> or Bind().
|
||||
template <typename T>
|
||||
struct CallbackParamTraits<T, true> {
|
||||
typedef T ForwardType;
|
||||
typedef T StorageType;
|
||||
struct CallbackParamTraitsForMoveOnlyType {
|
||||
using ForwardType = T;
|
||||
using StorageType = T;
|
||||
};
|
||||
|
||||
// CallbackForward() is a very limited simulation of C++11's std::forward()
|
||||
|
@ -155,7 +209,7 @@ struct CallbackParamTraits<T, true> {
|
|||
// default template compiles out to be a no-op.
|
||||
//
|
||||
// In C++11, std::forward would replace all uses of this function. However, it
|
||||
// is impossible to implement a general std::forward with C++11 due to a lack
|
||||
// is impossible to implement a general std::forward without C++11 due to a lack
|
||||
// of rvalue references.
|
||||
//
|
||||
// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
|
||||
|
@ -163,13 +217,15 @@ struct CallbackParamTraits<T, true> {
|
|||
// parameter to another callback. This is to support Callbacks that return
|
||||
// the movable-but-not-copyable types whitelisted above.
|
||||
template <typename T>
|
||||
typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
|
||||
typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(
|
||||
T& t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
|
||||
return t.Pass();
|
||||
typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(
|
||||
T& t) {
|
||||
return std::move(t);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
#if defined(COMPILER_MSVC)
|
||||
|
||||
// For _Printf_format_string_.
|
||||
#include <sal.h>
|
||||
|
||||
// Macros for suppressing and disabling warnings on MSVC.
|
||||
//
|
||||
// Warning numbers are enumerated at:
|
||||
|
@ -57,6 +60,7 @@
|
|||
|
||||
#else // Not MSVC
|
||||
|
||||
#define _Printf_format_string_
|
||||
#define MSVC_SUPPRESS_WARNING(n)
|
||||
#define MSVC_PUSH_DISABLE_WARNING(n)
|
||||
#define MSVC_PUSH_WARNING_LEVEL(n)
|
||||
|
@ -68,28 +72,6 @@
|
|||
#endif // COMPILER_MSVC
|
||||
|
||||
|
||||
// The C++ standard requires that static const members have an out-of-class
|
||||
// definition (in a single compilation unit), but MSVC chokes on this (when
|
||||
// language extensions, which are required, are enabled). (You're only likely to
|
||||
// notice the need for a definition if you take the address of the member or,
|
||||
// more commonly, pass it to a function that takes it as a reference argument --
|
||||
// probably an STL function.) This macro makes MSVC do the right thing. See
|
||||
// http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx for more
|
||||
// information. Use like:
|
||||
//
|
||||
// In .h file:
|
||||
// struct Foo {
|
||||
// static const int kBar = 5;
|
||||
// };
|
||||
//
|
||||
// In .cc file:
|
||||
// STATIC_CONST_MEMBER_DEFINITION const int Foo::kBar;
|
||||
#if defined(COMPILER_MSVC)
|
||||
#define STATIC_CONST_MEMBER_DEFINITION __declspec(selectany)
|
||||
#else
|
||||
#define STATIC_CONST_MEMBER_DEFINITION
|
||||
#endif
|
||||
|
||||
// Annotate a variable indicating it's ok if the variable is not used.
|
||||
// (Typically used to silence a compiler warning when the assignment
|
||||
// is important for some other reason.)
|
||||
|
@ -101,7 +83,7 @@
|
|||
// Annotate a typedef or function indicating it's ok if it's not used.
|
||||
// Use like:
|
||||
// typedef Foo Bar ALLOW_UNUSED_TYPE;
|
||||
#if defined(COMPILER_GCC)
|
||||
#if defined(COMPILER_GCC) || defined(__clang__)
|
||||
#define ALLOW_UNUSED_TYPE __attribute__((unused))
|
||||
#else
|
||||
#define ALLOW_UNUSED_TYPE
|
||||
|
@ -128,13 +110,11 @@
|
|||
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
|
||||
#endif
|
||||
|
||||
// Return the byte alignment of the given type (available at compile time). Use
|
||||
// sizeof(type) prior to checking __alignof to workaround Visual C++ bug:
|
||||
// http://goo.gl/isH0C
|
||||
// Return the byte alignment of the given type (available at compile time).
|
||||
// Use like:
|
||||
// ALIGNOF(int32) // this would be 4
|
||||
// ALIGNOF(int32_t) // this would be 4
|
||||
#if defined(COMPILER_MSVC)
|
||||
#define ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type))
|
||||
#define ALIGNOF(type) __alignof(type)
|
||||
#elif defined(COMPILER_GCC)
|
||||
#define ALIGNOF(type) __alignof__(type)
|
||||
#endif
|
||||
|
@ -142,8 +122,9 @@
|
|||
// Annotate a function indicating the caller must examine the return value.
|
||||
// Use like:
|
||||
// int foo() WARN_UNUSED_RESULT;
|
||||
// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
|
||||
#if defined(COMPILER_GCC)
|
||||
// To explicitly ignore a result, see |ignore_result()| in base/macros.h.
|
||||
#undef WARN_UNUSED_RESULT
|
||||
#if defined(COMPILER_GCC) || defined(__clang__)
|
||||
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
#define WARN_UNUSED_RESULT
|
||||
|
@ -175,9 +156,17 @@
|
|||
// Mark a memory region fully initialized.
|
||||
// Use this to annotate code that deliberately reads uninitialized data, for
|
||||
// example a GC scavenging root set pointers from the stack.
|
||||
#define MSAN_UNPOISON(p, s) __msan_unpoison(p, s)
|
||||
#define MSAN_UNPOISON(p, size) __msan_unpoison(p, size)
|
||||
|
||||
// Check a memory region for initializedness, as if it was being used here.
|
||||
// If any bits are uninitialized, crash with an MSan report.
|
||||
// Use this to sanitize data which MSan won't be able to track, e.g. before
|
||||
// passing data to another process via shared memory.
|
||||
#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) \
|
||||
__msan_check_mem_is_initialized(p, size)
|
||||
#else // MEMORY_SANITIZER
|
||||
#define MSAN_UNPOISON(p, s)
|
||||
#define MSAN_UNPOISON(p, size)
|
||||
#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
|
||||
#endif // MEMORY_SANITIZER
|
||||
|
||||
// Macro useful for writing cross-platform function pointers.
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
#ifndef BASE_CONTAINERS_HASH_TABLES_H_
|
||||
#define BASE_CONTAINERS_HASH_TABLES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
|
@ -45,15 +47,9 @@
|
|||
#undef __DEPRECATED
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID) && !defined(MOZ_WIDGET_GONK)
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#define BASE_HASH_IMPL_NAMESPACE std
|
||||
#else
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
#define BASE_HASH_IMPL_NAMESPACE __gnu_cxx
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -84,7 +80,6 @@ struct hash<T*> {
|
|||
}
|
||||
};
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
// The GNU C++ library provides identity hash functions for many integral types,
|
||||
// but not for |long long|. This hash function will truncate if |size_t| is
|
||||
// narrower than |long long|. This is probably good enough for what we will
|
||||
|
@ -102,7 +97,6 @@ DEFINE_TRIVIAL_HASH(long long);
|
|||
DEFINE_TRIVIAL_HASH(unsigned long long);
|
||||
|
||||
#undef DEFINE_TRIVIAL_HASH
|
||||
#endif // !defined(OS_ANDROID)
|
||||
|
||||
// Implement string hash functions so that strings of various flavors can
|
||||
// be used as keys in STL maps and sets. The hash algorithm comes from the
|
||||
|
@ -204,19 +198,19 @@ using hash_set = BASE_HASH_IMPL_NAMESPACE::hash_set<Key, Hash, Pred, Alloc>;
|
|||
// h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
|
||||
//
|
||||
// Contact danakj@chromium.org for any questions.
|
||||
inline std::size_t HashInts32(uint32 value1, uint32 value2) {
|
||||
uint64 value1_64 = value1;
|
||||
uint64 hash64 = (value1_64 << 32) | value2;
|
||||
inline std::size_t HashInts32(uint32_t value1, uint32_t value2) {
|
||||
uint64_t value1_64 = value1;
|
||||
uint64_t hash64 = (value1_64 << 32) | value2;
|
||||
|
||||
if (sizeof(std::size_t) >= sizeof(uint64))
|
||||
if (sizeof(std::size_t) >= sizeof(uint64_t))
|
||||
return static_cast<std::size_t>(hash64);
|
||||
|
||||
uint64 odd_random = 481046412LL << 32 | 1025306955LL;
|
||||
uint32 shift_random = 10121U << 16;
|
||||
uint64_t odd_random = 481046412LL << 32 | 1025306955LL;
|
||||
uint32_t shift_random = 10121U << 16;
|
||||
|
||||
hash64 = hash64 * odd_random + shift_random;
|
||||
std::size_t high_bits = static_cast<std::size_t>(
|
||||
hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
|
||||
hash64 >> (8 * (sizeof(uint64_t) - sizeof(std::size_t))));
|
||||
return high_bits;
|
||||
}
|
||||
|
||||
|
@ -225,87 +219,46 @@ inline std::size_t HashInts32(uint32 value1, uint32 value2) {
|
|||
// breaking the two 64-bit inputs into 4 32-bit values:
|
||||
// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
|
||||
// Then we reduce our result to 32 bits if required, similar to above.
|
||||
inline std::size_t HashInts64(uint64 value1, uint64 value2) {
|
||||
uint32 short_random1 = 842304669U;
|
||||
uint32 short_random2 = 619063811U;
|
||||
uint32 short_random3 = 937041849U;
|
||||
uint32 short_random4 = 3309708029U;
|
||||
inline std::size_t HashInts64(uint64_t value1, uint64_t value2) {
|
||||
uint32_t short_random1 = 842304669U;
|
||||
uint32_t short_random2 = 619063811U;
|
||||
uint32_t short_random3 = 937041849U;
|
||||
uint32_t short_random4 = 3309708029U;
|
||||
|
||||
uint32 value1a = static_cast<uint32>(value1 & 0xffffffff);
|
||||
uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff);
|
||||
uint32 value2a = static_cast<uint32>(value2 & 0xffffffff);
|
||||
uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff);
|
||||
uint32_t value1a = static_cast<uint32_t>(value1 & 0xffffffff);
|
||||
uint32_t value1b = static_cast<uint32_t>((value1 >> 32) & 0xffffffff);
|
||||
uint32_t value2a = static_cast<uint32_t>(value2 & 0xffffffff);
|
||||
uint32_t value2b = static_cast<uint32_t>((value2 >> 32) & 0xffffffff);
|
||||
|
||||
uint64 product1 = static_cast<uint64>(value1a) * short_random1;
|
||||
uint64 product2 = static_cast<uint64>(value1b) * short_random2;
|
||||
uint64 product3 = static_cast<uint64>(value2a) * short_random3;
|
||||
uint64 product4 = static_cast<uint64>(value2b) * short_random4;
|
||||
uint64_t product1 = static_cast<uint64_t>(value1a) * short_random1;
|
||||
uint64_t product2 = static_cast<uint64_t>(value1b) * short_random2;
|
||||
uint64_t product3 = static_cast<uint64_t>(value2a) * short_random3;
|
||||
uint64_t product4 = static_cast<uint64_t>(value2b) * short_random4;
|
||||
|
||||
uint64 hash64 = product1 + product2 + product3 + product4;
|
||||
uint64_t hash64 = product1 + product2 + product3 + product4;
|
||||
|
||||
if (sizeof(std::size_t) >= sizeof(uint64))
|
||||
if (sizeof(std::size_t) >= sizeof(uint64_t))
|
||||
return static_cast<std::size_t>(hash64);
|
||||
|
||||
uint64 odd_random = 1578233944LL << 32 | 194370989LL;
|
||||
uint32 shift_random = 20591U << 16;
|
||||
uint64_t odd_random = 1578233944LL << 32 | 194370989LL;
|
||||
uint32_t shift_random = 20591U << 16;
|
||||
|
||||
hash64 = hash64 * odd_random + shift_random;
|
||||
std::size_t high_bits = static_cast<std::size_t>(
|
||||
hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
|
||||
hash64 >> (8 * (sizeof(uint64_t) - sizeof(std::size_t))));
|
||||
return high_bits;
|
||||
}
|
||||
|
||||
#define DEFINE_32BIT_PAIR_HASH(Type1, Type2) \
|
||||
inline std::size_t HashPair(Type1 value1, Type2 value2) { \
|
||||
return HashInts32(value1, value2); \
|
||||
template<typename T1, typename T2>
|
||||
inline std::size_t HashPair(T1 value1, T2 value2) {
|
||||
// This condition is expected to be compile-time evaluated and optimised away
|
||||
// in release builds.
|
||||
if (sizeof(T1) > sizeof(uint32_t) || (sizeof(T2) > sizeof(uint32_t)))
|
||||
return HashInts64(value1, value2);
|
||||
|
||||
return HashInts32(value1, value2);
|
||||
}
|
||||
|
||||
DEFINE_32BIT_PAIR_HASH(int16, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(int16, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(int16, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(int16, uint32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint16, uint32);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(int32, uint32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, int16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, uint16);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, int32);
|
||||
DEFINE_32BIT_PAIR_HASH(uint32, uint32);
|
||||
|
||||
#undef DEFINE_32BIT_PAIR_HASH
|
||||
|
||||
#define DEFINE_64BIT_PAIR_HASH(Type1, Type2) \
|
||||
inline std::size_t HashPair(Type1 value1, Type2 value2) { \
|
||||
return HashInts64(value1, value2); \
|
||||
}
|
||||
|
||||
DEFINE_64BIT_PAIR_HASH(int16, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(int16, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint16, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint16, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(int32, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(int32, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint32, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint32, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, int16);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, uint16);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, int32);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, uint32);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(int64, uint64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, int16);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, uint16);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, int32);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, uint32);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, int64);
|
||||
DEFINE_64BIT_PAIR_HASH(uint64, uint64);
|
||||
|
||||
#undef DEFINE_64BIT_PAIR_HASH
|
||||
} // namespace base
|
||||
|
||||
namespace BASE_HASH_NAMESPACE {
|
||||
|
@ -320,7 +273,7 @@ struct hash<std::pair<Type1, Type2> > {
|
|||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace BASE_HASH_NAMESPACE
|
||||
|
||||
#undef DEFINE_PAIR_HASH_FUNCTION_START
|
||||
#undef DEFINE_PAIR_HASH_FUNCTION_END
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
|
||||
#include "base/cpu.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
|
@ -43,7 +46,7 @@ CPU::CPU()
|
|||
has_sse41_(false),
|
||||
has_sse42_(false),
|
||||
has_avx_(false),
|
||||
has_avx_hardware_(false),
|
||||
has_avx2_(false),
|
||||
has_aesni_(false),
|
||||
has_non_stop_time_stamp_counter_(false),
|
||||
has_broken_neon_(false),
|
||||
|
@ -72,7 +75,7 @@ void __cpuid(int cpu_info[4], int info_type) {
|
|||
|
||||
void __cpuid(int cpu_info[4], int info_type) {
|
||||
__asm__ volatile (
|
||||
"cpuid \n\t"
|
||||
"cpuid\n"
|
||||
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
|
||||
: "a"(info_type)
|
||||
);
|
||||
|
@ -82,11 +85,12 @@ void __cpuid(int cpu_info[4], int info_type) {
|
|||
|
||||
// _xgetbv returns the value of an Intel Extended Control Register (XCR).
|
||||
// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
|
||||
uint64 _xgetbv(uint32 xcr) {
|
||||
uint32 eax, edx;
|
||||
uint64_t _xgetbv(uint32_t xcr) {
|
||||
uint32_t eax, edx;
|
||||
|
||||
__asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr));
|
||||
return (static_cast<uint64>(edx) << 32) | eax;
|
||||
__asm__ volatile (
|
||||
"xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
|
||||
return (static_cast<uint64_t>(edx) << 32) | eax;
|
||||
}
|
||||
|
||||
#endif // !_MSC_VER
|
||||
|
@ -110,7 +114,7 @@ class LazyCpuInfoValue {
|
|||
revision = 0;
|
||||
const struct {
|
||||
const char key[17];
|
||||
unsigned *result;
|
||||
unsigned int* result;
|
||||
} kUnsignedValues[] = {
|
||||
{"CPU implementer", &implementer},
|
||||
{"CPU architecture", &architecture},
|
||||
|
@ -156,7 +160,7 @@ class LazyCpuInfoValue {
|
|||
|
||||
// The string may have leading "0x" or not, so we use strtoul to
|
||||
// handle that.
|
||||
char *endptr;
|
||||
char* endptr;
|
||||
std::string value(value_sp.as_string());
|
||||
unsigned long int result = strtoul(value.c_str(), &endptr, 0);
|
||||
if (*endptr == 0 && result <= UINT_MAX) {
|
||||
|
@ -211,7 +215,11 @@ void CPU::Initialize() {
|
|||
|
||||
// Interpret CPU feature information.
|
||||
if (num_ids > 0) {
|
||||
int cpu_info7[4] = {0};
|
||||
__cpuid(cpu_info, 1);
|
||||
if (num_ids >= 7) {
|
||||
__cpuid(cpu_info7, 7);
|
||||
}
|
||||
signature_ = cpu_info[0];
|
||||
stepping_ = cpu_info[0] & 0xf;
|
||||
model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
|
||||
|
@ -226,8 +234,6 @@ void CPU::Initialize() {
|
|||
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
|
||||
has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
|
||||
has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
|
||||
has_avx_hardware_ =
|
||||
(cpu_info[2] & 0x10000000) != 0;
|
||||
// AVX instructions will generate an illegal instruction exception unless
|
||||
// a) they are supported by the CPU,
|
||||
// b) XSAVE is supported by the CPU and
|
||||
|
@ -239,11 +245,12 @@ void CPU::Initialize() {
|
|||
// Because of that, we also test the XSAVE bit because its description in
|
||||
// the CPUID documentation suggests that it signals xgetbv support.
|
||||
has_avx_ =
|
||||
has_avx_hardware_ &&
|
||||
(cpu_info[2] & 0x10000000) != 0 &&
|
||||
(cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
|
||||
(cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
|
||||
(_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
|
||||
has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
|
||||
has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0;
|
||||
}
|
||||
|
||||
// Get the brand string of the cpu.
|
||||
|
@ -275,6 +282,7 @@ void CPU::Initialize() {
|
|||
}
|
||||
|
||||
CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
|
||||
if (has_avx2()) return AVX2;
|
||||
if (has_avx()) return AVX;
|
||||
if (has_sse42()) return SSE42;
|
||||
if (has_sse41()) return SSE41;
|
||||
|
|
|
@ -26,6 +26,7 @@ class BASE_EXPORT CPU {
|
|||
SSE41,
|
||||
SSE42,
|
||||
AVX,
|
||||
AVX2,
|
||||
MAX_INTEL_MICRO_ARCHITECTURE
|
||||
};
|
||||
|
||||
|
@ -46,12 +47,7 @@ class BASE_EXPORT CPU {
|
|||
bool has_sse41() const { return has_sse41_; }
|
||||
bool has_sse42() const { return has_sse42_; }
|
||||
bool has_avx() const { return has_avx_; }
|
||||
// has_avx_hardware returns true when AVX is present in the CPU. This might
|
||||
// differ from the value of |has_avx()| because |has_avx()| also tests for
|
||||
// operating system support needed to actually call AVX instuctions.
|
||||
// Note: you should never need to call this function. It was added in order
|
||||
// to workaround a bug in NSS but |has_avx()| is what you want.
|
||||
bool has_avx_hardware() const { return has_avx_hardware_; }
|
||||
bool has_avx2() const { return has_avx2_; }
|
||||
bool has_aesni() const { return has_aesni_; }
|
||||
bool has_non_stop_time_stamp_counter() const {
|
||||
return has_non_stop_time_stamp_counter_;
|
||||
|
@ -83,7 +79,7 @@ class BASE_EXPORT CPU {
|
|||
bool has_sse41_;
|
||||
bool has_sse42_;
|
||||
bool has_avx_;
|
||||
bool has_avx_hardware_;
|
||||
bool has_avx2_;
|
||||
bool has_aesni_;
|
||||
bool has_non_stop_time_stamp_counter_;
|
||||
bool has_broken_neon_;
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// debuggers. You should use this to test if you're running under a debugger,
|
||||
// and if you would like to yield (breakpoint) into the debugger.
|
||||
|
||||
#ifndef BASE_DEBUG_DEBUGGER_H
|
||||
#define BASE_DEBUG_DEBUGGER_H
|
||||
#ifndef BASE_DEBUG_DEBUGGER_H_
|
||||
#define BASE_DEBUG_DEBUGGER_H_
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
|
@ -41,4 +41,4 @@ BASE_EXPORT bool IsDebugUISuppressed();
|
|||
} // namespace debug
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_DEBUG_DEBUGGER_H
|
||||
#endif // BASE_DEBUG_DEBUGGER_H_
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
|
||||
#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
// This file defines macros which can be used to annotate intentional memory
|
||||
|
@ -21,15 +21,7 @@
|
|||
|
||||
#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
|
||||
|
||||
// Public LSan API from <sanitizer/lsan_interface.h>.
|
||||
extern "C" {
|
||||
void __lsan_disable();
|
||||
void __lsan_enable();
|
||||
void __lsan_ignore_object(const void *p);
|
||||
|
||||
// Invoke leak detection immediately. If leaks are found, the process will exit.
|
||||
void __lsan_do_leak_check();
|
||||
} // extern "C"
|
||||
#include <sanitizer/lsan_interface.h>
|
||||
|
||||
class ScopedLeakSanitizerDisabler {
|
||||
public:
|
||||
|
@ -46,7 +38,6 @@ class ScopedLeakSanitizerDisabler {
|
|||
|
||||
#else
|
||||
|
||||
// If neither HeapChecker nor LSan are used, the annotations should be no-ops.
|
||||
#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
|
||||
#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
|
||||
|
||||
|
|
|
@ -6,16 +6,18 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "base/debug/debugging_flags.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/pe_image.h"
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
// TODO(peria): Enable profiling on Windows.
|
||||
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
|
||||
#endif
|
||||
|
||||
|
@ -23,15 +25,15 @@ namespace base {
|
|||
namespace debug {
|
||||
|
||||
// TODO(peria): Enable profiling on Windows.
|
||||
#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
|
||||
static int profile_count = 0;
|
||||
|
||||
void StartProfiling(const std::string& name) {
|
||||
++profile_count;
|
||||
std::string full_name(name);
|
||||
std::string pid = StringPrintf("%d", GetCurrentProcId());
|
||||
std::string count = StringPrintf("%d", profile_count);
|
||||
std::string pid = IntToString(GetCurrentProcId());
|
||||
std::string count = IntToString(profile_count);
|
||||
ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
|
||||
ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
|
||||
ProfilerStart(full_name.c_str());
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_DEBUG_PROFILER_H
|
||||
#define BASE_DEBUG_PROFILER_H
|
||||
#ifndef BASE_DEBUG_PROFILER_H_
|
||||
#define BASE_DEBUG_PROFILER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
|
||||
// The Profiler functions allow usage of the underlying sampling based
|
||||
// profiler. If the application has not been built with the necessary
|
||||
|
@ -87,4 +88,4 @@ BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc();
|
|||
} // namespace debug
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_DEBUG_DEBUGGER_H
|
||||
#endif // BASE_DEBUG_PROFILER_H_
|
||||
|
|
|
@ -14,9 +14,16 @@ namespace base {
|
|||
// We introduct a special structure for file descriptors in order that we are
|
||||
// able to use template specialisation to special-case their handling.
|
||||
//
|
||||
// WARNING: (Chromium only) There are subtleties to consider if serialising
|
||||
// these objects over IPC. See comments in ipc/ipc_message_utils.h
|
||||
// above the template specialisation for this structure.
|
||||
// IMPORTANT: This is primarily intended for use when sending file descriptors
|
||||
// over IPC. Even if |auto_close| is true, base::FileDescriptor does NOT close()
|
||||
// |fd| when going out of scope. Instead, a consumer of a base::FileDescriptor
|
||||
// must invoke close() on |fd| if |auto_close| is true.
|
||||
//
|
||||
// In the case of IPC, the the IPC subsystem knows to close() |fd| after sending
|
||||
// a message that contains a base::FileDescriptor if auto_close == true. On the
|
||||
// other end, the receiver must make sure to close() |fd| after it has finished
|
||||
// processing the IPC message. See the IPC::ParamTraits<> specialization in
|
||||
// ipc/ipc_message_utils.h for all the details.
|
||||
// -----------------------------------------------------------------------------
|
||||
struct FileDescriptor {
|
||||
FileDescriptor() : fd(-1), auto_close(false) {}
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
// between char[]-based pathnames on POSIX systems and wchar_t[]-based
|
||||
// pathnames on Windows.
|
||||
//
|
||||
// Paths can't contain NULs as a precaution agaist premature truncation.
|
||||
// As a precaution against premature truncation, paths can't contain NULs.
|
||||
//
|
||||
// Because a FilePath object should not be instantiated at the global scope,
|
||||
// instead, use a FilePath::CharType[] and initialize it with
|
||||
|
@ -83,9 +83,9 @@
|
|||
// in case it ever comes across such a system. FilePath needs this support
|
||||
// for Windows UNC paths, anyway.
|
||||
// References:
|
||||
// The Open Group Base Specifications Issue 7, sections 3.266 ("Pathname")
|
||||
// The Open Group Base Specifications Issue 7, sections 3.267 ("Pathname")
|
||||
// and 4.12 ("Pathname Resolution"), available at:
|
||||
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_266
|
||||
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_267
|
||||
// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_12
|
||||
//
|
||||
// - Windows treats c:\\ the same way it treats \\. This was intended to
|
||||
|
@ -103,13 +103,17 @@
|
|||
#define BASE_FILES_FILE_PATH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/containers/hash_tables.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/string_piece.h" // For implicit conversions.
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
// Windows-style drive letter support and pathname separator characters can be
|
||||
|
@ -121,11 +125,20 @@
|
|||
#define FILE_PATH_USES_WIN_SEPARATORS
|
||||
#endif // OS_WIN
|
||||
|
||||
class Pickle;
|
||||
class PickleIterator;
|
||||
// To print path names portably use PRIsFP (based on PRIuS and friends from
|
||||
// C99 and format_macros.h) like this:
|
||||
// base::StringPrintf("Path is %" PRIsFP ".\n", path.value().c_str());
|
||||
#if defined(OS_POSIX)
|
||||
#define PRIsFP "s"
|
||||
#elif defined(OS_WIN)
|
||||
#define PRIsFP "ls"
|
||||
#endif // OS_WIN
|
||||
|
||||
namespace base {
|
||||
|
||||
class Pickle;
|
||||
class PickleIterator;
|
||||
|
||||
// An abstraction to isolate users from the differences between native
|
||||
// pathnames on different platforms.
|
||||
class BASE_EXPORT FilePath {
|
||||
|
@ -141,6 +154,7 @@ class BASE_EXPORT FilePath {
|
|||
typedef std::wstring StringType;
|
||||
#endif // OS_WIN
|
||||
|
||||
typedef BasicStringPiece<StringType> StringPieceType;
|
||||
typedef StringType::value_type CharType;
|
||||
|
||||
// Null-terminated array of separators used to separate components in
|
||||
|
@ -163,7 +177,7 @@ class BASE_EXPORT FilePath {
|
|||
|
||||
FilePath();
|
||||
FilePath(const FilePath& that);
|
||||
explicit FilePath(const StringType& path);
|
||||
explicit FilePath(StringPieceType path);
|
||||
~FilePath();
|
||||
FilePath& operator=(const FilePath& that);
|
||||
|
||||
|
@ -237,7 +251,7 @@ class BASE_EXPORT FilePath {
|
|||
// ASSERT(new_path == path.value());
|
||||
// NOTE: this is different from the original file_util implementation which
|
||||
// returned the extension without a leading "." ("jpg" instead of ".jpg")
|
||||
StringType Extension() const;
|
||||
StringType Extension() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns the path's file extension, as in Extension(), but will
|
||||
// never return a double extension.
|
||||
|
@ -246,7 +260,7 @@ class BASE_EXPORT FilePath {
|
|||
// we can rename this to Extension() and the other to something like
|
||||
// LongExtension(), defaulting to short extensions and leaving the
|
||||
// long "extensions" to logic like base::GetUniquePathNumber().
|
||||
StringType FinalExtension() const;
|
||||
StringType FinalExtension() const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
|
||||
// NOTE: this is slightly different from the similar file_util implementation
|
||||
|
@ -265,25 +279,23 @@ class BASE_EXPORT FilePath {
|
|||
// path == "C:\pics\jojo" suffix == " (1)", returns "C:\pics\jojo (1)"
|
||||
// path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)"
|
||||
FilePath InsertBeforeExtension(
|
||||
const StringType& suffix) const WARN_UNUSED_RESULT;
|
||||
StringPieceType suffix) const WARN_UNUSED_RESULT;
|
||||
FilePath InsertBeforeExtensionASCII(
|
||||
const base::StringPiece& suffix) const WARN_UNUSED_RESULT;
|
||||
StringPiece suffix) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Adds |extension| to |file_name|. Returns the current FilePath if
|
||||
// |extension| is empty. Returns "" if BaseName() == "." or "..".
|
||||
FilePath AddExtension(
|
||||
const StringType& extension) const WARN_UNUSED_RESULT;
|
||||
FilePath AddExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Replaces the extension of |file_name| with |extension|. If |file_name|
|
||||
// does not have an extension, then |extension| is added. If |extension| is
|
||||
// empty, then the extension is removed from |file_name|.
|
||||
// Returns "" if BaseName() == "." or "..".
|
||||
FilePath ReplaceExtension(
|
||||
const StringType& extension) const WARN_UNUSED_RESULT;
|
||||
FilePath ReplaceExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns true if the file path matches the specified extension. The test is
|
||||
// case insensitive. Don't forget the leading period if appropriate.
|
||||
bool MatchesExtension(const StringType& extension) const;
|
||||
bool MatchesExtension(StringPieceType extension) const;
|
||||
|
||||
// Returns a FilePath by appending a separator and the supplied path
|
||||
// component to this object's path. Append takes care to avoid adding
|
||||
|
@ -291,7 +303,7 @@ class BASE_EXPORT FilePath {
|
|||
// If this object's path is kCurrentDirectory, a new FilePath corresponding
|
||||
// only to |component| is returned. |component| must be a relative path;
|
||||
// it is an error to pass an absolute path.
|
||||
FilePath Append(const StringType& component) const WARN_UNUSED_RESULT;
|
||||
FilePath Append(StringPieceType component) const WARN_UNUSED_RESULT;
|
||||
FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Although Windows StringType is std::wstring, since the encoding it uses for
|
||||
|
@ -300,8 +312,7 @@ class BASE_EXPORT FilePath {
|
|||
// On Linux, although it can use any 8-bit encoding for paths, we assume that
|
||||
// ASCII is a valid subset, regardless of the encoding, since many operating
|
||||
// system paths will always be ASCII.
|
||||
FilePath AppendASCII(const base::StringPiece& component)
|
||||
const WARN_UNUSED_RESULT;
|
||||
FilePath AppendASCII(StringPiece component) const WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns true if this FilePath contains an absolute path. On Windows, an
|
||||
// absolute path begins with either a drive letter specification followed by
|
||||
|
@ -385,14 +396,14 @@ class BASE_EXPORT FilePath {
|
|||
// on parts of a file path, e.g., just the extension.
|
||||
// CompareIgnoreCase() returns -1, 0 or 1 for less-than, equal-to and
|
||||
// greater-than respectively.
|
||||
static int CompareIgnoreCase(const StringType& string1,
|
||||
const StringType& string2);
|
||||
static bool CompareEqualIgnoreCase(const StringType& string1,
|
||||
const StringType& string2) {
|
||||
static int CompareIgnoreCase(StringPieceType string1,
|
||||
StringPieceType string2);
|
||||
static bool CompareEqualIgnoreCase(StringPieceType string1,
|
||||
StringPieceType string2) {
|
||||
return CompareIgnoreCase(string1, string2) == 0;
|
||||
}
|
||||
static bool CompareLessIgnoreCase(const StringType& string1,
|
||||
const StringType& string2) {
|
||||
static bool CompareLessIgnoreCase(StringPieceType string1,
|
||||
StringPieceType string2) {
|
||||
return CompareIgnoreCase(string1, string2) < 0;
|
||||
}
|
||||
|
||||
|
@ -402,14 +413,14 @@ class BASE_EXPORT FilePath {
|
|||
// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
|
||||
// for further comments.
|
||||
// Returns the epmty string if the conversion failed.
|
||||
static StringType GetHFSDecomposedForm(const FilePath::StringType& string);
|
||||
static StringType GetHFSDecomposedForm(StringPieceType string);
|
||||
|
||||
// Special UTF-8 version of FastUnicodeCompare. Cf:
|
||||
// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
|
||||
// IMPORTANT: The input strings must be in the special HFS decomposed form!
|
||||
// (cf. above GetHFSDecomposedForm method)
|
||||
static int HFSFastUnicodeCompare(const StringType& string1,
|
||||
const StringType& string2);
|
||||
static int HFSFastUnicodeCompare(StringPieceType string1,
|
||||
StringPieceType string2);
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
|
@ -432,21 +443,22 @@ class BASE_EXPORT FilePath {
|
|||
StringType path_;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
// This is required by googletest to print a readable output on test failures.
|
||||
BASE_EXPORT extern void PrintTo(const base::FilePath& path, std::ostream* out);
|
||||
// This is declared here for use in gtest-based unit tests but is defined in
|
||||
// the test_support_base target. Depend on that to use this in your unit test.
|
||||
// This should not be used in production code - call ToString() instead.
|
||||
void PrintTo(const FilePath& path, std::ostream* out);
|
||||
|
||||
} // namespace base
|
||||
|
||||
// Macros for string literal initialization of FilePath::CharType[], and for
|
||||
// using a FilePath::CharType[] in a printf-style format string.
|
||||
#if defined(OS_POSIX)
|
||||
#define FILE_PATH_LITERAL(x) x
|
||||
#define PRFilePath "s"
|
||||
#define PRFilePathLiteral "%s"
|
||||
#elif defined(OS_WIN)
|
||||
#define FILE_PATH_LITERAL(x) L ## x
|
||||
#define PRFilePath "ls"
|
||||
#define PRFilePathLiteral L"%ls"
|
||||
#endif // OS_WIN
|
||||
|
||||
// Provide a hash function so that hash_sets and maps can contain FilePath
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_FLOAT_UTIL_H_
|
||||
#define BASE_FLOAT_UTIL_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename Float>
|
||||
inline bool IsFinite(const Float& number) {
|
||||
#if defined(OS_POSIX)
|
||||
return std::isfinite(number) != 0;
|
||||
#elif defined(OS_WIN)
|
||||
return _finite(number) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Float>
|
||||
inline bool IsNaN(const Float& number) {
|
||||
#if defined(OS_POSIX)
|
||||
return std::isnan(number) != 0;
|
||||
#elif defined(OS_WIN)
|
||||
return _isnan(number) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_FLOAT_UTIL_H_
|
|
@ -5,10 +5,11 @@
|
|||
#ifndef BASE_GUID_H_
|
||||
#define BASE_GUID_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
@ -24,7 +25,7 @@ BASE_EXPORT bool IsValidGUID(const std::string& guid);
|
|||
|
||||
#if defined(OS_POSIX)
|
||||
// For unit testing purposes only. Do not use outside of tests.
|
||||
BASE_EXPORT std::string RandomDataToGUIDString(const uint64 bytes[2]);
|
||||
BASE_EXPORT std::string RandomDataToGUIDString(const uint64_t bytes[2]);
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
|
|
@ -11,7 +11,7 @@ extern "C" uint32_t SuperFastHash(const char* data, int len);
|
|||
|
||||
namespace base {
|
||||
|
||||
uint32 SuperFastHash(const char* data, int len) {
|
||||
uint32_t SuperFastHash(const char* data, int len) {
|
||||
return ::SuperFastHash(data, len);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,21 +5,23 @@
|
|||
#ifndef BASE_HASH_H_
|
||||
#define BASE_HASH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
BASE_EXPORT uint32 SuperFastHash(const char* data, int len);
|
||||
BASE_EXPORT uint32_t SuperFastHash(const char* data, int len);
|
||||
|
||||
// Computes a hash of a memory buffer |data| of a given |length|.
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
inline uint32 Hash(const char* data, size_t length) {
|
||||
inline uint32_t Hash(const char* data, size_t length) {
|
||||
if (length > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
NOTREACHED();
|
||||
return 0;
|
||||
|
@ -29,7 +31,7 @@ inline uint32 Hash(const char* data, size_t length) {
|
|||
|
||||
// Computes a hash of a string |str|.
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
inline uint32 Hash(const std::string& str) {
|
||||
inline uint32_t Hash(const std::string& str) {
|
||||
return Hash(str.data(), str.size());
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/atomicops.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
|
||||
namespace base {
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
|
||||
#include "base/atomicops.h"
|
||||
#include "base/base_export.h"
|
||||
#include "base/basictypes.h"
|
||||
#include "base/debug/leak_annotations.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/aligned_memory.h"
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче