Merging cedar with mozilla-central.

This commit is contained in:
Mounir Lamouri 2011-06-05 15:31:36 +02:00
commit 8bc1be7f60
128 changed files with 3910 additions and 848 deletions

View File

@ -72,33 +72,3 @@
padding: 0;
font-weight: bold;
}
#channelSelector {
margin-top: 10px;
}
#channelSelectorStart {
-moz-margin-start: 0;
}
#channelMenulist {
margin: 0;
}
.channel-description {
margin: 10px 0;
}
#detailsBox,
#channelSelector,
.channel-description {
-moz-transition: opacity 250ms;
}
#contentDeck:not([selectedIndex="0"]) > #detailsBox,
#contentDeck:not([selectedIndex="1"]) > #channelSelector,
#channelDescriptionDeck:not([selectedIndex="0"]) > #releaseDescription,
#channelDescriptionDeck:not([selectedIndex="1"]) > #betaDescription,
#channelDescriptionDeck:not([selectedIndex="2"]) > #auroraDescription {
opacity: 0;
}

View File

@ -88,7 +88,9 @@ function init(aEvent)
gAppUpdater = new appUpdater();
#endif
gChannelSelector.init();
let defaults = Services.prefs.getDefaultBranch("");
let channelLabel = document.getElementById("currentChannel");
channelLabel.value = defaults.getCharPref("app.update.channel");
#ifdef XP_MACOSX
// it may not be sized at this point, and we need its width to calculate its position
@ -573,72 +575,3 @@ appUpdater.prototype =
}
};
#endif
var gChannelSelector = {
validChannels: { release: 1, beta: 1, aurora: 1 },
init: function() {
try {
this.channelValue = Services.prefs.getCharPref("app.update.desiredChannel");
} catch (e) {
let defaults = Services.prefs.getDefaultBranch("");
this.channelValue = defaults.getCharPref("app.update.channel");
}
// Only show channel selector UI on valid update channels.
if (this.channelValue in this.validChannels) {
document.getElementById("currentChannelText").hidden = false;
this.setChannelLabel(this.channelValue);
this.setChannelMenuitem(this.channelValue);
}
},
selectChannel: function(aSelectedItem) {
document.getElementById("channelDescriptionDeck").selectedPanel =
document.getElementById(aSelectedItem.value + "Description");
document.getElementById("channelMenulist").setAttribute("aria-describedby",
aSelectedItem.value + "Description");
},
cancel: function() {
this.setChannelMenuitem(this.channelValue);
this.hide();
},
apply: function() {
this.channelValue = document.getElementById("channelMenulist").selectedItem.value;
this.setChannelLabel(this.channelValue);
// Change app update channel.
Services.prefs.setCharPref("app.update.desiredChannel", this.channelValue);
// Stop any downloads in progress
gAppUpdater.aus.pauseDownload();
// App updater will look at app.update.desiredChannel for new channel value
// and will clear it when the update is complete.
gAppUpdater.isChecking = true;
gAppUpdater.checker.checkForUpdates(gAppUpdater.updateCheckListener, true);
this.hide();
},
show: function() {
document.getElementById("contentDeck").selectedPanel =
document.getElementById("channelSelector");
},
hide: function() {
document.getElementById("contentDeck").selectedPanel =
document.getElementById("detailsBox");
},
setChannelLabel: function(aValue) {
let channelLabel = document.getElementById("currentChannel");
channelLabel.value = document.getElementById(aValue + "Menuitem").label;
},
setChannelMenuitem: function(aValue) {
document.getElementById("channelMenulist").selectedItem =
document.getElementById(aValue + "Menuitem");
}
}

View File

@ -80,85 +80,50 @@
<label id="distribution" class="text-blurb"/>
<label id="distributionId" class="text-blurb"/>
<!-- Make sure the selectedIndex attribute is always set so that the CSS
selectors for transitions work -->
<deck id="contentDeck" selectedIndex="0">
<vbox id="detailsBox" aria-describedby="communityDesc contributeDesc">
<vbox id="updateBox">
<vbox id="detailsBox" aria-describedby="communityDesc contributeDesc">
<vbox id="updateBox">
#ifdef MOZ_UPDATER
<deck id="updateDeck" orient="vertical">
<hbox id="updateButtonBox" align="center">
<button id="updateButton" align="start"
oncommand="gAppUpdater.buttonOnCommand();"/>
<spacer flex="1"/>
</hbox>
<hbox id="checkingForUpdates" align="center">
<image class="update-throbber"/><label>&update.checkingForUpdates;</label>
</hbox>
<hbox id="checkingAddonCompat" align="center">
<image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
</hbox>
<hbox id="downloading" align="center">
<image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
</hbox>
<hbox id="downloadFailed" align="center">
<label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
</hbox>
<hbox id="adminDisabled" align="center">
<label>&update.adminDisabled;</label>
</hbox>
<hbox id="noUpdatesFound" align="center">
<label>&update.noUpdatesFound;</label>
</hbox>
<hbox id="manualUpdate" align="center">
<label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
</hbox>
</deck>
#endif
</vbox>
<description class="text-blurb" id="currentChannelText" hidden="true">
&channel.description.start;<label id="currentChannel"/>&channel.description.end;<label id="channelChangeLink" class="text-link" onclick="gChannelSelector.show();">&channel.change;</label>
</description>
<description class="text-blurb" id="communityDesc">
&community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2;
</description>
<description class="text-blurb" id="contributeDesc">
&contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
</description>
</vbox>
<vbox id="channelSelector">
<hbox pack="start" align="center">
<label id="channelSelectorStart">&channel.selector.start;</label>
<menulist id="channelMenulist" onselect="gChannelSelector.selectChannel(this.selectedItem);" aria-labelledby="channelSelectorStart channelMenulist channelSelectorEnd">
<menupopup>
<menuitem id="releaseMenuitem" label="Release" value="release"/>
<menuitem id="betaMenuitem" label="Beta" value="beta"/>
<menuseparator/>
<menuitem id="auroraMenuitem" label="Aurora" value="aurora"/>
</menupopup>
</menulist>
<label id="channelSelectorEnd">&channel.selector.end;</label>
</hbox>
<deck id="channelDescriptionDeck" selectedIndex="0">
<description id="releaseDescription" class="channel-description">&channel.release.description;</description>
<description id="betaDescription" class="channel-description">&channel.beta.description;</description>
<description id="auroraDescription" class="channel-description">&channel.aurora.description;</description>
<deck id="updateDeck" orient="vertical">
<hbox id="updateButtonBox" align="center">
<button id="updateButton" align="start"
oncommand="gAppUpdater.buttonOnCommand();"/>
<spacer flex="1"/>
</hbox>
<hbox id="checkingForUpdates" align="center">
<image class="update-throbber"/><label>&update.checkingForUpdates;</label>
</hbox>
<hbox id="checkingAddonCompat" align="center">
<image class="update-throbber"/><label>&update.checkingAddonCompat;</label>
</hbox>
<hbox id="downloading" align="center">
<image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
</hbox>
<hbox id="downloadFailed" align="center">
<label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
</hbox>
<hbox id="adminDisabled" align="center">
<label>&update.adminDisabled;</label>
</hbox>
<hbox id="noUpdatesFound" align="center">
<label>&update.noUpdatesFound;</label>
</hbox>
<hbox id="manualUpdate" align="center">
<label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
</hbox>
</deck>
<hbox id="channelSelectorButtons" pack="end">
#ifdef XP_UNIX
<button oncommand="gChannelSelector.cancel();" label="&channel.selector.cancelButton;"/>
<button oncommand="gChannelSelector.apply();" label="&channel.selector.applyButton;"/>
#else
<button oncommand="gChannelSelector.apply();" label="&channel.selector.applyButton;"/>
<button oncommand="gChannelSelector.cancel();" label="&channel.selector.cancelButton;"/>
#endif
</hbox>
</vbox>
</deck>
<description class="text-blurb" id="currentChannelText">
&channel.description.start;<label id="currentChannel"/>&channel.description.end;
</description>
<description class="text-blurb" id="communityDesc">
&community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end2;
</description>
<description class="text-blurb" id="contributeDesc">
&contribute.start;<label class="text-link" href="http://www.mozilla.org/contribute/">&contribute.getInvolvedLink;</label>&contribute.end;
</description>
</vbox>
</vbox>
</hbox>
<vbox id="bottomBox">

View File

@ -2257,7 +2257,11 @@ function loadURI(uri, referrer, postData, allowThirdPartyFixup)
}
}
function getShortcutOrURI(aURL, aPostDataRef) {
function getShortcutOrURI(aURL, aPostDataRef, aMayInheritPrincipal) {
// Initialize outparam to false
if (aMayInheritPrincipal)
aMayInheritPrincipal.value = false;
var shortcutURL = null;
var keyword = aURL;
var param = "";
@ -2329,6 +2333,11 @@ function getShortcutOrURI(aURL, aPostDataRef) {
return aURL;
}
// This URL came from a bookmark, so it's safe to let it inherit the current
// document's principal.
if (aMayInheritPrincipal)
aMayInheritPrincipal.value = true;
return shortcutURL;
}

View File

@ -608,7 +608,7 @@ iQClass.prototype = {
});
this.css({
'-moz-transition-property': 'all', // TODO: just animate the properties we're changing
'-moz-transition-property': Object.keys(css).join(", "),
'-moz-transition-duration': (duration / 1000) + 's',
'-moz-transition-timing-function': easing
});

View File

@ -999,7 +999,7 @@ let UI = {
"redo",
#endif
#ifdef XP_MACOSX
"preferencesCmdMac", "minimizeWindow",
"preferencesCmdMac", "minimizeWindow", "hideThisAppCmdMac",
#endif
"newNavigator", "newNavigatorTab", "undo", "cut", "copy", "paste",
"selectAll", "find"
@ -1043,6 +1043,10 @@ let UI = {
Keys.meta = true;
function processBrowserKeys(evt) {
// let any keys with alt to pass through
if (evt.altKey)
return;
#ifdef XP_MACOSX
if (evt.metaKey) {
#else
@ -1077,6 +1081,7 @@ let UI = {
#ifdef XP_MACOSX
case self._browserKeys.preferencesCmdMac:
case self._browserKeys.minimizeWindow:
case self._browserKeys.hideThisAppCmdMac:
#endif
case self._browserKeys.newNavigator:
case self._browserKeys.newNavigatorTab:

View File

@ -173,6 +173,7 @@ _BROWSER_FILES = \
browser_bug647886.js \
browser_bug655584.js \
browser_findbarClose.js \
browser_keywordBookmarklets.js \
browser_contextSearchTabPosition.js \
browser_ctrlTab.js \
browser_customize_popupNotification.js \

View File

@ -44,6 +44,7 @@ function test() {
// Verify that about:addons loads
waitForExplicitFinish();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
let browser = blanktab.linkedBrowser;
is(browser.currentURI.spec, "about:addons", "about:addons should load into blank tab.");
gBrowser.removeTab(blanktab);

View File

@ -11,9 +11,10 @@ function getPostDataString(aIS) {
return dataLines[dataLines.length-1];
}
function keywordResult(aURL, aPostData) {
function keywordResult(aURL, aPostData, aIsUnsafe) {
this.url = aURL;
this.postData = aPostData;
this.isUnsafe = aIsUnsafe;
}
function keyWordData() {}
@ -52,20 +53,20 @@ var testData = [
new keywordResult("http://bmget-nosearch/", null)],
[new searchKeywordData("searchget", "http://searchget/?search={searchTerms}", null, "foo4"),
new keywordResult("http://searchget/?search=foo4", null)],
new keywordResult("http://searchget/?search=foo4", null, true)],
[new searchKeywordData("searchpost", "http://searchpost/", "search={searchTerms}", "foo5"),
new keywordResult("http://searchpost/", "search=foo5")],
new keywordResult("http://searchpost/", "search=foo5", true)],
[new searchKeywordData("searchpostget", "http://searchpostget/?search1={searchTerms}", "search2={searchTerms}", "foo6"),
new keywordResult("http://searchpostget/?search1=foo6", "search2=foo6")],
new keywordResult("http://searchpostget/?search1=foo6", "search2=foo6", true)],
// Bookmark keywords that don't take parameters should not be activated if a
// parameter is passed (bug 420328).
[new bmKeywordData("bmget-noparam", "http://bmget-noparam/", null, "foo7"),
new keywordResult(null, null)],
new keywordResult(null, null, true)],
[new bmKeywordData("bmpost-noparam", "http://bmpost-noparam/", "not_a=param", "foo8"),
new keywordResult(null, null)],
new keywordResult(null, null, true)],
// Test escaping (%s = escaped, %S = raw)
// UTF-8 default
@ -82,6 +83,12 @@ var testData = [
// Explicitly-defined ISO-8859-1
[new bmKeywordData("bmget-escaping2", "http://bmget/?esc=%s&raw=%S&mozcharset=ISO-8859-1", null, "+/@"),
new keywordResult("http://bmget/?esc=%2B%2F%40&raw=+/@", null)],
// Test using a non-bmKeywordData object, to test the behavior of
// getShortcutOrURI for non-keywords (setupKeywords only adds keywords for
// bmKeywordData objects)
[{keyword: "http://gavinsharp.com"},
new keywordResult(null, null, true)]
];
function test() {
@ -94,12 +101,14 @@ function test() {
var query = data.keyword;
if (data.searchWord)
query += " " + data.searchWord;
var url = getShortcutOrURI(query, postData);
var mayInheritPrincipal = {};
var url = getShortcutOrURI(query, postData, mayInheritPrincipal);
// null result.url means we should expect the same query we sent in
var expected = result.url || query;
is(url, expected, "got correct URL for " + data.keyword);
is(getPostDataString(postData.value), result.postData, "got correct postData for " + data.keyword);
is(mayInheritPrincipal.value, !result.isUnsafe, "got correct mayInheritPrincipal for " + data.keyword);
}
cleanupKeywords();

View File

@ -0,0 +1,38 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let bmFolder = Application.bookmarks.menu.addFolder("keyword-test");
let tab = gBrowser.selectedTab = gBrowser.addTab();
registerCleanupFunction (function () {
bmFolder.remove();
gBrowser.removeTab(tab);
});
let bm = bmFolder.addBookmark("bookmarklet", makeURI("javascript:1;"));
bm.keyword = "bm";
addPageShowListener(function () {
let originalPrincipal = gBrowser.contentPrincipal;
// Enter bookmarklet keyword in the URL bar
gURLBar.value = "bm";
gURLBar.focus();
EventUtils.synthesizeKey("VK_RETURN", {});
addPageShowListener(function () {
ok(gBrowser.contentPrincipal.equals(originalPrincipal), "javascript bookmarklet should inherit principal");
finish();
});
});
}
function addPageShowListener(func) {
gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
func();
});
}

View File

@ -260,6 +260,7 @@
return; // Do nothing for right clicks
var url = this.value;
var mayInheritPrincipal = false;
var postData = null;
var action = this._parseActionUrl(url);
@ -277,7 +278,7 @@
}
}
else {
[url, postData] = this._canonizeURL(aTriggeringEvent);
[url, postData, mayInheritPrincipal] = this._canonizeURL(aTriggeringEvent);
if (!url)
return;
}
@ -293,10 +294,13 @@
}
function loadCurrent() {
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
// Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from
// inheriting the currently loaded document's principal.
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
// inheriting the currently loaded document's principal, unless this
// URL is marked as safe to inherit (e.g. came from a bookmark
// keyword).
if (!mayInheritPrincipal)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
gBrowser.loadURIWithFlags(url, flags, null, null, postData);
}
@ -339,7 +343,7 @@
<body><![CDATA[
var url = this.value;
if (!url)
return ["", null];
return ["", null, false];
// Only add the suffix when the URL bar value isn't already "URL-like",
// and only if we get a keyboard event, to match user expectations.
@ -402,9 +406,10 @@
}
var postData = {};
url = getShortcutOrURI(url, postData);
var mayInheritPrincipal = { value: false };
url = getShortcutOrURI(url, postData, mayInheritPrincipal);
return [url, postData.value];
return [url, postData.value, mayInheritPrincipal.value];
]]></body>
</method>

View File

@ -6,6 +6,5 @@ browser.jar:
content/branding/about-wordmark.png (about-wordmark.png)
content/branding/icon48.png (icon48.png)
content/branding/icon64.png (icon64.png)
content/branding/icon128.png (../mozicon128.png)
content/branding/icon16.png (../default16.png)
content/branding/aboutDialog.css (aboutDialog.css)

View File

@ -6,6 +6,5 @@ browser.jar:
content/branding/about-wordmark.png (about-wordmark.png)
content/branding/icon48.png (icon48.png)
content/branding/icon64.png (icon64.png)
content/branding/icon128.png (../mozicon128.png)
content/branding/icon16.png (../default16.png)
content/branding/aboutDialog.css (aboutDialog.css)

View File

@ -5,6 +5,5 @@ browser.jar:
content/branding/about-wordmark.png (about-wordmark.png)
content/branding/icon48.png (icon48.png)
content/branding/icon64.png (icon64.png)
content/branding/icon128.png (../mozicon128.png)
content/branding/icon16.png (../default16.png)
content/branding/aboutDialog.css (aboutDialog.css)

View File

@ -6,6 +6,5 @@ browser.jar:
content/branding/about-wordmark.png (about-wordmark.png)
content/branding/icon48.png (icon48.png)
content/branding/icon64.png (icon64.png)
content/branding/icon128.png (../mozicon128.png)
content/branding/icon16.png (../default16.png)
content/branding/aboutDialog.css (aboutDialog.css)

View File

