зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to central, a=merge
This commit is contained in:
Коммит
483fea00ef
|
@ -28,8 +28,8 @@ this.SessionCookies = Object.freeze({
|
|||
SessionCookiesInternal.update(windows);
|
||||
},
|
||||
|
||||
getHostsForWindow(window, checkPrivacy = false) {
|
||||
return SessionCookiesInternal.getHostsForWindow(window, checkPrivacy);
|
||||
getHostsForWindow(window) {
|
||||
return SessionCookiesInternal.getHostsForWindow(window);
|
||||
},
|
||||
|
||||
restore(cookies) {
|
||||
|
@ -58,16 +58,20 @@ var SessionCookiesInternal = {
|
|||
update(windows) {
|
||||
this._ensureInitialized();
|
||||
|
||||
// Check whether we're allowed to store cookies.
|
||||
let storeAnyCookies = PrivacyLevel.canSave(false);
|
||||
let storeSecureCookies = PrivacyLevel.canSave(true);
|
||||
|
||||
for (let window of windows) {
|
||||
let cookies = [];
|
||||
|
||||
// Collect all cookies for the current window.
|
||||
for (let host of this.getHostsForWindow(window, true)) {
|
||||
for (let cookie of CookieStore.getCookiesForHost(host)) {
|
||||
// getCookiesForHost() will only return hosts with the right privacy
|
||||
// rules. Check again here to exclude HTTPS-only cookies if needed.
|
||||
if (PrivacyLevel.canSave(cookie.secure)) {
|
||||
cookies.push(cookie);
|
||||
if (storeAnyCookies) {
|
||||
// Collect all cookies for the current window.
|
||||
for (let host of this.getHostsForWindow(window)) {
|
||||
for (let cookie of CookieStore.getCookiesForHost(host)) {
|
||||
if (!cookie.secure || storeSecureCookies) {
|
||||
cookies.push(cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,16 +91,14 @@ var SessionCookiesInternal = {
|
|||
*
|
||||
* @param window
|
||||
* A window state object containing tabs with history entries.
|
||||
* @param checkPrivacy (bool)
|
||||
* Whether to check the privacy level for each host.
|
||||
* @return {set} A set of hosts for a given window state object.
|
||||
*/
|
||||
getHostsForWindow(window, checkPrivacy = false) {
|
||||
getHostsForWindow(window) {
|
||||
let hosts = new Set();
|
||||
|
||||
for (let tab of window.tabs) {
|
||||
for (let entry of tab.entries) {
|
||||
this._extractHostsFromEntry(entry, hosts, checkPrivacy);
|
||||
this._extractHostsFromEntry(entry, hosts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,26 +173,19 @@ var SessionCookiesInternal = {
|
|||
* the history entry, serialized
|
||||
* @param hosts
|
||||
* the set that will be used to store hosts
|
||||
* @param checkPrivacy
|
||||
* should we check the privacy level for https
|
||||
*/
|
||||
_extractHostsFromEntry(entry, hosts, checkPrivacy) {
|
||||
_extractHostsFromEntry(entry, hosts) {
|
||||
try {
|
||||
// It's alright if this throws for about: URIs.
|
||||
let {host, scheme} = Utils.makeURI(entry.url);
|
||||
|
||||
if (scheme == "file") {
|
||||
if (/^(file|https?)$/.test(scheme)) {
|
||||
hosts.add(host);
|
||||
} else if (/https?/.test(scheme)) {
|
||||
if (!checkPrivacy || PrivacyLevel.canSave(scheme == "https")) {
|
||||
hosts.add(host);
|
||||
}
|
||||
}
|
||||
} catch (ex) { }
|
||||
|
||||
if (entry.children) {
|
||||
for (let child of entry.children) {
|
||||
this._extractHostsFromEntry(child, hosts, checkPrivacy);
|
||||
this._extractHostsFromEntry(child, hosts);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -6,7 +6,7 @@ const PATH = "/browser/browser/components/sessionstore/test/";
|
|||
* Remove all cookies to start off a clean slate.
|
||||
*/
|
||||
add_task(function* test_setup() {
|
||||
requestLongerTimeout(2);
|
||||
requestLongerTimeout(3);
|
||||
Services.cookies.removeAll();
|
||||
});
|
||||
|
||||
|
@ -79,6 +79,104 @@ add_task(function* test_run() {
|
|||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test multiple scenarios with different privacy levels.
|
||||
*/
|
||||
add_task(function* test_run_privacy_level() {
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
|
||||
});
|
||||
|
||||
// With the default privacy level we collect all cookies.
|
||||
yield testCookieCollection({
|
||||
host: "http://example.com",
|
||||
domain: ".example.com",
|
||||
cookieHost: ".example.com",
|
||||
cookieURIs: ["https://example.com/" + PATH, "http://example.com/" + PATH],
|
||||
noCookieURIs: ["about:robots"]
|
||||
});
|
||||
|
||||
// With the default privacy level we collect all cookies.
|
||||
yield testCookieCollection({
|
||||
host: "https://example.com",
|
||||
domain: ".example.com",
|
||||
cookieHost: ".example.com",
|
||||
cookieURIs: ["https://example.com/" + PATH, "http://example.com/" + PATH],
|
||||
noCookieURIs: ["about:robots"]
|
||||
});
|
||||
|
||||
// With the default privacy level we collect all cookies.
|
||||
yield testCookieCollection({
|
||||
isSecure: true,
|
||||
host: "https://example.com",
|
||||
domain: ".example.com",
|
||||
cookieHost: ".example.com",
|
||||
cookieURIs: ["https://example.com/" + PATH, "http://example.com/" + PATH],
|
||||
noCookieURIs: ["about:robots"]
|
||||
});
|
||||
|
||||
// Set level=encrypted, don't store any secure cookies.
|
||||
Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1);
|
||||
|
||||
// With level=encrypted, non-secure cookies will be stored.
|
||||
yield testCookieCollection({
|
||||
host: "http://example.com",
|
||||
domain: ".example.com",
|
||||
cookieHost: ".example.com",
|
||||
cookieURIs: ["https://example.com/" + PATH, "http://example.com/" + PATH],
|
||||
noCookieURIs: ["about:robots"]
|
||||
});
|
||||
|
||||
// With level=encrypted, non-secure cookies will be stored,
|
||||
// even if sent by an HTTPS site.
|
||||
yield testCookieCollection({
|
||||
host: "https://example.com",
|
||||
domain: ".example.com",
|
||||
cookieHost: ".example.com",
|
||||
cookieURIs: ["https://example.com/" + PATH, "http://example.com/" + PATH],
|
||||
noCookieURIs: ["about:robots"]
|
||||
});
|
||||
|
||||
// With level=encrypted, secure cookies will NOT be stored.
|
||||
yield testCookieCollection({
|
||||
isSecure: true,
|
||||
host: "https://example.com",
|
||||
domain: ".example.com",
|
||||
cookieHost: ".example.com",
|
||||
noCookieURIs: ["https://example.com/" + PATH, "http://example.com/" + PATH]
|
||||
});
|
||||
|
||||
// Set level=full, don't store any cookies.
|
||||
Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2);
|
||||
|
||||
// With level=full we must not store any cookies.
|
||||
yield testCookieCollection({
|
||||
host: "http://example.com",
|
||||
domain: ".example.com",
|
||||
cookieHost: ".example.com",
|
||||
noCookieURIs: ["https://example.com/" + PATH, "http://example.com/" + PATH]
|
||||
});
|
||||
|
||||
// With level=full we must not store any cookies.
|
||||
yield testCookieCollection({
|
||||
host: "https://example.com",
|
||||
domain: ".example.com",
|
||||
cookieHost: ".example.com",
|
||||
noCookieURIs: ["https://example.com/" + PATH, "http://example.com/" + PATH]
|
||||
});
|
||||
|
||||
// With level=full we must not store any cookies.
|
||||
yield testCookieCollection({
|
||||
isSecure: true,
|
||||
host: "https://example.com",
|
||||
domain: ".example.com",
|
||||
cookieHost: ".example.com",
|
||||
noCookieURIs: ["https://example.com/" + PATH, "http://example.com/" + PATH]
|
||||
});
|
||||
|
||||
Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
|
||||
});
|
||||
|
||||
/**
|
||||
* Generic test function to check sessionstore's cookie collection module with
|
||||
* different cookie domains given in the Set-Cookie header. See above for some
|
||||
|
@ -96,6 +194,10 @@ var testCookieCollection = async function(params) {
|
|||
urlParams.append("domain", params.domain);
|
||||
}
|
||||
|
||||
if (params.isSecure) {
|
||||
urlParams.append("secure", "1");
|
||||
}
|
||||
|
||||
// Construct request URI.
|
||||
let requestUri = `${params.host}${PATH}browser_cookies.sjs?${urlParams}`;
|
||||
|
||||
|
|
|
@ -12,10 +12,15 @@ function handleRequest(req, resp) {
|
|||
let value = params.get("value");
|
||||
|
||||
let domain = "";
|
||||
if (params.has("domain")) {
|
||||
if (params.has("domain")) {
|
||||
domain = `; Domain=${params.get("domain")}`;
|
||||
}
|
||||
|
||||
resp.setHeader("Set-Cookie", `foobar=${value}${domain}`);
|
||||
let secure = "";
|
||||
if (params.has("secure")) {
|
||||
secure = "; Secure";
|
||||
}
|
||||
|
||||
resp.setHeader("Set-Cookie", `foobar=${value}${domain}${secure}`);
|
||||
resp.write("<meta charset=utf-8>hi");
|
||||
}
|
||||
|
|
|
@ -9,28 +9,36 @@
|
|||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.requestCompleteLog();
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[ "dom.disable_open_during_load", false ]
|
||||
]
|
||||
}).then(function() {
|
||||
info("after pref");
|
||||
var sub = encodeURI("data:text/html,<!DOCTYPE html>\n"+
|
||||
"<html><script>"+
|
||||
"var context = new AudioContext();"+
|
||||
"setTimeout(function(){window.close();},1000);\x3C/script></html>");
|
||||
window.onload = function(){
|
||||
info("after onload");
|
||||
var a = window.open(sub);
|
||||
info("after open: " + a);
|
||||
a.onbeforeunload = function(){
|
||||
setTimeout(function(){
|
||||
try {
|
||||
info("before sp");
|
||||
a.context.createScriptProcessor(512, 1, 1);
|
||||
info("after sp");
|
||||
} catch(e) {
|
||||
ok (true,"got exception");
|
||||
}
|
||||
setTimeout(function() {
|
||||
ok (true,"no crash");
|
||||
info("finish");
|
||||
ok (true,"no crash");
|
||||
SimpleTest.finish();
|
||||
}, 0);
|
||||
}, 0);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<script id=o_xml type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
|
||||
<xb></xb>
|
||||
</script>
|
||||
<script id=o_xslt type="text/plain"><?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
<xsl:template match="xb[$v1]"></xsl:template>
|
||||
<xsl:variable name="v1">
|
||||
<xsl:attribute name="a1" namespace="z">
|
||||
<xsl:variable name="v2" select="$v2"></xsl:variable>
|
||||
</xsl:attribute>
|
||||
</xsl:variable>
|
||||
</xsl:transform>
|
||||
</script>
|
||||
<script>
|
||||
addEventListener("DOMContentLoaded", function(){
|
||||
let doc = new DOMParser();
|
||||
let xsltPrs = new XSLTProcessor();
|
||||
xsltPrs.importStylesheet(doc.parseFromString(o_xslt.textContent, "text/xml"));
|
||||
xsltPrs.transformToDocument(doc.parseFromString(o_xml.textContent, "text/xml"));
|
||||
});
|
||||
</script>
|
|
@ -18,3 +18,4 @@ load 667315.xml
|
|||
load 1089049.html
|
||||
load 1205163.xml
|
||||
load 1243337.xml
|
||||
load 1338277.html
|
||||
|
|
|
@ -206,10 +206,12 @@ EvalContextImpl::getVariable(int32_t aNamespace,
|
|||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
bool
|
||||
EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
nsresult
|
||||
EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode, bool& aAllowed)
|
||||
{
|
||||
return false;
|
||||
aAllowed = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void*
|
||||
|
|
|
@ -28,6 +28,7 @@ class txIMatchContext;
|
|||
class txIEvalContext;
|
||||
class txNodeSet;
|
||||
class txXPathNode;
|
||||
class txXPathTreeWalker;
|
||||
|
||||
/**
|
||||
* A Base Class for all XSL Expressions
|
||||
|
@ -394,8 +395,9 @@ public:
|
|||
* standalone. The NodeTest node() is different to the
|
||||
* Pattern "node()" (document node isn't matched)
|
||||
*/
|
||||
virtual bool matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext) = 0;
|
||||
virtual nsresult matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext,
|
||||
bool& aMatched) = 0;
|
||||
virtual double getDefaultPriority() = 0;
|
||||
|
||||
/**
|
||||
|
@ -424,7 +426,9 @@ public:
|
|||
|
||||
#define TX_DECL_NODE_TEST \
|
||||
TX_DECL_TOSTRING \
|
||||
bool matches(const txXPathNode& aNode, txIMatchContext* aContext) override; \
|
||||
nsresult matches(const txXPathNode& aNode, \
|
||||
txIMatchContext* aContext, \
|
||||
bool& aMatched) override; \
|
||||
double getDefaultPriority() override; \
|
||||
bool isSensitiveTo(Expr::ContextSensitivity aContext) override;
|
||||
|
||||
|
@ -630,10 +634,30 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void fromDescendants(const txXPathNode& aNode, txIMatchContext* aCs,
|
||||
txNodeSet* aNodes);
|
||||
void fromDescendantsRev(const txXPathNode& aNode, txIMatchContext* aCs,
|
||||
txNodeSet* aNodes);
|
||||
/**
|
||||
* Append the current position of aWalker to aNodes if it matches mNodeTest,
|
||||
* using aContext as the context for matching.
|
||||
*/
|
||||
nsresult appendIfMatching(const txXPathTreeWalker& aWalker,
|
||||
txIMatchContext* aContext,
|
||||
txNodeSet* aNodes);
|
||||
|
||||
/**
|
||||
* Append the descendants of the current position of aWalker to aNodes if
|
||||
* they match mNodeTest, using aContext as the context for matching.
|
||||
*/
|
||||
nsresult appendMatchingDescendants(const txXPathTreeWalker& aWalker,
|
||||
txIMatchContext* aContext,
|
||||
txNodeSet* aNodes);
|
||||
|
||||
/**
|
||||
* Append the descendants of the current position of aWalker to aNodes in
|
||||
* reverse order if they match mNodeTest, using aContext as the context for
|
||||
* matching.
|
||||
*/
|
||||
nsresult appendMatchingDescendantsRev(const txXPathTreeWalker& aWalker,
|
||||
txIMatchContext* aContext,
|
||||
txNodeSet* aNodes);
|
||||
|
||||
nsAutoPtr<txNodeTest> mNodeTest;
|
||||
LocationStepType mAxisIdentifier;
|
||||
|
|
|
@ -30,10 +30,11 @@ nsresult txForwardContext::getVariable(int32_t aNamespace, nsIAtom* aLName,
|
|||
return mInner->getVariable(aNamespace, aLName, aResult);
|
||||
}
|
||||
|
||||
bool txForwardContext::isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
nsresult
|
||||
txForwardContext::isStripSpaceAllowed(const txXPathNode& aNode, bool& aAllowed)
|
||||
{
|
||||
NS_ASSERTION(mInner, "mInner is null!!!");
|
||||
return mInner->isStripSpaceAllowed(aNode);
|
||||
return mInner->isStripSpaceAllowed(aNode, aAllowed);
|
||||
}
|
||||
|
||||
void* txForwardContext::getPrivateContext()
|
||||
|
|
|
@ -88,7 +88,8 @@ public:
|
|||
* Is whitespace stripping allowed for the given node?
|
||||
* See http://www.w3.org/TR/xslt#strip
|
||||
*/
|
||||
virtual bool isStripSpaceAllowed(const txXPathNode& aNode) = 0;
|
||||
virtual nsresult isStripSpaceAllowed(const txXPathNode& aNode,
|
||||
bool& aAllowed) = 0;
|
||||
|
||||
/**
|
||||
* Returns a pointer to the private context
|
||||
|
@ -106,7 +107,7 @@ public:
|
|||
#define TX_DECL_MATCH_CONTEXT \
|
||||
nsresult getVariable(int32_t aNamespace, nsIAtom* aLName, \
|
||||
txAExprResult*& aResult); \
|
||||
bool isStripSpaceAllowed(const txXPathNode& aNode); \
|
||||
nsresult isStripSpaceAllowed(const txXPathNode& aNode, bool& aAllowed); \
|
||||
void* getPrivateContext(); \
|
||||
txResultRecycler* recycler(); \
|
||||
void receiveError(const nsAString& aMsg, nsresult aRes)
|
||||
|
|
|
@ -49,9 +49,8 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
nodes->setReverse();
|
||||
|
||||
do {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} while (walker.moveToParent());
|
||||
|
||||
break;
|
||||
|
@ -63,29 +62,29 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
}
|
||||
|
||||
do {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} while (walker.moveToNextAttribute());
|
||||
break;
|
||||
}
|
||||
case DESCENDANT_OR_SELF_AXIS:
|
||||
{
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_FALLTHROUGH;
|
||||
}
|
||||
case DESCENDANT_AXIS:
|
||||
{
|
||||
fromDescendants(walker.getCurrentPosition(), aContext, nodes);
|
||||
rv = appendMatchingDescendants(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
}
|
||||
case FOLLOWING_AXIS:
|
||||
{
|
||||
if (txXPathNodeUtils::isAttribute(walker.getCurrentPosition())) {
|
||||
walker.moveToParent();
|
||||
fromDescendants(walker.getCurrentPosition(), aContext, nodes);
|
||||
rv = appendMatchingDescendants(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
bool cont = true;
|
||||
while (!walker.moveToNextSibling()) {
|
||||
|
@ -95,11 +94,11 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
}
|
||||
}
|
||||
while (cont) {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
fromDescendants(walker.getCurrentPosition(), aContext, nodes);
|
||||
rv = appendMatchingDescendants(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
while (!walker.moveToNextSibling()) {
|
||||
if (!walker.moveToParent()) {
|
||||
|
@ -113,9 +112,8 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
case FOLLOWING_SIBLING_AXIS:
|
||||
{
|
||||
while (walker.moveToNextSibling()) {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -127,9 +125,9 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
break;
|
||||
case PARENT_AXIS :
|
||||
{
|
||||
if (walker.moveToParent() &&
|
||||
mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
if (walker.moveToParent()) {
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -145,11 +143,11 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
}
|
||||
}
|
||||
while (cont) {
|
||||
fromDescendantsRev(walker.getCurrentPosition(), aContext, nodes);
|
||||
rv = appendMatchingDescendantsRev(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
while (!walker.moveToPreviousSibling()) {
|
||||
if (!walker.moveToParent()) {
|
||||
|
@ -165,17 +163,15 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
nodes->setReverse();
|
||||
|
||||
while (walker.moveToPreviousSibling()) {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SELF_AXIS:
|
||||
{
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
}
|
||||
default: // Children Axis
|
||||
|
@ -185,9 +181,8 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
}
|
||||
|
||||
do {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
rv = appendIfMatching(walker, aContext, nodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} while (walker.moveToNextSibling());
|
||||
break;
|
||||
}
|
||||
|
@ -206,42 +201,62 @@ LocationStep::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void LocationStep::fromDescendants(const txXPathNode& aNode,
|
||||
txIMatchContext* aCs,
|
||||
txNodeSet* aNodes)
|
||||
nsresult
|
||||
LocationStep::appendIfMatching(const txXPathTreeWalker& aWalker,
|
||||
txIMatchContext* aContext,
|
||||
txNodeSet* aNodes)
|
||||
{
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if (!walker.moveToFirstChild()) {
|
||||
return;
|
||||
}
|
||||
bool matched;
|
||||
const txXPathNode& child = aWalker.getCurrentPosition();
|
||||
nsresult rv = mNodeTest->matches(child, aContext, matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
do {
|
||||
const txXPathNode& child = walker.getCurrentPosition();
|
||||
if (mNodeTest->matches(child, aCs)) {
|
||||
aNodes->append(child);
|
||||
}
|
||||
fromDescendants(child, aCs, aNodes);
|
||||
} while (walker.moveToNextSibling());
|
||||
if (matched) {
|
||||
aNodes->append(child);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void LocationStep::fromDescendantsRev(const txXPathNode& aNode,
|
||||
txIMatchContext* aCs,
|
||||
txNodeSet* aNodes)
|
||||
nsresult
|
||||
LocationStep::appendMatchingDescendants(const txXPathTreeWalker& aWalker,
|
||||
txIMatchContext* aContext,
|
||||
txNodeSet* aNodes)
|
||||
{
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if (!walker.moveToLastChild()) {
|
||||
return;
|
||||
txXPathTreeWalker walker(aWalker);
|
||||
if (!walker.moveToFirstChild()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
do {
|
||||
const txXPathNode& child = walker.getCurrentPosition();
|
||||
fromDescendantsRev(child, aCs, aNodes);
|
||||
nsresult rv = appendIfMatching(walker, aContext, aNodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mNodeTest->matches(child, aCs)) {
|
||||
aNodes->append(child);
|
||||
}
|
||||
rv = appendMatchingDescendants(walker, aContext, aNodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} while (walker.moveToNextSibling());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
LocationStep::appendMatchingDescendantsRev(const txXPathTreeWalker& aWalker,
|
||||
txIMatchContext* aContext,
|
||||
txNodeSet* aNodes)
|
||||
{
|
||||
txXPathTreeWalker walker(aWalker);
|
||||
if (!walker.moveToLastChild()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
do {
|
||||
nsresult rv = appendMatchingDescendantsRev(walker, aContext, aNodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = appendIfMatching(walker, aContext, aNodes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} while (walker.moveToPreviousSibling());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Expr::ExprType
|
||||
|
|
|
@ -23,7 +23,9 @@ txNameTest::txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, int32_t aNSID,
|
|||
"Go fix txNameTest::matches");
|
||||
}
|
||||
|
||||
bool txNameTest::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
nsresult
|
||||
txNameTest::matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
if ((mNodeType == txXPathNodeType::ELEMENT_NODE &&
|
||||
!txXPathNodeUtils::isElement(aNode)) ||
|
||||
|
@ -31,26 +33,34 @@ bool txNameTest::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
|||
!txXPathNodeUtils::isAttribute(aNode)) ||
|
||||
(mNodeType == txXPathNodeType::DOCUMENT_NODE &&
|
||||
!txXPathNodeUtils::isRoot(aNode))) {
|
||||
return false;
|
||||
aMatched = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Totally wild?
|
||||
if (mLocalName == nsGkAtoms::_asterisk && !mPrefix)
|
||||
return true;
|
||||
if (mLocalName == nsGkAtoms::_asterisk && !mPrefix) {
|
||||
aMatched = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compare namespaces
|
||||
if (mNamespace != txXPathNodeUtils::getNamespaceID(aNode)
|
||||
&& !(mNamespace == kNameSpaceID_None &&
|
||||
txXPathNodeUtils::isHTMLElementInHTMLDocument(aNode))
|
||||
)
|
||||
return false;
|
||||
) {
|
||||
aMatched = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Name wild?
|
||||
if (mLocalName == nsGkAtoms::_asterisk)
|
||||
return true;
|
||||
if (mLocalName == nsGkAtoms::_asterisk) {
|
||||
aMatched = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compare local-names
|
||||
return txXPathNodeUtils::localNameEquals(aNode, mLocalName);
|
||||
aMatched = txXPathNodeUtils::localNameEquals(aNode, mLocalName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -29,10 +29,11 @@ nsresult txNodeSetContext::getVariable(int32_t aNamespace, nsIAtom* aLName,
|
|||
return mInner->getVariable(aNamespace, aLName, aResult);
|
||||
}
|
||||
|
||||
bool txNodeSetContext::isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
nsresult
|
||||
txNodeSetContext::isStripSpaceAllowed(const txXPathNode& aNode, bool& aAllowed)
|
||||
{
|
||||
NS_ASSERTION(mInner, "mInner is null!!!");
|
||||
return mInner->isStripSpaceAllowed(aNode);
|
||||
return mInner->isStripSpaceAllowed(aNode, aAllowed);
|
||||
}
|
||||
|
||||
void* txNodeSetContext::getPrivateContext()
|
||||
|
|
|
@ -8,32 +8,54 @@
|
|||
#include "txIXPathContext.h"
|
||||
#include "txXPathTreeWalker.h"
|
||||
|
||||
bool txNodeTypeTest::matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext)
|
||||
nsresult
|
||||
txNodeTypeTest::matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
switch (mNodeType) {
|
||||
case COMMENT_TYPE:
|
||||
{
|
||||
return txXPathNodeUtils::isComment(aNode);
|
||||
aMatched = txXPathNodeUtils::isComment(aNode);
|
||||
return NS_OK;
|
||||
}
|
||||
case TEXT_TYPE:
|
||||
{
|
||||
return txXPathNodeUtils::isText(aNode) &&
|
||||
!aContext->isStripSpaceAllowed(aNode);
|
||||
aMatched = txXPathNodeUtils::isText(aNode);
|
||||
if (aMatched) {
|
||||
bool allowed;
|
||||
nsresult rv = aContext->isStripSpaceAllowed(aNode, allowed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aMatched = !allowed;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
case PI_TYPE:
|
||||
{
|
||||
return txXPathNodeUtils::isProcessingInstruction(aNode) &&
|
||||
(!mNodeName ||
|
||||
txXPathNodeUtils::localNameEquals(aNode, mNodeName));
|
||||
aMatched = txXPathNodeUtils::isProcessingInstruction(aNode) &&
|
||||
(!mNodeName ||
|
||||
txXPathNodeUtils::localNameEquals(aNode, mNodeName));
|
||||
return NS_OK;
|
||||
}
|
||||
case NODE_TYPE:
|
||||
{
|
||||
return !txXPathNodeUtils::isText(aNode) ||
|
||||
!aContext->isStripSpaceAllowed(aNode);
|
||||
if (txXPathNodeUtils::isText(aNode)) {
|
||||
bool allowed;
|
||||
nsresult rv = aContext->isStripSpaceAllowed(aNode, allowed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aMatched = !allowed;
|
||||
} else {
|
||||
aMatched = true;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
NS_NOTREACHED("Didn't deal with all values of the NodeType enum!");
|
||||
|
||||
aMatched = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
txNodeTest::NodeTestType
|
||||
|
|
|
@ -160,7 +160,9 @@ PathExpr::evalDescendants(Expr* aStep, const txXPathNode& aNode,
|
|||
|
||||
resNodes->addAndTransfer(newSet);
|
||||
|
||||
bool filterWS = aContext->isStripSpaceAllowed(aNode);
|
||||
bool filterWS;
|
||||
rv = aContext->isStripSpaceAllowed(aNode, filterWS);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if (!walker.moveToFirstChild()) {
|
||||
|
|
|
@ -16,20 +16,25 @@ txPredicatedNodeTest::txPredicatedNodeTest(txNodeTest* aNodeTest,
|
|||
"predicate must not be context-nodeset-sensitive");
|
||||
}
|
||||
|
||||
bool
|
||||
nsresult
|
||||
txPredicatedNodeTest::matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext)
|
||||
txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
if (!mNodeTest->matches(aNode, aContext)) {
|
||||
return false;
|
||||
nsresult rv = mNodeTest->matches(aNode, aContext, aMatched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aMatched) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
txSingleNodeContext context(aNode, aContext);
|
||||
RefPtr<txAExprResult> res;
|
||||
nsresult rv = mPredicate->evaluate(&context, getter_AddRefs(res));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
rv = mPredicate->evaluate(&context, getter_AddRefs(res));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return res->booleanValue();
|
||||
aMatched = res->booleanValue();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
double
|
||||
|
|
|
@ -27,10 +27,11 @@ public:
|
|||
return mInner->getVariable(aNamespace, aLName, aResult);
|
||||
}
|
||||
|
||||
bool isStripSpaceAllowed(const txXPathNode& aNode) override
|
||||
nsresult isStripSpaceAllowed(const txXPathNode& aNode,
|
||||
bool& aAllowed) override
|
||||
{
|
||||
NS_ASSERTION(mInner, "mInner is null!!!");
|
||||
return mInner->isStripSpaceAllowed(aNode);
|
||||
return mInner->isStripSpaceAllowed(aNode, aAllowed);
|
||||
}
|
||||
|
||||
void* getPrivateContext() override
|
||||
|
|
|
@ -10,18 +10,22 @@
|
|||
#include "txExprResult.h"
|
||||
#include "txSingleNodeContext.h"
|
||||
|
||||
bool
|
||||
txUnionNodeTest::matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext)
|
||||
nsresult
|
||||
txUnionNodeTest::matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
uint32_t i, len = mNodeTests.Length();
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (mNodeTests[i]->matches(aNode, aContext)) {
|
||||
return true;
|
||||
nsresult rv = mNodeTests[i]->matches(aNode, aContext, aMatched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aMatched) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
aMatched = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
double
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
{
|
||||
MOZ_CRASH("shouldn't depend on this context");
|
||||
}
|
||||
bool isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
nsresult isStripSpaceAllowed(const txXPathNode& aNode, bool& aAllowed)
|
||||
{
|
||||
MOZ_CRASH("shouldn't depend on this context");
|
||||
}
|
||||
|
|
|
@ -87,10 +87,7 @@ txExecutionState::~txExecutionState()
|
|||
|
||||
txStackIterator handlerIter(&mResultHandlerStack);
|
||||
while (handlerIter.hasNext()) {
|
||||
txAXMLEventHandler* handler = (txAXMLEventHandler*)handlerIter.next();
|
||||
if (handler != mObsoleteHandler) {
|
||||
delete handler;
|
||||
}
|
||||
delete (txAXMLEventHandler*)handlerIter.next();
|
||||
}
|
||||
|
||||
txStackIterator paramIter(&mParamStack);
|
||||
|
@ -141,8 +138,11 @@ txExecutionState::init(const txXPathNode& aNode,
|
|||
// might use us.
|
||||
txStylesheet::ImportFrame* frame = 0;
|
||||
txExpandedName nullName;
|
||||
txInstruction* templ = mStylesheet->findTemplate(aNode, nullName,
|
||||
this, nullptr, &frame);
|
||||
txInstruction* templ;
|
||||
rv = mStylesheet->findTemplate(aNode, nullName, this, nullptr, &templ,
|
||||
&frame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
pushTemplateRule(frame, nullName, nullptr);
|
||||
|
||||
return runTemplate(templ);
|
||||
|
@ -162,17 +162,6 @@ txExecutionState::end(nsresult aResult)
|
|||
return mOutputHandler->endDocument(aResult);
|
||||
}
|
||||
|
||||
void
|
||||
txExecutionState::popAndDeleteEvalContext()
|
||||
{
|
||||
if (!mEvalContextStack.isEmpty()) {
|
||||
auto ctx = popEvalContext();
|
||||
if (ctx != mInitialEvalContext) {
|
||||
delete ctx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
txExecutionState::popAndDeleteEvalContextUntil(txIEvalContext* aContext)
|
||||
{
|
||||
|
@ -306,10 +295,10 @@ txExecutionState::getVariable(int32_t aNamespace, nsIAtom* aLName,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
txExecutionState::isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
nsresult
|
||||
txExecutionState::isStripSpaceAllowed(const txXPathNode& aNode, bool& aAllowed)
|
||||
{
|
||||
return mStylesheet->isStripSpaceAllowed(aNode, this);
|
||||
return mStylesheet->isStripSpaceAllowed(aNode, this, aAllowed);
|
||||
}
|
||||
|
||||
void*
|
||||
|
|
|
@ -95,8 +95,6 @@ public:
|
|||
nsresult pushEvalContext(txIEvalContext* aContext);
|
||||
txIEvalContext* popEvalContext();
|
||||
|
||||
void popAndDeleteEvalContext();
|
||||
|
||||
/**
|
||||
* Helper that deletes all entries before |aContext| and then
|
||||
* pops it off the stack. The caller must delete |aContext| if
|
||||
|
|
|
@ -27,9 +27,11 @@ txApplyDefaultElementTemplate::execute(txExecutionState& aEs)
|
|||
txExecutionState::TemplateRule* rule = aEs.getCurrentTemplateRule();
|
||||
txExpandedName mode(rule->mModeNsId, rule->mModeLocalName);
|
||||
txStylesheet::ImportFrame* frame = 0;
|
||||
txInstruction* templ =
|
||||
txInstruction* templ;
|
||||
nsresult rv =
|
||||
aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(),
|
||||
mode, &aEs, nullptr, &frame);
|
||||
mode, &aEs, nullptr, &templ, &frame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aEs.pushTemplateRule(frame, mode, aEs.mTemplateParams);
|
||||
|
||||
|
@ -53,9 +55,11 @@ txApplyImports::execute(txExecutionState& aEs)
|
|||
|
||||
txStylesheet::ImportFrame* frame = 0;
|
||||
txExpandedName mode(rule->mModeNsId, rule->mModeLocalName);
|
||||
txInstruction* templ =
|
||||
aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(),
|
||||
mode, &aEs, rule->mFrame, &frame);
|
||||
txInstruction* templ;
|
||||
rv = aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(),
|
||||
mode, &aEs, rule->mFrame, &templ,
|
||||
&frame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aEs.pushTemplateRule(frame, mode, rule->mParams);
|
||||
|
||||
|
@ -76,9 +80,11 @@ nsresult
|
|||
txApplyTemplates::execute(txExecutionState& aEs)
|
||||
{
|
||||
txStylesheet::ImportFrame* frame = 0;
|
||||
txInstruction* templ =
|
||||
txInstruction* templ;
|
||||
nsresult rv =
|
||||
aEs.mStylesheet->findTemplate(aEs.getEvalContext()->getContextNode(),
|
||||
mMode, &aEs, nullptr, &frame);
|
||||
mMode, &aEs, nullptr, &templ, &frame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aEs.pushTemplateRule(frame, mMode, aEs.mTemplateParams);
|
||||
|
||||
|
@ -470,7 +476,7 @@ txLoopNodeSet::execute(txExecutionState& aEs)
|
|||
txNodeSetContext* context =
|
||||
static_cast<txNodeSetContext*>(aEs.getEvalContext());
|
||||
if (!context->hasNext()) {
|
||||
aEs.popAndDeleteEvalContext();
|
||||
delete aEs.popEvalContext();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -338,7 +338,11 @@ nsresult txXSLKey::testNode(const txXPathNode& aNode,
|
|||
nsAutoString val;
|
||||
uint32_t currKey, numKeys = mKeys.Length();
|
||||
for (currKey = 0; currKey < numKeys; ++currKey) {
|
||||
if (mKeys[currKey].matchPattern->matches(aNode, &aEs)) {
|
||||
bool matched;
|
||||
nsresult rv = mKeys[currKey].matchPattern->matches(aNode, &aEs, matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
txSingleNodeContext *evalContext =
|
||||
new txSingleNodeContext(aNode, &aEs);
|
||||
NS_ENSURE_TRUE(evalContext, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
|
|
@ -441,9 +441,11 @@ public:
|
|||
aResult = nullptr;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
bool isStripSpaceAllowed(const txXPathNode& aNode)
|
||||
nsresult isStripSpaceAllowed(const txXPathNode& aNode, bool& aAllowed)
|
||||
{
|
||||
return false;
|
||||
aAllowed = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
void* getPrivateContext()
|
||||
{
|
||||
|
|
|
@ -88,17 +88,18 @@ txStylesheet::~txStylesheet()
|
|||
}
|
||||
}
|
||||
|
||||
txInstruction*
|
||||
nsresult
|
||||
txStylesheet::findTemplate(const txXPathNode& aNode,
|
||||
const txExpandedName& aMode,
|
||||
txIMatchContext* aContext,
|
||||
ImportFrame* aImportedBy,
|
||||
txInstruction** aTemplate,
|
||||
ImportFrame** aImportFrame)
|
||||
{
|
||||
NS_ASSERTION(aImportFrame, "missing ImportFrame pointer");
|
||||
|
||||
*aTemplate = nullptr;
|
||||
*aImportFrame = nullptr;
|
||||
txInstruction* matchTemplate = nullptr;
|
||||
ImportFrame* endFrame = nullptr;
|
||||
txListIterator frameIter(&mImportFrames);
|
||||
|
||||
|
@ -115,7 +116,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
|
|||
#endif
|
||||
|
||||
ImportFrame* frame;
|
||||
while (!matchTemplate &&
|
||||
while (!*aTemplate &&
|
||||
(frame = static_cast<ImportFrame*>(frameIter.next())) &&
|
||||
frame != endFrame) {
|
||||
|
||||
|
@ -126,10 +127,14 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
|
|||
if (templates) {
|
||||
// Find template with highest priority
|
||||
uint32_t i, len = templates->Length();
|
||||
for (i = 0; i < len && !matchTemplate; ++i) {
|
||||
for (i = 0; i < len && !*aTemplate; ++i) {
|
||||
MatchableTemplate& templ = (*templates)[i];
|
||||
if (templ.mMatch->matches(aNode, aContext)) {
|
||||
matchTemplate = templ.mFirstInstruction;
|
||||
bool matched;
|
||||
nsresult rv = templ.mMatch->matches(aNode, aContext, matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
*aTemplate = templ.mFirstInstruction;
|
||||
*aImportFrame = frame;
|
||||
#if defined(TX_TO_STRING)
|
||||
match = templ.mMatch;
|
||||
|
@ -145,7 +150,7 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
|
|||
aMode.mLocalName->ToString(mode);
|
||||
}
|
||||
txXPathNodeUtils::getNodeName(aNode, nodeName);
|
||||
if (matchTemplate) {
|
||||
if (*aTemplate) {
|
||||
nsAutoString matchAttr;
|
||||
#ifdef TX_TO_STRING
|
||||
match->toString(matchAttr);
|
||||
|
@ -164,23 +169,23 @@ txStylesheet::findTemplate(const txXPathNode& aNode,
|
|||
}
|
||||
}
|
||||
|
||||
if (!matchTemplate) {
|
||||
if (!*aTemplate) {
|
||||
// Test for these first since a node can be both a text node
|
||||
// and a root (if it is orphaned)
|
||||
if (txXPathNodeUtils::isAttribute(aNode) ||
|
||||
txXPathNodeUtils::isText(aNode)) {
|
||||
matchTemplate = mCharactersTemplate;
|
||||
*aTemplate = mCharactersTemplate;
|
||||
}
|
||||
else if (txXPathNodeUtils::isElement(aNode) ||
|
||||
txXPathNodeUtils::isRoot(aNode)) {
|
||||
matchTemplate = mContainerTemplate;
|
||||
*aTemplate = mContainerTemplate;
|
||||
}
|
||||
else {
|
||||
matchTemplate = mEmptyTemplate;
|
||||
*aTemplate = mEmptyTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
return matchTemplate;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
txDecimalFormat*
|
||||
|
@ -219,37 +224,53 @@ txStylesheet::getKeyMap()
|
|||
return mKeys;
|
||||
}
|
||||
|
||||
bool
|
||||
txStylesheet::isStripSpaceAllowed(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
nsresult
|
||||
txStylesheet::isStripSpaceAllowed(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext, bool& aAllowed)
|
||||
{
|
||||
int32_t frameCount = mStripSpaceTests.Length();
|
||||
if (frameCount == 0) {
|
||||
return false;
|
||||
aAllowed = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
txXPathTreeWalker walker(aNode);
|
||||
|
||||
if (txXPathNodeUtils::isText(walker.getCurrentPosition()) &&
|
||||
(!txXPathNodeUtils::isWhitespace(aNode) || !walker.moveToParent())) {
|
||||
return false;
|
||||
aAllowed = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const txXPathNode& node = walker.getCurrentPosition();
|
||||
|
||||
if (!txXPathNodeUtils::isElement(node)) {
|
||||
return false;
|
||||
aAllowed = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// check Whitespace stipping handling list against given Node
|
||||
int32_t i;
|
||||
for (i = 0; i < frameCount; ++i) {
|
||||
txStripSpaceTest* sst = mStripSpaceTests[i];
|
||||
if (sst->matches(node, aContext)) {
|
||||
return sst->stripsSpace() && !XMLUtils::getXMLSpacePreserve(node);
|
||||
bool matched;
|
||||
nsresult rv = sst->matches(node, aContext, matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
aAllowed = sst->stripsSpace() &&
|
||||
!XMLUtils::getXMLSpacePreserve(node);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
aAllowed = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -35,19 +35,21 @@ public:
|
|||
|
||||
NS_INLINE_DECL_REFCOUNTING(txStylesheet)
|
||||
|
||||
txInstruction* findTemplate(const txXPathNode& aNode,
|
||||
const txExpandedName& aMode,
|
||||
txIMatchContext* aContext,
|
||||
ImportFrame* aImportedBy,
|
||||
ImportFrame** aImportFrame);
|
||||
nsresult findTemplate(const txXPathNode& aNode,
|
||||
const txExpandedName& aMode,
|
||||
txIMatchContext* aContext,
|
||||
ImportFrame* aImportedBy,
|
||||
txInstruction** aTemplate,
|
||||
ImportFrame** aImportFrame);
|
||||
txDecimalFormat* getDecimalFormat(const txExpandedName& aName);
|
||||
txInstruction* getAttributeSet(const txExpandedName& aName);
|
||||
txInstruction* getNamedTemplate(const txExpandedName& aName);
|
||||
txOutputFormat* getOutputFormat();
|
||||
GlobalVariable* getGlobalVariable(const txExpandedName& aName);
|
||||
const txOwningExpandedNameMap<txXSLKey>& getKeyMap();
|
||||
bool isStripSpaceAllowed(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext);
|
||||
nsresult isStripSpaceAllowed(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext,
|
||||
bool& aAllowed);
|
||||
|
||||
/**
|
||||
* Called by the stylesheet compiler once all stylesheets has been read.
|
||||
|
@ -166,8 +168,10 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
bool matches(const txXPathNode& aNode, txIMatchContext* aContext) {
|
||||
return mNameTest.matches(aNode, aContext);
|
||||
nsresult matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
return mNameTest.matches(aNode, aContext, aMatched);
|
||||
}
|
||||
|
||||
bool stripsSpace() {
|
||||
|
|
|
@ -108,13 +108,12 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
// Otherwise use count/from/level
|
||||
|
||||
txPattern* countPattern = aCountPattern;
|
||||
bool ownsCountPattern = false;
|
||||
nsAutoPtr<txPattern> newCountPattern;
|
||||
const txXPathNode& currNode = aContext->getContextNode();
|
||||
|
||||
// Parse count- and from-attributes
|
||||
|
||||
if (!aCountPattern) {
|
||||
ownsCountPattern = true;
|
||||
txNodeTest* nodeTest;
|
||||
uint16_t nodeType = txXPathNodeUtils::getNodeType(currNode);
|
||||
switch (nodeType) {
|
||||
|
@ -160,7 +159,7 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
}
|
||||
}
|
||||
MOZ_ASSERT(nodeTest);
|
||||
countPattern = new txStepPattern(nodeTest, false);
|
||||
countPattern = newCountPattern = new txStepPattern(nodeTest, false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -170,14 +169,28 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
if (aLevel == eLevelSingle) {
|
||||
txXPathTreeWalker walker(currNode);
|
||||
do {
|
||||
if (aFromPattern && !walker.isOnNode(currNode) &&
|
||||
aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
break;
|
||||
if (aFromPattern && !walker.isOnNode(currNode)) {
|
||||
bool matched;
|
||||
rv = aFromPattern->matches(walker.getCurrentPosition(),
|
||||
aContext, matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
|
||||
aContext)));
|
||||
bool matched;
|
||||
rv = countPattern->matches(walker.getCurrentPosition(), aContext,
|
||||
matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
int32_t count;
|
||||
rv = getSiblingCount(walker, countPattern, aContext, &count);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aValues.add(NS_INT32_TO_PTR(count));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -189,7 +202,12 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
if (aFromPattern && aValues.getLength()) {
|
||||
bool hasParent;
|
||||
while ((hasParent = walker.moveToParent())) {
|
||||
if (aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
bool matched;
|
||||
rv = aFromPattern->matches(walker.getCurrentPosition(),
|
||||
aContext, matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -205,16 +223,28 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
txXPathTreeWalker walker(currNode);
|
||||
bool matchedFrom = false;
|
||||
do {
|
||||
if (aFromPattern && !walker.isOnNode(currNode) &&
|
||||
aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
//... we find one that matches from
|
||||
matchedFrom = true;
|
||||
break;
|
||||
if (aFromPattern && !walker.isOnNode(currNode)) {
|
||||
rv = aFromPattern->matches(walker.getCurrentPosition(),
|
||||
aContext, matchedFrom);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matchedFrom) {
|
||||
//... we find one that matches from
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
|
||||
aContext)));
|
||||
bool matched;
|
||||
rv = countPattern->matches(walker.getCurrentPosition(), aContext,
|
||||
matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
int32_t count;
|
||||
rv = getSiblingCount(walker, countPattern, aContext, &count);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aValues.add(NS_INT32_TO_PTR(count));
|
||||
}
|
||||
} while (walker.moveToParent());
|
||||
|
||||
|
@ -232,13 +262,22 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
|
||||
txXPathTreeWalker walker(currNode);
|
||||
do {
|
||||
if (aFromPattern && !walker.isOnNode(currNode) &&
|
||||
aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
matchedFrom = true;
|
||||
break;
|
||||
if (aFromPattern && !walker.isOnNode(currNode)) {
|
||||
rv = aFromPattern->matches(walker.getCurrentPosition(),
|
||||
aContext, matchedFrom);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matchedFrom) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
bool matched;
|
||||
rv = countPattern->matches(walker.getCurrentPosition(), aContext,
|
||||
matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
++value;
|
||||
}
|
||||
|
||||
|
@ -256,10 +295,6 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
|
|||
}
|
||||
}
|
||||
|
||||
if (ownsCountPattern) {
|
||||
delete countPattern;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -388,18 +423,27 @@ txXSLTNumber::getCounters(Expr* aGroupSize, Expr* aGroupSeparator,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
nsresult
|
||||
txXSLTNumber::getSiblingCount(txXPathTreeWalker& aWalker,
|
||||
txPattern* aCountPattern,
|
||||
txIMatchContext* aContext)
|
||||
txIMatchContext* aContext,
|
||||
int32_t* aCount)
|
||||
{
|
||||
int32_t value = 1;
|
||||
while (aWalker.moveToPreviousSibling()) {
|
||||
if (aCountPattern->matches(aWalker.getCurrentPosition(), aContext)) {
|
||||
bool matched;
|
||||
nsresult rv = aCountPattern->matches(aWalker.getCurrentPosition(),
|
||||
aContext, matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
++value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
||||
*aCount = value;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -46,9 +46,10 @@ private:
|
|||
* position.
|
||||
*
|
||||
*/
|
||||
static int32_t getSiblingCount(txXPathTreeWalker& aWalker,
|
||||
txPattern* aCountPattern,
|
||||
txIMatchContext* aContext);
|
||||
static nsresult getSiblingCount(txXPathTreeWalker& aWalker,
|
||||
txPattern* aCountPattern,
|
||||
txIMatchContext* aContext,
|
||||
int32_t* aCount);
|
||||
|
||||
static bool getPrevInDocumentOrder(txXPathTreeWalker& aWalker);
|
||||
|
||||
|
|
|
@ -32,15 +32,25 @@ double txUnionPattern::getDefaultPriority()
|
|||
* This should be called on the simple patterns for xsl:template,
|
||||
* but is fine for xsl:key and xsl:number
|
||||
*/
|
||||
bool txUnionPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
nsresult
|
||||
txUnionPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
uint32_t i, len = mLocPathPatterns.Length();
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (mLocPathPatterns[i]->matches(aNode, aContext)) {
|
||||
return true;
|
||||
nsresult rv = mLocPathPatterns[i]->matches(aNode, aContext, aMatched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aMatched) {
|
||||
aMatched = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
aMatched = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
txPattern::Type
|
||||
|
@ -103,7 +113,9 @@ nsresult txLocPathPattern::addStep(txPattern* aPattern, bool isChild)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool txLocPathPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
nsresult
|
||||
txLocPathPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
NS_ASSERTION(mSteps.Length() > 1, "Internal error");
|
||||
|
||||
|
@ -121,18 +133,39 @@ bool txLocPathPattern::matches(const txXPathNode& aNode, txIMatchContext* aConte
|
|||
|
||||
uint32_t pos = mSteps.Length();
|
||||
Step* step = &mSteps[--pos];
|
||||
if (!step->pattern->matches(aNode, aContext))
|
||||
return false;
|
||||
nsresult rv = step->pattern->matches(aNode, aContext, aMatched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aMatched) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
txXPathTreeWalker walker(aNode);
|
||||
bool hasParent = walker.moveToParent();
|
||||
|
||||
while (step->isChild) {
|
||||
if (!pos)
|
||||
return true; // all steps matched
|
||||
if (!pos) {
|
||||
aMatched = true;
|
||||
|
||||
return NS_OK; // all steps matched
|
||||
}
|
||||
|
||||
if (!hasParent) {
|
||||
// no more ancestors
|
||||
aMatched = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
step = &mSteps[--pos];
|
||||
if (!hasParent || !step->pattern->matches(walker.getCurrentPosition(), aContext))
|
||||
return false; // no more ancestors or no match
|
||||
rv = step->pattern->matches(walker.getCurrentPosition(), aContext,
|
||||
aMatched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aMatched) {
|
||||
// no match
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
hasParent = walker.moveToParent();
|
||||
}
|
||||
|
@ -142,12 +175,19 @@ bool txLocPathPattern::matches(const txXPathNode& aNode, txIMatchContext* aConte
|
|||
uint32_t blockPos = pos;
|
||||
|
||||
while (pos) {
|
||||
if (!hasParent)
|
||||
return false; // There are more steps in the current block
|
||||
// than ancestors of the tested node
|
||||
if (!hasParent) {
|
||||
aMatched = false; // There are more steps in the current block
|
||||
// than ancestors of the tested node
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
step = &mSteps[--pos];
|
||||
if (!step->pattern->matches(walker.getCurrentPosition(), aContext)) {
|
||||
bool matched;
|
||||
rv = step->pattern->matches(walker.getCurrentPosition(), aContext,
|
||||
matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!matched) {
|
||||
// Didn't match. We restart at beginning of block using a new
|
||||
// start node
|
||||
pos = blockPos;
|
||||
|
@ -164,7 +204,9 @@ bool txLocPathPattern::matches(const txXPathNode& aNode, txIMatchContext* aConte
|
|||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
aMatched = true;
|
||||
|
||||
return NS_OK;
|
||||
} // txLocPathPattern::matches
|
||||
|
||||
double txLocPathPattern::getDefaultPriority()
|
||||
|
@ -218,9 +260,13 @@ txLocPathPattern::toString(nsAString& aDest)
|
|||
* a txPattern matching the document node, or '/'
|
||||
*/
|
||||
|
||||
bool txRootPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
nsresult
|
||||
txRootPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
return txXPathNodeUtils::isRoot(aNode);
|
||||
aMatched = txXPathNodeUtils::isRoot(aNode);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
double txRootPattern::getDefaultPriority()
|
||||
|
@ -264,10 +310,14 @@ txIdPattern::txIdPattern(const nsSubstring& aString)
|
|||
}
|
||||
}
|
||||
|
||||
bool txIdPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
nsresult
|
||||
txIdPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
if (!txXPathNodeUtils::isElement(aNode)) {
|
||||
return false;
|
||||
aMatched = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get a ID attribute, if there is
|
||||
|
@ -275,7 +325,9 @@ bool txIdPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
|||
NS_ASSERTION(content, "a Element without nsIContent");
|
||||
|
||||
nsIAtom* id = content->GetID();
|
||||
return id && mIds.IndexOf(id) > -1;
|
||||
aMatched = id && mIds.IndexOf(id) > -1;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
double txIdPattern::getDefaultPriority()
|
||||
|
@ -320,18 +372,22 @@ txIdPattern::toString(nsAString& aDest)
|
|||
* argument.
|
||||
*/
|
||||
|
||||
bool txKeyPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
nsresult
|
||||
txKeyPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
txExecutionState* es = (txExecutionState*)aContext->getPrivateContext();
|
||||
nsAutoPtr<txXPathNode> contextDoc(txXPathNodeUtils::getOwnerDocument(aNode));
|
||||
NS_ENSURE_TRUE(contextDoc, false);
|
||||
NS_ENSURE_TRUE(contextDoc, NS_ERROR_FAILURE);
|
||||
|
||||
RefPtr<txNodeSet> nodes;
|
||||
nsresult rv = es->getKeyNodes(mName, *contextDoc, mValue, true,
|
||||
getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return nodes->contains(aNode);
|
||||
aMatched = nodes->contains(aNode);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
double txKeyPattern::getDefaultPriority()
|
||||
|
@ -373,21 +429,32 @@ txKeyPattern::toString(nsAString& aDest)
|
|||
* a txPattern to hold the NodeTest and the Predicates of a StepPattern
|
||||
*/
|
||||
|
||||
bool txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
||||
nsresult
|
||||
txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext,
|
||||
bool& aMatched)
|
||||
{
|
||||
NS_ASSERTION(mNodeTest, "Internal error");
|
||||
|
||||
if (!mNodeTest->matches(aNode, aContext))
|
||||
return false;
|
||||
nsresult rv = mNodeTest->matches(aNode, aContext, aMatched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aMatched) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
txXPathTreeWalker walker(aNode);
|
||||
if ((!mIsAttr &&
|
||||
txXPathNodeUtils::isAttribute(walker.getCurrentPosition())) ||
|
||||
!walker.moveToParent()) {
|
||||
return false;
|
||||
aMatched = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (isEmpty()) {
|
||||
return true;
|
||||
aMatched = true;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -410,13 +477,17 @@ bool txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
|||
|
||||
// Create the context node set for evaluating the predicates
|
||||
RefPtr<txNodeSet> nodes;
|
||||
nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool hasNext = mIsAttr ? walker.moveToFirstAttribute() :
|
||||
walker.moveToFirstChild();
|
||||
while (hasNext) {
|
||||
if (mNodeTest->matches(walker.getCurrentPosition(), aContext)) {
|
||||
bool matched;
|
||||
rv = mNodeTest->matches(walker.getCurrentPosition(), aContext, matched);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (matched) {
|
||||
nodes->append(walker.getCurrentPosition());
|
||||
}
|
||||
hasNext = mIsAttr ? walker.moveToNextAttribute() :
|
||||
|
@ -426,7 +497,7 @@ bool txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
|||
Expr* predicate = mPredicates[0];
|
||||
RefPtr<txNodeSet> newNodes;
|
||||
rv = aContext->recycler()->getNodeSet(getter_AddRefs(newNodes));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t i, predLen = mPredicates.Length();
|
||||
for (i = 1; i < predLen; ++i) {
|
||||
|
@ -437,7 +508,7 @@ bool txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
|||
predContext.next();
|
||||
RefPtr<txAExprResult> exprResult;
|
||||
rv = predicate->evaluate(&predContext, getter_AddRefs(exprResult));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
switch(exprResult->getResultType()) {
|
||||
case txAExprResult::NUMBER:
|
||||
|
@ -464,20 +535,25 @@ bool txStepPattern::matches(const txXPathNode& aNode, txIMatchContext* aContext)
|
|||
nodes->clear();
|
||||
nodes->append(*newNodes);
|
||||
if (!contextIsInPredicate) {
|
||||
return false;
|
||||
aMatched = false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
predicate = mPredicates[i];
|
||||
}
|
||||
txForwardContext evalContext(aContext, aNode, nodes);
|
||||
RefPtr<txAExprResult> exprResult;
|
||||
rv = predicate->evaluate(&evalContext, getter_AddRefs(exprResult));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exprResult->getResultType() == txAExprResult::NUMBER)
|
||||
if (exprResult->getResultType() == txAExprResult::NUMBER) {
|
||||
// handle default, [position() == numberValue()]
|
||||
return ((double)evalContext.position() == exprResult->numberValue());
|
||||
aMatched = ((double)evalContext.position() == exprResult->numberValue());
|
||||
} else {
|
||||
aMatched = exprResult->booleanValue();
|
||||
}
|
||||
|
||||
return exprResult->booleanValue();
|
||||
return NS_OK;
|
||||
} // matches
|
||||
|
||||
double txStepPattern::getDefaultPriority()
|
||||
|
|
|
@ -26,8 +26,9 @@ public:
|
|||
/*
|
||||
* Determines whether this Pattern matches the given node.
|
||||
*/
|
||||
virtual bool matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext) = 0;
|
||||
virtual nsresult matches(const txXPathNode& aNode,
|
||||
txIMatchContext* aContext,
|
||||
bool& aMatched) = 0;
|
||||
|
||||
/*
|
||||
* Returns the default priority of this Pattern.
|
||||
|
@ -86,7 +87,8 @@ public:
|
|||
};
|
||||
|
||||
#define TX_DECL_PATTERN_BASE \
|
||||
bool matches(const txXPathNode& aNode, txIMatchContext* aContext) override; \
|
||||
nsresult matches(const txXPathNode& aNode, txIMatchContext* aContext, \
|
||||
bool& aMatched) override; \
|
||||
double getDefaultPriority() override; \
|
||||
virtual Expr* getSubExprAt(uint32_t aPos) override; \
|
||||
virtual void setSubExprAt(uint32_t aPos, Expr* aExpr) override; \
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "nsString.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::image;
|
||||
|
@ -58,6 +59,11 @@ nsBMPEncoder::InitFromData(const uint8_t* aData,
|
|||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
CheckedInt32 check = CheckedInt32(aWidth) * 4;
|
||||
if (MOZ_UNLIKELY(!check.isValid())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Stride is the padded width of each row, so it better be longer
|
||||
if ((aInputFormat == INPUT_FORMAT_RGB &&
|
||||
aStride < aWidth * 3) ||
|
||||
|
@ -86,19 +92,19 @@ nsBMPEncoder::InitFromData(const uint8_t* aData,
|
|||
|
||||
// Just a helper method to make it explicit in calculations that we are dealing
|
||||
// with bytes and not bits
|
||||
static inline uint32_t
|
||||
BytesPerPixel(uint32_t aBPP)
|
||||
static inline uint16_t
|
||||
BytesPerPixel(uint16_t aBPP)
|
||||
{
|
||||
return aBPP / 8;
|
||||
}
|
||||
|
||||
// Calculates the number of padding bytes that are needed per row of image data
|
||||
static inline uint32_t
|
||||
PaddingBytes(uint32_t aBPP, uint32_t aWidth)
|
||||
PaddingBytes(uint16_t aBPP, uint32_t aWidth)
|
||||
{
|
||||
uint32_t rowSize = aWidth * BytesPerPixel(aBPP);
|
||||
uint8_t paddingSize = 0;
|
||||
if(rowSize % 4) {
|
||||
if (rowSize % 4) {
|
||||
paddingSize = (4 - (rowSize % 4));
|
||||
}
|
||||
return paddingSize;
|
||||
|
@ -125,14 +131,21 @@ nsBMPEncoder::StartImageEncode(uint32_t aWidth,
|
|||
|
||||
// parse and check any provided output options
|
||||
Version version;
|
||||
uint32_t bpp;
|
||||
uint16_t bpp;
|
||||
nsresult rv = ParseOptions(aOutputOptions, version, bpp);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
MOZ_ASSERT(bpp <= 32);
|
||||
|
||||
InitFileHeader(version, bpp, aWidth, aHeight);
|
||||
InitInfoHeader(version, bpp, aWidth, aHeight);
|
||||
rv = InitFileHeader(version, bpp, aWidth, aHeight);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = InitInfoHeader(version, bpp, aWidth, aHeight);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mImageBufferSize = mBMPFileHeader.filesize;
|
||||
mImageBufferStart = static_cast<uint8_t*>(malloc(mImageBufferSize));
|
||||
|
@ -187,12 +200,26 @@ nsBMPEncoder::AddImageFrame(const uint8_t* aData,
|
|||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
auto row = MakeUniqueFallible<uint8_t[]>(mBMPInfoHeader.width *
|
||||
BytesPerPixel(mBMPInfoHeader.bpp));
|
||||
if (mBMPInfoHeader.width < 0) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
CheckedUint32 size =
|
||||
CheckedUint32(mBMPInfoHeader.width) * CheckedUint32(BytesPerPixel(mBMPInfoHeader.bpp));
|
||||
if (MOZ_UNLIKELY(!size.isValid())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
auto row = MakeUniqueFallible<uint8_t[]>(size.value());
|
||||
if (!row) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
CheckedUint32 check = CheckedUint32(mBMPInfoHeader.height) * aStride;
|
||||
if (MOZ_UNLIKELY(!check.isValid())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// write each row: if we add more input formats, we may want to
|
||||
// generalize the conversions
|
||||
if (aInputFormat == INPUT_FORMAT_HOSTARGB) {
|
||||
|
@ -256,7 +283,7 @@ nsBMPEncoder::EndImageEncode()
|
|||
// See InitFromData for a description of the parse options
|
||||
nsresult
|
||||
nsBMPEncoder::ParseOptions(const nsAString& aOptions, Version& aVersionOut,
|
||||
uint32_t& aBppOut)
|
||||
uint16_t& aBppOut)
|
||||
{
|
||||
aVersionOut = VERSION_3;
|
||||
aBppOut = 24;
|
||||
|
@ -424,7 +451,7 @@ nsBMPEncoder::ConvertHostARGBRow(const uint8_t* aSrc,
|
|||
const UniquePtr<uint8_t[]>& aDest,
|
||||
uint32_t aPixelWidth)
|
||||
{
|
||||
int bytes = BytesPerPixel(mBMPInfoHeader.bpp);
|
||||
uint16_t bytes = BytesPerPixel(mBMPInfoHeader.bpp);
|
||||
|
||||
if (mBMPInfoHeader.bpp == 32) {
|
||||
for (uint32_t x = 0; x < aPixelWidth; x++) {
|
||||
|
@ -473,8 +500,8 @@ nsBMPEncoder::NotifyListener()
|
|||
}
|
||||
|
||||
// Initializes the BMP file header mBMPFileHeader to the passed in values
|
||||
void
|
||||
nsBMPEncoder::InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
|
||||
nsresult
|
||||
nsBMPEncoder::InitFileHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth,
|
||||
uint32_t aHeight)
|
||||
{
|
||||
memset(&mBMPFileHeader, 0, sizeof(mBMPFileHeader));
|
||||
|
@ -491,13 +518,25 @@ nsBMPEncoder::InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
|
|||
if (aBPP <= 8) {
|
||||
uint32_t numColors = 1 << aBPP;
|
||||
mBMPFileHeader.dataoffset += 4 * numColors;
|
||||
mBMPFileHeader.filesize = mBMPFileHeader.dataoffset + aWidth * aHeight;
|
||||
CheckedUint32 filesize =
|
||||
CheckedUint32(mBMPFileHeader.dataoffset) + CheckedUint32(aWidth) * aHeight;
|
||||
if (MOZ_UNLIKELY(!filesize.isValid())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mBMPFileHeader.filesize = filesize.value();
|
||||
} else {
|
||||
mBMPFileHeader.filesize = mBMPFileHeader.dataoffset +
|
||||
(aWidth * BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth)) * aHeight;
|
||||
CheckedUint32 filesize =
|
||||
CheckedUint32(mBMPFileHeader.dataoffset) +
|
||||
(CheckedUint32(aWidth) * BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth)) * aHeight;
|
||||
if (MOZ_UNLIKELY(!filesize.isValid())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mBMPFileHeader.filesize = filesize.value();
|
||||
}
|
||||
|
||||
mBMPFileHeader.reserved = 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#define ENCODE(pImageBufferCurr, value) \
|
||||
|
@ -505,8 +544,8 @@ nsBMPEncoder::InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
|
|||
*pImageBufferCurr += sizeof value;
|
||||
|
||||
// Initializes the bitmap info header mBMPInfoHeader to the passed in values
|
||||
void
|
||||
nsBMPEncoder::InitInfoHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
|
||||
nsresult
|
||||
nsBMPEncoder::InitInfoHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth,
|
||||
uint32_t aHeight)
|
||||
{
|
||||
memset(&mBMPInfoHeader, 0, sizeof(mBMPInfoHeader));
|
||||
|
@ -516,18 +555,39 @@ nsBMPEncoder::InitInfoHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
|
|||
MOZ_ASSERT(aVersion == VERSION_5);
|
||||
mBMPInfoHeader.bihsize = InfoHeaderLength::WIN_V5;
|
||||
}
|
||||
mBMPInfoHeader.width = aWidth;
|
||||
mBMPInfoHeader.height = aHeight;
|
||||
|
||||
CheckedInt32 width(aWidth);
|
||||
CheckedInt32 height(aHeight);
|
||||
if (MOZ_UNLIKELY(!width.isValid() || !height.isValid())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mBMPInfoHeader.width = width.value();
|
||||
mBMPInfoHeader.height = height.value();
|
||||
|
||||
mBMPInfoHeader.planes = 1;
|
||||
mBMPInfoHeader.bpp = aBPP;
|
||||
mBMPInfoHeader.compression = 0;
|
||||
mBMPInfoHeader.colors = 0;
|
||||
mBMPInfoHeader.important_colors = 0;
|
||||
|
||||
CheckedUint32 check = CheckedUint32(aWidth) * BytesPerPixel(aBPP);
|
||||
if (MOZ_UNLIKELY(!check.isValid())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (aBPP <= 8) {
|
||||
mBMPInfoHeader.image_size = aWidth * aHeight;
|
||||
CheckedUint32 imagesize = CheckedUint32(aWidth) * aHeight;
|
||||
if (MOZ_UNLIKELY(!imagesize.isValid())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mBMPInfoHeader.image_size = imagesize.value();
|
||||
} else {
|
||||
mBMPInfoHeader.image_size =
|
||||
(aWidth * BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth)) * aHeight;
|
||||
CheckedUint32 imagesize =
|
||||
(CheckedUint32(aWidth) * BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth)) * CheckedUint32(aHeight);
|
||||
if (MOZ_UNLIKELY(!imagesize.isValid())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mBMPInfoHeader.image_size = imagesize.value();
|
||||
}
|
||||
mBMPInfoHeader.xppm = 0;
|
||||
mBMPInfoHeader.yppm = 0;
|
||||
|
@ -554,6 +614,8 @@ nsBMPEncoder::InitInfoHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
|
|||
mBMPInfoHeader.profile_size = 0;
|
||||
mBMPInfoHeader.reserved = 0;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Encodes the BMP file header mBMPFileHeader
|
||||
|
|
|
@ -104,7 +104,7 @@ protected:
|
|||
|
||||
// See InitData in the cpp for valid parse options
|
||||
nsresult ParseOptions(const nsAString& aOptions, Version& aVersionOut,
|
||||
uint32_t& aBppOut);
|
||||
uint16_t& aBppOut);
|
||||
// Obtains data with no alpha in machine-independent byte order
|
||||
void ConvertHostARGBRow(const uint8_t* aSrc,
|
||||
const mozilla::UniquePtr<uint8_t[]>& aDest,
|
||||
|
@ -113,11 +113,11 @@ protected:
|
|||
void NotifyListener();
|
||||
|
||||
// Initializes the bitmap file header member mBMPFileHeader
|
||||
void InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
|
||||
uint32_t aHeight);
|
||||
nsresult InitFileHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth,
|
||||
uint32_t aHeight);
|
||||
// Initializes the bitmap info header member mBMPInfoHeader
|
||||
void InitInfoHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
|
||||
uint32_t aHeight);
|
||||
nsresult InitInfoHeader(Version aVersion, uint16_t aBPP, uint32_t aWidth,
|
||||
uint32_t aHeight);
|
||||
|
||||
// Encodes the bitmap file header member mBMPFileHeader
|
||||
void EncodeFileHeader();
|
||||
|
|
|
@ -228,10 +228,11 @@ nsICOEncoder::StartImageEncode(uint32_t aWidth,
|
|||
}
|
||||
|
||||
// parse and check any provided output options
|
||||
uint32_t bpp = 24;
|
||||
uint16_t bpp = 24;
|
||||
bool usePNG = true;
|
||||
nsresult rv = ParseOptions(aOutputOptions, bpp, usePNG);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_ASSERT(bpp <= 32);
|
||||
|
||||
mUsePNG = usePNG;
|
||||
|
||||
|
@ -265,7 +266,7 @@ nsICOEncoder::EndImageEncode()
|
|||
// Parses the encoder options and sets the bits per pixel to use and PNG or BMP
|
||||
// See InitFromData for a description of the parse options
|
||||
nsresult
|
||||
nsICOEncoder::ParseOptions(const nsAString& aOptions, uint32_t& aBppOut,
|
||||
nsICOEncoder::ParseOptions(const nsAString& aOptions, uint16_t& aBppOut,
|
||||
bool& aUsePNGOut)
|
||||
{
|
||||
// If no parsing options just use the default of 24BPP and PNG yes
|
||||
|
@ -469,7 +470,7 @@ nsICOEncoder::InitFileHeader()
|
|||
|
||||
// Initializes the icon directory info header mICODirEntry
|
||||
void
|
||||
nsICOEncoder::InitInfoHeader(uint32_t aBPP, uint8_t aWidth, uint8_t aHeight)
|
||||
nsICOEncoder::InitInfoHeader(uint16_t aBPP, uint8_t aWidth, uint8_t aHeight)
|
||||
{
|
||||
memset(&mICODirEntry, 0, sizeof(mICODirEntry));
|
||||
mICODirEntry.mBitCount = aBPP;
|
||||
|
|
|
@ -50,14 +50,14 @@ public:
|
|||
protected:
|
||||
~nsICOEncoder();
|
||||
|
||||
nsresult ParseOptions(const nsAString& aOptions, uint32_t& aBppOut,
|
||||
nsresult ParseOptions(const nsAString& aOptions, uint16_t& aBppOut,
|
||||
bool& aUsePNGOut);
|
||||
void NotifyListener();
|
||||
|
||||
// Initializes the icon file header mICOFileHeader
|
||||
void InitFileHeader();
|
||||
// Initializes the icon directory info header mICODirEntry
|
||||
void InitInfoHeader(uint32_t aBPP, uint8_t aWidth, uint8_t aHeight);
|
||||
void InitInfoHeader(uint16_t aBPP, uint8_t aWidth, uint8_t aHeight);
|
||||
// Encodes the icon file header mICOFileHeader
|
||||
void EncodeFileHeader();
|
||||
// Encodes the icon directory info header mICODirEntry
|
||||
|
|
|
@ -902,6 +902,8 @@ LIRGeneratorARM::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins)
|
|||
MOZ_ASSERT(base->type() == MIRType::Int32);
|
||||
|
||||
if (byteSize(ins->access().type()) != 4 && !HasLDSTREXBHD()) {
|
||||
gen->setPerformsCall();
|
||||
|
||||
LAsmJSCompareExchangeCallout* lir =
|
||||
new(alloc()) LAsmJSCompareExchangeCallout(useFixedAtStart(base, IntArgReg2),
|
||||
useFixedAtStart(ins->oldValue(), IntArgReg3),
|
||||
|
@ -929,6 +931,8 @@ LIRGeneratorARM::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins)
|
|||
MOZ_ASSERT(ins->access().offset() == 0);
|
||||
|
||||
if (byteSize(ins->access().type()) < 4 && !HasLDSTREXBHD()) {
|
||||
gen->setPerformsCall();
|
||||
|
||||
// Call out on ARMv6.
|
||||
defineReturn(new(alloc()) LAsmJSAtomicExchangeCallout(useFixedAtStart(ins->base(), IntArgReg2),
|
||||
useFixedAtStart(ins->value(), IntArgReg3),
|
||||
|
@ -953,6 +957,8 @@ LIRGeneratorARM::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins)
|
|||
MOZ_ASSERT(base->type() == MIRType::Int32);
|
||||
|
||||
if (byteSize(ins->access().type()) != 4 && !HasLDSTREXBHD()) {
|
||||
gen->setPerformsCall();
|
||||
|
||||
LAsmJSAtomicBinopCallout* lir =
|
||||
new(alloc()) LAsmJSAtomicBinopCallout(useFixedAtStart(base, IntArgReg2),
|
||||
useFixedAtStart(ins->value(), IntArgReg3),
|
||||
|
|
|
@ -238,6 +238,19 @@ AssertedCast(const From aFrom)
|
|||
return static_cast<To>(aFrom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a value of integral type |From| to a value of integral type |To|,
|
||||
* release asserting that the cast will be a safe cast per C++ (that is, that
|
||||
* |to| is in the range of values permitted for the type |From|).
|
||||
*/
|
||||
template<typename To, typename From>
|
||||
inline To
|
||||
ReleaseAssertedCast(const From aFrom)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT((detail::IsInBounds<From, To>(aFrom)));
|
||||
return static_cast<To>(aFrom);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_Casting_h */
|
||||
|
|
32
mfbt/Range.h
32
mfbt/Range.h
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "mozilla/RangedPtr.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/Span.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -44,6 +45,19 @@ public:
|
|||
mEnd(aOther.mEnd)
|
||||
{}
|
||||
|
||||
MOZ_IMPLICIT Range(Span<T> aSpan)
|
||||
: Range(aSpan.Elements(), aSpan.Length())
|
||||
{
|
||||
}
|
||||
|
||||
template<typename U,
|
||||
class = typename EnableIf<IsConvertible<U (*)[], T (*)[]>::value,
|
||||
int>::Type>
|
||||
MOZ_IMPLICIT Range(const Span<U>& aSpan)
|
||||
: Range(aSpan.Elements(), aSpan.Length())
|
||||
{
|
||||
}
|
||||
|
||||
RangedPtr<T> begin() const { return mStart; }
|
||||
RangedPtr<T> end() const { return mEnd; }
|
||||
size_t length() const { return mEnd - mStart; }
|
||||
|
@ -51,8 +65,26 @@ public:
|
|||
T& operator[](size_t aOffset) const { return mStart[aOffset]; }
|
||||
|
||||
explicit operator bool() const { return mStart != nullptr; }
|
||||
|
||||
operator Span<T>() { return Span<T>(mStart.get(), length()); }
|
||||
|
||||
operator Span<const T>() const { return Span<T>(mStart.get(), length()); }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
Span<T>
|
||||
MakeSpan(Range<T>& aRange)
|
||||
{
|
||||
return aRange;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Span<const T>
|
||||
MakeSpan(const Range<T>& aRange)
|
||||
{
|
||||
return aRange;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_Range_h */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -82,6 +82,7 @@ EXPORTS.mozilla = [
|
|||
'SegmentedVector.h',
|
||||
'SHA1.h',
|
||||
'SizePrintfMacros.h',
|
||||
'Span.h',
|
||||
'SplayTree.h',
|
||||
'Sprintf.h',
|
||||
'StaticAnalysisFunctions.h',
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,15 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'TestSpan.cpp',
|
||||
]
|
||||
|
||||
#LOCAL_INCLUDES += [
|
||||
# '../../base',
|
||||
#]
|
||||
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
|
@ -4,6 +4,11 @@
|
|||
# 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/.
|
||||
|
||||
if not CONFIG['JS_STANDALONE']:
|
||||
TEST_DIRS += [
|
||||
'gtest',
|
||||
]
|
||||
|
||||
CppUnitTests([
|
||||
'TestArray',
|
||||
'TestArrayUtils',
|
||||
|
|
|
@ -55,7 +55,7 @@ public final class EventDispatcher extends JNIObject {
|
|||
new HashMap<String, List<BundleEventListener>>(DEFAULT_BACKGROUND_EVENTS_COUNT);
|
||||
|
||||
private boolean mAttachedToGecko;
|
||||
private final StateHolder mStateHolder;
|
||||
private volatile StateHolder mStateHolder;
|
||||
|
||||
@ReflectionTarget
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
|
@ -71,6 +71,13 @@ public final class EventDispatcher extends JNIObject {
|
|||
mStateHolder = stateHolder;
|
||||
}
|
||||
|
||||
/* package */ void setStateHolder(final NativeQueue.StateHolder stateHolder) {
|
||||
mStateHolder = stateHolder;
|
||||
// Force queue flushing.
|
||||
final NativeQueue.State state = mStateHolder.getState();
|
||||
mStateHolder.checkAndSetState(state, state);
|
||||
}
|
||||
|
||||
private boolean isReadyForDispatchingToGecko() {
|
||||
return mStateHolder.isReady();
|
||||
}
|
||||
|
|
|
@ -47,10 +47,10 @@ public class GeckoView extends LayerView
|
|||
@WrapForJNI INITIAL(0),
|
||||
@WrapForJNI READY(1);
|
||||
|
||||
private int rank;
|
||||
private int mRank;
|
||||
|
||||
private State(int rank) {
|
||||
this.rank = rank;
|
||||
mRank = rank;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,22 +61,17 @@ public class GeckoView extends LayerView
|
|||
@Override
|
||||
public boolean isAtLeast(final NativeQueue.State other) {
|
||||
if (other instanceof State) {
|
||||
return this.rank >= ((State) other).rank;
|
||||
return mRank >= ((State) other).mRank;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private final StateHolder mStateHolder =
|
||||
private static final StateHolder sDummyStateHolder =
|
||||
new StateHolder(State.INITIAL, State.READY);
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private void setState(final State newState) {
|
||||
mStateHolder.setState(newState);
|
||||
}
|
||||
|
||||
private final EventDispatcher mEventDispatcher =
|
||||
new EventDispatcher(mStateHolder);
|
||||
new EventDispatcher(sDummyStateHolder);
|
||||
|
||||
private ChromeDelegate mChromeDelegate;
|
||||
/* package */ ContentListener mContentListener;
|
||||
|
@ -92,6 +87,10 @@ public class GeckoView extends LayerView
|
|||
|
||||
@WrapForJNI(dispatchTo = "proxy")
|
||||
protected static final class Window extends JNIObject {
|
||||
@WrapForJNI(skip = true)
|
||||
/* package */ final StateHolder mStateHolder =
|
||||
new StateHolder(State.INITIAL, State.READY);
|
||||
|
||||
@WrapForJNI(skip = true)
|
||||
/* package */ Window() {}
|
||||
|
||||
|
@ -101,9 +100,18 @@ public class GeckoView extends LayerView
|
|||
int screenId);
|
||||
|
||||
@Override protected native void disposeNative();
|
||||
|
||||
native void close();
|
||||
native void reattach(GeckoView view, Object compositor, EventDispatcher dispatcher);
|
||||
|
||||
native void reattach(GeckoView view, Object compositor,
|
||||
EventDispatcher dispatcher);
|
||||
|
||||
native void loadUri(String uri, int flags);
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private void setState(final State newState) {
|
||||
mStateHolder.setState(newState);
|
||||
}
|
||||
}
|
||||
|
||||
// Object to hold onto our nsWindow connection when GeckoView gets destroyed.
|
||||
|
@ -197,9 +205,9 @@ public class GeckoView extends LayerView
|
|||
}
|
||||
}
|
||||
|
||||
protected Window window;
|
||||
private boolean stateSaved;
|
||||
private final Listener listener = new Listener();
|
||||
protected Window mWindow;
|
||||
private boolean mStateSaved;
|
||||
private final Listener mListener = new Listener();
|
||||
|
||||
public GeckoView(Context context) {
|
||||
super(context);
|
||||
|
@ -227,7 +235,7 @@ public class GeckoView extends LayerView
|
|||
GeckoAppShell.setLayerView(this);
|
||||
|
||||
initializeView();
|
||||
listener.registerListeners();
|
||||
mListener.registerListeners();
|
||||
|
||||
mSettings = new GeckoViewSettings(getEventDispatcher());
|
||||
}
|
||||
|
@ -235,8 +243,8 @@ public class GeckoView extends LayerView
|
|||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
final Parcelable superState = super.onSaveInstanceState();
|
||||
stateSaved = true;
|
||||
return new StateBinder(superState, this.window);
|
||||
mStateSaved = true;
|
||||
return new StateBinder(superState, mWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -244,9 +252,9 @@ public class GeckoView extends LayerView
|
|||
final StateBinder stateBinder = (StateBinder) state;
|
||||
|
||||
if (stateBinder.window != null) {
|
||||
this.window = stateBinder.window;
|
||||
mWindow = stateBinder.window;
|
||||
}
|
||||
stateSaved = false;
|
||||
mStateSaved = false;
|
||||
|
||||
if (mOnAttachedToWindowCalled) {
|
||||
reattachWindow();
|
||||
|
@ -263,12 +271,12 @@ public class GeckoView extends LayerView
|
|||
}
|
||||
|
||||
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
|
||||
Window.open(window, this, getCompositor(), mEventDispatcher,
|
||||
Window.open(mWindow, this, getCompositor(), mEventDispatcher,
|
||||
mChromeUri, mSettings.asBundle(), mScreenId);
|
||||
} else {
|
||||
GeckoThread.queueNativeCallUntil(
|
||||
GeckoThread.State.PROFILE_READY,
|
||||
Window.class, "open", window,
|
||||
Window.class, "open", mWindow,
|
||||
GeckoView.class, this,
|
||||
Object.class, getCompositor(),
|
||||
EventDispatcher.class, mEventDispatcher,
|
||||
|
@ -279,11 +287,13 @@ public class GeckoView extends LayerView
|
|||
}
|
||||
|
||||
protected void reattachWindow() {
|
||||
mEventDispatcher.setStateHolder(mWindow.mStateHolder);
|
||||
|
||||
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
|
||||
window.reattach(this, getCompositor(), mEventDispatcher);
|
||||
mWindow.reattach(this, getCompositor(), mEventDispatcher);
|
||||
} else {
|
||||
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
|
||||
window, "reattach", GeckoView.class, this,
|
||||
mWindow, "reattach", GeckoView.class, this,
|
||||
Object.class, getCompositor(), EventDispatcher.class, mEventDispatcher);
|
||||
}
|
||||
}
|
||||
|
@ -292,9 +302,10 @@ public class GeckoView extends LayerView
|
|||
public void onAttachedToWindow() {
|
||||
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
||||
|
||||
if (window == null) {
|
||||
if (mWindow == null) {
|
||||
// Open a new nsWindow if we didn't have one from before.
|
||||
window = new Window();
|
||||
mWindow = new Window();
|
||||
mEventDispatcher.setStateHolder(mWindow.mStateHolder);
|
||||
openWindow();
|
||||
} else {
|
||||
reattachWindow();
|
||||
|
@ -310,21 +321,22 @@ public class GeckoView extends LayerView
|
|||
super.onDetachedFromWindow();
|
||||
super.destroy();
|
||||
|
||||
if (stateSaved) {
|
||||
if (mStateSaved) {
|
||||
// If we saved state earlier, we don't want to close the nsWindow.
|
||||
return;
|
||||
}
|
||||
|
||||
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
|
||||
window.close();
|
||||
window.disposeNative();
|
||||
mWindow.close();
|
||||
mWindow.disposeNative();
|
||||
} else {
|
||||
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
|
||||
window, "close");
|
||||
mWindow, "close");
|
||||
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
|
||||
window, "disposeNative");
|
||||
mWindow, "disposeNative");
|
||||
}
|
||||
|
||||
mEventDispatcher.setStateHolder(sDummyStateHolder);
|
||||
mOnAttachedToWindowCalled = false;
|
||||
}
|
||||
|
||||
|
@ -339,14 +351,14 @@ public class GeckoView extends LayerView
|
|||
* @param flags The load flags (TODO).
|
||||
*/
|
||||
public void loadUri(String uri, int flags) {
|
||||
if (window == null) {
|
||||
if (mWindow == null) {
|
||||
throw new IllegalStateException("Not attached to window");
|
||||
}
|
||||
|
||||
if (GeckoThread.isRunning()) {
|
||||
window.loadUri(uri, flags);
|
||||
mWindow.loadUri(uri, flags);
|
||||
} else {
|
||||
GeckoThread.queueNativeCall(window, "loadUri", String.class, uri, flags);
|
||||
GeckoThread.queueNativeCall(mWindow, "loadUri", String.class, uri, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ EXPORTS += [
|
|||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AppCacheStorage.cpp',
|
||||
'CacheEntry.cpp',
|
||||
'CacheFile.cpp',
|
||||
'CacheFileChunk.cpp',
|
||||
|
@ -46,11 +47,6 @@ UNIFIED_SOURCES += [
|
|||
'OldWrappers.cpp',
|
||||
]
|
||||
|
||||
# AppCacheStorage.cpp cannot be built in unified mode because it uses plarena.h.
|
||||
SOURCES += [
|
||||
'AppCacheStorage.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/netwerk/base',
|
||||
'/netwerk/cache',
|
||||
|
|
|
@ -63,9 +63,6 @@ using namespace mozilla::ipc;
|
|||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
extern bool
|
||||
WillRedirect(nsHttpResponseHead * response);
|
||||
|
||||
namespace {
|
||||
|
||||
const uint32_t kMaxFileDescriptorsPerMessage = 250;
|
||||
|
@ -3179,14 +3176,14 @@ HttpChannelChild::OverrideWithSynthesizedResponse(nsAutoPtr<nsHttpResponseHead>&
|
|||
|
||||
// Intercepted responses should already be decoded. If its a redirect,
|
||||
// however, we want to respect the encoding of the final result instead.
|
||||
if (!WillRedirect(aResponseHead)) {
|
||||
if (!nsHttpChannel::WillRedirect(aResponseHead)) {
|
||||
SetApplyConversion(false);
|
||||
}
|
||||
|
||||
mResponseHead = aResponseHead;
|
||||
mSynthesizedResponse = true;
|
||||
|
||||
if (WillRedirect(mResponseHead)) {
|
||||
if (nsHttpChannel::WillRedirect(mResponseHead)) {
|
||||
mShouldInterceptSubsequentRedirect = true;
|
||||
// Continue with the original cross-process request
|
||||
nsresult rv = ContinueAsyncOpen();
|
||||
|
|
|
@ -21,9 +21,6 @@
|
|||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
extern bool
|
||||
WillRedirect(const nsHttpResponseHead * response);
|
||||
|
||||
extern nsresult
|
||||
DoUpdateExpirationTime(nsHttpChannel* aSelf,
|
||||
nsICacheEntry* aCacheEntry,
|
||||
|
@ -246,7 +243,7 @@ InterceptedChannelChrome::FinishSynthesizedResponse(const nsACString& aFinalURLS
|
|||
|
||||
// If the synthesized response is a redirect, then we want to respect
|
||||
// the encoding of whatever is loaded as a result.
|
||||
if (WillRedirect(mSynthesizedResponseHead.ref())) {
|
||||
if (nsHttpChannel::WillRedirect(mSynthesizedResponseHead.ref())) {
|
||||
nsresult rv = mChannel->SetApplyConversion(mOldApplyConversion);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
|
|
@ -49,18 +49,15 @@ EXPORTS.mozilla.net += [
|
|||
'TimingStruct.h',
|
||||
]
|
||||
|
||||
# ASpdySession.cpp and nsHttpAuthCache cannot be built in unified mode because
|
||||
# they use plarena.h.
|
||||
SOURCES += [
|
||||
'AlternateServices.cpp',
|
||||
'ASpdySession.cpp',
|
||||
'nsHttpAuthCache.cpp',
|
||||
'nsHttpChannelAuthProvider.cpp', # redefines GetAuthType
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AltDataOutputStreamChild.cpp',
|
||||
'AltDataOutputStreamParent.cpp',
|
||||
'AlternateServices.cpp',
|
||||
'ASpdySession.cpp',
|
||||
'CacheControlParser.cpp',
|
||||
'ConnectionDiagnostics.cpp',
|
||||
'HSTSPrimerListener.cpp',
|
||||
|
@ -78,6 +75,7 @@ UNIFIED_SOURCES += [
|
|||
'nsCORSListenerProxy.cpp',
|
||||
'nsHttp.cpp',
|
||||
'nsHttpActivityDistributor.cpp',
|
||||
'nsHttpAuthCache.cpp',
|
||||
'nsHttpAuthManager.cpp',
|
||||
'nsHttpBasicAuth.cpp',
|
||||
'nsHttpChannel.cpp',
|
||||
|
|
|
@ -192,9 +192,9 @@ Hash(const char *buf, nsACString &hash)
|
|||
// We only treat 3xx responses as redirects if they have a Location header and
|
||||
// the status code is in a whitelist.
|
||||
bool
|
||||
WillRedirect(nsHttpResponseHead * response)
|
||||
nsHttpChannel::WillRedirect(nsHttpResponseHead * response)
|
||||
{
|
||||
return nsHttpChannel::IsRedirectStatus(response->Status()) &&
|
||||
return IsRedirectStatus(response->Status()) &&
|
||||
response->HasHeader(nsHttp::Location);
|
||||
}
|
||||
|
||||
|
|
|
@ -138,6 +138,7 @@ public:
|
|||
Http2PushedStream *pushedStream);
|
||||
|
||||
static bool IsRedirectStatus(uint32_t status);
|
||||
static bool WillRedirect(nsHttpResponseHead * response);
|
||||
|
||||
|
||||
// Methods HttpBaseChannel didn't implement for us or that we override.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "HttpLog.h"
|
||||
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpDigestAuth.h"
|
||||
|
|
|
@ -699,6 +699,10 @@ nsIndexedToHTML::OnIndexAvailable(nsIRequest *aRequest,
|
|||
|
||||
// Adjust the length in case unescaping shortened the string.
|
||||
loc.Truncate(nsUnescapeCount(loc.BeginWriting()));
|
||||
|
||||
if (loc.IsEmpty()) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
if (loc.First() == char16_t('.'))
|
||||
pushBuffer.AppendLiteral(" class=\"hidden-object\"");
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
<li><a href="about:license#gears">Google Gears License</a></li>
|
||||
<li><a href="about:license#gears-istumbler">Google Gears/iStumbler License</a></li>
|
||||
<li><a href="about:license#vp8">Google VP8 License</a></li>
|
||||
<li><a href="about:license#gsl">GSL License</a></li>
|
||||
<li><a href="about:license#gyp">gyp License</a></li>
|
||||
<li><a href="about:license#halloc">halloc License</a></li>
|
||||
<li><a href="about:license#harfbuzz">HarfBuzz License</a></li>
|
||||
|
@ -3415,6 +3416,38 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a id="gsl"></a>GSL License</h1>
|
||||
|
||||
<p>This license applies to <span class="path">mfbt/Span.h</span> and
|
||||
<span class="path">mfbt/tests/gtest/TestSpan.cpp</span>.</p>
|
||||
<!-- https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/LICENSE -->
|
||||
<pre>
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
|
||||
This code is licensed under the MIT License (MIT).
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a id="gyp"></a>gyp License</h1>
|
||||
|
|
|
@ -116,6 +116,13 @@ using google_breakpad::PageAllocator;
|
|||
using namespace mozilla;
|
||||
using mozilla::ipc::CrashReporterClient;
|
||||
|
||||
// From toolkit/library/rust/shared/lib.rs
|
||||
extern "C" {
|
||||
void install_rust_panic_hook();
|
||||
bool get_rust_panic_reason(char** reason, size_t* length);
|
||||
}
|
||||
|
||||
|
||||
namespace CrashReporter {
|
||||
|
||||
#ifdef XP_WIN32
|
||||
|
@ -1131,7 +1138,17 @@ bool MinidumpCallback(
|
|||
WriteGlobalMemoryStatus(&apiData, &eventFile);
|
||||
#endif // XP_WIN
|
||||
|
||||
if (gMozCrashReason) {
|
||||
char* rust_panic_reason;
|
||||
size_t rust_panic_len;
|
||||
if (get_rust_panic_reason(&rust_panic_reason, &rust_panic_len)) {
|
||||
// rust_panic_reason is not null-terminated.
|
||||
WriteLiteral(apiData, "MozCrashReason=");
|
||||
apiData.WriteBuffer(rust_panic_reason, rust_panic_len);
|
||||
WriteLiteral(apiData, "\n");
|
||||
WriteLiteral(eventFile, "MozCrashReason=");
|
||||
eventFile.WriteBuffer(rust_panic_reason, rust_panic_len);
|
||||
WriteLiteral(eventFile, "\n");
|
||||
} else if (gMozCrashReason) {
|
||||
WriteAnnotation(apiData, "MozCrashReason", gMozCrashReason);
|
||||
WriteAnnotation(eventFile, "MozCrashReason", gMozCrashReason);
|
||||
}
|
||||
|
@ -1577,6 +1594,8 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory,
|
|||
if (gExceptionHandler)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
install_rust_panic_hook();
|
||||
|
||||
#if !defined(DEBUG) || defined(MOZ_WIDGET_GONK)
|
||||
// In non-debug builds, enable the crash reporter by default, and allow
|
||||
// disabling it with the MOZ_CRASHREPORTER_DISABLE environment variable.
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
function run_test() {
|
||||
// Try crashing with a Rust panic
|
||||
do_crash(function() {
|
||||
Components.classes["@mozilla.org/xpcom/debug;1"].getService(Components.interfaces.nsIDebug2).rustPanic("OH NO");
|
||||
},
|
||||
function(mdump, extra) {
|
||||
do_check_eq(extra.MozCrashReason, "OH NO");
|
||||
},
|
||||
// process will exit with a zero exit status
|
||||
true);
|
||||
}
|
|
@ -7,6 +7,9 @@ support-files =
|
|||
|
||||
[test_crash_moz_crash.js]
|
||||
[test_crash_purevirtual.js]
|
||||
[test_crash_rust_panic.js]
|
||||
# Fails on Win64, bug 1302078.
|
||||
fail-if = os == 'win' && bits == 64
|
||||
[test_crash_after_js_oom_reported.js]
|
||||
[test_crash_after_js_oom_recovered.js]
|
||||
[test_crash_after_js_oom_reported_2.js]
|
||||
|
|
|
@ -10,3 +10,59 @@ extern crate nsstring;
|
|||
extern crate rust_url_capi;
|
||||
#[cfg(feature = "quantum_render")]
|
||||
extern crate webrender_bindings;
|
||||
|
||||
use std::boxed::Box;
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
use std::panic;
|
||||
|
||||
/// Used to implement `nsIDebug2::RustPanic` for testing purposes.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn intentional_panic(message: *const c_char) {
|
||||
panic!("{}", unsafe { CStr::from_ptr(message) }.to_string_lossy());
|
||||
}
|
||||
|
||||
/// Contains the panic message, if set.
|
||||
static mut PANIC_REASON: Option<(*const str, usize)> = None;
|
||||
|
||||
/// Configure a panic hook to capture panic messages for crash reports.
|
||||
///
|
||||
/// We don't store this in `gMozCrashReason` because:
|
||||
/// a) Rust strings aren't null-terminated, so we'd have to allocate
|
||||
/// memory to get a null-terminated string
|
||||
/// b) The panic=abort handler is going to call `abort()` on non-Windows,
|
||||
/// which is `mozalloc_abort` for us, which will use `MOZ_CRASH` and
|
||||
/// overwrite `gMozCrashReason` with an unhelpful string.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn install_rust_panic_hook() {
|
||||
panic::set_hook(Box::new(|info| {
|
||||
// Try to handle &str/String payloads, which should handle 99% of cases.
|
||||
let payload = info.payload();
|
||||
// We'll hold a raw *const str here, but it will be OK because
|
||||
// Rust is going to abort the process before the payload could be
|
||||
// deallocated.
|
||||
if let Some(s) = payload.downcast_ref::<&str>() {
|
||||
unsafe { PANIC_REASON = Some((*s as *const str, s.len())) }
|
||||
} else if let Some(s) = payload.downcast_ref::<String>() {
|
||||
unsafe { PANIC_REASON = Some((s.as_str() as *const str, s.len())) }
|
||||
} else {
|
||||
// Not the most helpful thing, but seems unlikely to happen
|
||||
// in practice.
|
||||
println!("Unhandled panic payload!");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_rust_panic_reason(reason: *mut *const c_char, length: *mut usize) -> bool {
|
||||
unsafe {
|
||||
match PANIC_REASON {
|
||||
Some((s, len)) => {
|
||||
*reason = s as *const c_char;
|
||||
*length = len;
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -967,14 +967,6 @@ auto GeckoThread::State::RUNNING() -> State::LocalRef
|
|||
const char GeckoView::name[] =
|
||||
"org/mozilla/gecko/GeckoView";
|
||||
|
||||
constexpr char GeckoView::SetState_t::name[];
|
||||
constexpr char GeckoView::SetState_t::signature[];
|
||||
|
||||
auto GeckoView::SetState(mozilla::jni::Object::Param a0) const -> void
|
||||
{
|
||||
return mozilla::jni::Method<SetState_t>::Call(GeckoView::mCtx, nullptr, a0);
|
||||
}
|
||||
|
||||
const char GeckoView::State::name[] =
|
||||
"org/mozilla/gecko/GeckoView$State";
|
||||
|
||||
|
@ -1012,6 +1004,14 @@ constexpr char GeckoView::Window::Open_t::signature[];
|
|||
constexpr char GeckoView::Window::Reattach_t::name[];
|
||||
constexpr char GeckoView::Window::Reattach_t::signature[];
|
||||
|
||||
constexpr char GeckoView::Window::SetState_t::name[];
|
||||
constexpr char GeckoView::Window::SetState_t::signature[];
|
||||
|
||||
auto GeckoView::Window::SetState(mozilla::jni::Object::Param a0) const -> void
|
||||
{
|
||||
return mozilla::jni::Method<SetState_t>::Call(Window::mCtx, nullptr, a0);
|
||||
}
|
||||
|
||||
const char PrefsHelper::name[] =
|
||||
"org/mozilla/gecko/PrefsHelper";
|
||||
|
||||
|
|
|
@ -2883,26 +2883,6 @@ public:
|
|||
class State;
|
||||
class Window;
|
||||
|
||||
struct SetState_t {
|
||||
typedef GeckoView Owner;
|
||||
typedef void ReturnType;
|
||||
typedef void SetterType;
|
||||
typedef mozilla::jni::Args<
|
||||
mozilla::jni::Object::Param> Args;
|
||||
static constexpr char name[] = "setState";
|
||||
static constexpr char signature[] =
|
||||
"(Lorg/mozilla/gecko/GeckoView$State;)V";
|
||||
static const bool isStatic = false;
|
||||
static const mozilla::jni::ExceptionMode exceptionMode =
|
||||
mozilla::jni::ExceptionMode::ABORT;
|
||||
static const mozilla::jni::CallingThread callingThread =
|
||||
mozilla::jni::CallingThread::GECKO;
|
||||
static const mozilla::jni::DispatchTarget dispatchTarget =
|
||||
mozilla::jni::DispatchTarget::CURRENT;
|
||||
};
|
||||
|
||||
auto SetState(mozilla::jni::Object::Param) const -> void;
|
||||
|
||||
static const int32_t LOAD_DEFAULT = 0;
|
||||
|
||||
static const int32_t LOAD_NEW_TAB = 1;
|
||||
|
@ -2910,7 +2890,7 @@ public:
|
|||
static const int32_t LOAD_SWITCH_TAB = 2;
|
||||
|
||||
static const mozilla::jni::CallingThread callingThread =
|
||||
mozilla::jni::CallingThread::GECKO;
|
||||
mozilla::jni::CallingThread::ANY;
|
||||
|
||||
};
|
||||
|
||||
|
@ -3068,6 +3048,26 @@ public:
|
|||
mozilla::jni::DispatchTarget::PROXY;
|
||||
};
|
||||
|
||||
struct SetState_t {
|
||||
typedef Window Owner;
|
||||
typedef void ReturnType;
|
||||
typedef void SetterType;
|
||||
typedef mozilla::jni::Args<
|
||||
mozilla::jni::Object::Param> Args;
|
||||
static constexpr char name[] = "setState";
|
||||
static constexpr char signature[] =
|
||||
"(Lorg/mozilla/gecko/GeckoView$State;)V";
|
||||
static const bool isStatic = false;
|
||||
static const mozilla::jni::ExceptionMode exceptionMode =
|
||||
mozilla::jni::ExceptionMode::ABORT;
|
||||
static const mozilla::jni::CallingThread callingThread =
|
||||
mozilla::jni::CallingThread::GECKO;
|
||||
static const mozilla::jni::DispatchTarget dispatchTarget =
|
||||
mozilla::jni::DispatchTarget::CURRENT;
|
||||
};
|
||||
|
||||
auto SetState(mozilla::jni::Object::Param) const -> void;
|
||||
|
||||
static const mozilla::jni::CallingThread callingThread =
|
||||
mozilla::jni::CallingThread::ANY;
|
||||
|
||||
|
|
|
@ -242,7 +242,7 @@ class nsWindow::GeckoViewSupport final
|
|||
, public SupportsWeakPtr<GeckoViewSupport>
|
||||
{
|
||||
nsWindow& window;
|
||||
GeckoView::GlobalRef mView;
|
||||
GeckoView::Window::GlobalRef mGeckoViewWindow;
|
||||
|
||||
public:
|
||||
typedef GeckoView::Window::Natives<GeckoViewSupport> Base;
|
||||
|
@ -265,10 +265,9 @@ public:
|
|||
}
|
||||
|
||||
GeckoViewSupport(nsWindow* aWindow,
|
||||
const GeckoView::Window::LocalRef& aInstance,
|
||||
GeckoView::Param aView)
|
||||
const GeckoView::Window::LocalRef& aInstance)
|
||||
: window(*aWindow)
|
||||
, mView(aView)
|
||||
, mGeckoViewWindow(aInstance)
|
||||
{
|
||||
Base::AttachNative(aInstance, static_cast<SupportsWeakPtr*>(this));
|
||||
}
|
||||
|
@ -1252,7 +1251,7 @@ nsWindow::GeckoViewSupport::Open(const jni::Class::LocalRef& aCls,
|
|||
|
||||
// Attach a new GeckoView support object to the new window.
|
||||
window->mGeckoViewSupport = mozilla::MakeUnique<GeckoViewSupport>(
|
||||
window, GeckoView::Window::LocalRef(aCls.Env(), aWindow), aView);
|
||||
window, (GeckoView::Window::LocalRef(aCls.Env(), aWindow)));
|
||||
|
||||
window->mGeckoViewSupport->mDOMWindow = pdomWindow;
|
||||
|
||||
|
@ -1297,6 +1296,7 @@ nsWindow::GeckoViewSupport::Close()
|
|||
|
||||
mDOMWindow->ForceClose();
|
||||
mDOMWindow = nullptr;
|
||||
mGeckoViewWindow = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2078,8 +2078,10 @@ nsWindow::GetEventTimeStamp(int64_t aEventTime)
|
|||
void
|
||||
nsWindow::GeckoViewSupport::EnableEventDispatcher()
|
||||
{
|
||||
MOZ_ASSERT(mView);
|
||||
mView->SetState(GeckoView::State::READY());
|
||||
if (!mGeckoViewWindow) {
|
||||
return;
|
||||
}
|
||||
mGeckoViewWindow->SetState(GeckoView::State::READY());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -148,6 +148,16 @@ nsDebugImpl::Abort(const char* aFile, int32_t aLine)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// From toolkit/library/rust/lib.rs
|
||||
extern "C" void intentional_panic(const char* message);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDebugImpl::RustPanic(const char* aMessage)
|
||||
{
|
||||
intentional_panic(aMessage);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDebugImpl::GetIsDebugBuild(bool* aResult)
|
||||
{
|
||||
|
|
|
@ -79,4 +79,11 @@ interface nsIDebug2 : nsISupports
|
|||
*/
|
||||
void abort(in string aFile,
|
||||
in long aLine);
|
||||
|
||||
/**
|
||||
* Request the process to trigger a fatal panic!() from Rust code.
|
||||
*
|
||||
* @param aMessage the string to pass to panic!().
|
||||
*/
|
||||
void rustPanic(in string aMessage);
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "mozilla/Move.h"
|
||||
#include "mozilla/ReverseIterator.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/Span.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
@ -1116,6 +1117,18 @@ public:
|
|||
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
||||
const_reverse_iterator crend() const { return rend(); }
|
||||
|
||||
// Span integration
|
||||
|
||||
operator mozilla::Span<elem_type>()
|
||||
{
|
||||
return mozilla::Span<elem_type>(Elements(), Length());
|
||||
}
|
||||
|
||||
operator mozilla::Span<const elem_type>() const
|
||||
{
|
||||
return mozilla::Span<const elem_type>(Elements(), Length());
|
||||
}
|
||||
|
||||
//
|
||||
// Search methods
|
||||
//
|
||||
|
@ -1340,6 +1353,16 @@ protected:
|
|||
return ReplaceElementsAt<Item, ActualAlloc>(
|
||||
aStart, aCount, aArray.Elements(), aArray.Length());
|
||||
}
|
||||
|
||||
template<class Item, typename ActualAlloc = Alloc>
|
||||
elem_type* ReplaceElementsAt(index_type aStart,
|
||||
size_type aCount,
|
||||
mozilla::Span<const Item> aSpan)
|
||||
{
|
||||
return ReplaceElementsAt<Item, ActualAlloc>(
|
||||
aStart, aCount, aSpan.Elements(), aSpan.Length());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<class Item>
|
||||
|
@ -1351,6 +1374,15 @@ public:
|
|||
return ReplaceElementsAt<Item, FallibleAlloc>(aStart, aCount, aArray);
|
||||
}
|
||||
|
||||
template<class Item>
|
||||
MOZ_MUST_USE elem_type* ReplaceElementsAt(index_type aStart,
|
||||
size_type aCount,
|
||||
mozilla::Span<const Item> aSpan,
|
||||
const mozilla::fallible_t&)
|
||||
{
|
||||
return ReplaceElementsAt<Item, FallibleAlloc>(aStart, aCount, aSpan);
|
||||
}
|
||||
|
||||
// A variation on the ReplaceElementsAt method defined above.
|
||||
protected:
|
||||
template<class Item, typename ActualAlloc = Alloc>
|
||||
|
@ -1403,6 +1435,15 @@ protected:
|
|||
return ReplaceElementsAt<Item, ActualAlloc>(
|
||||
aIndex, 0, aArray.Elements(), aArray.Length());
|
||||
}
|
||||
|
||||
template<class Item, typename ActualAlloc = Alloc>
|
||||
elem_type* InsertElementsAt(index_type aIndex,
|
||||
mozilla::Span<const Item> aSpan)
|
||||
{
|
||||
return ReplaceElementsAt<Item, ActualAlloc>(
|
||||
aIndex, 0, aSpan.Elements(), aSpan.Length());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<class Item, class Allocator>
|
||||
|
@ -1414,6 +1455,14 @@ public:
|
|||
return InsertElementsAt<Item, Allocator, FallibleAlloc>(aIndex, aArray);
|
||||
}
|
||||
|
||||
template<class Item>
|
||||
MOZ_MUST_USE elem_type* InsertElementsAt(index_type aIndex,
|
||||
mozilla::Span<const Item> aSpan,
|
||||
const mozilla::fallible_t&)
|
||||
{
|
||||
return InsertElementsAt<Item, FallibleAlloc>(aIndex, aSpan);
|
||||
}
|
||||
|
||||
// Insert a new element without copy-constructing. This is useful to avoid
|
||||
// temporaries.
|
||||
// @return A pointer to the newly inserted element, or null on OOM.
|
||||
|
@ -1548,6 +1597,13 @@ protected:
|
|||
template<class Item, typename ActualAlloc = Alloc>
|
||||
elem_type* AppendElements(const Item* aArray, size_type aArrayLen);
|
||||
|
||||
template<class Item, typename ActualAlloc = Alloc>
|
||||
elem_type* AppendElements(mozilla::Span<const Item> aSpan)
|
||||
{
|
||||
return AppendElements<Item, FallibleAlloc>(aSpan.Elements(),
|
||||
aSpan.Length());
|
||||
}
|
||||
|
||||
template<class Item, size_t Length, typename ActualAlloc = Alloc>
|
||||
elem_type* AppendElements(const mozilla::Array<Item, Length>& aArray)
|
||||
{
|
||||
|
@ -1564,6 +1620,15 @@ public:
|
|||
return AppendElements<Item, FallibleAlloc>(aArray, aArrayLen);
|
||||
}
|
||||
|
||||
template<class Item>
|
||||
/* MOZ_MUST_USE */
|
||||
elem_type* AppendElements(mozilla::Span<const Item> aSpan,
|
||||
const mozilla::fallible_t&)
|
||||
{
|
||||
return AppendElements<Item, FallibleAlloc>(aSpan.Elements(),
|
||||
aSpan.Length());
|
||||
}
|
||||
|
||||
// A variation on the AppendElements method defined above.
|
||||
protected:
|
||||
template<class Item, class Allocator, typename ActualAlloc = Alloc>
|
||||
|
@ -2397,6 +2462,25 @@ struct nsTArray_CopyChooser<AutoTArray<E, N>>
|
|||
typedef nsTArray_CopyWithConstructors<AutoTArray<E, N>> Type;
|
||||
};
|
||||
|
||||
// Span integration
|
||||
namespace mozilla {
|
||||
|
||||
template<class ElementType, class TArrayAlloc>
|
||||
Span<ElementType>
|
||||
MakeSpan(nsTArray_Impl<ElementType, TArrayAlloc>& aTArray)
|
||||
{
|
||||
return aTArray;
|
||||
}
|
||||
|
||||
template<class ElementType, class TArrayAlloc>
|
||||
Span<const ElementType>
|
||||
MakeSpan(const nsTArray_Impl<ElementType, TArrayAlloc>& aTArray)
|
||||
{
|
||||
return aTArray;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
// Assert that AutoTArray doesn't have any extra padding inside.
|
||||
//
|
||||
// It's important that the data stored in this auto array takes up a multiple of
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/IntegerTypeTraits.h"
|
||||
#include "mozilla/Span.h"
|
||||
|
||||
#ifndef MOZILLA_INTERNAL_API
|
||||
#error "Using XPCOM strings is limited to code linked into libxul."
|
||||
|
@ -922,6 +924,68 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Span integration
|
||||
*/
|
||||
|
||||
operator mozilla::Span<char_type>()
|
||||
{
|
||||
return mozilla::MakeSpan(BeginWriting(), Length());
|
||||
}
|
||||
|
||||
operator mozilla::Span<const char_type>() const
|
||||
{
|
||||
return mozilla::MakeSpan(BeginReading(), Length());
|
||||
}
|
||||
|
||||
void Append(mozilla::Span<const char_type> aSpan)
|
||||
{
|
||||
auto len = aSpan.Length();
|
||||
MOZ_RELEASE_ASSERT(len <= mozilla::MaxValue<size_type>::value);
|
||||
Append(aSpan.Elements(), len);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool Append(mozilla::Span<const char_type> aSpan,
|
||||
const fallible_t& aFallible)
|
||||
{
|
||||
auto len = aSpan.Length();
|
||||
if (len > mozilla::MaxValue<size_type>::value) {
|
||||
return false;
|
||||
}
|
||||
return Append(aSpan.Elements(), len, aFallible);
|
||||
}
|
||||
|
||||
#if !defined(CharT_is_PRUnichar)
|
||||
operator mozilla::Span<uint8_t>()
|
||||
{
|
||||
return mozilla::MakeSpan(reinterpret_cast<uint8_t*>(BeginWriting()),
|
||||
Length());
|
||||
}
|
||||
|
||||
operator mozilla::Span<const uint8_t>() const
|
||||
{
|
||||
return mozilla::MakeSpan(reinterpret_cast<const uint8_t*>(BeginReading()),
|
||||
Length());
|
||||
}
|
||||
|
||||
void Append(mozilla::Span<const uint8_t> aSpan)
|
||||
{
|
||||
auto len = aSpan.Length();
|
||||
MOZ_RELEASE_ASSERT(len <= mozilla::MaxValue<size_type>::value);
|
||||
Append(reinterpret_cast<const char*>(aSpan.Elements()), len);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool Append(mozilla::Span<const uint8_t> aSpan,
|
||||
const fallible_t& aFallible)
|
||||
{
|
||||
auto len = aSpan.Length();
|
||||
if (len > mozilla::MaxValue<size_type>::value) {
|
||||
return false;
|
||||
}
|
||||
return Append(
|
||||
reinterpret_cast<const char*>(aSpan.Elements()), len, aFallible);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* string data is never null, but can be marked void. if true, the
|
||||
|
@ -1272,3 +1336,22 @@ public:
|
|||
return mArray[index];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Span integration
|
||||
*/
|
||||
namespace mozilla {
|
||||
|
||||
inline Span<CharT>
|
||||
MakeSpan(nsTSubstring_CharT& aString)
|
||||
{
|
||||
return aString;
|
||||
}
|
||||
|
||||
inline Span<const CharT>
|
||||
MakeSpan(const nsTSubstring_CharT& aString)
|
||||
{
|
||||
return aString;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
Загрузка…
Ссылка в новой задаче