@ -145,6 +145,15 @@ Site.prototype = {
* @return A boolean indicating whether or not a permission is set.
*/
getPermission: function Site_getPermission(aType, aResultObj) {
// Password saving isn't a nsIPermissionManager permission type, so handle
// it seperately.
if (aType == "password") {
aResultObj.value = this.loginSavingEnabled ?
Ci.nsIPermissionManager.ALLOW_ACTION :
Ci.nsIPermissionManager.DENY_ACTION;
return true;
}
let permissionValue;
if (TEST_EXACT_PERM_TYPES.indexOf(aType) == -1) {
permissionValue = Services.perms.testPermission(this.httpURI, aType);
@ -167,6 +176,13 @@ Site.prototype = {
* be one of the constants defined in nsIPermissionManager.
*/
setPermission: function Site_setPermission(aType, aPerm) {
// Password saving isn't a nsIPermissionManager permission type, so handle
// it seperately.
if (aType == "password") {
this.loginSavingEnabled = aPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
return;
}
// Using httpURI is kind of bogus, but the permission manager stores the
// permission for the host, so the right thing happens in the end.
Services.perms.add(this.httpURI, aType, aPerm);
@ -685,14 +701,8 @@ let AboutPermissions = {
let permissionMenulist = document.getElementById(aType + "-menulist");
let permissionValue;
if (!this._selectedSite) {
// If there is no selected site, we are updating the default permissions interface.
permissionValue = PermissionDefaults[aType];
} else if (aType == "password") {
// Services.logins.getLoginSavingEnabled already looks at the default
// permission, so we don't need to.
permissionValue = this._selectedSite.loginSavingEnabled ?
PermissionDefaults.ALLOW : PermissionDefaults.DENY;
} else {
let result = {};
permissionValue = this._selectedSite.getPermission(aType, result) ?
@ -709,9 +719,6 @@ let AboutPermissions = {
if (!this._selectedSite) {
// If there is no selected site, we are setting the default permission.
PermissionDefaults[permissionType] = permissionValue;
} else if (permissionType == "password") {
let isEnabled = permissionValue == PermissionDefaults.ALLOW;
this._selectedSite.loginSavingEnabled = isEnabled;
} else {
this._selectedSite.setPermission(permissionType, permissionValue);
}

View File

@ -60,21 +60,3 @@
example: You are currently on the _Stable_ update channel. -->
<!ENTITY channel.description.start "You are currently on the ">
<!ENTITY channel.description.end " update channel. ">
<!ENTITY channel.change "Change">
<!ENTITY channel.release.description "Enjoy the tried and tested final release being used by hundreds of millions around the world. Stay in control of your online experience with super speed, easy customization and the latest Web technologies.">
<!ENTITY channel.beta.description "Experience cutting edge features with more stability. Provide feedback to help refine and polish what will be in the final release.">
<!ENTITY channel.aurora.description "Experience the newest innovations in an unstable environment that's not for the faint of heart. Provide feedback on features and performance to help determine what makes the final release.">
<!-- LOCALIZATION NOTE (channel.selector.start,channel.selector.end): channel.selector.start and
channel.selector.end create one sentence, with a channel selection menulist instered in between.
This is all in one line, so try to make the localized text short.
example: Switch to the [Stable] update channel. -->
<!ENTITY channel.selector.start "Switch to the">
<!ENTITY channel.selector.end "update channel.">
<!-- LOCALIZATION NOTE (channel.selector.applyButton): This button applies the user's choice to switch
to a new update channel and starts the application update process. -->
<!ENTITY channel.selector.applyButton "Apply and Update">
<!ENTITY channel.selector.cancelButton "Cancel">

View File

@ -23,5 +23,5 @@
<!ENTITY robots.errorTrailerDescText "And they have a plan.">
<!-- TV: Battlestar Galactica (2004 series). Common expletive referring to Cylons. -->
<!ENTITY robots.imgtitle "Frakkin' Toasters">
<!-- Book: Hitchiker's Guide To The Galaxy. Arthur presses a button and it warns him. -->
<!-- Book: Hitchhiker's Guide To The Galaxy. Arthur presses a button and it warns him. -->
<!ENTITY robots.dontpress "Please do not press this button again.">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 B

View File

@ -42,7 +42,6 @@ browser.jar:
skin/classic/browser/section_collapsed-rtl.png
skin/classic/browser/section_expanded.png
skin/classic/browser/Secure-Glyph-White.png
skin/classic/browser/Secure-background.gif
skin/classic/browser/Toolbar.png
skin/classic/browser/toolbarbutton-dropmarker.png
skin/classic/browser/urlbar-arrow.png

View File

@ -555,12 +555,6 @@ nsDOMAttribute::GetIsId(PRBool* aReturn)
return NS_OK;
}
NS_IMETHODIMP
nsDOMAttribute::GetSchemaTypeInfo(nsIDOM3TypeInfo** aReturn)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
PRBool
nsDOMAttribute::IsNodeOfType(PRUint32 aFlags) const
{

View File

@ -863,6 +863,9 @@ nsEventStateManager::Init()
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
if (sESMInstanceCount == 1) {
sKeyCausesActivation =
Preferences::GetBool("accessibility.accesskeycausesactivation",
sKeyCausesActivation);
sLeftClickOnly =
Preferences::GetBool("nglayout.events.dispatchLeftClickOnly",
sLeftClickOnly);

View File

@ -22,6 +22,7 @@
*
* Contributor(s):
* Mats Palmgren <mats.palmgren@bredband.net>
* Ms2ger <ms2ger@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -444,27 +445,7 @@ static const nsAttrValue::EnumTable kDirTable[] = {
{ 0 }
};
nsresult
nsGenericHTMLElement::GetDir(nsAString& aDir)
{
const nsAttrValue* attr = mAttrsAndChildren.GetAttr(nsGkAtoms::dir);
if (attr && attr->Type() == nsAttrValue::eEnum) {
attr->ToString(aDir);
}
else {
aDir.Truncate();
}
return NS_OK;
}
nsresult
nsGenericHTMLElement::SetDir(const nsAString& aDir)
{
SetAttr(kNameSpaceID_None, nsGkAtoms::dir, aDir, PR_TRUE);
return NS_OK;
}
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsGenericHTMLElement, Dir, dir, NULL)
nsresult
nsGenericHTMLElement::GetClassName(nsAString& aClassName)
@ -2331,7 +2312,7 @@ nsGenericHTMLElement::GetEnumAttr(nsIAtom* aAttr,
if (attrVal && attrVal->Type() == nsAttrValue::eEnum) {
attrVal->GetEnumString(aResult, PR_TRUE);
} else {
} else if (aDefault) {
AppendASCIItoUTF16(nsDependentCString(aDefault), aResult);
}

View File

@ -116,8 +116,8 @@ public:
nsresult SetTitle(const nsAString& aTitle);
nsresult GetLang(nsAString& aLang);
nsresult SetLang(const nsAString& aLang);
nsresult GetDir(nsAString& aDir);
nsresult SetDir(const nsAString& aDir);
NS_IMETHOD GetDir(nsAString& aDir);
NS_IMETHOD SetDir(const nsAString& aDir);
nsresult GetClassName(nsAString& aClassName);
nsresult SetClassName(const nsAString& aClassName);

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
* Ms2ger <ms2ger@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -314,8 +315,7 @@ NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLBodyElement)
NS_IMPL_ELEMENT_CLONE(nsHTMLBodyElement)
NS_IMPL_URI_ATTR(nsHTMLBodyElement, Background, background)
NS_IMPL_STRING_ATTR(nsHTMLBodyElement, Background, background)
NS_IMPL_STRING_ATTR(nsHTMLBodyElement, VLink, vlink)
NS_IMPL_STRING_ATTR(nsHTMLBodyElement, ALink, alink)
NS_IMPL_STRING_ATTR(nsHTMLBodyElement, Link, link)

View File

@ -280,6 +280,7 @@ _TEST_FILES = \
test_bug658746.html \
test_bug659596.html \
test_bug659743.xml \
test_bug660663.html \
test_restore_from_parser_fragment.html \
$(NULL)

View File

@ -93,3 +93,47 @@ function reflectUnsignedInt(aElement, aAttr, aNonNull, aDefault)
is(aElement[aAttr], 0, "." + aAttr + " should be equals to 0");
}
}
/**
* @param aElement Element node to test on
* @param aAttr String name of the attribute
* @param aSupportedValues Array values we supported
* @param aUnsupportedValues Array values we don't support
*/
function reflectLimitedEnumerated(aElement, aAttr, aSupportedValues,
aUnsupportedValues)
{
aSupportedValues.forEach(function (v) {
aElement.setAttribute(aAttr, v);
is(aElement[aAttr], v);
is(aElement.getAttribute(aAttr), v);
aElement.removeAttribute(aAttr);
aElement.setAttribute(aAttr, v.toUpperCase());
is(aElement[aAttr], v);
is(aElement.getAttribute(aAttr), v.toUpperCase());
aElement.removeAttribute(aAttr);
aElement[aAttr] = v;
is(aElement[aAttr], v);
is(aElement.getAttribute(aAttr), v);
aElement.removeAttribute(aAttr);
aElement[aAttr] = v.toUpperCase();
is(aElement[aAttr], v);
is(aElement.getAttribute(aAttr), v.toUpperCase());
aElement.removeAttribute(aAttr);
});
["cheesecake"].concat(aUnsupportedValues).forEach(function (v) {
aElement.setAttribute(aAttr, v);
is(aElement[aAttr], "");
is(aElement.getAttribute(aAttr), v);
aElement.removeAttribute(aAttr);
aElement[aAttr] = v;
is(aElement[aAttr], "");
is(aElement.getAttribute(aAttr), v);
aElement.removeAttribute(aAttr);
});
}

View File

@ -0,0 +1,29 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=660663
-->
<head>
<title>Test for Bug 660663</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="reflect.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=660663">Mozilla Bug 660663</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 660663 **/
reflectLimitedEnumerated(document.createElement("div"),
"dir",
["ltr", "rtl"],
["auto"]);
</script>
</pre>
</body>
</html>

View File

@ -991,7 +991,7 @@ nsHTMLDocument::StopDocumentLoad()
mWriteState = eDocumentClosed;
// Remove the wyciwyg channel request from the document load group
// that we added in OpenCommon().
// that we added in Open().
NS_ASSERTION(mWyciwygChannel, "nsHTMLDocument::StopDocumentLoad(): "
"Trying to remove nonexistent wyciwyg channel!");
RemoveWyciwygChannel();
@ -1516,33 +1516,50 @@ nsHTMLDocument::SetCookie(const nsAString& aCookie)
return NS_OK;
}
nsresult
nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
PRBool aReplace)
NS_IMETHODIMP
nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
const nsAString& aReplaceOrName,
const nsAString& aFeatures,
JSContext* cx, PRUint8 aOptionalArgCount,
nsISupports** aReturn)
{
if (!IsHTML() || mDisableDocWrite) {
// No calling document.open() on XHTML
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
PRBool loadAsHtml5 = nsHtml5Module::sEnabled;
nsresult rv = NS_OK;
// If we already have a parser we ignore the document.open call.
if (mParser) {
return NS_OK;
}
NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)),
"XOW should have caught this!");
if (!aContentType.EqualsLiteral("text/html") &&
!aContentType.EqualsLiteral("text/plain")) {
NS_WARNING("Unsupported type; fix the caller");
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
// When called with 3 or more arguments, document.open() calls window.open().
if (aOptionalArgCount > 2) {
nsCOMPtr<nsIDOMWindowInternal> window = GetWindowInternal();
if (!window) {
return NS_OK;
}
nsCOMPtr<nsIDOMWindow> newWindow;
nsresult rv = window->Open(aContentTypeOrUrl, aReplaceOrName, aFeatures,
getter_AddRefs(newWindow));
*aReturn = newWindow.forget().get();
return rv;
}
if (!IsHTML() || mDisableDocWrite) {
// No calling document.open() on XHTML
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
nsCAutoString contentType;
contentType.AssignLiteral("text/html");
if (aOptionalArgCount > 0) {
nsAutoString type;
ToLowerCase(aContentTypeOrUrl, type);
nsCAutoString actualType, dummy;
NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
if (!actualType.EqualsLiteral("text/html") &&
!type.EqualsLiteral("replace")) {
contentType.AssignLiteral("text/plain");
}
}
// If we already have a parser we ignore the document.open call.
if (mParser) {
return NS_OK;
}
// check whether we're in the middle of unload. If so, ignore this call.
@ -1602,7 +1619,7 @@ nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
if (thisURI) {
thisURI->GetSpec(thisSpec);
}
printf("nsHTMLDocument::OpenCommon callerDoc %s this %s\n", callerSpec.get(), thisSpec.get());
printf("nsHTMLDocument::Open callerDoc %s this %s\n", callerSpec.get(), thisSpec.get());
#endif
return NS_ERROR_DOM_SECURITY_ERR;
@ -1615,9 +1632,7 @@ nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
if (cv) {
PRBool okToUnload;
rv = cv->PermitUnload(PR_FALSE, &okToUnload);
if (NS_SUCCEEDED(rv) && !okToUnload) {
if (NS_SUCCEEDED(cv->PermitUnload(PR_FALSE, &okToUnload)) && !okToUnload) {
// We don't want to unload, so stop here, but don't throw an
// exception.
return NS_OK;
@ -1639,7 +1654,7 @@ nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, group);
nsresult rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, group);
if (NS_FAILED(rv)) {
return rv;
@ -1700,6 +1715,7 @@ nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
// resetting the document.
mSecurityInfo = securityInfo;
PRBool loadAsHtml5 = nsHtml5Module::sEnabled;
if (loadAsHtml5) {
mParser = nsHtml5Module::NewHtml5Parser();
rv = NS_OK;
@ -1708,7 +1724,7 @@ nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
}
// This will be propagated to the parser when someone actually calls write()
SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType));
SetContentTypeInternal(contentType);
mWriteState = eDocumentOpened;
@ -1739,7 +1755,9 @@ nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
// so, we need to tell the docshell to not create a new history
// entry for this load. Otherwise, make sure that we're doing a normal load,
// not whatever type of load was previously done on this docshell.
shell->SetLoadType(aReplace ? LOAD_NORMAL_REPLACE : LOAD_NORMAL);
shell->SetLoadType(
(aOptionalArgCount > 1 && aReplaceOrName.EqualsLiteral("replace"))
? LOAD_NORMAL_REPLACE : LOAD_NORMAL);
nsCOMPtr<nsIContentViewer> cv;
shell->GetContentViewer(getter_AddRefs(cv));
@ -1749,7 +1767,7 @@ nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
}
// Add a wyciwyg channel request into the document load group
NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::OpenCommon(): wyciwyg "
NS_ASSERTION(!mWyciwygChannel, "nsHTMLDocument::Open(): wyciwyg "
"channel already exists!");
// In case the editor is listening and will see the new channel
@ -1762,46 +1780,7 @@ nsHTMLDocument::OpenCommon(JSContext* cx, const nsAString& aContentType,
--mWriteLevel;
return rv;
}
NS_IMETHODIMP
nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
const nsAString& aReplaceOrName,
const nsAString& aFeatures,
JSContext* cx, PRUint8 aOptionalArgCount,
nsISupports** aReturn)
{
// When called with 3 or more arguments, document.open() calls window.open().
if (aOptionalArgCount > 2) {
nsCOMPtr<nsIDOMWindowInternal> window = GetWindowInternal();
if (!window) {
return NS_OK;
}
nsCOMPtr<nsIDOMWindow> newWindow;
nsresult rv = window->Open(aContentTypeOrUrl, aReplaceOrName, aFeatures,
getter_AddRefs(newWindow));
*aReturn = newWindow.forget().get();
return rv;
}
nsAutoString contentType;
contentType.AssignLiteral("text/html");
if (aOptionalArgCount > 0) {
nsAutoString type;
ToLowerCase(aContentTypeOrUrl, type);
nsCAutoString actualType, dummy;
NS_ParseContentType(NS_ConvertUTF16toUTF8(type), actualType, dummy);
if (!actualType.EqualsLiteral("text/html") &&
!type.EqualsLiteral("replace")) {
contentType.AssignLiteral("text/plain");
}
}
nsresult rv = OpenCommon(cx, contentType,
aOptionalArgCount > 1 && aReplaceOrName.EqualsLiteral("replace"));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(this, aReturn);
}

View File

@ -233,8 +233,6 @@ protected:
nsresult WriteCommon(JSContext *cx, const nsAString& aText,
PRBool aNewlineTerminate);
nsresult OpenCommon(JSContext *cx, const nsAString& aContentType,
PRBool aReplace);
nsresult CreateAndAddWyciwygChannel(void);
nsresult RemoveWyciwygChannel(void);

View File

@ -228,7 +228,6 @@
#include "nsIDOMComment.h"
#include "nsIDOMCDATASection.h"
#include "nsIDOMProcessingInstruction.h"
#include "nsIDOMNotation.h"
#include "nsIDOMNSEvent.h"
#include "nsIDOMDataContainerEvent.h"
#include "nsIDOMKeyEvent.h"
@ -607,8 +606,6 @@ DOMCI_DATA(DOMConstructor, void)
DOMCI_DATA(Worker, void)
DOMCI_DATA(ChromeWorker, void)
DOMCI_DATA(Notation, void)
#define NS_DEFINE_CLASSINFO_DATA_WITH_NAME(_class, _name, _helper, \
_flags) \
{ #_name, \
@ -732,7 +729,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(CDATASection, nsNodeSH, NODE_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(ProcessingInstruction, nsNodeSH,
NODE_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(Notation, nsNodeSH, NODE_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(NodeList, nsNodeListSH, ARRAY_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(NamedNodeMap, nsNamedNodeMapSH,
ARRAY_SCRIPTABLE_FLAGS)
@ -2558,10 +2554,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOM3Node)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(Notation, nsIDOMNotation)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNotation)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(NodeList, nsIDOMNodeList)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeList)
DOM_CLASSINFO_MAP_END

View File

@ -63,7 +63,6 @@ DOMCI_CLASS(Text)
DOMCI_CLASS(Comment)
DOMCI_CLASS(CDATASection)
DOMCI_CLASS(ProcessingInstruction)
DOMCI_CLASS(Notation)
DOMCI_CLASS(NodeList)
DOMCI_CLASS(NamedNodeMap)

View File

@ -190,7 +190,7 @@
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
#include "nsIDOMXULControlElement.h"
#include "nsIFrame.h"
#include "nsMenuPopupFrame.h"
#endif
#include "xpcprivate.h"
@ -10214,9 +10214,28 @@ nsGlobalChromeWindow::GetAttentionWithCycleCount(PRInt32 aCycleCount)
}
NS_IMETHODIMP
nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent)
nsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent *aMouseDownEvent, nsIDOMElement* aPanel)
{
nsCOMPtr<nsIWidget> widget = GetMainWidget();
nsCOMPtr<nsIWidget> widget;
// if a panel was supplied, use its widget instead.
#ifdef MOZ_XUL
if (aPanel) {
nsCOMPtr<nsIContent> panel = do_QueryInterface(aPanel);
NS_ENSURE_TRUE(panel, NS_ERROR_FAILURE);
nsIFrame* frame = panel->GetPrimaryFrame();
NS_ENSURE_TRUE(frame && frame->GetType() == nsGkAtoms::menuPopupFrame, NS_OK);
(static_cast<nsMenuPopupFrame*>(frame))->GetWidget(getter_AddRefs(widget));
}
else {
#endif
widget = GetMainWidget();
#ifdef MOZ_XUL
}
#endif
if (!widget) {
return NS_OK;
}

View File

@ -55,7 +55,6 @@ interface nsIDOMNSElement;
interface nsIDOMNamedNodeMap;
interface nsIDOMNode;
interface nsIDOMNodeList;
interface nsIDOMNotation;
interface nsIDOMProcessingInstruction;
interface nsIDOMText;
interface nsIDOMDOMStringList;

View File

@ -43,7 +43,7 @@ interface nsIDOMElement;
interface nsIDOMEvent;
interface nsIChromeFrameMessageManager;
[scriptable, uuid(ec38cbaf-372f-4874-bc7a-dbf1f0b3d755)]
[scriptable, uuid(7cfbc355-cbf9-4408-8e4c-a3c603ff1428)]
interface nsIDOMChromeWindow : nsISupports
{
const unsigned short STATE_MAXIMIZED = 1;
@ -84,8 +84,10 @@ interface nsIDOMChromeWindow : nsISupports
* start dragging the window. This function will fail unless called
* while the left mouse button is held down, callers must check this.
*
* The optional panel argument should be set when moving a panel.
*
* Returns NS_ERROR_NOT_IMPLEMENTED (and thus throws in JS) if the OS
* doesn't support this.
*/
void beginWindowMove(in nsIDOMEvent mouseDownEvent);
void beginWindowMove(in nsIDOMEvent mouseDownEvent, [optional] in nsIDOMElement panel);
};

View File

@ -60,13 +60,11 @@ SDK_XPIDLSRCS = \
nsIDOMNamedNodeMap.idl \
nsIDOMNode.idl \
nsIDOMNodeList.idl \
nsIDOMNotation.idl \
nsIDOMProcessingInstruction.idl \
nsIDOMText.idl \
$(NULL)
XPIDLSRCS = \
nsIDOM3Node.idl \
nsIDOM3TypeInfo.idl \
nsIDOM3Attr.idl \
nsIDOMDOMStringList.idl \
nsIDOMNameList.idl \

View File

@ -35,13 +35,10 @@
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
#include "nsIDOM3TypeInfo.idl"
[scriptable, uuid(274ef301-065c-450d-a75b-e7673d257293)]
[scriptable, uuid(dc3ac0ee-9afb-4d1e-a49c-f5042e5bcf65)]
interface nsIDOM3Attr : nsISupports
{
// Introduced in DOM Level 3:
readonly attribute nsIDOM3TypeInfo schemaTypeInfo;
// Introduced in DOM Level 3:
readonly attribute boolean isId;
};

View File

@ -603,8 +603,12 @@ PluginInstanceParent::GetImage(ImageContainer* aContainer, Image** aImage)
Image::Format format = Image::CAIRO_SURFACE;
#ifdef XP_MACOSX
if (mIOSurface)
if (mIOSurface) {
format = Image::MAC_IO_SURFACE;
if (!aContainer->Manager()) {
return NS_ERROR_FAILURE;
}
}
#endif
nsRefPtr<Image> image;

View File

@ -95,9 +95,7 @@ function HTMLBodyElement02() {
assertSize("Asize",1,nodeList);
testNode = nodeList.item(0);
vbackground = testNode.background;
// its not clear if this test is valid
//assertEquals("backgroundLink","./pix/back1.gif",vbackground);
todo_is(vbackground, "./pix/back1.gif", "backgroundLink");
assertEquals("backgroundLink","./pix/back1.gif",vbackground);
}

View File

@ -59,6 +59,20 @@ class Channel : public Message::Sender {
//
Channel(const std::wstring& channel_id, Mode mode, Listener* listener);
#if defined(CHROMIUM_MOZILLA_BUILD)
// XXX it would nice not to have yet more platform-specific code in
// here but it's just not worth the trouble.
# if defined(OS_POSIX)
// Connect to a pre-created channel |fd| as |mode|.
Channel(int fd, Mode mode, Listener* listener);
# elif defined(OS_WIN)
// Connect to a pre-created channel as |mode|. Clients connect to
// the pre-existing server pipe, and servers take over |server_pipe|.
Channel(const std::wstring& channel_id, void* server_pipe,
Mode mode, Listener* listener);
# endif
#endif
~Channel();
// Connect the pipe. On the server side, this will initiate
@ -99,6 +113,16 @@ class Channel : public Message::Sender {
// a named FIFO is used as the channel transport mechanism rather than a
// socketpair() in which case this method returns -1 for both parameters.
void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const;
# if defined(CHROMIUM_MOZILLA_BUILD)
// Return the server side of the socketpair.
int GetServerFileDescriptor() const;
# endif
#elif defined(OS_WIN)
# if defined(CHROMIUM_MOZILLA_BUILD)
// Return the server pipe handle.
void* GetServerPipeHandle() const;
# endif
#endif // defined(OS_POSIX)
private:

View File

@ -257,18 +257,10 @@ bool SetCloseOnExec(int fd) {
Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
Listener* listener)
: mode_(mode),
is_blocked_on_write_(false),
message_send_bytes_written_(0),
uses_fifo_(CommandLine::ForCurrentProcess()->HasSwitch(
switches::kIPCUseFIFO)),
server_listen_pipe_(-1),
pipe_(-1),
client_pipe_(-1),
listener_(listener),
waiting_connect_(true),
processing_incoming_(false),
factory_(this) {
: factory_(this) {
Init(mode, listener);
uses_fifo_ = CommandLine::ForCurrentProcess()->HasSwitch(switches::kIPCUseFIFO);
if (!CreatePipe(channel_id, mode)) {
// The pipe may have been closed already.
LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
@ -277,6 +269,28 @@ Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
}
}
Channel::ChannelImpl::ChannelImpl(int fd, Mode mode, Listener* listener)
: factory_(this) {
Init(mode, listener);
pipe_ = fd;
waiting_connect_ = (MODE_SERVER == mode);
EnqueueHelloMessage();
}
void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
mode_ = mode;
is_blocked_on_write_ = false;
message_send_bytes_written_ = 0;
uses_fifo_ = false;
server_listen_pipe_ = -1;
pipe_ = -1;
client_pipe_ = -1;
listener_ = listener;
waiting_connect_ = true;
processing_incoming_ = false;
}
bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
Mode mode) {
DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
@ -334,6 +348,10 @@ bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
}
// Create the Hello message to be sent when Connect is called
return EnqueueHelloMessage();
}
bool Channel::ChannelImpl::EnqueueHelloMessage() {
scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
HELLO_MESSAGE_TYPE,
IPC::Message::PRIORITY_NORMAL));
@ -796,6 +814,12 @@ Channel::Channel(const std::wstring& channel_id, Mode mode,
: channel_impl_(new ChannelImpl(channel_id, mode, listener)) {
}
#if defined(CHROMIUM_MOZILLA_BUILD)
Channel::Channel(int fd, Mode mode, Listener* listener)
: channel_impl_(new ChannelImpl(fd, mode, listener)) {
}
#endif
Channel::~Channel() {
delete channel_impl_;
}
@ -826,4 +850,10 @@ void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const {
return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd);
}
#ifdef CHROMIUM_MOZILLA_BUILD
int Channel::GetServerFileDescriptor() const {
return channel_impl_->GetServerFileDescriptor();
}
#endif
} // namespace IPC

View File

@ -24,6 +24,7 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
public:
// Mirror methods of Channel, see ipc_channel.h for description.
ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener);
ChannelImpl(int fd, Mode mode, Listener* listener);
~ChannelImpl() { Close(); }
bool Connect();
void Close();
@ -38,9 +39,17 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
#endif
bool Send(Message* message);
void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const;
#ifdef CHROMIUM_MOZILLA_BUILD
int GetServerFileDescriptor() const {
DCHECK(mode_ == MODE_SERVER);
return pipe_;
}
#endif
private:
void Init(Mode mode, Listener* listener);
bool CreatePipe(const std::wstring& channel_id, Mode mode);
bool EnqueueHelloMessage();
bool ProcessIncomingMessages();
bool ProcessOutgoingMessages();

View File

@ -35,11 +35,9 @@ Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
Listener* listener)
: ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)),
pipe_(INVALID_HANDLE_VALUE),
listener_(listener),
waiting_connect_(mode == MODE_SERVER),
processing_incoming_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {
Init(mode, listener);
if (!CreatePipe(channel_id, mode)) {
// The pipe may have been closed already.
LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
@ -47,6 +45,37 @@ Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
}
}
#if defined(CHROMIUM_MOZILLA_BUILD)
Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id,
HANDLE server_pipe,
Mode mode, Listener* listener)
: ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {
Init(mode, listener);
if (mode == MODE_SERVER) {
// Use the existing handle that was dup'd to us
pipe_ = server_pipe;
EnqueueHelloMessage();
} else {
// Take the normal init path to connect to the server pipe
CreatePipe(channel_id, mode);
}
}
void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
pipe_ = INVALID_HANDLE_VALUE;
listener_ = listener;
waiting_connect_ = (mode == MODE_SERVER);
processing_incoming_ = false;
}
HANDLE Channel::ChannelImpl::GetServerPipeHandle() const {
return pipe_;
}
#endif
void Channel::ChannelImpl::Close() {
if (thread_check_.get()) {
DCHECK(thread_check_->CalledOnValidThread());
@ -164,6 +193,10 @@ bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
}
// Create the Hello message to be sent when Connect is called
return EnqueueHelloMessage();
}
bool Channel::ChannelImpl::EnqueueHelloMessage() {
scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE,
HELLO_MESSAGE_TYPE,
IPC::Message::PRIORITY_NORMAL));
@ -426,6 +459,13 @@ Channel::Channel(const std::wstring& channel_id, Mode mode,
: channel_impl_(new ChannelImpl(channel_id, mode, listener)) {
}
#ifdef CHROMIUM_MOZILLA_BUILD
Channel::Channel(const std::wstring& channel_id, void* server_pipe,
Mode mode, Listener* listener)
: channel_impl_(new ChannelImpl(channel_id, server_pipe, mode, listener)) {
}
#endif
Channel::~Channel() {
delete channel_impl_;
}
@ -439,6 +479,10 @@ void Channel::Close() {
}
#ifdef CHROMIUM_MOZILLA_BUILD
void* Channel::GetServerPipeHandle() const {
return channel_impl_->GetServerPipeHandle();
}
Channel::Listener* Channel::set_listener(Listener* listener) {
return channel_impl_->set_listener(listener);
}

View File

@ -20,6 +20,8 @@ class Channel::ChannelImpl : public MessageLoopForIO::IOHandler {
public:
// Mirror methods of Channel, see ipc_channel.h for description.
ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener);
ChannelImpl(const std::wstring& channel_id, HANDLE server_pipe,
Mode mode, Listener* listener);
~ChannelImpl() {
if (pipe_ != INVALID_HANDLE_VALUE) {
Close();
@ -28,6 +30,8 @@ class Channel::ChannelImpl : public MessageLoopForIO::IOHandler {
bool Connect();
void Close();
#ifdef CHROMIUM_MOZILLA_BUILD
HANDLE GetServerPipeHandle() const;
Listener* set_listener(Listener* listener) {
Listener* old = listener_;
listener_ = listener;
@ -38,8 +42,10 @@ class Channel::ChannelImpl : public MessageLoopForIO::IOHandler {
#endif
bool Send(Message* message);
private:
void Init(Mode mode, Listener* listener);
const std::wstring PipeName(const std::wstring& channel_id) const;
bool CreatePipe(const std::wstring& channel_id, Mode mode);
bool EnqueueHelloMessage();
bool ProcessConnection();
bool ProcessIncomingMessages(MessageLoopForIO::IOContext* context,

View File

@ -123,7 +123,7 @@ AsyncChannel::~AsyncChannel()
}
bool
AsyncChannel::Open(Transport* aTransport, MessageLoop* aIOLoop)
AsyncChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
{
NS_PRECONDITION(!mTransport, "Open() called > once");
NS_PRECONDITION(aTransport, "need transport layer");
@ -136,8 +136,16 @@ AsyncChannel::Open(Transport* aTransport, MessageLoop* aIOLoop)
// FIXME figure out whether we're in parent or child, grab IO loop
// appropriately
bool needOpen = true;
if(!aIOLoop) {
if(aIOLoop) {
// We're a child or using the new arguments. Either way, we
// need an open.
needOpen = true;
mChild = (aSide == Unknown) || (aSide == Child);
} else {
NS_PRECONDITION(aSide == Unknown, "expected default side arg");
// parent
mChild = false;
needOpen = false;
aIOLoop = XRE_GetIOMessageLoop();
// FIXME assuming that the parent waits for the OnConnected event.
@ -145,8 +153,6 @@ AsyncChannel::Open(Transport* aTransport, MessageLoop* aIOLoop)
mChannelState = ChannelConnected;
}
mChild = needOpen;
mIOLoop = aIOLoop;
mWorkerLoop = MessageLoop::current();
@ -241,6 +247,33 @@ AsyncChannel::Send(Message* msg)
return true;
}
bool
AsyncChannel::Echo(Message* msg)
{
AssertWorkerThread();
mMonitor.AssertNotCurrentThreadOwns();
NS_ABORT_IF_FALSE(MSG_ROUTING_NONE != msg->routing_id(), "need a route");
{
MonitorAutoLock lock(mMonitor);
if (!Connected()) {
ReportConnectionError("AsyncChannel");
return false;
}
// NB: Go through this OnMessageReceived indirection so that
// echoing this message does the right thing for SyncChannel
// and RPCChannel too
mIOLoop->PostTask(
FROM_HERE,
NewRunnableMethod(this, &AsyncChannel::OnEchoMessage, msg));
// OnEchoMessage takes ownership of |msg|
}
return true;
}
void
AsyncChannel::OnDispatchMessage(const Message& msg)
{
@ -464,6 +497,14 @@ AsyncChannel::OnMessageReceived(const Message& msg)
NewRunnableMethod(this, &AsyncChannel::OnDispatchMessage, msg));
}
void
AsyncChannel::OnEchoMessage(Message* msg)
{
AssertIOThread();
OnMessageReceived(*msg);
delete msg;
}
void
AsyncChannel::OnChannelOpened()
{

View File

@ -42,10 +42,9 @@
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "chrome/common/ipc_channel.h"
#include "mozilla/Monitor.h"
#include "mozilla/ipc/Transport.h"
//-----------------------------------------------------------------------------
@ -66,7 +65,7 @@ struct HasResultCodes
};
};
class AsyncChannel : public IPC::Channel::Listener, protected HasResultCodes
class AsyncChannel : public Transport::Listener, protected HasResultCodes
{
protected:
typedef mozilla::Monitor Monitor;
@ -81,8 +80,8 @@ protected:
};
public:
typedef IPC::Channel Transport;
typedef IPC::Message Message;
typedef mozilla::ipc::Transport Transport;
class /*NS_INTERFACE_CLASS*/ AsyncListener: protected HasResultCodes
{
@ -96,6 +95,8 @@ public:
virtual void OnChannelConnected(int32 peer_pid) {};
};
enum Side { Parent, Child, Unknown };
public:
//
// These methods are called on the "worker" thread
@ -108,7 +109,7 @@ public:
//
// Returns true iff the transport layer was successfully connected,
// i.e., mChannelState == ChannelConnected.
bool Open(Transport* aTransport, MessageLoop* aIOLoop=0);
bool Open(Transport* aTransport, MessageLoop* aIOLoop=0, Side aSide=Unknown);
// Close the underlying transport channel.
void Close();
@ -116,6 +117,10 @@ public:
// Asynchronously send a message to the other side of the channel
virtual bool Send(Message* msg);
// Asynchronously deliver a message back to this side of the
// channel
virtual bool Echo(Message* msg);
// Send OnChannelConnected notification to listeners.
void DispatchOnChannelConnected(int32 peer_pid);
@ -123,7 +128,7 @@ public:
// These methods are called on the "IO" thread
//
// Implement the IPC::Channel::Listener interface
// Implement the Transport::Listener interface
NS_OVERRIDE virtual void OnMessageReceived(const Message& msg);
NS_OVERRIDE virtual void OnChannelConnected(int32 peer_pid);
NS_OVERRIDE virtual void OnChannelError();
@ -176,6 +181,7 @@ protected:
void OnChannelOpened();
void OnCloseChannel();
void PostErrorNotifyTask();
void OnEchoMessage(Message* msg);
// Return true if |msg| is a special message targeted at the IO
// thread, in which case it shouldn't be delivered to the worker.
@ -190,7 +196,7 @@ protected:
MessageLoop* mWorkerLoop; // thread where work is done
bool mChild; // am I the child or parent?
CancelableTask* mChannelErrorTask; // NotifyMaybeChannelError runnable
IPC::Channel::Listener* mExistingListener; // channel's previous listener
Transport::Listener* mExistingListener; // channel's previous listener
};

View File

@ -84,6 +84,12 @@ using mozilla::ipc::GeckoChildProcessHost;
static const int kMagicAndroidSystemPropFd = 5;
#endif
static bool
ShouldHaveDirectoryService()
{
return GeckoProcessType_Default == XRE_GetProcessType();
}
template<>
struct RunnableMethodTraits<GeckoChildProcessHost>
{
@ -139,15 +145,20 @@ void GetPathToBinary(FilePath& exePath)
exePath = exePath.DirName();
exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
#elif defined(OS_POSIX)
nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
nsCOMPtr<nsIFile> greDir;
nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
if (NS_SUCCEEDED(rv)) {
nsCString path;
greDir->GetNativePath(path);
exePath = FilePath(path.get());
if (ShouldHaveDirectoryService()) {
nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
NS_ASSERTION(directoryService, "Expected XPCOM to be available");
if (directoryService) {
nsCOMPtr<nsIFile> greDir;
nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
if (NS_SUCCEEDED(rv)) {
nsCString path;
greDir->GetNativePath(path);
exePath = FilePath(path.get());
}
}
}
else {
if (exePath.empty()) {
exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
exePath = exePath.DirName();
}
@ -421,41 +432,50 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
#if defined(OS_LINUX) || defined(OS_MACOSX)
base::environment_map newEnvVars;
nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
nsCOMPtr<nsIFile> greDir;
nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
if (NS_SUCCEEDED(rv)) {
nsCString path;
greDir->GetNativePath(path);
#ifdef OS_LINUX
#ifdef ANDROID
path += "/lib";
#endif
newEnvVars["LD_LIBRARY_PATH"] = path.get();
#elif OS_MACOSX
newEnvVars["DYLD_LIBRARY_PATH"] = path.get();
// XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin
// process, and has no effect on other subprocesses (the hooks in
// libplugin_child_interpose.dylib become noops). But currently it
// gets set when launching any kind of subprocess.
//
// Trigger "dyld interposing" for the dylib that contains
// plugin_child_interpose.mm. This allows us to hook OS calls in the
// plugin process (ones that don't work correctly in a background
// process). Don't break any other "dyld interposing" that has already
// been set up by whatever may have launched the browser.
const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
nsCString interpose;
if (prevInterpose) {
interpose.Assign(prevInterpose);
interpose.AppendLiteral(":");
// XPCOM may not be initialized in some subprocesses. We don't want
// to initialize XPCOM just for the directory service, especially
// since LD_LIBRARY_PATH is already set correctly in subprocesses
// (meaning that we don't need to set that up in the environment).
if (ShouldHaveDirectoryService()) {
nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
NS_ASSERTION(directoryService, "Expected XPCOM to be available");
if (directoryService) {
nsCOMPtr<nsIFile> greDir;
nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
if (NS_SUCCEEDED(rv)) {
nsCString path;
greDir->GetNativePath(path);
# ifdef OS_LINUX
# ifdef ANDROID
path += "/lib";
# endif // ANDROID
newEnvVars["LD_LIBRARY_PATH"] = path.get();
# elif OS_MACOSX
newEnvVars["DYLD_LIBRARY_PATH"] = path.get();
// XXX DYLD_INSERT_LIBRARIES should only be set when launching a plugin
// process, and has no effect on other subprocesses (the hooks in
// libplugin_child_interpose.dylib become noops). But currently it
// gets set when launching any kind of subprocess.
//
// Trigger "dyld interposing" for the dylib that contains
// plugin_child_interpose.mm. This allows us to hook OS calls in the
// plugin process (ones that don't work correctly in a background
// process). Don't break any other "dyld interposing" that has already
// been set up by whatever may have launched the browser.
const char* prevInterpose = PR_GetEnv("DYLD_INSERT_LIBRARIES");
nsCString interpose;
if (prevInterpose) {
interpose.Assign(prevInterpose);
interpose.AppendLiteral(":");
}
interpose.Append(path.get());
interpose.AppendLiteral("/libplugin_child_interpose.dylib");
newEnvVars["DYLD_INSERT_LIBRARIES"] = interpose.get();
# endif // OS_LINUX
}
}
interpose.Append(path.get());
interpose.AppendLiteral("/libplugin_child_interpose.dylib");
newEnvVars["DYLD_INSERT_LIBRARIES"] = interpose.get();
#endif
}
#endif
#endif // OS_LINUX || OS_MACOSX
FilePath exePath;
GetPathToBinary(exePath);
@ -509,18 +529,20 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
childArgv.insert(childArgv.end(), aExtraOpts.begin(), aExtraOpts.end());
// Make sure the child process can find the omnijar
// See XRE_InitCommandLine in nsAppRunner.cpp
nsCAutoString path;
nsCOMPtr<nsIFile> file = mozilla::Omnijar::GetPath(mozilla::Omnijar::GRE);
if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
childArgv.push_back("-greomni");
childArgv.push_back(path.get());
}
file = mozilla::Omnijar::GetPath(mozilla::Omnijar::APP);
if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
childArgv.push_back("-appomni");
childArgv.push_back(path.get());
if (Omnijar::IsInitialized()) {
// Make sure that child processes can find the omnijar
// See XRE_InitCommandLine in nsAppRunner.cpp
nsCAutoString path;
nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
childArgv.push_back("-greomni");
childArgv.push_back(path.get());
}
file = Omnijar::GetPath(Omnijar::APP);
if (file && NS_SUCCEEDED(file->GetNativePath(path))) {
childArgv.push_back("-appomni");
childArgv.push_back(path.get());
}
}
childArgv.push_back(pidstring);
@ -624,18 +646,20 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
cmdLine.AppendLooseValue(std::wstring(mGroupId.get()));
// Make sure the child process can find the omnijar
// See XRE_InitCommandLine in nsAppRunner.cpp
nsAutoString path;
nsCOMPtr<nsIFile> file = mozilla::Omnijar::GetPath(mozilla::Omnijar::GRE);
if (file && NS_SUCCEEDED(file->GetPath(path))) {
cmdLine.AppendLooseValue(UTF8ToWide("-greomni"));
cmdLine.AppendLooseValue(path.get());
}
file = mozilla::Omnijar::GetPath(mozilla::Omnijar::APP);
if (file && NS_SUCCEEDED(file->GetPath(path))) {
cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
cmdLine.AppendLooseValue(path.get());
if (Omnijar::IsInitialized()) {
// Make sure the child process can find the omnijar
// See XRE_InitCommandLine in nsAppRunner.cpp
nsAutoString path;
nsCOMPtr<nsIFile> file = Omnijar::GetPath(Omnijar::GRE);
if (file && NS_SUCCEEDED(file->GetPath(path))) {
cmdLine.AppendLooseValue(UTF8ToWide("-greomni"));
cmdLine.AppendLooseValue(path.get());
}
file = Omnijar::GetPath(Omnijar::APP);
if (file && NS_SUCCEEDED(file->GetPath(path))) {
cmdLine.AppendLooseValue(UTF8ToWide("-appomni"));
cmdLine.AppendLooseValue(path.get());
}
}
cmdLine.AppendLooseValue(UTF8ToWide(pidstring));

View File

@ -68,8 +68,20 @@ EXPORTS_mozilla/ipc = \
Shmem.h \
SyncChannel.h \
ScopedXREEmbed.h \
Transport.h \
$(NULL)
ifeq ($(OS_ARCH),WINNT) #{
EXPORTS_mozilla/ipc += \
Transport_win.h \
$(NULL)
else
# POSIX
EXPORTS_mozilla/ipc += \
Transport_posix.h \
$(NULL)
endif #}
ifeq ($(OS_TARGET),Android)
# Android has its own,
# almost-but-not-quite-compatible-with-POSIX-or-/dev/shm shared memory
@ -85,6 +97,7 @@ CPPSRCS += \
GeckoChildProcessHost.cpp \
MessagePump.cpp \
ProcessChild.cpp \
ProtocolUtils.cpp \
RPCChannel.cpp \
ScopedXREEmbed.cpp \
SharedMemory.cpp \
@ -93,15 +106,19 @@ CPPSRCS += \
SyncChannel.cpp \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
ifeq ($(OS_ARCH),WINNT) #{
CPPSRCS += \
SharedMemory_windows.cpp \
Transport_win.cpp \
WindowsMessageLoop.cpp \
$(NULL)
else
# This generic code works on android.
CPPSRCS += SharedMemory_posix.cpp
endif
# POSIX
CPPSRCS += \
SharedMemory_posix.cpp \
Transport_posix.cpp \
$(NULL)
endif #}
ifeq ($(OS_TARGET),Android)
CPPSRCS += SharedMemoryBasic_android.cpp

161
ipc/glue/ProtocolUtils.cpp Normal file
View File

@ -0,0 +1,161 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Jones <jones.chris.g@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "base/process_util.h"
#include "mozilla/ipc/AsyncChannel.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/ipc/Transport.h"
using namespace base;
using namespace IPC;
namespace mozilla {
namespace ipc {
class ChannelOpened : public IPC::Message
{
public:
ChannelOpened(TransportDescriptor aDescriptor,
ProcessId aOtherProcess,
ProtocolId aProtocol)
: IPC::Message(MSG_ROUTING_CONTROL, // these only go to top-level actors
CHANNEL_OPENED_MESSAGE_TYPE,
PRIORITY_NORMAL)
{
IPC::WriteParam(this, aDescriptor);
IPC::WriteParam(this, aOtherProcess);
IPC::WriteParam(this, static_cast<uint32>(aProtocol));
}
static bool Read(const IPC::Message& aMsg,
TransportDescriptor* aDescriptor,
ProcessId* aOtherProcess,
ProtocolId* aProtocol)
{
void* iter = nsnull;
if (!IPC::ReadParam(&aMsg, &iter, aDescriptor) ||
!IPC::ReadParam(&aMsg, &iter, aOtherProcess) ||
!IPC::ReadParam(&aMsg, &iter, reinterpret_cast<uint32*>(aProtocol))) {
return false;
}
aMsg.EndRead(iter);
return true;
}
};
bool
Bridge(const PrivateIPDLInterface&,
AsyncChannel* aParentChannel, ProcessHandle aParentProcess,
AsyncChannel* aChildChannel, ProcessHandle aChildProcess,
ProtocolId aProtocol)
{
ProcessId parentId = GetProcId(aParentProcess);
ProcessId childId = GetProcId(aChildProcess);
if (!parentId || !childId) {
return false;
}
TransportDescriptor parentSide, childSide;
if (!CreateTransport(aParentProcess, aChildProcess,
&parentSide, &childSide)) {
return false;
}
if (!aParentChannel->Send(new ChannelOpened(parentSide,
childId,
aProtocol)) ||
!aChildChannel->Send(new ChannelOpened(childSide,
parentId,
aProtocol))) {
CloseDescriptor(parentSide);
CloseDescriptor(childSide);
return false;
}
return true;
}
bool
Open(const PrivateIPDLInterface&,
AsyncChannel* aOpenerChannel, ProcessHandle aOtherProcess,
Transport::Mode aOpenerMode,
ProtocolId aProtocol)
{
bool isParent = (Transport::MODE_SERVER == aOpenerMode);
ProcessHandle thisHandle = GetCurrentProcessHandle();
ProcessHandle parentHandle = isParent ? thisHandle : aOtherProcess;
ProcessHandle childHandle = !isParent ? thisHandle : aOtherProcess;
ProcessId parentId = GetProcId(parentHandle);
ProcessId childId = GetProcId(childHandle);
if (!parentId || !childId) {
return false;
}
TransportDescriptor parentSide, childSide;
if (!CreateTransport(parentHandle, childHandle,
&parentSide, &childSide)) {
return false;
}
Message* parentMsg = new ChannelOpened(parentSide, childId, aProtocol);
Message* childMsg = new ChannelOpened(childSide, parentId, aProtocol);
nsAutoPtr<Message> messageForUs(isParent ? parentMsg : childMsg);
nsAutoPtr<Message> messageForOtherSide(!isParent ? parentMsg : childMsg);
if (!aOpenerChannel->Echo(messageForUs.forget()) ||
!aOpenerChannel->Send(messageForOtherSide.forget())) {
CloseDescriptor(parentSide);
CloseDescriptor(childSide);
return false;
}
return true;
}
bool
UnpackChannelOpened(const PrivateIPDLInterface&,
const Message& aMsg,
TransportDescriptor* aTransport,
ProcessId* aOtherProcess,
ProtocolId* aProtocol)
{
return ChannelOpened::Read(aMsg, aTransport, aOtherProcess, aProtocol);
}
} // namespace ipc
} // namespace mozilla

View File

@ -46,12 +46,21 @@
#include "prenv.h"
#include "IPCMessageStart.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/Transport.h"
// WARNING: this takes into account the private, special-message-type
// enum in ipc_channel.h. They need to be kept in sync.
namespace {
// XXX the max message ID is actually kuint32max now ... when this
// changed, the assumptions of the special message IDs changed in that
// they're not carving out messages from likely-unallocated space, but
// rather carving out messages from the end of space allocated to
// protocol 0. Oops! We can get away with this until protocol 0
// starts approaching its 65,536th message.
enum {
CHANNEL_OPENED_MESSAGE_TYPE = kuint16max - 6,
SHMEM_DESTROYED_MESSAGE_TYPE = kuint16max - 5,
UNBLOCK_CHILD_MESSAGE_TYPE = kuint16max - 4,
BLOCK_CHILD_MESSAGE_TYPE = kuint16max - 3,
@ -63,6 +72,7 @@ enum {
namespace mozilla {
namespace ipc {
class AsyncChannel;
// Used to pass references to protocol actors across the wire.
// Actors created on the parent-side have a positive ID, and actors
@ -117,8 +127,9 @@ public:
virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*) = 0;
virtual bool DestroySharedMemory(Shmem&) = 0;
// XXX odd duck, acknowledged
// XXX odd ducks, acknowledged
virtual ProcessHandle OtherProcess() const = 0;
virtual AsyncChannel* GetIPCChannel() = 0;
};
@ -133,6 +144,25 @@ LoggingEnabled()
}
typedef IPCMessageStart ProtocolId;
struct PrivateIPDLInterface {};
bool
Bridge(const PrivateIPDLInterface&,
AsyncChannel*, base::ProcessHandle, AsyncChannel*, base::ProcessHandle,
ProtocolId);
bool
Open(const PrivateIPDLInterface&,
AsyncChannel*, base::ProcessHandle, Transport::Mode,
ProtocolId);
bool
UnpackChannelOpened(const PrivateIPDLInterface&,
const IPC::Message&,
TransportDescriptor*, base::ProcessId*, ProtocolId*);
} // namespace ipc
} // namespace mozilla

View File

@ -1,9 +1,12 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* the License. You may obtain a copy of the License at:
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
@ -11,18 +14,19 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
* The Original Code is Mozilla Code.
*
* The Initial Developer of the Original Code is
* Alexander J. Vincent <ajvincent@gmail.com>.
* Portions created by the Initial Developer are Copyright (C) 2006
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Jones <jones.chris.g@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
@ -34,22 +38,33 @@
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
#ifndef mozilla_ipc_Transport_h
#define mozilla_ipc_Transport_h 1
// Introduced in DOM Level 3:
[scriptable, uuid(2a1088c7-499a-49a7-9d3b-1970d21532ab)]
interface nsIDOM3TypeInfo : nsISupports
{
readonly attribute DOMString typeName;
readonly attribute DOMString typeNamespace;
#include "base/process_util.h"
#include "chrome/common/ipc_channel.h"
// DerivationMethods
const unsigned long DERIVATION_RESTRICTION = 0x00000001;
const unsigned long DERIVATION_EXTENSION = 0x00000002;
const unsigned long DERIVATION_UNION = 0x00000004;
const unsigned long DERIVATION_LIST = 0x00000008;
#ifdef OS_POSIX
# include "mozilla/ipc/Transport_posix.h"
#elif OS_WIN
# include "mozilla/ipc/Transport_win.h"
#endif
boolean isDerivedFrom(in DOMString typeNamespaceArg,
in DOMString typeNameArg,
in unsigned long derivationMethod);
};
namespace mozilla {
namespace ipc {
typedef IPC::Channel Transport;
bool CreateTransport(base::ProcessHandle aProcOne, base::ProcessHandle aProcTwo,
TransportDescriptor* aOne, TransportDescriptor* aTwo);
Transport* OpenDescriptor(const TransportDescriptor& aTd,
Transport::Mode aMode);
void CloseDescriptor(const TransportDescriptor& aTd);
} // namespace ipc
} // namespace mozilla
#endif // mozilla_ipc_Transport_h

View File

@ -0,0 +1,98 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Jones <jones.chris.g@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <unistd.h>
#include <string>
#include "chrome/common/child_process_info.h"
#include "mozilla/ipc/Transport.h"
using namespace base;
using namespace std;
namespace mozilla {
namespace ipc {
bool
CreateTransport(ProcessHandle /*unused*/, ProcessHandle /*unused*/,
TransportDescriptor* aOne, TransportDescriptor* aTwo)
{
// Gecko doesn't care about this random ID, and the argument to this
// function isn't really necessary, it can be just any random
// pointer value
wstring id = ChildProcessInfo::GenerateRandomChannelID(aOne);
// Use MODE_SERVER to force creation of the socketpair
Transport t(id, Transport::MODE_SERVER, nsnull);
int fd1 = t.GetServerFileDescriptor();
int fd2, dontcare;
t.GetClientFileDescriptorMapping(&fd2, &dontcare);
if (fd1 < 0 || fd2 < 0) {
return false;
}
// The Transport closes these fds when it goes out of scope, so we
// dup them here
fd1 = dup(fd1);
fd2 = dup(fd2);
if (fd1 < 0 || fd2 < 0) {
return false;
}
aOne->mFd = FileDescriptor(fd1, true/*close after sending*/);
aTwo->mFd = FileDescriptor(fd2, true/*close after sending*/);
return true;
}
Transport*
OpenDescriptor(const TransportDescriptor& aTd, Transport::Mode aMode)
{
return new Transport(aTd.mFd.fd, aMode, nsnull);
}
void
CloseDescriptor(const TransportDescriptor& aTd)
{
close(aTd.mFd.fd);
}
} // namespace ipc
} // namespace mozilla

View File

@ -1,10 +1,12 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* the License. You may obtain a copy of the License at:
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
@ -12,20 +14,19 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
* The Original Code is Mozilla Code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2000
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vidur Apparao <vidur@netscape.com> (original author)
* Johnny Stenback <jst@netscape.com>
* Chris Jones <jones.chris.g@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
@ -37,20 +38,41 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsIDOMNode.idl"
#ifndef mozilla_ipc_Transport_posix_h
#define mozilla_ipc_Transport_posix_h 1
/**
* The nsIDOMNotation interface represents a notation declared in the DTD.
* A notation either declares, by name, the format of an unparsed entity,
* or is used for formal declaration of processing instruction targets.
*
* For more information on this interface please see
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
#include "IPC/IPCMessageUtils.h"
[scriptable, uuid(43658ade-a157-447a-8dcd-aa7fc824ef0a)]
interface nsIDOMNotation : nsIDOMNode
namespace mozilla {
namespace ipc {
struct TransportDescriptor
{
readonly attribute DOMString publicId;
readonly attribute DOMString systemId;
base::FileDescriptor mFd;
};
} // namespace ipc
} // namespace mozilla
namespace IPC {
template<>
struct ParamTraits<mozilla::ipc::TransportDescriptor>
{
typedef mozilla::ipc::TransportDescriptor paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mFd);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, &aResult->mFd);
}
};
} // namespace IPC
#endif // mozilla_ipc_Transport_posix_h

101
ipc/glue/Transport_win.cpp Normal file
View File

@ -0,0 +1,101 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Jones <jones.chris.g@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "base/message_loop.h"
#include "chrome/common/child_process_info.h"
#include "mozilla/ipc/Transport.h"
using namespace base;
using namespace std;
namespace mozilla {
namespace ipc {
bool
CreateTransport(ProcessHandle aProcOne, ProcessHandle /*unused*/,
TransportDescriptor* aOne, TransportDescriptor* aTwo)
{
// This id is used to name the IPC pipe. The pointer passed to this
// function isn't significant.
wstring id = ChildProcessInfo::GenerateRandomChannelID(aOne);
// Use MODE_SERVER to force creation of the pipe
Transport t(id, Transport::MODE_SERVER, nsnull);
HANDLE serverPipe = t.GetServerPipeHandle();
if (!serverPipe) {
return false;
}
// NB: we create the server pipe immediately, instead of just
// grabbing an ID, on purpose. In the current setup, the client
// needs to connect to an existing server pipe, so to prevent race
// conditions, we create the server side here and then dup it to the
// eventual server process.
HANDLE serverDup;
DWORD access = 0;
DWORD options = DUPLICATE_SAME_ACCESS;
if (!DuplicateHandle(GetCurrentProcess(), serverPipe, aProcOne,
&serverDup,
access,
FALSE/*not inheritable*/,
options)) {
return false;
}
aOne->mPipeName = aTwo->mPipeName = id;
aOne->mServerPipe = serverDup;
aTwo->mServerPipe = 0;
return true;
}
Transport*
OpenDescriptor(const TransportDescriptor& aTd, Transport::Mode aMode)
{
return new Transport(aTd.mPipeName, aTd.mServerPipe, aMode, nsnull);
}
void
CloseDescriptor(const TransportDescriptor& aTd)
{
CloseHandle(aTd.mServerPipe);
}
} // namespace ipc
} // namespace mozilla

83
ipc/glue/Transport_win.h Normal file
View File

@ -0,0 +1,83 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Jones <jones.chris.g@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_ipc_Transport_win_h
#define mozilla_ipc_Transport_win_h 1
#include <string>
#include "IPC/IPCMessageUtils.h"
namespace mozilla {
namespace ipc {
struct TransportDescriptor
{
std::wstring mPipeName;
HANDLE mServerPipe;
};
} // namespace ipc
} // namespace mozilla
namespace IPC {
template<>
struct ParamTraits<mozilla::ipc::TransportDescriptor>
{
typedef mozilla::ipc::TransportDescriptor paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mPipeName);
WriteParam(aMsg, aParam.mServerPipe);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return (ReadParam(aMsg, aIter, &aResult->mPipeName) &&
ReadParam(aMsg, aIter, &aResult->mServerPipe));
}
};
} // namespace IPC
#endif // mozilla_ipc_Transport_win_h

View File

@ -97,6 +97,7 @@ $(foreach IPDLDIR,$(IPDLDIRS),$(eval $(ADD_IPDLDIR)))
CPPSRCS = \
$(PROTOCOLS:%.ipdl=%Parent.cpp) \
$(PROTOCOLS:%.ipdl=%Child.cpp) \
$(PROTOCOLS:%.ipdl=%.cpp) \
$(NULL)
GARBAGE += $(CPPSRCS)

View File

@ -75,14 +75,19 @@ log(2, 'Generated C++ sources will be generated in "%s"', cppdir)
allprotocols = []
def normalizedFilename(f):
if f == '-':
return '<stdin>'
return f
# First pass: parse and type-check all protocols
for f in files:
log(1, os.path.basename(f))
filename = normalizedFilename(f)
if f == '-':
fd = sys.stdin
filename = '<stdin>'
else:
fd = open(f)
filename = f
specstring = fd.read()
fd.close()
@ -92,8 +97,6 @@ for f in files:
print >>sys.stderr, 'Specification could not be parsed.'
sys.exit(1)
allprotocols.append('%sMsgStart' % ast.protocol.name)
log(2, 'checking types')
if not ipdl.typecheck(ast):
print >>sys.stderr, 'Specification is not well typed.'
@ -103,7 +106,14 @@ for f in files:
log(3, ' pretty printed code:')
ipdl.genipdl(ast, codedir)
# Second pass: generate code
for f in files:
# Read from parser cache
filename = normalizedFilename(f)
ast = ipdl.parse(None, filename, includedirs=includedirs)
ipdl.gencxx(filename, ast, headersdir, cppdir)
allprotocols.append('%sMsgStart' % ast.protocol.name)
allprotocols.sort()

View File

@ -77,6 +77,8 @@ class Visitor:
spawns.accept(self)
for bridges in p.bridgesStmts:
bridges.accept(self)
for opens in p.opensStmts:
opens.accept(self)
for mgr in p.managers:
mgr.accept(self)
for managed in p.managesStmts:
@ -95,6 +97,9 @@ class Visitor:
def visitBridgesStmt(self, bridges):
pass
def visitOpensStmt(self, opens):
pass
def visitManager(self, mgr):
pass
@ -269,6 +274,7 @@ class Protocol(NamespacedNode):
self.sendSemantics = ASYNC
self.spawnsStmts = [ ]
self.bridgesStmts = [ ]
self.opensStmts = [ ]
self.managers = [ ]
self.managesStmts = [ ]
self.messageDecls = [ ]
@ -304,6 +310,12 @@ class BridgesStmt(Node):
self.parentSide = parentSide
self.childSide = childSide
class OpensStmt(Node):
def __init__(self, loc, side, proto):
Node.__init__(self, loc)
self.side = side
self.proto = proto
class Manager(Node):
def __init__(self, loc, managerName):
Node.__init__(self, loc)

View File

@ -110,6 +110,12 @@ class Visitor:
meth.decl.accept(self)
self.visitBlock(meth)
def visitFunctionDecl(self, fun):
self.visitMethodDecl(fun)
def visitFunctionDefn(self, fd):
self.visitMethodDefn(fd)
def visitConstructorDecl(self, ctor):
self.visitMethodDecl(ctor)
@ -509,6 +515,20 @@ class MethodDefn(Block):
Block.__init__(self)
self.decl = decl
class FunctionDecl(MethodDecl):
def __init__(self, name, params=[ ], ret=Type('void'),
static=0, warn_unused=0,
inline=0, force_inline=0,
T=None):
MethodDecl.__init__(self, name, params=params, ret=ret,
static=static, warn_unused=warn_unused,
inline=inline, force_inline=force_inline,
T=T)
class FunctionDefn(MethodDefn):
def __init__(self, decl):
MethodDefn.__init__(self, decl)
class ConstructorDecl(MethodDecl):
def __init__(self, name, params=[ ], explicit=0, force_inline=0):
MethodDecl.__init__(self, name, params=params, ret=None,

View File

@ -35,7 +35,7 @@ from copy import deepcopy
import ipdl.ast
from ipdl.cxx.ast import *
from ipdl.type import TypeVisitor
from ipdl.type import ActorType, ProcessGraph, TypeVisitor
# FIXME/cjones: the chromium Message logging code doesn't work on
# gcc/POSIX, because it wprintf()s across the chromium/mozilla
@ -55,8 +55,8 @@ lowered form of |tu|'''
pname = tu.protocol.name
pheader = File(pname +'.h')
_GenerateProtocolHeader().lower(tu, pheader)
pheader, pcpp = File(pname +'.h'), File(pname +'.cpp')
_GenerateProtocolCode().lower(tu, pheader, pcpp)
parentheader, parentcpp = File(pname +'Parent.h'), File(pname +'Parent.cpp')
_GenerateProtocolParentCode().lower(
@ -66,7 +66,7 @@ lowered form of |tu|'''
_GenerateProtocolChildCode().lower(
tu, pname+'Child', childheader, childcpp)
return [ pheader, parentheader, childheader ], [ parentcpp, childcpp ]
return [ pheader, parentheader, childheader ], [ pcpp, parentcpp, childcpp ]
##-----------------------------------------------------------------------------
@ -76,6 +76,14 @@ lowered form of |tu|'''
_NULL_ACTOR_ID = ExprLiteral.ZERO
_FREED_ACTOR_ID = ExprLiteral.ONE
_DISCLAIMER = Whitespace('''//
// Automatically generated by ipdlc.
// Edit at your own risk
//
''')
class _struct: pass
def _protocolHeaderName(p, side=''):
@ -134,6 +142,9 @@ def _actorManager(actor):
def _actorState(actor):
return ExprSelect(actor, '->', 'mState')
def _backstagePass():
return ExprCall(ExprVar('mozilla::ipc::PrivateIPDLInterface'))
def _nullState(proto=None):
pfx = ''
if proto is not None: pfx = proto.name() +'::'
@ -346,6 +357,11 @@ def _otherSide(side):
if side == 'parent': return 'child'
assert 0
def _sideToTransportMode(side):
if side == 'parent': mode = 'SERVER'
elif side == 'child': mode = 'CLIENT'
return ExprVar('mozilla::ipc::Transport::MODE_'+ mode)
def _ifLogging(stmts):
iflogging = StmtIf(ExprCall(ExprVar('mozilla::ipc::LoggingEnabled')))
iflogging.addifstmts(stmts)
@ -1052,6 +1068,21 @@ class Protocol(ipdl.ast.Protocol):
def otherProcessMethod(self):
return ExprVar('OtherProcess')
def callOtherProcess(self, actorThis=None):
fn = self.otherProcessMethod()
if actorThis is not None:
fn = ExprSelect(actorThis, '->', fn.name)
return ExprCall(fn)
def getChannelMethod(self):
return ExprVar('GetIPCChannel')
def callGetChannel(self, actorThis=None):
fn = self.getChannelMethod()
if actorThis is not None:
fn = ExprSelect(actorThis, '->', fn.name)
return ExprCall(fn)
def processingErrorVar(self):
assert self.decl.type.isToplevel()
return ExprVar('ProcessingError')
@ -1311,46 +1342,58 @@ with some new IPDL/C++ nodes that are tuned for C++ codegen."""
##-----------------------------------------------------------------------------
class _GenerateProtocolHeader(ipdl.ast.Visitor):
'''Creates a header containing code common to both the parent and
child actors.'''
class _GenerateProtocolCode(ipdl.ast.Visitor):
'''Creates code common to both the parent and child actors.'''
def __init__(self):
self.protocol = None # protocol we're generating a class for
self.file = None # File stuff is stuck in
self.hdrfile = None # what will become Protocol.h
self.cppfile = None # what will become Protocol.cpp
self.cppIncludeHeaders = []
self.structUnionDefns = []
self.funcDefns = []
def lower(self, tu, outcxxfile):
def lower(self, tu, cxxHeaderFile, cxxFile):
self.protocol = tu.protocol
self.file = outcxxfile
self.hdrfile = cxxHeaderFile
self.cppfile = cxxFile
tu.accept(self)
def visitTranslationUnit(self, tu):
f = self.file
hf = self.hdrfile
f.addthing(Whitespace('''//
// Automatically generated by the IPDL compiler.
// Edit at your own risk
//
'''))
f.addthings(_includeGuardStart(f))
f.addthing(Whitespace.NL)
hf.addthing(_DISCLAIMER)
hf.addthings(_includeGuardStart(hf))
hf.addthing(Whitespace.NL)
ipdl.ast.Visitor.visitTranslationUnit(self, tu)
f.addthings(self.structUnionDefns)
hf.addthing(Whitespace.NL)
hf.addthings(_includeGuardEnd(hf))
f.addthing(Whitespace.NL)
f.addthings(_includeGuardEnd(f))
cf = self.cppfile
cf.addthings((
[ _DISCLAIMER, Whitespace.NL ]
+ [ CppDirective('include','"'+h+'.h"')
for h in self.cppIncludeHeaders ]
+ [ Whitespace.NL ]
))
# construct the namespace into which we'll stick all our defns
ns = Namespace(self.protocol.name)
cf.addthing(_putInNamespaces(ns, self.protocol.namespaces))
ns.addstmts(([ Whitespace.NL]
+ self.funcDefns
+[ Whitespace.NL ]))
cf.addthings(self.structUnionDefns)
def visitCxxInclude(self, inc):
self.file.addthing(CppDirective('include', '"'+ inc.file +'"'))
self.hdrfile.addthing(CppDirective('include', '"'+ inc.file +'"'))
def processStructOrUnionClass(self, su, which, forwarddecls, cls):
clsdecl, methoddefns = _splitClassDeclDefn(cls, inlinedefns=1)
clsdecl, methoddefns = _splitClassDeclDefn(cls)
self.file.addthings(
self.hdrfile.addthings(
[ Whitespace.NL ]
+ forwarddecls
+ [ Whitespace("""
@ -1379,7 +1422,29 @@ child actors.'''
*_generateCxxUnion(ud))
def visitProtocol(self, p):
self.file.addthing(Whitespace("""
self.cppIncludeHeaders.append(_protocolHeaderName(self.protocol, ''))
bridges = ProcessGraph.bridgesOf(p.decl.type)
for bridge in bridges:
ppt, pside = bridge.parent.ptype, _otherSide(bridge.parent.side)
cpt, cside = bridge.child.ptype, _otherSide(bridge.child.side)
self.hdrfile.addthings([
Whitespace.NL,
_makeForwardDeclForActor(ppt, pside),
_makeForwardDeclForActor(cpt, cside)
])
self.cppIncludeHeaders.append(_protocolHeaderName(ppt._p, pside))
self.cppIncludeHeaders.append(_protocolHeaderName(cpt._p, cside))
opens = ProcessGraph.opensOf(p.decl.type)
for o in opens:
optype, oside = o.opener.ptype, o.opener.side
self.hdrfile.addthings([
Whitespace.NL,
_makeForwardDeclForActor(optype, oside)
])
self.cppIncludeHeaders.append(_protocolHeaderName(optype._p, oside))
self.hdrfile.addthing(Whitespace("""
//-----------------------------------------------------------------------------
// Code common to %sChild and %sParent
//
@ -1387,9 +1452,22 @@ child actors.'''
# construct the namespace into which we'll stick all our decls
ns = Namespace(self.protocol.name)
self.file.addthing(_putInNamespaces(ns, p.namespaces))
self.hdrfile.addthing(_putInNamespaces(ns, p.namespaces))
ns.addstmt(Whitespace.NL)
# user-facing methods for connecting two process with a new channel
for bridge in bridges:
bdecl, bdefn = _splitFuncDeclDefn(self.genBridgeFunc(bridge))
ns.addstmts([ bdecl, Whitespace.NL ])
self.funcDefns.append(bdefn)
# user-facing methods for opening a new channel across two
# existing endpoints
for o in opens:
odecl, odefn = _splitFuncDeclDefn(self.genOpenFunc(o))
ns.addstmts([ odecl, Whitespace.NL ])
self.funcDefns.append(odefn)
# state information
stateenum = TypeEnum('State')
# NB: __Dead is the first state on purpose, so that it has
@ -1421,7 +1499,9 @@ child actors.'''
msgenum.addId(self.protocol.name +'End')
ns.addstmts([ StmtDecl(Decl(msgenum, '')), Whitespace.NL ])
ns.addstmts([ self.genTransitionFunc(), Whitespace.NL ])
tfDecl, tfDefn = _splitFuncDeclDefn(self.genTransitionFunc())
ns.addstmts([ tfDecl, Whitespace.NL ])
self.funcDefns.append(tfDefn)
typedefs = self.protocol.decl.cxxtypedefs
for md in p.messageDecls:
@ -1439,6 +1519,50 @@ child actors.'''
ns.addstmts([ Whitespace.NL, Whitespace.NL ])
def genBridgeFunc(self, bridge):
p = self.protocol
parentHandleType = _cxxBareType(ActorType(bridge.parent.ptype),
_otherSide(bridge.parent.side))
parentvar = ExprVar('parentHandle')
childHandleType = _cxxBareType(ActorType(bridge.child.ptype),
_otherSide(bridge.child.side))
childvar = ExprVar('childHandle')
bridgefunc = MethodDefn(MethodDecl(
'Bridge',
params=[ Decl(parentHandleType, parentvar.name),
Decl(childHandleType, childvar.name) ],
ret=Type.BOOL))
bridgefunc.addstmt(StmtReturn(ExprCall(
ExprVar('mozilla::ipc::Bridge'),
args=[ _backstagePass(),
p.callGetChannel(parentvar), p.callOtherProcess(parentvar),
p.callGetChannel(childvar), p.callOtherProcess(childvar),
_protocolId(p.decl.type)
])))
return bridgefunc
def genOpenFunc(self, o):
p = self.protocol
localside = o.opener.side
openertype = _cxxBareType(ActorType(o.opener.ptype), o.opener.side)
openervar = ExprVar('opener')
openfunc = MethodDefn(MethodDecl(
'Open',
params=[ Decl(openertype, openervar.name) ],
ret=Type.BOOL))
openfunc.addstmt(StmtReturn(ExprCall(
ExprVar('mozilla::ipc::Open'),
args=[ _backstagePass(),
p.callGetChannel(openervar), p.callOtherProcess(openervar),
_sideToTransportMode(localside),
_protocolId(p.decl.type)
])))
return openfunc
def genTransitionFunc(self):
ptype = self.protocol.decl.type
usesend, sendvar = set(), ExprVar('__Send')
@ -1466,13 +1590,12 @@ child actors.'''
msgexpr = ExprSelect(triggervar, '.', 'mMsg')
actionexpr = ExprSelect(triggervar, '.', 'mAction')
transitionfunc = MethodDefn(MethodDecl(
transitionfunc = FunctionDefn(FunctionDecl(
'Transition',
params=[ Decl(Type('State'), fromvar.name),
Decl(Type('mozilla::ipc::Trigger'), triggervar.name),
Decl(Type('State', ptr=1), nextvar.name) ],
ret=Type.BOOL,
inline=1))
ret=Type.BOOL))
fromswitch = StmtSwitch(fromvar)
@ -2244,6 +2367,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
Typedef(Type(self.protocol.channelName()), 'Channel'),
Typedef(Type(self.protocol.fqListenerName()), 'ChannelListener'),
Typedef(Type('base::ProcessHandle'), 'ProcessHandle'),
Typedef(Type('mozilla::ipc::AsyncChannel'), 'AsyncChannel'),
Typedef(Type('mozilla::ipc::SharedMemory'), 'SharedMemory'),
Typedef(Type('mozilla::ipc::Trigger'), 'Trigger')
]
@ -2255,15 +2379,9 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
hf = self.hdrfile
cf = self.cppfile
disclaimer = Whitespace('''//
// Automatically generated by ipdlc.
// Edit at your own risk
//
''')
# make the C++ header
hf.addthings(
[ disclaimer ]
[ _DISCLAIMER ]
+ _includeGuardStart(hf)
+[
Whitespace.NL,
@ -2318,7 +2436,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
# make the .cpp file
cf.addthings([
disclaimer,
_DISCLAIMER,
Whitespace.NL,
CppDirective(
'include',
@ -2396,6 +2514,10 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
Inherit(p.managerInterfaceType(), viz='protected') ],
abstract=True)
bridgeActorsCreated = ProcessGraph.bridgeEndpointsOf(ptype, self.side)
opensActorsCreated = ProcessGraph.opensEndpointsOf(ptype, self.side)
channelOpenedActors = bridgeActorsCreated + opensActorsCreated
friends = _FindFriends().findFriends(ptype)
if ptype.isManaged():
friends.update(ptype.managers)
@ -2417,11 +2539,27 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
self.prettyside)),
Whitespace.NL ])
for actor in channelOpenedActors:
self.hdrfile.addthings([
Whitespace.NL,
_makeForwardDeclForActor(actor.ptype, actor.side),
Whitespace.NL
])
self.cls.addstmt(Label.PROTECTED)
for typedef in p.cxxTypedefs():
self.cls.addstmt(typedef)
for typedef in self.includedActorTypedefs:
self.cls.addstmt(typedef)
# XXX these don't really fit in the other lists; just include
# them here for now
self.cls.addstmts([
Typedef(Type('base::ProcessId'), 'ProcessId'),
Typedef(Type('mozilla::ipc::ProtocolId'), 'ProtocolId'),
Typedef(Type('mozilla::ipc::Transport'), 'Transport'),
Typedef(Type('mozilla::ipc::TransportDescriptor'), 'TransportDescriptor')
])
self.cls.addstmt(Whitespace.NL)
self.cls.addstmts([ Typedef(p.fqStateType(), 'State'), Whitespace.NL ])
@ -2467,6 +2605,17 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
ret=Type.BOOL,
virtual=1, pure=1)))
for actor in channelOpenedActors:
# add the Alloc interface for actors created when a
# new channel is opened
actortype = _cxxBareType(actor.asType(), actor.side)
self.cls.addstmt(StmtDecl(MethodDecl(
_allocMethod(actor.ptype).name,
params=[ Decl(Type('Transport', ptr=1), 'transport'),
Decl(Type('ProcessId'), 'otherProcess') ],
ret=actortype,
virtual=1, pure=1)))
# optional ActorDestroy() method; default is no-op
self.cls.addstmts([
Whitespace.NL,
@ -2551,6 +2700,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
aTransportVar = ExprVar('aTransport')
aThreadVar = ExprVar('aThread')
processvar = ExprVar('aOtherProcess')
sidevar = ExprVar('aSide')
openmeth = MethodDefn(
MethodDecl(
'Open',
@ -2559,13 +2709,16 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
Decl(Type('ProcessHandle'), processvar.name),
Param(Type('MessageLoop', ptr=True),
aThreadVar.name,
default=ExprLiteral.NULL) ],
default=ExprLiteral.NULL),
Param(Type('AsyncChannel::Side'),
sidevar.name,
default=ExprVar('Channel::Unknown')) ],
ret=Type.BOOL))
openmeth.addstmts([
StmtExpr(ExprAssn(p.otherProcessVar(), processvar)),
StmtReturn(ExprCall(ExprSelect(p.channelVar(), '.', 'Open'),
[ aTransportVar, aThreadVar ]))
[ aTransportVar, aThreadVar, sidevar ]))
])
self.cls.addstmts([
openmeth,
@ -2656,6 +2809,11 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
for md in p.messageDecls:
self.visitMessageDecl(md)
# Handlers for the creation of actors when a new channel is
# opened
if len(channelOpenedActors):
self.makeChannelOpenedHandlers(channelOpenedActors)
# add default cases
default = StmtBlock()
default.addstmt(StmtReturn(_Result.NotKnown))
@ -2939,8 +3097,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
Whitespace.NL
])
ifkill = StmtIf(ExprNot(
_killProcess(ExprCall(p.otherProcessMethod()))))
ifkill = StmtIf(ExprNot(_killProcess(p.callOtherProcess())))
ifkill.addifstmt(
_printErrorMessage(" may have failed to kill child!"))
fatalerror.addstmt(ifkill)
@ -3178,6 +3335,10 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
ret=Type('ProcessHandle'),
const=1,
virtual=1))
getchannel = MethodDefn(MethodDecl(
p.getChannelMethod().name,
ret=Type('AsyncChannel', ptr=1),
virtual=1))
if p.decl.type.isToplevel():
tmpvar = ExprVar('tmp')
@ -3230,7 +3391,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
p.nextShmemIdExpr(self.side) ]),
StmtDecl(Decl(Type('Message', ptr=1), descriptorvar.name),
init=_shmemShareTo(shmemvar,
ExprCall(p.otherProcessMethod()),
p.callOtherProcess(),
p.routingId()))
])
failif = StmtIf(ExprNot(descriptorvar))
@ -3271,7 +3432,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
p.nextShmemIdExpr(self.side) ]),
StmtDecl(Decl(Type('Message', ptr=1), descriptorvar.name),
init=_shmemShareTo(shmemvar,
ExprCall(p.otherProcessMethod()),
p.callOtherProcess(),
p.routingId()))
])
failif = StmtIf(ExprNot(descriptorvar))
@ -3325,7 +3486,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
StmtDecl(Decl(Type('Message', ptr=1), descriptorvar.name),
init=_shmemUnshareFrom(
shmemvar,
ExprCall(p.otherProcessMethod()),
p.callOtherProcess(),
p.routingId())),
Whitespace.NL,
StmtExpr(p.removeShmemId(idvar)),
@ -3360,6 +3521,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
CaseLabel('SHMEM_DESTROYED_MESSAGE_TYPE'), abort)
otherprocess.addstmt(StmtReturn(p.otherProcessVar()))
getchannel.addstmt(StmtReturn(ExprAddrOf(p.channelVar())))
else:
# delegate registration to manager
register.addstmt(StmtReturn(ExprCall(
@ -3390,9 +3552,9 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
destroyshmem.addstmt(StmtReturn(ExprCall(
ExprSelect(p.managerVar(), '->', p.destroySharedMemory().name),
[ shmemvar ])))
otherprocess.addstmt(StmtReturn(ExprCall(
ExprSelect(p.managerVar(), '->',
p.otherProcessMethod().name))))
otherprocess.addstmt(StmtReturn(
p.callOtherProcess(p.managerVar())))
getchannel.addstmt(StmtReturn(p.channelVar()))
# all protocols share the "same" RemoveManagee() implementation
pvar = ExprVar('aProtocolId')
@ -3445,6 +3607,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
istracking,
destroyshmem,
otherprocess,
getchannel,
Whitespace.NL ]
def makeShmemIface(self):
@ -3635,6 +3798,68 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return case
def makeChannelOpenedHandlers(self, actors):
handlers = StmtBlock()
# unpack the transport descriptor et al.
msgvar = self.msgvar
tdvar = ExprVar('td')
pidvar = ExprVar('pid')
pvar = ExprVar('p')
iffail = StmtIf(ExprNot(ExprCall(
ExprVar('mozilla::ipc::UnpackChannelOpened'),
args=[ _backstagePass(),
msgvar,
ExprAddrOf(tdvar), ExprAddrOf(pidvar), ExprAddrOf(pvar) ])))
iffail.addifstmt(StmtReturn(_Result.PayloadError))
handlers.addstmts([
StmtDecl(Decl(Type('TransportDescriptor'), tdvar.name)),
StmtDecl(Decl(Type('ProcessId'), pidvar.name)),
StmtDecl(Decl(Type('ProtocolId'), pvar.name)),
iffail,
Whitespace.NL
])
def makeHandlerCase(actor):
case = StmtBlock()
modevar = _sideToTransportMode(actor.side)
tvar = ExprVar('t')
iffailopen = StmtIf(ExprNot(ExprAssn(
tvar,
ExprCall(ExprVar('mozilla::ipc::OpenDescriptor'),
args=[ tdvar, modevar ]))))
iffailopen.addifstmt(StmtReturn(_Result.ValuError))
iffailalloc = StmtIf(ExprNot(ExprCall(
_allocMethod(actor.ptype),
args=[ tvar, pidvar ])))
iffailalloc.addifstmt(StmtReturn(_Result.ProcessingError))
case.addstmts([
StmtDecl(Decl(Type('Transport', ptr=1), tvar.name)),
iffailopen,
iffailalloc,
StmtBreak()
])
return CaseLabel(_protocolId(actor.ptype).name), case
pswitch = StmtSwitch(pvar)
for actor in actors:
label, case = makeHandlerCase(actor)
pswitch.addcase(label, case)
die = Block()
die.addstmts([ _runtimeAbort('Invalid protocol'),
StmtReturn(_Result.ValuError) ])
pswitch.addcase(DefaultLabel(), die)
handlers.addstmts([
pswitch,
StmtReturn(_Result.Processed)
])
self.asyncSwitch.addcase(CaseLabel('CHANNEL_OPENED_MESSAGE_TYPE'),
handlers)
##-------------------------------------------------------------------------
## The next few functions are the crux of the IPDL code generator.
## They generate code for all the nasty work of message
@ -4684,7 +4909,7 @@ class _GenerateProtocolChildCode(_GenerateProtocolActorCode):
## Utility passes
##
def _splitClassDeclDefn(cls, inlinedefns=0):
def _splitClassDeclDefn(cls):
"""Destructively split |cls| methods into declarations and
definitions (if |not methodDecl.force_inline|). Return classDecl,
methodDefns."""
@ -4692,25 +4917,29 @@ methodDefns."""
for i, stmt in enumerate(cls.stmts):
if isinstance(stmt, MethodDefn) and not stmt.decl.force_inline:
decl, defn = _splitMethodDefn(stmt, cls.name, inlinedefns)
decl, defn = _splitMethodDefn(stmt, cls.name)
cls.stmts[i] = StmtDecl(decl)
defns.addstmts([ defn, Whitespace.NL ])
return cls, defns
def _splitMethodDefn(md, clsname, inlinedefn):
def _splitMethodDefn(md, clsname):
saveddecl = deepcopy(md.decl)
md.decl.name = (clsname +'::'+ md.decl.name)
md.decl.virtual = 0
md.decl.static = 0
md.decl.warn_unused = 0
md.decl.inline = inlinedefn
for param in md.decl.params:
if isinstance(param, Param):
param.default = None
return saveddecl, md
def _splitFuncDeclDefn(fun):
assert not fun.decl.inline
return StmtDecl(fun.decl), fun
# XXX this is tantalizingly similar to _splitClassDeclDefn, but just
# different enough that I don't see the need to define
# _GenerateSkeleton in terms of that

View File

@ -155,6 +155,7 @@ reserved = set((
'manages',
'namespace',
'nullable',
'opens',
'or',
'parent',
'protocol',
@ -343,7 +344,7 @@ def p_ProtocolBody(p):
p[0] = p[1]
##--------------------
## spawns/bridges stmts
## spawns/bridges/opens stmts
def p_SpawnsStmtsOpt(p):
"""SpawnsStmtsOpt : SpawnsStmt SpawnsStmtsOpt
@ -370,7 +371,7 @@ def p_AsOpt(p):
def p_BridgesStmtsOpt(p):
"""BridgesStmtsOpt : BridgesStmt BridgesStmtsOpt
| ManagersStmtOpt"""
| OpensStmtsOpt"""
if 2 == len(p):
p[0] = p[1]
else:
@ -381,6 +382,20 @@ def p_BridgesStmt(p):
"""BridgesStmt : BRIDGES ID ',' ID ';'"""
p[0] = BridgesStmt(locFromTok(p, 1), p[2], p[4])
def p_OpensStmtsOpt(p):
"""OpensStmtsOpt : OpensStmt OpensStmtsOpt
| ManagersStmtOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].opensStmts.insert(0, p[1])
p[0] = p[2]
def p_OpensStmt(p):
"""OpensStmt : PARENT OPENS ID ';'
| CHILD OPENS ID ';'"""
p[0] = OpensStmt(locFromTok(p, 1), p[1], p[3])
##--------------------
## manager/manages stmts

View File

@ -294,7 +294,7 @@ class ProtocolType(IPDLType):
self.qname = qname
self.sendSemantics = sendSemantics
self.spawns = set() # ProtocolType
self.bridges = set() # [ Bridge ]
self.opens = set() # ProtocolType
self.managers = set() # ProtocolType
self.manages = [ ]
self.stateless = stateless
@ -314,8 +314,9 @@ class ProtocolType(IPDLType):
assert self.isToplevel() and ptype.isToplevel()
self.spawns.add(ptype)
def addBridge(self, parentPType, childPType):
self.bridges.add(Bridge(parentPType, childPType))
def addOpen(self, ptype):
assert self.isToplevel() and ptype.isToplevel()
self.opens.add(ptype)
def managedBy(self, mgr):
self.managers = mgr
@ -777,6 +778,9 @@ class GatherDecls(TcheckVisitor):
for bridges in p.bridgesStmts:
bridges.accept(self)
for opens in p.opensStmts:
opens.accept(self)
seenmgrs = set()
for mgr in p.managers:
if mgr.name in seenmgrs:
@ -927,6 +931,14 @@ class GatherDecls(TcheckVisitor):
bridges.parentSide = lookup(bridges.parentSide)
bridges.childSide = lookup(bridges.childSide)
def visitOpensStmt(self, opens):
pname = opens.proto
opens.proto = self.symtab.lookup(pname)
if opens.proto is None:
self.error(opens.loc,
"opened protocol `%s' has not been declared",
pname)
def visitManager(self, mgr):
mgrdecl = self.symtab.lookup(mgr.name)
@ -1234,6 +1246,11 @@ class CheckTypes(TcheckVisitor):
"protocol `%s' is not top-level and so cannot declare |bridges|",
pname)
if len(p.opensStmts) and not ptype.isToplevel():
self.error(p.decl.loc,
"protocol `%s' is not top-level and so cannot declare |opens|",
pname)
for mgrtype in ptype.managers:
if mgrtype is not None and ptype.needsMoreJuiceThan(mgrtype):
self.error(
@ -1300,8 +1317,23 @@ class CheckTypes(TcheckVisitor):
self.error(bridges.loc,
"cannot bridge non-top-level-protocol(s) `%s' and `%s'",
parentType.name(), childType.name())
def visitOpensStmt(self, opens):
if not self.ptype.isToplevel():
self.error(opens.loc,
"only top-level protocols can have |opens| statements; `%s' cannot",
self.ptype.name())
return
openedType = opens.proto.type
if not (openedType.isIPDL() and openedType.isProtocol()
and openedType.isToplevel()):
self.error(opens.loc,
"cannot open non-top-level-protocol `%s'",
openedType.name())
else:
self.ptype.addBridge(parentType, childType)
self.ptype.addOpen(openedType)
def visitManagesStmt(self, mgs):
@ -1442,6 +1474,8 @@ class Actor:
self.ptype = ptype
self.side = side
def asType(self):
return ActorType(self.ptype)
def other(self):
return Actor(self.ptype, _otherside(self.side))
@ -1471,11 +1505,20 @@ class BridgeEdge:
self.parent, self.bridgeProto.name(), self.child)
def __str__(self): return repr(self)
class OpensEdge:
def __init__(self, opener, openedProto):
self.opener = opener # Actor
self.openedProto = openedProto # ProtocolType
def __repr__(self):
return '(%r)--opens-->(%s)'% (self.opener, self.openedProto.name())
def __str__(self): return repr(self)
# "singleton" class with state that persists across type checking of
# all protocols
class ProcessGraph:
processes = set() # set(Process)
bridges = { } # ProtocolType -> BridgeEdge
bridges = { } # ProtocolType -> [ BridgeEdge ]
opens = { } # ProtocolType -> [ OpensEdge ]
actorToProcess = { } # Actor -> Process
visitedSpawns = set() # set(ActorType)
visitedBridges = set() # set(ActorType)
@ -1493,6 +1536,48 @@ class ProcessGraph:
cls.actorToProcess[actor] = p
return cls.actorToProcess[actor]
@classmethod
def bridgesOf(cls, bridgeP):
return cls.bridges.get(bridgeP, [])
@classmethod
def bridgeEndpointsOf(cls, ptype, side):
actor = Actor(ptype, side)
endpoints = []
for b in cls.iterbridges():
if b.parent == actor:
endpoints.append(Actor(b.bridgeProto, 'parent'))
elif b.child == actor:
endpoints.append(Actor(b.bridgeProto, 'child'))
return endpoints
@classmethod
def iterbridges(cls):
for edges in cls.bridges.itervalues():
for bridge in edges:
yield bridge
@classmethod
def opensOf(cls, openedP):
return cls.opens.get(openedP, [])
@classmethod
def opensEndpointsOf(cls, ptype, side):
actor = Actor(ptype, side)
endpoints = []
for o in cls.iteropens():
if actor == o.opener:
endpoints.append(Actor(o.openedProto, o.opener.side))
elif actor == o.opener.other():
endpoints.append(Actor(o.openedProto, o.opener.other().side))
return endpoints
@classmethod
def iteropens(cls):
for edges in cls.opens.itervalues():
for opens in edges:
yield opens
@classmethod
def spawn(cls, spawner, remoteSpawn):
localSpawn = remoteSpawn.other()
@ -1502,7 +1587,26 @@ class ProcessGraph:
@classmethod
def bridge(cls, parent, child, bridgeP):
cls.bridges[bridgeP] = BridgeEdge(bridgeP, parent, child)
bridgeParent = Actor(bridgeP, 'parent')
parentProcess = ProcessGraph.getProcess(parent)
parentProcess.merge(ProcessGraph.getProcess(bridgeParent))
bridgeChild = Actor(bridgeP, 'child')
childProcess = ProcessGraph.getProcess(child)
childProcess.merge(ProcessGraph.getProcess(bridgeChild))
if bridgeP not in cls.bridges:
cls.bridges[bridgeP] = [ ]
cls.bridges[bridgeP].append(BridgeEdge(bridgeP, parent, child))
@classmethod
def open(cls, opener, opened, openedP):
remoteOpener, remoteOpened, = opener.other(), opened.other()
openerProcess = ProcessGraph.getProcess(opener)
openerProcess.merge(ProcessGraph.getProcess(opened))
remoteOpenerProcess = ProcessGraph.getProcess(remoteOpener)
remoteOpenerProcess.merge(ProcessGraph.getProcess(remoteOpened))
if openedP not in cls.opens:
cls.opens[openedP] = [ ]
cls.opens[openedP].append(OpensEdge(opener, openedP))
class BuildProcessGraph(TcheckVisitor):
@ -1610,6 +1714,22 @@ class BuildProcessGraph(TcheckVisitor):
ProcessGraph.bridge(parentSideActor, childSideActor, bridgeProto)
def visitOpensStmt(self, opens):
openedP = opens.proto.type
opener = Actor(self.visiting, opens.side)
opened = Actor(openedP, opens.side)
# The picture here is:
# [ opener | opened ] (process 1)
# | |
# | |
# [ remoteOpener | remoteOpened ] (process 2)
#
# An opens stmt tells us that the pairs |opener|/|opened|
# and |remoteOpener|/|remoteOpened| are each in the same
# process.
ProcessGraph.open(opener, opened, openedP)
class CheckProcessGraph(TcheckVisitor):
def __init__(self, errors):
@ -1625,8 +1745,13 @@ class CheckProcessGraph(TcheckVisitor):
for edge in process.iteredges():
print ' ', edge
print 'Bridges'
for bridge in ProcessGraph.bridges.itervalues():
print ' ', bridge
for bridgeList in ProcessGraph.bridges.itervalues():
for bridge in bridgeList:
print ' ', bridge
print 'Opens'
for opensList in ProcessGraph.opens.itervalues():
for opens in opensList:
print ' ', opens
##-----------------------------------------------------------------------------

View File

@ -59,6 +59,7 @@ EXPORT_LIBRARY = 1
IPDLTESTS = \
TestBlockChild \
TestBridgeMain \
TestCrashCleanup \
TestDataStructures \
TestDesc \
@ -69,6 +70,7 @@ IPDLTESTS = \
TestManyChildAllocs \
TestMultiMgrs \
TestNestedLoops \
TestOpens \
TestRPCErrorCleanup \
TestRPCRaces \
TestRPCShutdownRace \
@ -89,6 +91,10 @@ ifeq ($(OS_ARCH),Linux)
IPDLTESTS += TestSysVShmem
endif
EXTRA_PROTOCOLS = \
TestBridgeSub \
$(NULL)
IPDLTESTSRCS = $(addsuffix .cpp,$(IPDLTESTS))
IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS)))
@ -110,7 +116,7 @@ include $(topsrcdir)/config/rules.mk
IPDLUNITTEST_BIN = $(DEPTH)/dist/bin/ipdlunittest$(BIN_SUFFIX)
IPDLUnitTests.cpp : Makefile.in $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS)
$(PYTHON) $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTS) > $@
$(PYTHON) $(GENTESTER) $(TESTER_TEMPLATE) -t $(IPDLTESTS) -e $(EXTRA_PROTOCOLS) > $@
check::
@$(EXIT_ON_ERROR) \

View File

@ -0,0 +1,24 @@
include protocol PTestBridgeSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestBridgeMain {
child spawns PTestBridgeSub;
child:
Start();
parent:
__delete__();
state START:
send Start goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View File

@ -0,0 +1,33 @@
include protocol PTestBridgeMain;
include protocol PTestBridgeSub;
namespace mozilla {
namespace _ipdltest {
// (Bridge protocols can have different semantics than the endpoints
// they bridge)
rpc protocol PTestBridgeMainSub {
bridges PTestBridgeMain, PTestBridgeSub;
child:
Hi();
rpc HiRpc();
parent:
Hello();
sync HelloSync();
rpc HelloRpc();
__delete__();
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View File

@ -0,0 +1,24 @@
namespace mozilla {
namespace _ipdltest {
protocol PTestBridgeSub {
child:
Ping();
parent:
BridgeEm();
__delete__();
state START:
send Ping goto BRIDGEEM;
state BRIDGEEM:
recv BridgeEm goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View File

@ -0,0 +1,25 @@
include protocol PTestOpensOpened;
namespace mozilla {
namespace _ipdltest {
protocol PTestOpens {
// This channel is opened and parked on a non-main thread
child opens PTestOpensOpened;
child:
Start();
parent:
__delete__();
state START:
send Start goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View File

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest {
// (Opens protocols can have different semantics than the endpoints
// that opened them)
rpc protocol PTestOpensOpened {
child:
Hi();
rpc HiRpc();
parent:
Hello();
sync HelloSync();
rpc HelloRpc();
__delete__();
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View File

@ -0,0 +1,252 @@
#include "TestBridgeMain.h"
#include "IPDLUnitTests.h" // fail etc.
#include "IPDLUnitTestSubprocess.h"
using namespace std;
template<>
struct RunnableMethodTraits<mozilla::_ipdltest::TestBridgeMainSubChild>
{
static void RetainCallee(mozilla::_ipdltest::TestBridgeMainSubChild* obj) { }
static void ReleaseCallee(mozilla::_ipdltest::TestBridgeMainSubChild* obj) { }
};
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// main process
void
TestBridgeMainParent::Main()
{
if (!SendStart())
fail("sending Start");
}
PTestBridgeMainSubParent*
TestBridgeMainParent::AllocPTestBridgeMainSub(Transport* transport,
ProcessId otherProcess)
{
ProcessHandle h;
if (!base::OpenProcessHandle(otherProcess, &h)) {
return nsnull;
}
nsAutoPtr<TestBridgeMainSubParent> a(new TestBridgeMainSubParent(transport));
if (!a->Open(transport, h, XRE_GetIOMessageLoop(), AsyncChannel::Parent)) {
return nsnull;
}
return a.forget();
}
void
TestBridgeMainParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
bool
TestBridgeMainSubParent::RecvHello()
{
return SendHi();
}
bool
TestBridgeMainSubParent::RecvHelloSync()
{
return true;
}
bool
TestBridgeMainSubParent::AnswerHelloRpc()
{
return CallHiRpc();
}
void
TestBridgeMainSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
FROM_HERE,
new DeleteTask<TestBridgeMainSubParent>(this));
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
new DeleteTask<Transport>(mTransport));
}
//-----------------------------------------------------------------------------
// sub process --- child of main
TestBridgeMainChild* gBridgeMainChild;
TestBridgeMainChild::TestBridgeMainChild()
: mSubprocess(nsnull)
{
gBridgeMainChild = this;
}
bool
TestBridgeMainChild::RecvStart()
{
vector<string> subsubArgs;
subsubArgs.push_back("TestBridgeSub");
mSubprocess = new IPDLUnitTestSubprocess();
if (!mSubprocess->SyncLaunch(subsubArgs))
fail("problem launching subprocess");
IPC::Channel* transport = mSubprocess->GetChannel();
if (!transport)
fail("no transport");
TestBridgeSubParent* bsp = new TestBridgeSubParent();
bsp->Open(transport, mSubprocess->GetChildProcessHandle());
bsp->Main();
return true;
}
void
TestBridgeMainChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
// NB: this is kosher because QuitChild() joins with the IO thread
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
new DeleteTask<IPDLUnitTestSubprocess>(mSubprocess));
QuitChild();
}
void
TestBridgeSubParent::Main()
{
if (!SendPing())
fail("sending Ping");
}
bool
TestBridgeSubParent::RecvBridgeEm()
{
if (!PTestBridgeMainSub::Bridge(gBridgeMainChild, this))
fail("bridging Main and Sub");
return true;
}
void
TestBridgeSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
gBridgeMainChild->Close();
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
FROM_HERE,
new DeleteTask<TestBridgeSubParent>(this));
}
//-----------------------------------------------------------------------------
// subsub process --- child of sub
static TestBridgeSubChild* gBridgeSubChild;
TestBridgeSubChild::TestBridgeSubChild()
{
gBridgeSubChild = this;
}
bool
TestBridgeSubChild::RecvPing()
{
if (!SendBridgeEm())
fail("sending BridgeEm");
return true;
}
PTestBridgeMainSubChild*
TestBridgeSubChild::AllocPTestBridgeMainSub(Transport* transport,
ProcessId otherProcess)
{
ProcessHandle h;
if (!base::OpenProcessHandle(otherProcess, &h)) {
return nsnull;
}
nsAutoPtr<TestBridgeMainSubChild> a(new TestBridgeMainSubChild(transport));
if (!a->Open(transport, h, XRE_GetIOMessageLoop(), AsyncChannel::Child)) {
return nsnull;
}
if (!a->SendHello())
fail("sending Hello");
return a.forget();
}
void
TestBridgeSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
bool
TestBridgeMainSubChild::RecvHi()
{
if (!SendHelloSync())
fail("sending HelloSync");
if (!CallHelloRpc())
fail("calling HelloRpc");
if (!mGotHi)
fail("didn't answer HiRpc");
// Need to close the channel without message-processing frames on
// the C++ stack
MessageLoop::current()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &TestBridgeMainSubChild::Close));
return true;
}
bool
TestBridgeMainSubChild::AnswerHiRpc()
{
mGotHi = true; // d00d
return true;
}
void
TestBridgeMainSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
gBridgeSubChild->Close();
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
FROM_HERE,
new DeleteTask<TestBridgeMainSubChild>(this));
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
new DeleteTask<Transport>(mTransport));
}
} // namespace mozilla
} // namespace _ipdltest

View File

@ -0,0 +1,152 @@
#ifndef mozilla__ipdltest_TestBridgeMain_h
#define mozilla__ipdltest_TestBridgeMain_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestBridgeMainParent.h"
#include "mozilla/_ipdltest/PTestBridgeMainChild.h"
#include "mozilla/_ipdltest/PTestBridgeSubParent.h"
#include "mozilla/_ipdltest/PTestBridgeSubChild.h"
#include "mozilla/_ipdltest/PTestBridgeMainSubParent.h"
#include "mozilla/_ipdltest/PTestBridgeMainSubChild.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// "Main" process
//
class TestBridgeMainParent :
public PTestBridgeMainParent
{
public:
TestBridgeMainParent() {}
virtual ~TestBridgeMainParent() {}
void Main();
protected:
NS_OVERRIDE
virtual PTestBridgeMainSubParent*
AllocPTestBridgeMainSub(Transport* transport,
ProcessId otherProcess);
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
};
class TestBridgeMainSubParent :
public PTestBridgeMainSubParent
{
public:
TestBridgeMainSubParent(Transport* aTransport)
: mTransport(aTransport)
{}
virtual ~TestBridgeMainSubParent() {}
protected:
NS_OVERRIDE
virtual bool RecvHello();
NS_OVERRIDE
virtual bool RecvHelloSync();
NS_OVERRIDE
virtual bool AnswerHelloRpc();
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
Transport* mTransport;
};
//-----------------------------------------------------------------------------
// "Sub" process --- child of "main"
//
class TestBridgeSubParent;
class TestBridgeMainChild :
public PTestBridgeMainChild
{
public:
TestBridgeMainChild();
virtual ~TestBridgeMainChild() {}
protected:
NS_OVERRIDE
virtual bool RecvStart();
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
IPDLUnitTestSubprocess* mSubprocess;
};
class TestBridgeSubParent :
public PTestBridgeSubParent
{
public:
TestBridgeSubParent() {}
virtual ~TestBridgeSubParent() {}
void Main();
protected:
NS_OVERRIDE
virtual bool RecvBridgeEm();
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
};
//-----------------------------------------------------------------------------
// "Subsub" process --- child of "sub"
//
class TestBridgeSubChild :
public PTestBridgeSubChild
{
public:
TestBridgeSubChild();
virtual ~TestBridgeSubChild() {}
protected:
NS_OVERRIDE
virtual bool RecvPing();
NS_OVERRIDE
virtual PTestBridgeMainSubChild*
AllocPTestBridgeMainSub(Transport* transport,
ProcessId otherProcess);
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
};
class TestBridgeMainSubChild :
public PTestBridgeMainSubChild
{
public:
TestBridgeMainSubChild(Transport* aTransport)
: mGotHi(false)
, mTransport(aTransport)
{}
virtual ~TestBridgeMainSubChild() {}
protected:
NS_OVERRIDE
virtual bool RecvHi();
NS_OVERRIDE
virtual bool AnswerHiRpc();
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
bool mGotHi;
Transport* mTransport;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestBridgeMain_h

View File

@ -0,0 +1,266 @@
#include "base/thread.h"
#include "TestOpens.h"
#include "IPDLUnitTests.h" // fail etc.
template<>
struct RunnableMethodTraits<mozilla::_ipdltest::TestOpensChild>
{
static void RetainCallee(mozilla::_ipdltest::TestOpensChild* obj) { }
static void ReleaseCallee(mozilla::_ipdltest::TestOpensChild* obj) { }
};
template<>
struct RunnableMethodTraits<mozilla::_ipdltest::TestOpensOpenedChild>
{
static void RetainCallee(mozilla::_ipdltest::TestOpensOpenedChild* obj) { }
static void ReleaseCallee(mozilla::_ipdltest::TestOpensOpenedChild* obj) { }
};
using namespace base;
using namespace mozilla::ipc;
namespace mozilla {
namespace _ipdltest {
static MessageLoop* gMainThread;
static void
AssertNotMainThread()
{
if (!gMainThread)
fail("gMainThread is not initialized");
if (MessageLoop::current() == gMainThread)
fail("unexpectedly called on the main thread");
}
//-----------------------------------------------------------------------------
// parent
// Thread on which TestOpensOpenedParent runs
static Thread* gParentThread;
void
TestOpensParent::Main()
{
if (!SendStart())
fail("sending Start");
}
static void
OpenParent(TestOpensOpenedParent* aParent,
Transport* aTransport, ProcessHandle aOtherProcess)
{
AssertNotMainThread();
// Open the actor on the off-main thread to park it there.
// Messages will be delivered to this thread's message loop
// instead of the main thread's.
if (!aParent->Open(aTransport, aOtherProcess,
XRE_GetIOMessageLoop(), AsyncChannel::Parent))
fail("opening Parent");
}
PTestOpensOpenedParent*
TestOpensParent::AllocPTestOpensOpened(Transport* transport,
ProcessId otherProcess)
{
gMainThread = MessageLoop::current();
ProcessHandle h;
if (!base::OpenProcessHandle(otherProcess, &h)) {
return nsnull;
}
gParentThread = new Thread("ParentThread");
if (!gParentThread->Start())
fail("starting parent thread");
TestOpensOpenedParent* a = new TestOpensOpenedParent(transport);
gParentThread->message_loop()->PostTask(
FROM_HERE,
NewRunnableFunction(OpenParent, a, transport, h));
return a;
}
void
TestOpensParent::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gParentThread;
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
bool
TestOpensOpenedParent::RecvHello()
{
AssertNotMainThread();
return SendHi();
}
bool
TestOpensOpenedParent::RecvHelloSync()
{
AssertNotMainThread();
return true;
}
bool
TestOpensOpenedParent::AnswerHelloRpc()
{
AssertNotMainThread();
return CallHiRpc();
}
void
TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
if (NormalShutdown != why)
fail("unexpected destruction!");
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
FROM_HERE,
new DeleteTask<TestOpensOpenedParent>(this));
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
new DeleteTask<Transport>(mTransport));
}
//-----------------------------------------------------------------------------
// child
static TestOpensChild* gOpensChild;
// Thread on which TestOpensOpenedChild runs
static Thread* gChildThread;
TestOpensChild::TestOpensChild()
{
gOpensChild = this;
}
bool
TestOpensChild::RecvStart()
{
if (!PTestOpensOpened::Open(this))
fail("opening PTestOpensOpened");
return true;
}
static void
OpenChild(TestOpensOpenedChild* aChild,
Transport* aTransport, ProcessHandle aOtherProcess)
{
AssertNotMainThread();
// Open the actor on the off-main thread to park it there.
// Messages will be delivered to this thread's message loop
// instead of the main thread's.
if (!aChild->Open(aTransport, aOtherProcess,
XRE_GetIOMessageLoop(), AsyncChannel::Child))
fail("opening Child");
// Kick off the unit tests
if (!aChild->SendHello())
fail("sending Hello");
}
PTestOpensOpenedChild*
TestOpensChild::AllocPTestOpensOpened(Transport* transport,
ProcessId otherProcess)
{
gMainThread = MessageLoop::current();
ProcessHandle h;
if (!base::OpenProcessHandle(otherProcess, &h)) {
return nsnull;
}
gChildThread = new Thread("ChildThread");
if (!gChildThread->Start())
fail("starting child thread");
TestOpensOpenedChild* a = new TestOpensOpenedChild(transport);
gChildThread->message_loop()->PostTask(
FROM_HERE,
NewRunnableFunction(OpenChild, a, transport, h));
return a;
}
void
TestOpensChild::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gChildThread;
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
bool
TestOpensOpenedChild::RecvHi()
{
AssertNotMainThread();
if (!SendHelloSync())
fail("sending HelloSync");
if (!CallHelloRpc())
fail("calling HelloRpc");
if (!mGotHi)
fail("didn't answer HiRpc");
// Need to close the channel without message-processing frames on
// the C++ stack
MessageLoop::current()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &TestOpensOpenedChild::Close));
return true;
}
bool
TestOpensOpenedChild::AnswerHiRpc()
{
AssertNotMainThread();
mGotHi = true; // d00d
return true;
}
void
TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
if (NormalShutdown != why)
fail("unexpected destruction!");
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
FROM_HERE,
new DeleteTask<TestOpensOpenedChild>(this));
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
new DeleteTask<Transport>(mTransport));
// Kick off main-thread shutdown.
gMainThread->PostTask(
FROM_HERE,
NewRunnableMethod(gOpensChild, &TestOpensChild::Close));
}
} // namespace _ipdltest
} // namespace mozilla

View File

@ -0,0 +1,104 @@
#ifndef mozilla__ipdltest_TestOpens_h
#define mozilla__ipdltest_TestOpens_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestOpensParent.h"
#include "mozilla/_ipdltest/PTestOpensChild.h"
#include "mozilla/_ipdltest/PTestOpensOpenedParent.h"
#include "mozilla/_ipdltest/PTestOpensOpenedChild.h"
namespace mozilla {
namespace _ipdltest {
// parent process
class TestOpensParent : public PTestOpensParent
{
public:
TestOpensParent() {}
virtual ~TestOpensParent() {}
void Main();
protected:
NS_OVERRIDE
virtual PTestOpensOpenedParent*
AllocPTestOpensOpened(Transport* transport, ProcessId otherProcess);
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
};
class TestOpensOpenedParent : public PTestOpensOpenedParent
{
public:
TestOpensOpenedParent(Transport* aTransport)
: mTransport(aTransport)
{}
virtual ~TestOpensOpenedParent() {}
protected:
NS_OVERRIDE
virtual bool RecvHello();
NS_OVERRIDE
virtual bool RecvHelloSync();
NS_OVERRIDE
virtual bool AnswerHelloRpc();
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
Transport* mTransport;
};
// child process
class TestOpensChild : public PTestOpensChild
{
public:
TestOpensChild();
virtual ~TestOpensChild() {}
protected:
NS_OVERRIDE
virtual bool RecvStart();
NS_OVERRIDE
virtual PTestOpensOpenedChild*
AllocPTestOpensOpened(Transport* transport, ProcessId otherProcess);
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
};
class TestOpensOpenedChild : public PTestOpensOpenedChild
{
public:
TestOpensOpenedChild(Transport* aTransport)
: mGotHi(false)
, mTransport(aTransport)
{}
virtual ~TestOpensOpenedChild() {}
protected:
NS_OVERRIDE
virtual bool RecvHi();
NS_OVERRIDE
virtual bool AnswerHiRpc();
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why);
bool mGotHi;
Transport* mTransport;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestOpens_h

View File

@ -37,30 +37,50 @@
import string, sys
def usage():
print >>sys.stderr, """
%s template_file -t unit_tests... -e extra_protocols...
TEMPLATE_FILE is used to generate to generate the unit-tester .cpp
UNIT_TESTS are the top-level protocols defining unit tests
EXTRA_PROTOCOLS are top-level protocols for subprocesses that can be
spawned in tests but are not unit tests in and of
themselves
"""% (sys.argv[0])
sys.exit(1)
def main(argv):
template = argv[1]
unittests = argv[2:]
if argv[2] != '-t': usage()
i = 3
unittests = []
while argv[i] != '-e':
unittests.append(argv[i])
i += 1
extras = argv[(i+1):]
includes = '\n'.join([
'#include "%s.h"'% (t) for t in unittests ])
enum_values = '\n'.join([
' %s,'% (t) for t in unittests ])
' %s,'% (t) for t in unittests+extras ])
last_enum = unittests[-1]
string_to_enums = '\n'.join([
''' else if (!strcmp(aString, "%s"))
return %s;'''% (t, t) for t in unittests ])
return %s;'''% (t, t) for t in unittests+extras ])
enum_to_strings = '\n'.join([
''' case %s:
return "%s";'''%(t, t) for t in unittests ])
return "%s";'''%(t, t) for t in unittests+extras ])
parent_delete_cases = '\n'.join([
''' case %s: {
delete reinterpret_cast<mozilla::_ipdltest::%sParent*>(gParentActor);
delete reinterpret_cast<%sParent*>(gParentActor);
return;
}
'''% (t, t) for t in unittests ])
@ -77,10 +97,10 @@ def main(argv):
child_delete_cases = '\n'.join([
''' case %s: {
delete reinterpret_cast<mozilla::_ipdltest::%sChild*>(gChildActor);
delete reinterpret_cast<%sChild*>(gChildActor);
return;
}
'''% (t, t) for t in unittests ])
'''% (t, t) for t in unittests+extras ])
child_init_cases = '\n'.join([
@ -91,7 +111,7 @@ def main(argv):
(*child)->Open(transport, parent, worker);
return;
}
'''% (t, t, t, t) for t in unittests ])
'''% (t, t, t, t) for t in unittests+extras ])
templatefile = open(template, 'r')
sys.stdout.write(

View File

@ -1,5 +1,8 @@
IPDLSRCS = \
PTestBlockChild.ipdl \
PTestBridgeMain.ipdl \
PTestBridgeSub.ipdl \
PTestBridgeMainSub.ipdl \
PTestCrashCleanup.ipdl \
PTestDataStructures.ipdl \
PTestDataStructuresSub.ipdl \
@ -20,6 +23,8 @@ IPDLSRCS = \
PTestMultiMgrsRight.ipdl \
PTestMultiMgrsBottom.ipdl \
PTestNestedLoops.ipdl \
PTestOpens.ipdl \
PTestOpensOpened.ipdl \
PTestRaceDeferral.ipdl \
PTestRacyReentry.ipdl \
PTestRacyRPCReplies.ipdl \

View File

@ -0,0 +1,6 @@
protocol opensNonexistent {
parent opens Unicorn;
child: __delete__();
state DEAD: send __delete__;
};

View File

@ -0,0 +1,13 @@
include protocol subprotocolOpens;
protocol opensSubprotocol {
child opens subprotocolOpens;
manages subprotocolOpens;
child:
subprotocolOpens();
__delete__();
state DEAD: send __delete__;
};

View File

@ -0,0 +1,10 @@
include protocol opensSubprotocol;
protocol subprotocolOpens {
parent opens opensSubprotocol;
manager opensSubprotocol;
child: __delete__();
state DEAD: send __delete__;
};

View File

@ -1,11 +1,13 @@
include protocol compositor;
include protocol jetpack;
include protocol media;
include protocol plugin;
sync protocol content {
parent spawns compositor as parent;
parent spawns jetpack;
child spawns plugin;
child opens media;
child:
__delete__();

View File

@ -0,0 +1,7 @@
sync protocol media {
child:
__delete__();
state DEAD:
send __delete__;
};

View File

@ -282,14 +282,14 @@ HTTP(../..) == inline--position-relative--01.xhtml inline--position-relative-
# tests do not have any width or height on the <object> element so they should
# be sized purely by the embedded SVG's intrinsic size.
== object--auto-auto--0-0.html pass-empty.svg # XXX add border
== object--auto-auto--0-pct.html object--auto-auto--0-pct--ref.html
== object--auto-auto--0-px.html object--auto-auto--0-px--ref.html
== object--auto-auto--pct-0.html object--auto-auto--pct-0--ref.html
random-if(Android) == object--auto-auto--0-0.html pass-empty.svg # XXX add border
random-if(Android) == object--auto-auto--0-pct.html object--auto-auto--0-pct--ref.html
random-if(Android) == object--auto-auto--0-px.html object--auto-auto--0-px--ref.html
random-if(Android) == object--auto-auto--pct-0.html object--auto-auto--pct-0--ref.html
# The following four commented out tests fail post bug 428023:
#== object--auto-auto--pct-pct.html object--auto-auto--pct-pct--ref.html
#== object--auto-auto--pct-px.html object--auto-auto--pct-px--ref.html
== object--auto-auto--px-0.html object--auto-auto--px-0--ref.html
random-if(Android) == object--auto-auto--px-0.html object--auto-auto--px-0--ref.html
#== object--auto-auto--px-pct.html object--auto-auto--px-pct--ref.html
random-if(Android) == object--auto-auto--px-px.html object--auto-auto--px-px--ref.html
#== object--pct-pct--0-0.html pass.svg

View File

@ -42,8 +42,9 @@
interface nsIDOMElement;
interface nsIDOMNode;
interface nsIDOMEvent;
interface nsIDOMClientRect;
[scriptable, uuid(548a9e3f-af78-42b0-a260-035ece15c19f)]
[scriptable, uuid(6AD1B199-95D3-448B-98D7-896BCE3A1DCD)]
interface nsIPopupBoxObject : nsISupports
{
/**
@ -183,6 +184,12 @@ interface nsIPopupBoxObject : nsISupports
* menu, the parent menu.
*/
readonly attribute nsIDOMElement anchorNode;
/*
* Retrieve the screen rectangle of the popup, including the area occupied by
* any titlebar or borders present.
*/
nsIDOMClientRect getOuterScreenRect();
};
%{C++

View File

@ -50,6 +50,7 @@
#include "nsINameSpaceManager.h"
#include "nsGkAtoms.h"
#include "nsMenuPopupFrame.h"
#include "nsClientRect.h"
class nsPopupBoxObject : public nsBoxObject,
public nsIPopupBoxObject
@ -290,6 +291,39 @@ nsPopupBoxObject::GetAnchorNode(nsIDOMElement** aAnchor)
return NS_OK;
}
NS_IMETHODIMP
nsPopupBoxObject::GetOuterScreenRect(nsIDOMClientRect** aRect)
{
nsClientRect* rect = new nsClientRect();
if (!rect)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aRect = rect);
nsMenuPopupFrame *menuPopupFrame = GetMenuPopupFrame();
if (!menuPopupFrame)
return NS_OK;
// Return an empty rectangle if the popup is not open.
nsPopupState state = menuPopupFrame->PopupState();
if (state != ePopupOpen && state != ePopupOpenAndVisible)
return NS_OK;
nsIView* view = menuPopupFrame->GetView();
if (view) {
nsIWidget* widget = view->GetWidget();
if (widget) {
nsIntRect screenRect;
widget->GetScreenBounds(screenRect);
PRInt32 pp = menuPopupFrame->PresContext()->AppUnitsPerDevPixel();
rect->SetLayoutRect(screenRect.ToAppUnits(pp));
}
}
return NS_OK;
}
// Creation Routine ///////////////////////////////////////////////////////////////////////
nsresult

View File

@ -531,9 +531,11 @@ var BrowserUI = {
DownloadsView.init();
ConsoleView.init();
// Pre-start the content process
Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
.ensureContentProcess();
if (Services.prefs.getBoolPref("browser.tabs.remote")) {
// Pre-start the content process
Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
.ensureContentProcess();
}
#ifdef MOZ_SERVICES_SYNC
// Init the sync system

View File

@ -23,31 +23,31 @@ documenttab {
}
settings {
-moz-binding: url("chrome://browser/content/bindings/setting.xml#settings");
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#settings");
}
setting[type="bool"] {
-moz-binding: url("chrome://browser/content/bindings/setting.xml#setting-bool");
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-bool");
}
setting[type="bool"][localized="true"] {
-moz-binding: url("chrome://browser/content/bindings/setting.xml#setting-localized-bool");
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-localized-bool");
}
setting[type="boolint"] {
-moz-binding: url("chrome://browser/content/bindings/setting.xml#setting-boolint");
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-boolint");
}
setting[type="integer"] {
-moz-binding: url("chrome://browser/content/bindings/setting.xml#setting-integer");
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-integer");
}
setting[type="control"] {
-moz-binding: url("chrome://browser/content/bindings/setting.xml#setting-control");
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-control");
}
setting[type="string"] {
-moz-binding: url("chrome://browser/content/bindings/setting.xml#setting-string");
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-string");
}
#browsers > notificationbox {

View File

@ -2731,7 +2731,8 @@ Tab.prototype = {
try {
let flags = aParams.flags || Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
browser.loadURIWithFlags(aURI, flags, aParams.referrerURI, aParams.charset, aParams.postData);
let postData = aParams.postData ? aParams.postData.value : null;
browser.loadURIWithFlags(aURI, flags, aParams.referrerURI, aParams.charset, postData);
} catch(e) {
dump("Error: " + e + "\n");
}

View File

@ -534,7 +534,7 @@
</hbox>
<separator class="prompt-line"/>
<vbox id="syncsetup-simple" class="syncsetup-page" flex="1">
<scrollbox class="prompt-message" orient="vertical" flex="1">
<scrollbox id="sync-message" class="prompt-message" orient="vertical" flex="1">
<description class="syncsetup-desc syncsetup-center" flex="1">&sync.setup.jpake;</description>
<description class="syncsetup-center syncsetup-link" flex="1" onclick="WeaveGlue.openTutorial();">&sync.setup.tutorial;</description>
<separator/>

View File

@ -885,8 +885,11 @@ var FormHelperUI = {
doAutoComplete: function formHelperDoAutoComplete(aElement) {
// Suggestions are only in <label>s. Ignore the rest.
if (aElement instanceof Ci.nsIDOMXULLabelElement)
this._currentBrowser.messageManager.sendAsyncMessage("FormAssist:AutoComplete", { value: aElement.getAttribute("data") });
if (!(aElement instanceof Ci.nsIDOMXULLabelElement))
return;
this._currentBrowser.messageManager.sendAsyncMessage("FormAssist:AutoComplete", { value: aElement.getAttribute("data") });
ContentPopupHelper.popup = null;
},
get _open() {

View File

@ -256,13 +256,13 @@ var ViewConfig = {
row.setAttribute("default", aPref.default);
let label = document.createElement("label");
label.setAttribute("class", "preftitle");
label.setAttribute("class", "preferences-title");
label.setAttribute("value", aPref.name);
label.setAttribute("crop", "end");
row.appendChild(label);
label = document.createElement("label");
label.setAttribute("class", "prefvalue");
label.setAttribute("class", "preferences-value");
label.setAttribute("value", aPref.value);
label.setAttribute("crop", "end");
row.appendChild(label);

View File

@ -636,8 +636,11 @@ let Content = {
}
if (isTouchClick) {
let rect = rects[0];
let point = (new Rect(rect.left, rect.top, rect.width, rect.height)).center();
let rect = new Rect(rects[0]);
if (rect.isEmpty())
return;
let point = rect.center();
aX = point.x;
aY = point.y;
}

View File

@ -48,7 +48,6 @@ chrome.jar:
content/bindings/console.xml (content/bindings/console.xml)
content/bindings/dialog.xml (content/bindings/dialog.xml)
content/bindings/pageaction.xml (content/bindings/pageaction.xml)
content/bindings/setting.xml (content/bindings/setting.xml)
content/bindings/arrowbox.xml (content/bindings/arrowbox.xml)
content/browser.css (content/browser.css)
content/cursor.css (content/cursor.css)

View File

@ -81,8 +81,10 @@ SessionStore.prototype = {
// Get file references
this._sessionFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
this._sessionFileBackup = this._sessionFile.clone();
this._sessionCache = this._sessionFile.clone();
this._sessionFile.append("sessionstore.js");
this._sessionFileBackup.append("sessionstore.bak");
this._sessionCache.append("sessionstoreCache");
this._loadState = STATE_STOPPED;
@ -91,6 +93,7 @@ SessionStore.prototype = {
this._shouldRestore = true;
this._sessionFileBackup.remove(false);
}
if (this._sessionFile.exists()) {
// Disable crash recovery if we have exceeded the timeout
this._lastSessionTime = this._sessionFile.lastModifiedTime;
@ -101,6 +104,9 @@ SessionStore.prototype = {
this._sessionFile.copyTo(null, this._sessionFileBackup.leafName);
}
if (!this._sessionCache.exists() || !this._sessionCache.isDirectory())
this._sessionCache.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
} catch (ex) {
Cu.reportError(ex); // file was write-locked?
}
@ -130,6 +136,37 @@ SessionStore.prototype = {
this._sessionFileBackup.remove(false);
} catch (ex) { dump(ex + '\n'); } // couldn't remove the file - what now?
}
this._clearCache();
},
_clearCache: function ss_clearCache() {
// First, let's get a list of files we think should be active
let activeFiles = [];
this._forEachBrowserWindow(function(aWindow) {
let tabs = aWindow.Browser.tabs;
for (let i = 0; i < tabs.length; i++) {
let browser = tabs[i].browser;
if (browser.__SS_extdata && "thumbnail" in browser.__SS_extdata)
activeFiles.push(browser.__SS_extdata.thumbnail);
}
});
// Now, let's find the stale files in the cache folder
let staleFiles = [];
let cacheFiles = this._sessionCache.directoryEntries;
while (cacheFiles.hasMoreElements()) {
let file = cacheFiles.getNext().QueryInterface(Ci.nsILocalFile);
let fileURI = Services.io.newFileURI(file);
if (activeFiles.indexOf(fileURI) == -1)
staleFiles.push(file);
}
// Remove the stale files in a separate step to keep the enumerator from
// messing up if we remove the files as we collect them.
staleFiles.forEach(function(aFile) {
aFile.remove(false);
})
},
observe: function ss_observe(aSubject, aTopic, aData) {
@ -289,8 +326,10 @@ SessionStore.prototype = {
this._lastSaveTime = Date.now();
// Nothing to restore, notify observers things are complete
if (!this._shouldRestore)
if (!this._shouldRestore) {
this._clearCache();
Services.obs.notifyObservers(null, "sessionstore-windows-restored", "");
}
}
// Add tab change listeners to all already existing tabs
@ -482,8 +521,8 @@ SessionStore.prototype = {
let tabs = aWindow.Browser.tabs;
for (let i = 0; i < tabs.length; i++) {
if (tabs[i].browser.__SS_data) {
let browser = tabs[i].browser;
let browser = tabs[i].browser;
if (browser.__SS_data) {
let tabData = browser.__SS_data;
if (browser.__SS_extdata)
tabData.extData = browser.__SS_extdata;
@ -616,6 +655,23 @@ SessionStore.prototype = {
setTabValue: function ss_setTabValue(aTab, aKey, aStringValue) {
let browser = aTab.linkedBrowser;
// Thumbnails are actually stored in the cache, so do the save and update the URI
if (aKey == "thumbnail") {
let file = this._sessionCache.clone();
file.append("thumbnail-" + browser.contentWindowId);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
let source = Services.io.newURI(aStringValue, "UTF8", null);
let target = Services.io.newFileURI(file)
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
persist.saveURI(source, null, null, null, null, file);
aStringValue = target.spec;
}
if (!browser.__SS_extdata)
browser.__SS_extdata = {};
browser.__SS_extdata[aKey] = aStringValue;
@ -636,18 +692,17 @@ SessionStore.prototype = {
restoreLastSession: function ss_restoreLastSession(aBringToFront) {
// The previous session data has already been renamed to the backup file
let dirService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
let session = dirService.get("ProfD", Ci.nsILocalFile);
session.append("sessionstore.bak");
if (!session.exists())
if (!this._sessionFileBackup.exists())
return;
let self = this;
function notifyObservers() {
self._clearCache();
Services.obs.notifyObservers(null, "sessionstore-windows-restored", "");
}
try {
let channel = NetUtil.newChannel(session);
let channel = NetUtil.newChannel(this._sessionFileBackup);
channel.contentType = "application/json";
NetUtil.asyncFetch(channel, function(aStream, aResult) {
if (!Components.isSuccessCode(aResult)) {

View File

@ -1216,37 +1216,41 @@ pageaction:not([image]) > hbox >.pageaction-image {
border-bottom: @border_width_tiny@ solid #cacdd5;
}
/* XXX should be a richlistitem */
.prefbox {
setting {
padding: @padding_xsmall@;
border-bottom: @border_width_tiny@ solid rgb(207,207,207);
min-height: @touch_row@; /* row size */
-moz-box-align: center;
-moz-box-orient: horizontal;
}
.setting-group > .prefbox {
.setting-label {
-moz-box-flex: 1;
}
.setting-group > setting {
border-bottom: none;
}
.setting-subgroup > .prefbox {
.setting-subgroup > setting {
border-bottom: none;
-moz-margin-start: @margin_xxxnormal@;
}
.setting-subgroup + :not(.setting-subgroup) > .prefbox {
.setting-subgroup + :not(.setting-subgroup) > setting {
border-top: @border_width_tiny@ solid rgb(207,207,207);
}
/* Put setting textboxes on a separate row in portrait */
@media (@orientation@: portrait) {
.setting-integer,
.setting-string {
setting[type="integer"],
setting[type="string"] {
-moz-box-align: start;
-moz-box-orient: vertical;
}
.setting-integer > .setting-input > textbox,
.setting-string > .setting-input > textbox {
setting[type="integer"] > .setting-input > textbox,
setting[type="string"] > .setting-input > textbox {
width: 499px; /* textboxes seem to need a width in order to flex */
-moz-box-flex: 1;
}
@ -1256,17 +1260,17 @@ pageaction:not([image]) > hbox >.pageaction-image {
-moz-margin-start: 28px; /* sized based on the 32px addon image */
}
.options-box > setting:last-child > .prefbox {
.options-box > setting:last-child {
border-bottom: 0;
}
/* XXX should be a richlistitem description.title */
.preftitle {
.preferences-title {
font-size: @font_normal@ !important;
}
/* XXX should be a richlistitem description.normal */
.prefdesc {
.preferences-description {
font-size: @font_small@ !important;
color: grey;
}
@ -1461,6 +1465,10 @@ pageaction:not([image]) > hbox >.pageaction-image {
-moz-margin-start: @margin_xnormal@;
}
#sync-message {
padding-bottom: 2em;
}
/* content scrollbars */
.scroller {
opacity: 0;

View File

@ -44,7 +44,7 @@ richlistitem {
-moz-box-align: center;
}
richlistitem .preftitle {
richlistitem .preferences-title {
pointer-events: none;
min-width: 200px;
-moz-box-flex: 1;
@ -52,7 +52,7 @@ richlistitem .preftitle {
}
/* XXX look + sync */
richlistitem[default="false"] .preftitle {
richlistitem[default="false"] .preferences-title {
font-weight: bold;
}
@ -98,11 +98,11 @@ richlistitem .prefvalue {
display: none;
}
#editor[default="false"] .preftitle {
#editor[default="false"] .preferences-title {
font-weight: bold;
}
#editor-setting .prefbox {
#editor-setting setting {
border-color: transparent !important;
}

View File

@ -1195,37 +1195,41 @@ pageaction:not([image]) > hbox >.pageaction-image {
border-bottom: @border_width_tiny@ solid #cacdd5;
}
/* XXX should be a richlistitem */
.prefbox {
setting {
padding: @padding_xsmall@;
border-bottom: @border_width_tiny@ solid @color_divider_border@;
min-height: @touch_row@; /* row size */
-moz-box-align: center;
-moz-box-orient: horizontal;
}
.setting-group > .prefbox {
.setting-label {
-moz-box-flex: 1;
}
.setting-group > setting {
border-bottom: none;
}
.setting-subgroup > .prefbox {
.setting-subgroup > setting {
border-bottom: none;
-moz-margin-start: @margin_xxxnormal@;
}
.setting-subgroup + :not(.setting-subgroup) > .prefbox {
.setting-subgroup + :not(.setting-subgroup) > setting {
border-top: @border_width_tiny@ solid rgb(207,207,207);
}
/* Put setting textboxes on a separate row in portrait */
@media (@orientation@: portrait) {
.setting-integer,
.setting-string {
setting[type="integer"],
setting[type="string"] {
-moz-box-align: start;
-moz-box-orient: vertical;
}
.setting-integer > .setting-input > textbox,
.setting-string > .setting-input > textbox {
setting[type="integer"] > .setting-input > textbox,
setting[type="string"] > .setting-input > textbox {
width: 499px; /* textboxes seem to need a width in order to flex */
-moz-box-flex: 1;
}
@ -1235,17 +1239,17 @@ pageaction:not([image]) > hbox >.pageaction-image {
-moz-margin-start: 28px; /* sized based on the 32px addon image */
}
.options-box > setting:last-child > .prefbox {
.options-box > setting:last-child {
border-bottom: 0;
}
/* XXX should be a richlistitem description.title */
.preftitle {
.preferences-title {
font-size: @font_normal@ !important;
}
/* XXX should be a richlistitem description.normal */
.prefdesc {
.preferences-description {
font-size: @font_small@ !important;
color: @color_subtext_default@;
}

View File

@ -1824,7 +1824,7 @@ pref("gfx.font_rendering.cleartype_params.rendering_mode", -1);
// of gfx.font_rendering.cleartype_params.rendering_mode.
// Currently we apply this setting to the sans-serif Microsoft "core Web fonts".
pref("gfx.font_rendering.cleartype_params.force_gdi_classic_for_families",
"Arial,Courier New,Tahoma,Trebuchet MS,Verdana");
"Arial,Courier New,Segoe UI,Tahoma,Trebuchet MS,Verdana");
// The maximum size at which we will force GDI classic mode using
// force_gdi_classic_for_families.
pref("gfx.font_rendering.cleartype_params.force_gdi_classic_max_size", 15);

View File

@ -102,18 +102,6 @@ static PRLogModuleInfo *webSocketLog = nsnull;
// An implementation of draft-ietf-hybi-thewebsocketprotocol-07
#define SEC_WEBSOCKET_VERSION "7"
/*
* About using rand() without a srand() or initstate()
*
* rand() is commonly called throughout the codebase with the assumption
* that it has been seeded securely. That does indeed happen in
* the initialization of the nsUUIDGenerator sevice - getting secure
* seed information from PR_GetRandomNoise() and giving that to
* initstate(). We won't repeat that here "just in case" because
* it is easy to drain some systems of their true random sources.
*/
/*
* About SSL unsigned certificates
*
@ -1162,7 +1150,18 @@ nsWebSocketHandler::PrimeNewOutgoingMessage()
// Perfom the sending mask. never use a zero mask
PRUint32 mask;
while (!(mask = (PRUint32) rand()));
do {
PRUint8 *buffer;
nsresult rv = mRandomGenerator->GenerateRandomBytes(4, &buffer);
if (NS_FAILED(rv)) {
LOG(("WebSocketHandler:: PrimeNewOutgoingMessage() "
"GenerateRandomBytes failure %x\n", rv));
StopSession(rv);
return;
}
mask = * reinterpret_cast<PRUint32 *>(buffer);
NS_Free(buffer);
} while (!mask);
*(((PRUint32 *)payload) - 1) = PR_htonl(mask);
LOG(("WebSocketHandler:: PrimeNewOutgoingMessage() "
@ -1475,13 +1474,13 @@ nsWebSocketHandler::SetupRequest()
NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"),
NS_LITERAL_CSTRING("deflate-stream"), PR_FALSE);
PRUint32 secKey[4];
PRUint8 *secKey;
nsCAutoString secKeyString;
secKey[0] = (PRUint32) rand();
secKey[1] = (PRUint32) rand();
secKey[2] = (PRUint32) rand();
secKey[3] = (PRUint32) rand();
rv = mRandomGenerator->GenerateRandomBytes(16, &secKey);
NS_ENSURE_SUCCESS(rv, rv);
char* b64 = PL_Base64Encode((const char *)secKey, 16, nsnull);
NS_Free(secKey);
if (!b64) return NS_ERROR_OUT_OF_MEMORY;
secKeyString.Assign(b64);
PR_Free(b64);
@ -1633,7 +1632,7 @@ nsWebSocketHandler::AsyncOnChannelRedirect(
if (NS_FAILED(rv)) {
LOG(("nsWebSocketHandler Redirect could not QI to HTTP\n"));
callback->OnRedirectVerifyCallback(NS_ERROR_FAILURE);
callback->OnRedirectVerifyCallback(rv);
return NS_OK;
}
@ -1642,17 +1641,22 @@ nsWebSocketHandler::AsyncOnChannelRedirect(
if (NS_FAILED(rv)) {
LOG(("nsWebSocketHandler Redirect could not QI to HTTP Upgrade\n"));
callback->OnRedirectVerifyCallback(NS_ERROR_FAILURE);
callback->OnRedirectVerifyCallback(rv);
return NS_OK;
}
// The redirect is OK
// The redirect is likely OK
newChannel->SetNotificationCallbacks(this);
mURI = newuri;
mHttpChannel = newHttpChannel;
mChannel = newUpgradeChannel;
SetupRequest();
rv = SetupRequest();
if (NS_FAILED(rv)) {
LOG(("nsWebSocketHandler Redirect could not SetupRequest()\n"));
callback->OnRedirectVerifyCallback(rv);
return NS_OK;
}
// We cannot just tell the callback OK right now due to the 1 connect at
// a time policy. First we need to complete the old location and then
@ -1667,7 +1671,7 @@ nsWebSocketHandler::AsyncOnChannelRedirect(
rv = ApplyForAdmission();
if (NS_FAILED(rv)) {
LOG(("nsWebSocketHandler Redirect failed due to DNS failure\n"));
callback->OnRedirectVerifyCallback(NS_ERROR_FAILURE);
callback->OnRedirectVerifyCallback(rv);
mRedirectCallback = nsnull;
}
@ -1851,6 +1855,13 @@ nsWebSocketHandler::AsyncOpen(nsIURI *aURI,
return rv;
}
mRandomGenerator = do_GetService("@mozilla.org/security/random-generator;1",
&rv);
if (NS_FAILED(rv)) {
NS_WARNING("unable to continue without random number generator");
return rv;
}
nsCOMPtr<nsIPrefBranch> prefService;
prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);

View File

@ -56,6 +56,7 @@
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIStringStream.h"
#include "nsIHttpChannelInternal.h"
#include "nsIRandomGenerator.h"
#include "nsCOMPtr.h"
#include "nsString.h"
@ -196,6 +197,7 @@ private:
nsCOMPtr<nsILoadGroup> mLoadGroup;
nsCOMPtr<nsICancelable> mDNSRequest;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIRandomGenerator> mRandomGenerator;
nsCString mProtocol;
nsCString mOrigin;

View File

@ -0,0 +1,43 @@
do_load_httpd_js();
var httpserver = new nsHttpServer();
var index = 0;
function setupChannel(url)
{
var ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var chan = ios.newChannel("http://localhost:4444" + url, "", null);
var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel);
return httpChan;
}
function completeTest1(request, data, ctx)
{
httpserver.stop(do_test_finished);
}
function run_test()
{
httpserver.registerPathHandler("/2xcl", handler);
httpserver.start(4444);
var channel = setupChannel("/2xcl");
channel.asyncOpen(new ChannelListener(completeTest1,
channel, CL_EXPECT_FAILURE), null);
do_test_pending();
}
function handler(metadata, response)
{
var body = "012345678901234567890123456789";
response.seizePower();
response.write("HTTP/1.0 200 OK\r\n");
response.write("Content-Type: text/plain\r\n");
response.write("Content-Length: 20\r\n");
response.write("Content-Length: 30\r\n");
response.write("\r\n");
response.write(body);
response.finish();
}

View File

@ -68,6 +68,7 @@ tail =
[test_cookie_header.js]
[test_data_protocol.js]
[test_dns_service.js]
[test_double_content_length.js]
[test_event_sink.js]
[test_extract_charset_from_content_type.js]
[test_fallback_no-cache-entry_canceled.js]

View File

@ -35,93 +35,92 @@
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = toolkit/components/passwordmgr/test
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = toolkit/components/passwordmgr/test
include $(topsrcdir)/config/config.mk
ifneq (mobile,$(MOZ_BUILD_APP))
DIRS = \
browser \
$(NULL)
browser \
$(NULL)
endif
# Module name for xpcshell tests.
MODULE = test_passwordmgr
MODULE = test_passwordmgr
XPCSHELL_TESTS = unit
# Mochitest tests
MOCHI_TESTS = \
test_basic_form.html \
test_basic_form_html5.html \
test_basic_form_2.html \
test_basic_form_0pw.html \
test_basic_form_1pw.html \
test_basic_form_1pw_2.html \
test_basic_form_2pw_1.html \
test_basic_form_2pw_2.html \
test_basic_form_3pw_1.html \
test_basic_form_autocomplete.html \
test_basic_form_observer_autofillForms.html \
test_basic_form_observer_autocomplete.html \
test_basic_form_observer_foundLogins.html \
test_basic_form_pwonly.html \
test_bug_227640.html \
test_bug_242956.html \
test_bug_360493_1.html \
test_bug_360493_2.html \
test_bug_391514.html \
test_bug_427033.html \
test_bug_444968.html \
test_master_password.html \
test_master_password_cleanup.html \
test_prompt_async.html \
test_xhr.html \
test_xml_load.html \
test_zzz_finish.html \
$(NULL)
test_basic_form.html \
test_basic_form_html5.html \
test_basic_form_2.html \
test_basic_form_0pw.html \
test_basic_form_1pw.html \
test_basic_form_1pw_2.html \
test_basic_form_2pw_1.html \
test_basic_form_2pw_2.html \
test_basic_form_3pw_1.html \
test_basic_form_autocomplete.html \
test_basic_form_observer_autofillForms.html \
test_basic_form_observer_autocomplete.html \
test_basic_form_observer_foundLogins.html \
test_basic_form_pwonly.html \
test_bug_227640.html \
test_bug_242956.html \
test_bug_360493_1.html \
test_bug_360493_2.html \
test_bug_391514.html \
test_bug_427033.html \
test_bug_444968.html \
test_master_password.html \
test_master_password_cleanup.html \
test_prompt_async.html \
test_xhr.html \
test_xml_load.html \
test_zzz_finish.html \
$(NULL)
MOCHI_CONTENT = \
pwmgr_common.js \
prompt_common.js \
notification_common.js \
authenticate.sjs \
formsubmit.sjs \
subtst_privbrowsing_1.html \
subtst_privbrowsing_2.html \
subtst_privbrowsing_3.html \
subtst_privbrowsing_4.html \
subtst_master_pass.html \
subtst_notifications_1.html \
subtst_notifications_2.html \
subtst_notifications_3.html \
subtst_notifications_4.html \
subtst_notifications_5.html \
subtst_notifications_6.html \
subtst_notifications_7.html \
subtst_notifications_8.html \
subtst_notifications_9.html \
subtst_notifications_10.html \
subtst_prompt_async.html \
$(NULL)
pwmgr_common.js \
prompt_common.js \
notification_common.js \
authenticate.sjs \
formsubmit.sjs \
subtst_privbrowsing_1.html \
subtst_privbrowsing_2.html \
subtst_privbrowsing_3.html \
subtst_privbrowsing_4.html \
subtst_master_pass.html \
subtst_notifications_1.html \
subtst_notifications_2.html \
subtst_notifications_3.html \
subtst_notifications_4.html \
subtst_notifications_5.html \
subtst_notifications_6.html \
subtst_notifications_7.html \
subtst_notifications_8.html \
subtst_notifications_9.html \
subtst_notifications_10.html \
subtst_prompt_async.html \
$(NULL)
# Don't run these tests in suite
ifndef MOZ_SUITE
MOCHI_TESTS += \
test_privbrowsing.html \
test_prompt.html \
test_notifications.html \
$(NULL)
test_privbrowsing.html \
test_prompt.html \
test_notifications.html \
$(NULL)
else
$(warning test_prompt.html is disabled until doorhanger notfications work. Bug 598360)
$(warning test_notifications.html is disabled until doorhanger notfications work. Bug 598360)
$(warning test_privbrowsing.html is disabled due to doorhangers, Bug 598360, and no privatebrowsing support)
endif
XPCSHELL_TESTS = unit
# This test doesn't pass because we can't ensure a cross-platform
# event that occurs between DOMContentLoaded and Pageload
# test_bug_221634.html

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