[JAEGER] Merge from tracemonkey.

This commit is contained in:
David Mandelin 2010-08-11 11:30:10 -07:00
commit 53500d5d01
202 changed files with 14319 additions and 5467 deletions

View File

@ -322,6 +322,7 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
notifications are */
.notification-anchor-icon {
display: none;
-moz-user-focus: normal;
}
#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,

View File

@ -159,9 +159,13 @@ XPCOMUtils.defineLazyGetter(this, "Weave", function() {
XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () {
let tmp = {};
Cu.import("resource://gre/modules/PopupNotifications.jsm", tmp);
return new tmp.PopupNotifications(gBrowser,
document.getElementById("notification-popup"),
document.getElementById("notification-popup-box"));
try {
return new tmp.PopupNotifications(gBrowser,
document.getElementById("notification-popup"),
document.getElementById("notification-popup-box"));
} catch (ex) {
Cu.reportError(ex);
}
});
let gInitialPages = [

View File

@ -222,7 +222,8 @@
noautofocus="true"
noautohide="true"
onclick="InspectorUI.stopInspecting();"
onmousemove="InspectorUI.highlighter.handleMouseMove(event);"/>
onmousemove="InspectorUI.highlighter.handleMouseMove(event);"
onMozMousePixelScroll="InspectorUI.highlighter.handlePixelScroll(event);"/>
<panel id="inspector-panel"
orient="vertical"
@ -694,8 +695,8 @@
onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
<box id="notification-popup-box" hidden="true" align="center">
<image id="geo-notification-icon" class="notification-anchor-icon"/>
<image id="addons-notification-icon" class="notification-anchor-icon"/>
<image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
</box>
<!-- Use onclick instead of normal popup= syntax since the popup
code fires onmousedown, and hence eats our favicon drag events.

View File

@ -24,6 +24,7 @@
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com> (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Julian Viereck <jviereck@mozilla.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
@ -320,6 +321,29 @@ PanelHighlighter.prototype = {
InspectorUI.inspectNode(element);
}
},
/**
* Handle MozMousePixelScroll in panel when InspectorUI.inspecting is true.
*
* @param aEvent
* The onMozMousePixelScrollEvent triggering the method.
* @returns void
*/
handlePixelScroll: function PanelHighlighter_handlePixelScroll(aEvent) {
if (!InspectorUI.inspecting) {
return;
}
let browserRect = this.browser.getBoundingClientRect();
let element = InspectorUI.elementFromPoint(this.win.document,
aEvent.clientX - browserRect.left, aEvent.clientY - browserRect.top);
let win = element.ownerDocument.defaultView;
if (aEvent.axis == aEvent.HORIZONTAL_AXIS) {
win.scrollBy(aEvent.detail, 0);
} else {
win.scrollBy(0, aEvent.detail);
}
}
};
///////////////////////////////////////////////////////////////////////////

View File

@ -488,33 +488,38 @@
},
onLocationChange: function (aWebProgress, aRequest, aLocation) {
// The document loaded correctly, clear the value if we should
if (this.mBrowser.userTypedClear > 0)
this.mBrowser.userTypedValue = null;
// OnLocationChange is called for both the top-level content
// and the subframes.
let topLevel = aWebProgress.DOMWindow == this.mBrowser.contentWindow;
// Don't clear the favicon if this onLocationChange was triggered
// by a pushState or a replaceState. See bug 550565.
if (aWebProgress.DOMWindow == this.mBrowser.contentWindow &&
aWebProgress.isLoadingDocument &&
!(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE)) {
this.mBrowser.mIconURL = null;
if (topLevel) {
// The document loaded correctly, clear the value if we should
if (this.mBrowser.userTypedClear > 0)
this.mBrowser.userTypedValue = null;
// Clear out the missing plugins list since it's related to the
// previous location.
this.mBrowser.missingPlugins = null;
// Don't clear the favicon if this onLocationChange was
// triggered by a pushState or a replaceState. See bug 550565.
if (aWebProgress.isLoadingDocument &&
!(this.mBrowser.docShell.loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE))
this.mBrowser.mIconURL = null;
let browserHistory = this.mTabBrowser.mBrowserHistory;
if (this.mBrowser.lastURI)
browserHistory.unregisterOpenPage(this.mBrowser.lastURI);
browserHistory.registerOpenPage(aLocation);
}
// changing location, clear out the missing plugins list
this.mBrowser.missingPlugins = null;
var browserHistory = this.mTabBrowser.mBrowserHistory;
if ("lastURI" in this.mBrowser && this.mBrowser.lastURI)
browserHistory.unregisterOpenPage(this.mBrowser.lastURI);
browserHistory.registerOpenPage(aLocation);
if (!this.mBlank) {
this._callProgressListeners("onLocationChange",
[aWebProgress, aRequest, aLocation]);
}
this.mBrowser.lastURI = aLocation;
if (topLevel)
this.mBrowser.lastURI = aLocation;
},
onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
@ -1410,9 +1415,8 @@
filter.removeProgressListener(this.mTabListeners[aTab._tPos]);
this.mTabListeners[aTab._tPos].destroy();
let closedBrowser = this.getBrowserForTab(aTab);
if (closedBrowser.currentURI)
this.mBrowserHistory.unregisterOpenPage(closedBrowser.currentURI);
if (browser.currentURI)
this.mBrowserHistory.unregisterOpenPage(browser.currentURI);
// We are no longer the primary content area.
browser.setAttribute("type", "content-targetable");

View File

@ -0,0 +1,155 @@
/* ***** 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 TabView AllTabs.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Edward Lee <edilee@mozilla.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 ***** */
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
let EXPORTED_SYMBOLS = ["AllTabs"];
let AllTabs = {
/**
* Get an array of all tabs from all tabbrowser windows.
*
* @usage let numAllTabs = AllTabs.tabs.length;
* AllTabs.tabs.forEach(handleAllTabs);
*/
get tabs() {
// Get tabs from each browser window and flatten them into one array
return Array.concat.apply(null, browserWindows.map(function(browserWindow) {
return Array.slice(browserWindow.gBrowser.tabs);
}));
},
/**
* Attach a callback for a given tab event.
*
* @param eventName
* Name of the corresponding Tab* Event; one of "attrModified",
* "close", "move", "open", "select".
* @param callback
* Callback that gets called with the tab as the first argument and
* the event as the second argument.
* @usage AllTabs.register("change", function handleChange(tab, event) {});
*/
register: function register(eventName, callback) {
// Either add additional callbacks or create the first entry
let listeners = eventListeners[eventName];
if (listeners)
listeners.push(callback);
else
eventListeners[eventName] = [callback];
},
/**
* Remove a callback for a given tab event.
*
* @param eventName
* Name of the corresponding Tab* Event; one of "attrModified",
* "close", "move", "open", "select".
* @param callback
* The callback given for the original AllTabs.register call.
* @usage AllTabs.unregister("close", handleClose);
*/
unregister: function unregister(eventName, callback) {
// Nothing to remove for this event
let listeners = eventListeners[eventName];
if (!listeners)
return;
// Can only remove a callback if we have it
let index = listeners.indexOf(callback);
if (index == -1)
return;
listeners.splice(index, 1);
}
};
__defineGetter__("browserWindows", function browserWindows() {
let browserWindows = [];
let windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements())
browserWindows.push(windows.getNext());
return browserWindows;
});
let events = ["attrModified", "close", "move", "open", "select"];
let eventListeners = {};
function registerBrowserWindow(browserWindow) {
events.forEach(function(eventName) {
let tabEvent = "Tab" + eventName[0].toUpperCase() + eventName.slice(1);
browserWindow.addEventListener(tabEvent, function(event) {
// Make sure we've gotten listeners before trying to call
let listeners = eventListeners[eventName];
if (!listeners)
return;
let tab = event.target;
// Make a copy of the listeners, so it can't change as we call back
listeners.slice().forEach(function(callback) {
try {
callback(tab, event);
}
// Don't let failing callbacks stop us but report the failure
catch(ex) {
Cu.reportError(ex);
}
});
}, true);
});
}
function observer(subject, topic, data) {
switch (topic) {
case "domwindowopened":
subject.addEventListener("load", function() {
subject.removeEventListener("load", arguments.callee, false);
// Now that the window has loaded, only register on browser windows
let doc = subject.document.documentElement;
if (doc.getAttribute("windowtype") == "navigator:browser")
registerBrowserWindow(subject);
}, false);
break;
}
}
// Register listeners on all browser windows and future ones
browserWindows.forEach(registerBrowserWindow);
Services.obs.addObserver(observer, "domwindowopened", false);

View File

@ -151,6 +151,7 @@ _BROWSER_FILES = \
browser_inspector_highlighter.js \
browser_inspector_stylePanel.js \
browser_inspector_iframeTest.js \
browser_inspector_scrolling.js \
browser_pageInfo.js \
browser_page_style_menu.js \
browser_pinnedTabs.js \

View File

@ -0,0 +1,113 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** 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 Inspector iframe Tests.
*
* 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):
* Rob Campbell <rcampbell@mozilla.com>
* Mihai Șucan <mihai.sucan@gmail.com>
* Julian Viereck <jviereck@mozilla.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 ***** */
let doc;
let div;
let iframe;
function createDocument()
{
doc.title = "Inspector scrolling Tests";
iframe = doc.createElement("iframe");
iframe.addEventListener("load", function () {
iframe.removeEventListener("load", arguments.callee, false);
div = iframe.contentDocument.createElement("div");
div.textContent = "big div";
div.setAttribute("style", "height:500px; width:500px; border:1px solid gray;");
iframe.contentDocument.body.appendChild(div);
toggleInspector();
}, false);
iframe.src = "data:text/html,foo bar";
doc.body.appendChild(iframe);
}
function toggleInspector()
{
document.addEventListener("popupshown", inspectNode, false);
InspectorUI.toggleInspectorUI();
}
function inspectNode(aEvent)
{
if (aEvent.target.id != "inspector-panel") {
return true;
}
document.removeEventListener("popupshown", inspectNode, false);
document.addEventListener("popupshown", performScrollingTest, false);
InspectorUI.inspectNode(div)
}
function performScrollingTest(aEvent)
{
if (aEvent.target.id != "highlighter-panel") {
return true;
}
document.removeEventListener("popupshown", performScrollingTest, false);
EventUtils.synthesizeMouseScroll(aEvent.target, 10, 10,
{axis:"vertical", delta:50, type:"MozMousePixelScroll"}, window);
is(iframe.contentDocument.body.scrollTop, 50, "inspected iframe scrolled");
InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,mouse scrolling test for inspector";
}

View File

@ -296,7 +296,7 @@ var tests = [
this.firstNotification = showNotification(this.notifyObj);
this.notifyObj2 = new basicNotification();
this.notifyObj2.id += "-2";
this.notifyObj2.anchorID = "urlbar";
this.notifyObj2.anchorID = "addons-notification-icon";
// Second showNotification() overrides the first
this.secondNotification = showNotification(this.notifyObj2);
},
@ -485,15 +485,17 @@ function triggerSecondaryCommand(popup, index) {
}
function loadURI(uri, callback) {
gBrowser.addEventListener("load", function() {
// Ignore the about:blank load
if (gBrowser.currentURI.spec != uri)
return;
if (callback) {
gBrowser.addEventListener("load", function() {
// Ignore the about:blank load
if (gBrowser.currentURI.spec != uri)
return;
gBrowser.removeEventListener("load", arguments.callee, true);
gBrowser.removeEventListener("load", arguments.callee, true);
callback();
}, true);
callback();
}, true);
}
gBrowser.loadURI(uri);
}
@ -502,4 +504,4 @@ function dismissNotification(popup) {
executeSoon(function () {
EventUtils.synthesizeKey("VK_ESCAPE", {});
});
}
}

View File

@ -102,6 +102,23 @@ var gTestSteps = [
ensure_opentabs_match_db();
nextStep()
});
},
function() {
info("Running step 6 - ensure we don't register subframes as open pages");
let tab = gBrowser.addTab();
tab.linkedBrowser.addEventListener("load", function () {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
// Start the sub-document load.
executeSoon(function () {
tab.linkedBrowser.addEventListener("load", function (e) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
ensure_opentabs_match_db();
nextStep()
}, true);
tab.linkedBrowser.contentDocument.querySelector("iframe").src = "http://test2.example.org/";
});
}, true);
tab.linkedBrowser.loadURI('data:text/html,<body><iframe src=""></iframe></body>');
}
];

View File

@ -36,6 +36,20 @@ function closeContextMenu() {
contextMenu.hidePopup();
}
function executeCopyCommand(command, expectedValue)
{
// Just execute the command directly rather than simulating a context menu
// press to avoid having to deal with its asynchronous nature
subwindow.controllers.getControllerForCommand(command).doCommand(command);
// The easiest way to check the clipboard is to paste the contents into a
// textbox
input.focus();
input.value = "";
input.controllers.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
is(input.value, expectedValue, "paste for command " + command);
}
function getVisibleMenuItems(aMenu) {
var items = [];
var accessKeys = {};
@ -391,6 +405,13 @@ function runTest(testNum) {
"spell-add-dictionaries", true], null]);
closeContextMenu();
openContextMenuFor(link); // Invoke context menu for next test.
break;
case 15:
executeCopyCommand("cmd_copyLink", "http://mozilla.com/");
closeContextMenu();
subwindow.close();
SimpleTest.finish();
return;

View File

@ -207,6 +207,7 @@ repackage-win32-installer: $(WIN32_INSTALLER_IN) $(SUBMAKEFILES)
# those are just for language packs
cp -r $(DIST)/xpi-stage/locale-$(AB_CD) l10n-stage/localized
$(RM) l10n-stage/localized/install.rdf l10n-stage/localized/chrome.manifest
mv l10n-stage/localized/chrome/$(AB_CD).manifest l10n-stage/localized/chrome/localized.manifest
$(MAKE) -C ../installer/windows CONFIG_DIR=l10ngen l10ngen/setup.exe l10ngen/7zSD.sfx
cp ../installer/windows/l10ngen/setup.exe l10n-stage
$(NSINSTALL) -D l10n-stage/localized/uninstall

View File

@ -1007,6 +1007,10 @@ toolbar[iconsize="small"] #fullscreen-button {
height: 16px;
}
.notification-anchor-icon:-moz-focusring {
outline: 1px dotted -moz-DialogText;
}
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}

View File

@ -1868,6 +1868,11 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
margin: 0 2px;
}
.notification-anchor-icon:-moz-focusring {
-moz-box-shadow: 0 0 3px 1px -moz-mac-focusring inset,
0 0 3px 2px -moz-mac-focusring;
}
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}

View File

@ -1107,9 +1107,16 @@ richlistitem[type="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-i
#TabsToolbar:not(:-moz-lwtheme),
#TabsToolbar[tabsontop="false"] {
background-image: -moz-linear-gradient(transparent, transparent 50%,
rgba(0,0,0,.05) 90%, rgba(0,0,0,.1));
}
#TabsToolbar[tabsontop="true"]:not(:-moz-lwtheme) {
-moz-box-shadow: 0 -1px ThreeDShadow inset;
background-image: -moz-linear-gradient(transparent, transparent 10%,
rgba(0,0,0,.03) 50%, rgba(0,0,0,.1) 90%, rgba(0,0,0,.2));
}
#TabsToolbar[tabsontop="false"] {
border-bottom: 1px solid ThreeDShadow !important;
}
.tabbrowser-tabs:-moz-system-metric(touch-enabled) {
@ -1611,6 +1618,11 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
height: 16px;
}
.notification-anchor-icon:-moz-focusring {
outline: 1px dotted -moz-DialogText;
outline-offset: -3px;
}
#geo-notification-icon {
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
}

View File

@ -186,7 +186,7 @@ check::
mkdir unify-sort-test unify-sort-test/a unify-sort-test/b
printf "lmn\nabc\nxyz\n" > unify-sort-test/a/file.foo
printf "xyz\nlmn\nabc" > unify-sort-test/b/file.foo
printf "abc\nlmn\nxyz\n" > unify-sort-test/expected-result
printf "lmn\nabc\nxyz\n" > unify-sort-test/expected-result
@if ! $(srcdir)/macosx/universal/unify --unify-with-sort "\.foo$$" \
./unify-sort-test/a ./unify-sort-test/b \
./unify-sort-test/c; then \

View File

@ -201,7 +201,6 @@ sub copyIfIdentical($$$);
sub slurp($);
sub get_sorted($);
sub compare_sorted($$);
sub copy_sorted($$);
sub copyIfIdenticalWhenSorted($$$);
sub createUniqueFile($$);
sub makeUniversal($$$);
@ -541,21 +540,6 @@ sub compare_sorted($$) {
return 0;
}
# copy_sorted($source, $destination)
#
# $source and $destination are filenames. Read the contents of $source
# into an array, sort it, and then write the sorted contents to $destination.
# Returns 1 on success, and undef on failure.
sub copy_sorted($$) {
my ($src, $dest) = @_;
my @lines = get_sorted($src);
return undef unless @lines;
open FILE, "> $dest" or return undef;
print FILE @lines;
close FILE;
return 1;
}
# copyIfIdenticalWhenSorted($source1, $source2, $target)
#
# $source1 and $source2 are FileAttrCache objects that are compared, and if
@ -605,8 +589,8 @@ sub copyIfIdenticalWhenSorted($$$) {
return 0;
}
if (!copy_sorted($source1->path(), $target)) {
complain(1, 'copyIfIdenticalWhenSorted: copy_sorted: '.$!
if (!copy($source1->path(), $target)) {
complain(1, 'copyIfIdenticalWhenSorted: copy: '.$!
.' while copying',
$source1->path(),
$target);

View File

@ -1,5 +1,2 @@
repo: f5ab154deef2ffa97f1b2139589ae4a1962090a4
node: e50be3234e397322410b29a9e226365e23cb322e
branch: default
latesttag: null
latesttagdistance: 255
node: 7ae0b4af32617677698f9de3ab76bcb154bbf085

View File

@ -10,10 +10,8 @@ import sys, os
import pymake.command, pymake.process
import gc
gc.disable()
if __name__ == '__main__':
gc.disable()
pymake.command.main(sys.argv[1:], os.environ, os.getcwd(), cb=sys.exit)
pymake.process.ParallelContext.spin()
assert False, "Not reached"
pymake.command.main(sys.argv[1:], os.environ, os.getcwd(), cb=sys.exit)
pymake.process.ParallelContext.spin()
assert False, "Not reached"

View File

@ -1,68 +1,10 @@
# Basic commands implemented in Python
import sys, os, shutil, time
from getopt import getopt, GetoptError
"""
Implicit variables; perhaps in the future this will also include some implicit
rules, at least match-anything cancellation rules.
"""
from process import PythonException
__all__ = ["rm", "sleep", "touch"]
def rm(args):
"""
Emulate most of the behavior of rm(1).
Only supports the -r (--recursive) and -f (--force) arguments.
"""
try:
opts, args = getopt(args, "rRf", ["force", "recursive"])
except GetoptError, e:
raise PythonException, ("rm: %s" % e, 1)
force = False
recursive = False
for o, a in opts:
if o in ('-f', '--force'):
force = True
elif o in ('-r', '-R', '--recursive'):
recursive = True
for f in args:
if os.path.isdir(f):
if not recursive:
raise PythonException, ("rm: cannot remove '%s': Is a directory" % f, 1)
else:
shutil.rmtree(f, force)
elif os.path.exists(f):
try:
os.unlink(f)
except:
if not force:
raise PythonException, ("rm: failed to remove '%s': %s" % (f, sys.exc_info()[0]), 1)
elif not force:
raise PythonException, ("rm: cannot remove '%s': No such file or directory" % f, 1)
def sleep(args):
"""
Emulate the behavior of sleep(1).
"""
total = 0
values = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}
for a in args:
multiplier = 1
for k, v in values.iteritems():
if a.endswith(k):
a = a[:-1]
multiplier = v
break
try:
f = float(a)
total += f * multiplier
except ValueError:
raise PythonException, ("sleep: invalid time interval '%s'" % a, 1)
time.sleep(total)
def touch(args):
"""
Emulate the behavior of touch(1).
"""
for f in args:
if os.path.exists(f):
os.utime(f, None)
else:
open(f, 'w').close()
variables = {
'RM': 'rm -f',
'.LIBPATTERNS': 'lib%.so lib%.a',
'.PYMAKE': '1',
}

View File

@ -106,8 +106,7 @@ class _MakeContext(object):
makeoverrides=self.overrides,
workdir=self.workdir,
context=self.context, env=self.env, makelevel=self.makelevel,
targets=self.targets, keepgoing=self.options.keepgoing,
silent=self.options.silent)
targets=self.targets, keepgoing=self.options.keepgoing)
self.restarts += 1
@ -187,8 +186,6 @@ def main(args, env, cwd, cb):
dest="printdir")
op.add_option('--no-print-directory', action="store_false",
dest="printdir", default=True)
op.add_option('-s', '--silent', action="store_true",
dest="silent", default=False)
options, arguments1 = op.parse_args(parsemakeflags(env))
options, arguments2 = op.parse_args(args, values=options)
@ -211,10 +208,6 @@ def main(args, env, cwd, cb):
if options.printdir:
shortflags.append('w')
if options.silent:
shortflags.append('s')
options.printdir = False
loglevel = logging.WARNING
if options.verbose:
loglevel = logging.DEBUG

View File

@ -3,7 +3,7 @@ A representation of makefile data structures.
"""
import logging, re, os, sys
import parserdata, parser, functions, process, util, implicit
import parserdata, parser, functions, process, util, builtins
from cStringIO import StringIO
_log = logging.getLogger('pymake.data')
@ -1142,18 +1142,17 @@ def splitcommand(command):
def findmodifiers(command):
"""
Find any of +-@% prefixed on the command.
@returns (command, isHidden, isRecursive, ignoreErrors, isNative)
Find any of +-@ prefixed on the command.
@returns (command, isHidden, isRecursive, ignoreErrors)
"""
isHidden = False
isRecursive = False
ignoreErrors = False
isNative = False
realcommand = command.lstrip(' \t\n@+-%')
realcommand = command.lstrip(' \t\n@+-')
modset = set(command[:-len(realcommand)])
return realcommand, '@' in modset, '+' in modset, '-' in modset, '%' in modset
return realcommand, '@' in modset, '+' in modset, '-' in modset
class _CommandWrapper(object):
def __init__(self, cline, ignoreErrors, loc, context, **kwargs):
@ -1174,32 +1173,6 @@ class _CommandWrapper(object):
self.usercb = cb
process.call(self.cline, loc=self.loc, cb=self._cb, context=self.context, **self.kwargs)
class _NativeWrapper(_CommandWrapper):
def __init__(self, cline, ignoreErrors, loc, context,
pycommandpath, **kwargs):
_CommandWrapper.__init__(self, cline, ignoreErrors, loc, context,
**kwargs)
# get the module and method to call
parts, badchar = process.clinetoargv(cline)
if parts is None:
raise DataError("native command '%s': shell metacharacter '%s' in command line" % (cline, badchar), self.loc)
if len(parts) < 2:
raise DataError("native command '%s': no method name specified" % cline, self.loc)
if pycommandpath:
self.pycommandpath = re.split('[%s\s]+' % os.pathsep,
pycommandpath)
else:
self.pycommandpath = None
self.module = parts[0]
self.method = parts[1]
self.cline_list = parts[2:]
def __call__(self, cb):
self.usercb = cb
process.call_native(self.module, self.method, self.cline_list,
loc=self.loc, cb=self._cb, context=self.context,
pycommandpath=self.pycommandpath, **self.kwargs)
def getcommandsforrule(rule, target, makefile, prerequisites, stem):
v = Variables(parent=target.variables)
setautomaticvariables(v, makefile, target, prerequisites)
@ -1211,22 +1184,13 @@ def getcommandsforrule(rule, target, makefile, prerequisites, stem):
for c in rule.commands:
cstring = c.resolvestr(makefile, v)
for cline in splitcommand(cstring):
cline, isHidden, isRecursive, ignoreErrors, isNative = findmodifiers(cline)
if isHidden or makefile.silent:
cline, isHidden, isRecursive, ignoreErrors = findmodifiers(cline)
if isHidden:
echo = None
else:
echo = "%s$ %s" % (c.loc, cline)
if not isNative:
yield _CommandWrapper(cline, ignoreErrors=ignoreErrors, env=env, cwd=makefile.workdir, loc=c.loc, context=makefile.context,
echo=echo)
else:
f, s, e = v.get("PYCOMMANDPATH", True)
if e:
e = e.resolvestr(makefile, v, ["PYCOMMANDPATH"])
yield _NativeWrapper(cline, ignoreErrors=ignoreErrors,
env=env, cwd=makefile.workdir,
loc=c.loc, context=makefile.context,
echo=echo, pycommandpath=e)
yield _CommandWrapper(cline, ignoreErrors=ignoreErrors, env=env, cwd=makefile.workdir, loc=c.loc, context=makefile.context,
echo=echo)
class Rule(object):
"""
@ -1371,8 +1335,7 @@ class Makefile(object):
def __init__(self, workdir=None, env=None, restarts=0, make=None,
makeflags='', makeoverrides='',
makelevel=0, context=None, targets=(), keepgoing=False,
silent=False):
makelevel=0, context=None, targets=(), keepgoing=False):
self.defaulttarget = None
if env is None:
@ -1386,7 +1349,6 @@ class Makefile(object):
self.exportedvars = {}
self._targets = {}
self.keepgoing = keepgoing
self.silent = silent
self._patternvariables = [] # of (pattern, variables)
self.implicitrules = []
self.parsingfinished = False
@ -1406,8 +1368,6 @@ class Makefile(object):
self.variables.set('MAKE_RESTARTS', Variables.FLAVOR_SIMPLE,
Variables.SOURCE_AUTOMATIC, restarts > 0 and str(restarts) or '')
self.variables.set('.PYMAKE', Variables.FLAVOR_SIMPLE,
Variables.SOURCE_MAKEFILE, "1")
if make is not None:
self.variables.set('MAKE', Variables.FLAVOR_SIMPLE,
Variables.SOURCE_MAKEFILE, make)
@ -1432,7 +1392,7 @@ class Makefile(object):
self.variables.set('MAKECMDGOALS', Variables.FLAVOR_SIMPLE,
Variables.SOURCE_AUTOMATIC, ' '.join(targets))
for vname, val in implicit.variables.iteritems():
for vname, val in builtins.variables.iteritems():
self.variables.set(vname,
Variables.FLAVOR_SIMPLE,
Variables.SOURCE_IMPLICIT, val)

View File

@ -1,13 +0,0 @@
"""
Implicit variables; perhaps in the future this will also include some implicit
rules, at least match-anything cancellation rules.
"""
variables = {
'RM': '%pymake.builtins rm -f',
'SLEEP': '%pymake.builtins sleep',
'TOUCH': '%pymake.builtins touch',
'.LIBPATTERNS': 'lib%.so lib%.a',
'.PYMAKE': '1',
}

View File

@ -3,9 +3,7 @@ Skipping shell invocations is good, when possible. This wrapper around subproces
parsing command lines into argv and making sure that no shell magic is being used.
"""
#TODO: ship pyprocessing?
from multiprocessing import Pool, Condition
import subprocess, shlex, re, logging, sys, traceback, os, imp
import subprocess, shlex, re, logging, sys, traceback, os
import command, util
if sys.platform=='win32':
import win32process
@ -81,11 +79,6 @@ def call(cline, env, cwd, loc, cb, context, echo):
context.call(argv, executable=executable, shell=False, env=env, cwd=cwd, cb=cb, echo=echo)
def call_native(module, method, argv, env, cwd, loc, cb, context, echo,
pycommandpath=None):
context.call_native(module, method, argv, env=env, cwd=cwd, cb=cb,
echo=echo, pycommandpath=pycommandpath)
def statustoresult(status):
"""
Convert the status returned from waitpid into a prettier numeric result.
@ -96,127 +89,17 @@ def statustoresult(status):
return status >>8
class Job(object):
"""
A single job to be executed on the process pool.
"""
done = False # set to true when the job completes
def __init__(self):
self.exitcode = -127
def notify(self, condition, result):
condition.acquire()
self.done = True
self.exitcode = result
condition.notify()
condition.release()
def get_callback(self, condition):
return lambda result: self.notify(condition, result)
class PopenJob(Job):
"""
A job that executes a command using subprocess.Popen.
"""
def __init__(self, argv, executable, shell, env, cwd):
Job.__init__(self)
self.argv = argv
self.executable = executable
self.shell = shell
self.env = env
self.cwd = cwd
def run(self):
try:
p = subprocess.Popen(self.argv, executable=self.executable, shell=self.shell, env=self.env, cwd=self.cwd)
return p.wait()
except OSError, e:
print >>sys.stderr, e
return -127
class PythonException(Exception):
def __init__(self, message, exitcode):
Exception.__init__(self)
self.message = message
self.exitcode = exitcode
def __str__(self):
return self.message
def load_module_recursive(module, path):
"""
Emulate the behavior of __import__, but allow
passing a custom path to search for modules.
"""
bits = module.split('.')
for i, bit in enumerate(bits):
dotname = '.'.join(bits[:i+1])
try:
f, path, desc = imp.find_module(bit, path)
m = imp.load_module(dotname, f, path, desc)
if f is None:
path = m.__path__
except ImportError:
return
class PythonJob(Job):
"""
A job that calls a Python method.
"""
def __init__(self, module, method, argv, env, cwd, pycommandpath=None):
self.module = module
self.method = method
self.argv = argv
self.env = env
self.cwd = cwd
self.pycommandpath = pycommandpath or []
def run(self):
oldenv = os.environ
try:
os.chdir(self.cwd)
os.environ = self.env
if self.module not in sys.modules:
load_module_recursive(self.module,
sys.path + self.pycommandpath)
if self.module not in sys.modules:
print >>sys.stderr, "No module named '%s'" % self.module
return -127
m = sys.modules[self.module]
if self.method not in m.__dict__:
print >>sys.stderr, "No method named '%s' in module %s" % (method, module)
return -127
m.__dict__[self.method](self.argv)
except PythonException, e:
print >>sys.stderr, e
return e.exitcode
except:
print >>sys.stderr, sys.exc_info()[1]
return -127
finally:
os.environ = oldenv
return 0
def job_runner(job):
"""
Run a job. Called in a Process pool.
"""
return job.run()
class ParallelContext(object):
"""
Manages the parallel execution of processes.
"""
_allcontexts = set()
_condition = Condition()
def __init__(self, jcount):
self.jcount = jcount
self.exit = False
self.pool = Pool(processes=jcount)
self.pending = [] # list of (cb, args, kwargs)
self.running = [] # list of (subprocess, cb)
@ -224,8 +107,6 @@ class ParallelContext(object):
def finish(self):
assert len(self.pending) == 0 and len(self.running) == 0, "pending: %i running: %i" % (len(self.pending), len(self.running))
self.pool.close()
self.pool.join()
self._allcontexts.remove(self)
def run(self):
@ -238,19 +119,16 @@ class ParallelContext(object):
self.pending.append((cb, args, kwargs))
def _docall(self, argv, executable, shell, env, cwd, cb, echo):
if echo is not None:
print echo
job = PopenJob(argv, executable=executable, shell=shell, env=env, cwd=cwd)
self.pool.apply_async(job_runner, args=(job,), callback=job.get_callback(ParallelContext._condition))
self.running.append((job, cb))
if echo is not None:
print echo
try:
p = subprocess.Popen(argv, executable=executable, shell=shell, env=env, cwd=cwd)
except OSError, e:
print >>sys.stderr, e
cb(-127)
return
def _docallnative(self, module, method, argv, env, cwd, cb, echo,
pycommandpath=None):
if echo is not None:
print echo
job = PythonJob(module, method, argv, env, cwd, pycommandpath)
self.pool.apply_async(job_runner, args=(job,), callback=job.get_callback(ParallelContext._condition))
self.running.append((job, cb))
self.running.append((p, cb))
def call(self, argv, shell, env, cwd, cb, echo, executable=None):
"""
@ -259,43 +137,24 @@ class ParallelContext(object):
self.defer(self._docall, argv, executable, shell, env, cwd, cb, echo)
def call_native(self, module, method, argv, env, cwd, cb,
echo, pycommandpath=None):
"""
Asynchronously call the native function
"""
if sys.platform == 'win32':
@staticmethod
def _waitany():
return win32process.WaitForAnyProcess([p for c in ParallelContext._allcontexts for p, cb in c.running])
self.defer(self._docallnative, module, method, argv, env, cwd, cb,
echo, pycommandpath)
@staticmethod
def _comparepid(pid, process):
return pid == process
@staticmethod
def _waitany():
def _checkdone():
jobs = []
for c in ParallelContext._allcontexts:
for i in xrange(0, len(c.running)):
if c.running[i][0].done:
jobs.append(c.running[i])
for j in jobs:
if j in c.running:
c.running.remove(j)
return jobs
else:
@staticmethod
def _waitany():
return os.waitpid(-1, 0)
# We must acquire the lock, and then check to see if any jobs have
# finished. If we don't check after acquiring the lock it's possible
# that all outstanding jobs will have completed before we wait and we'll
# wait for notifications that have already occurred.
ParallelContext._condition.acquire()
jobs = _checkdone()
@staticmethod
def _comparepid(pid, process):
return pid == process.pid
if jobs == []:
ParallelContext._condition.wait()
jobs = _checkdone()
ParallelContext._condition.release()
return jobs
@staticmethod
def spin():
"""
@ -307,10 +166,39 @@ class ParallelContext(object):
for c in clist:
c.run()
# In python 2.4, subprocess instances wait on child processes under the hood when they are created... this
# unfortunate behavior means that before using os.waitpid, we need to check the status using .poll()
# see http://bytes.com/groups/python/675403-os-wait-losing-child
found = False
for c in clist:
for i in xrange(0, len(c.running)):
p, cb = c.running[i]
result = p.poll()
if result != None:
del c.running[i]
cb(result)
found = True
break
if found: break
if found: continue
dowait = util.any((len(c.running) for c in ParallelContext._allcontexts))
if dowait:
for job, cb in ParallelContext._waitany():
cb(job.exitcode)
pid, status = ParallelContext._waitany()
result = statustoresult(status)
for c in ParallelContext._allcontexts:
for i in xrange(0, len(c.running)):
p, cb = c.running[i]
if ParallelContext._comparepid(pid, p):
del c.running[i]
cb(result)
found = True
break
if found: break
else:
assert any(len(c.pending) for c in ParallelContext._allcontexts)

View File

@ -1,10 +0,0 @@
#T gmake skip
export EXPECTED := some data
CMD = %pycmd writeenvtofile
PYCOMMANDPATH = $(TESTPATH)
all:
$(CMD) results EXPECTED
test "$$(cat results)" = "$(EXPECTED)"
@echo TEST-PASS

View File

@ -1,21 +0,0 @@
#T gmake skip
EXPECTED := some data
# verify that we can load native command modules from
# multiple directories in PYCOMMANDPATH separated by the native
# path separator
ifdef __WIN32__
PS:=;
else
PS:=:
endif
CMD = %pycmd writetofile
CMD2 = %pymod writetofile
PYCOMMANDPATH = $(TESTPATH)$(PS)$(TESTPATH)/subdir
all:
$(CMD) results $(EXPECTED)
test "$$(cat results)" = "$(EXPECTED)"
$(CMD2) results2 $(EXPECTED)
test "$$(cat results2)" = "$(EXPECTED)"
@echo TEST-PASS

View File

@ -1,15 +0,0 @@
#T gmake skip
EXPECTED := some data
# verify that we can load native command modules from
# multiple space-separated directories in PYCOMMANDPATH
CMD = %pycmd writetofile
CMD2 = %pymod writetofile
PYCOMMANDPATH = $(TESTPATH) $(TESTPATH)/subdir
all:
$(CMD) results $(EXPECTED)
test "$$(cat results)" = "$(EXPECTED)"
$(CMD2) results2 $(EXPECTED)
test "$$(cat results2)" = "$(EXPECTED)"
@echo TEST-PASS

View File

@ -1,10 +0,0 @@
ifndef TOUCH
TOUCH = touch
endif
all: testfile
test -f testfile
@echo TEST-PASS
testfile:
$(TOUCH) $@

View File

@ -1,21 +0,0 @@
#T commandline: ['-j2']
# ensure that calling python commands doesn't block other targets
ifndef SLEEP
SLEEP := sleep
endif
PRINTF = printf "$@:0:" >>results
EXPECTED = target2:0:target1:0:
all:: target1 target2
cat results
test "$$(cat results)" = "$(EXPECTED)"
@echo TEST-PASS
target1:
$(SLEEP) 0.1
$(PRINTF)
target2:
$(PRINTF)

View File

@ -1,9 +0,0 @@
import os
def writetofile(args):
with open(args[0], 'w') as f:
f.write(' '.join(args[1:]))
def writeenvtofile(args):
with open(args[0], 'w') as f:
f.write(os.environ[args[1]])

View File

@ -1,7 +0,0 @@
#T returncode: 2
all:
mkdir newdir
test -d newdir
touch newdir/newfile
$(RM) newdir
@echo TEST-PASS

View File

@ -1,13 +0,0 @@
all:
# $(RM) defaults to -f
$(RM) nosuchfile
touch newfile
test -f newfile
$(RM) newfile
test ! -f newfile
mkdir newdir
test -d newdir
touch newdir/newfile
$(RM) -r newdir
test ! -d newdir
@echo TEST-PASS

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
"""
Run the test(s) listed on the command line. If a directory is listed, the script will recursively
walk the directory for files named .mk and run each.

View File

@ -1,3 +0,0 @@
def writetofile(args):
with open(args[0], 'w') as f:
f.write(' '.join(args[1:]))

View File

@ -52,8 +52,9 @@ from MozZipFile import ZipFile
from cStringIO import StringIO
from datetime import datetime
from utils import pushback_iter
from utils import pushback_iter, lockFile
from Preprocessor import Preprocessor
from buildlist import addEntriesToListFile
__all__ = ['JarMaker']
@ -164,7 +165,7 @@ class JarMaker(object):
pass
def finalizeJar(self, jarPath, chromebasepath, register,
doZip=True):
doZip=True):
'''Helper method to write out the chrome registration entries to
jarfile.manifest or chrome.manifest, or both.
@ -173,35 +174,42 @@ class JarMaker(object):
# rewrite the manifest, if entries given
if not register:
return
chromeManifest = os.path.join(os.path.dirname(jarPath),
'..', 'chrome.manifest')
if self.useJarfileManifest:
self.updateManifest(jarPath + '.manifest', chromebasepath % '',
register)
addEntriesToListFile(chromeManifest, ['manifest chrome/%s.manifest' % (os.path.basename(jarPath),)])
if self.useChromeManifest:
manifestPath = os.path.join(os.path.dirname(jarPath),
'..', 'chrome.manifest')
self.updateManifest(manifestPath, chromebasepath % 'chrome/',
self.updateManifest(chromeManifest, chromebasepath % 'chrome/',
register)
def updateManifest(self, manifestPath, chromebasepath, register):
'''updateManifest replaces the % in the chrome registration entries
with the given chrome base path, and updates the given manifest file.
'''
myregister = dict.fromkeys(map(lambda s: s.replace('%', chromebasepath),
register.iterkeys()))
manifestExists = os.path.isfile(manifestPath)
mode = (manifestExists and 'r+b') or 'wb'
mf = open(manifestPath, mode)
if manifestExists:
# import previous content into hash, ignoring empty ones and comments
imf = re.compile('(#.*)?$')
for l in re.split('[\r\n]+', mf.read()):
if imf.match(l):
continue
myregister[l] = None
mf.seek(0)
for k in myregister.iterkeys():
mf.write(k + os.linesep)
mf.close()
lock = lockFile(manifestPath + '.lck')
try:
myregister = dict.fromkeys(map(lambda s: s.replace('%', chromebasepath),
register.iterkeys()))
manifestExists = os.path.isfile(manifestPath)
mode = (manifestExists and 'r+b') or 'wb'
mf = open(manifestPath, mode)
if manifestExists:
# import previous content into hash, ignoring empty ones and comments
imf = re.compile('(#.*)?$')
for l in re.split('[\r\n]+', mf.read()):
if imf.match(l):
continue
myregister[l] = None
mf.seek(0)
for k in myregister.iterkeys():
mf.write(k + os.linesep)
mf.close()
finally:
lock = None
def makeJar(self, infile=None,
jardir='',

View File

@ -908,6 +908,7 @@ ifdef IS_COMPONENT
$(INSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(FINAL_TARGET)/components
$(ELF_DYNSTR_GC) $(FINAL_TARGET)/components/$(SHARED_LIBRARY)
ifndef NO_COMPONENTS_MANIFEST
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/components.manifest"
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/components.manifest "binary-component $(SHARED_LIBRARY)"
endif
ifdef BEOS_ADDON_WORKAROUND
@ -1782,6 +1783,7 @@ ifndef NO_DIST_INSTALL
$(INSTALL) $(IFLAGS1) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(FINAL_TARGET)/components
ifndef NO_INTERFACES_MANIFEST
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPIDL_MODULE).xpt"
@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
endif
endif
@ -1897,7 +1899,12 @@ ifndef NO_DIST_INSTALL
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $$i > $$dest; \
done
endif
endif
EXTRA_MANIFESTS = $(filter %.manifest,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS))
ifneq (,$(EXTRA_MANIFESTS))
libs::
$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest $(patsubst %,"manifest components/%",$(notdir $(EXTRA_MANIFESTS)))
endif
################################################################################
@ -2338,6 +2345,8 @@ FREEZE_VARIABLES = \
REQUIRES \
SHORT_LIBNAME \
TIERS \
EXTRA_COMPONENTS \
EXTRA_PP_COMPONENTS \
$(NULL)
$(foreach var,$(FREEZE_VARIABLES),$(eval $(var)_FROZEN := '$($(var))'))

View File

@ -43,7 +43,7 @@ class TestJarMaker(unittest.TestCase):
"""
Unit tests for JarMaker.py
"""
debug = False # set to True to debug failing tests on disk
debug = True # set to True to debug failing tests on disk
def setUp(self):
self.tmpdir = mkdtemp()
self.srcdir = os.path.join(self.tmpdir, 'src')
@ -142,6 +142,10 @@ class TestJarMaker(unittest.TestCase):
os.mkdir(ldir)
open(os.path.join(ldir, relpath), 'w').write(relpath+" content\n")
# create reference
mf = open(os.path.join(self.refdir, 'chrome.manifest'), 'w')
mf.write('manifest chrome/ab-CD.manifest\n')
mf.close()
chrome_ref = os.path.join(self.refdir, 'chrome')
os.mkdir(chrome_ref)
mf = open(os.path.join(chrome_ref, 'ab-CD.manifest'), 'wb')

View File

@ -132,7 +132,7 @@ GCONF_VERSION=1.2.1
GIO_VERSION=2.0
STARTUP_NOTIFICATION_VERSION=0.8
DBUS_VERSION=0.60
SQLITE_VERSION=3.6.23.1
SQLITE_VERSION=3.7.0.1
LIBNOTIFY_VERSION=0.4
MSMANIFEST_TOOL=
@ -5915,42 +5915,43 @@ if test -n "$MOZ_WEBM"; then
dnl For Darwin x86, Darwin x86_64, Linux x86, and WINNT x86_64
dnl we can use YASM.
AC_MSG_CHECKING([for YASM assembler])
AC_CHECK_PROGS(VPX_AS, yasm, "")
if test -n "$VPX_AS"; then
dnl We have YASM, see if we have assembly on this platform.
case "$OS_ARCH:$OS_TEST" in
Linux:x86|Linux:i?86)
VPX_ASFLAGS="-f elf32 -rnasm -pnasm"
AC_CHECK_PROGS(VPX_AS, $YASM yasm, "")
dnl We have YASM, see if we have assembly on this platform.
case "$OS_ARCH:$OS_TEST" in
Linux:x86|Linux:i?86)
VPX_ASFLAGS="-f elf32 -rnasm -pnasm"
VPX_X86_ASM=1
;;
Linux:x86_64)
VPX_ASFLAGS="-f elf64 -rnasm -pnasm -DPIC"
VPX_X86_ASM=1
;;
SunOS:i?86)
VPX_ASFLAGS="-f elf32 -rnasm -pnasm"
VPX_X86_ASM=1
;;
SunOS:x86_64)
VPX_ASFLAGS="-f elf64 -rnasm -pnasm -DPIC"
VPX_X86_ASM=1
;;
Darwin:i?86)
VPX_ASFLAGS="-f macho32 -rnasm -pnasm -DPIC"
VPX_X86_ASM=1
;;
Darwin:x86_64)
VPX_ASFLAGS="-f macho64 -rnasm -pnasm -DPIC"
VPX_X86_ASM=1
;;
WINNT:x86_64)
if test -z "$GNU_CC"; then
VPX_ASFLAGS="-f x64 -rnasm -pnasm"
VPX_X86_ASM=1
;;
Linux:x86_64)
VPX_ASFLAGS="-f elf64 -rnasm -pnasm -DPIC"
VPX_X86_ASM=1
;;
SunOS:i?86)
VPX_ASFLAGS="-f elf32 -rnasm -pnasm"
VPX_X86_ASM=1
;;
SunOS:x86_64)
VPX_ASFLAGS="-f elf64 -rnasm -pnasm -DPIC"
VPX_X86_ASM=1
;;
Darwin:i?86)
VPX_ASFLAGS="-f macho32 -rnasm -pnasm -DPIC"
VPX_X86_ASM=1
;;
Darwin:x86_64)
VPX_ASFLAGS="-f macho64 -rnasm -pnasm -DPIC"
VPX_X86_ASM=1
;;
WINNT:x86_64)
if test -z "$GNU_CC"; then
VPX_ASFLAGS="-f x64 -rnasm -pnasm"
VPX_X86_ASM=1
fi
;;
esac
fi # end have YASM
fi
;;
esac
if test -n "$VPX_X86_ASM" -a -z "$VPX_AS"; then
AC_MSG_ERROR([yasm is a required build tool for this architecture when webm is enabled. You may either install yasm or --disable-webm (which disables the WebM video format). See https://developer.mozilla.org/en/YASM for more details.])
fi
fi # end !WINNT_x86_MSVC
if test -n "$VPX_X86_ASM"; then

View File

@ -1889,7 +1889,11 @@ nsFrameLoader::EnsureMessageManager()
return rv;
}
if (!mIsTopLevelContent) {
if (!mIsTopLevelContent
#ifdef MOZ_IPC
&& !mRemoteFrame
#endif
) {
return NS_OK;
}

View File

@ -36,7 +36,6 @@
* ***** END LICENSE BLOCK ***** */
#include "jscntxt.h"
#include "nsFrameMessageManager.h"
#include "nsContentUtils.h"
#include "nsIXPConnect.h"
@ -44,6 +43,9 @@
#include "jsarray.h"
#include "jsinterp.h"
#include "nsJSUtils.h"
#include "nsNetUtil.h"
#include "nsScriptLoader.h"
#include "nsIJSContextStack.h"
NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
@ -505,3 +507,168 @@ NS_NewGlobalMessageManager(nsIChromeFrameMessageManager** aResult)
NS_ENSURE_TRUE(mm, NS_ERROR_OUT_OF_MEMORY);
return CallQueryInterface(mm, aResult);
}
nsDataHashtable<nsStringHashKey, nsFrameScriptExecutorJSObjectHolder*>*
nsFrameScriptExecutor::sCachedScripts = nsnull;
void
nsFrameScriptExecutor::DidCreateCx()
{
NS_ASSERTION(mCx, "Should have mCx!");
if (!sCachedScripts) {
sCachedScripts =
new nsDataHashtable<nsStringHashKey, nsFrameScriptExecutorJSObjectHolder*>;
sCachedScripts->Init();
}
}
void
nsFrameScriptExecutor::DestroyCx()
{
nsIXPConnect* xpc = nsContentUtils::XPConnect();
if (xpc) {
xpc->ReleaseJSContext(mCx, PR_TRUE);
} else {
JS_DestroyContext(mCx);
}
mCx = nsnull;
}
static PLDHashOperator
CachedScriptUnrooter(const nsAString& aKey,
nsFrameScriptExecutorJSObjectHolder*& aData,
void* aUserArg)
{
JSContext* cx = static_cast<JSContext*>(aUserArg);
JS_RemoveObjectRoot(cx, &(aData->mObject));
return PL_DHASH_REMOVE;
}
// static
void
nsFrameScriptExecutor::Shutdown()
{
if (sCachedScripts) {
JSContext* cx = nsnull;
nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx);
if (cx) {
#ifdef DEBUG_smaug
printf("Will clear cached frame manager scripts!\n");
#endif
JSAutoRequest ar(cx);
NS_ASSERTION(sCachedScripts != nsnull, "Need cached scripts");
sCachedScripts->Enumerate(CachedScriptUnrooter, cx);
} else {
NS_WARNING("No context available. Leaking cached scripts!\n");
}
delete sCachedScripts;
sCachedScripts = nsnull;
}
}
void
nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL)
{
if (!mGlobal || !mCx) {
return;
}
nsFrameScriptExecutorJSObjectHolder* holder = sCachedScripts->Get(aURL);
if (holder) {
nsContentUtils::ThreadJSContextStack()->Push(mCx);
{
// Need to scope JSAutoRequest to happen after Push but before Pop,
// at least for now. See bug 584673.
JSAutoRequest ar(mCx);
JSObject* global = nsnull;
mGlobal->GetJSObject(&global);
if (global) {
jsval val;
JS_ExecuteScript(mCx, global,
(JSScript*)JS_GetPrivate(mCx, holder->mObject),
&val);
}
}
JSContext* unused;
nsContentUtils::ThreadJSContextStack()->Pop(&unused);
return;
}
nsCString url = NS_ConvertUTF16toUTF8(aURL);
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
if (NS_FAILED(rv)) {
return;
}
nsCOMPtr<nsIChannel> channel;
NS_NewChannel(getter_AddRefs(channel), uri);
if (!channel) {
return;
}
nsCOMPtr<nsIInputStream> input;
channel->Open(getter_AddRefs(input));
nsString dataString;
if (input) {
const PRUint32 bufferSize = 1024;
char buffer[bufferSize];
nsCString data;
PRUint32 avail = 0;
input->Available(&avail);
PRUint32 read = 0;
if (avail) {
while (NS_SUCCEEDED(input->Read(buffer, bufferSize, &read)) && read) {
data.Append(buffer, read);
read = 0;
}
}
nsScriptLoader::ConvertToUTF16(channel, (PRUint8*)data.get(), data.Length(),
EmptyString(), nsnull, dataString);
}
if (!dataString.IsEmpty()) {
nsContentUtils::ThreadJSContextStack()->Push(mCx);
{
// Need to scope JSAutoRequest to happen after Push but before Pop,
// at least for now. See bug 584673.
JSAutoRequest ar(mCx);
JSObject* global = nsnull;
mGlobal->GetJSObject(&global);
if (global) {
JSPrincipals* jsprin = nsnull;
mPrincipal->GetJSPrincipals(mCx, &jsprin);
nsContentUtils::XPConnect()->FlagSystemFilenamePrefix(url.get(), PR_TRUE);
JSScript* script =
JS_CompileUCScriptForPrincipals(mCx, nsnull, jsprin,
(jschar*)dataString.get(),
dataString.Length(),
url.get(), 1);
if (script) {
JSObject* scriptObj = JS_NewScriptObject(mCx, script);
JS_AddObjectRoot(mCx, &scriptObj);
nsCAutoString scheme;
uri->GetScheme(scheme);
// We don't cache data: scripts!
if (!scheme.EqualsLiteral("data")) {
nsFrameScriptExecutorJSObjectHolder* holder =
new nsFrameScriptExecutorJSObjectHolder(scriptObj);
// Root the object also for caching.
JS_AddNamedObjectRoot(mCx, &(holder->mObject),
"Cached message manager script");
sCachedScripts->Put(aURL, holder);
}
jsval val;
JS_ExecuteScript(mCx, global,
(JSScript*)JS_GetPrivate(mCx, scriptObj), &val);
JS_RemoveObjectRoot(mCx, &scriptObj);
}
//XXX Argh, JSPrincipals are manually refcounted!
JSPRINCIPALS_DROP(mCx, jsprin);
}
}
JSContext* unused;
nsContentUtils::ThreadJSContextStack()->Pop(&unused);
}
}

View File

@ -45,6 +45,9 @@
#include "nsIAtom.h"
#include "nsCycleCollectionParticipant.h"
#include "nsTArray.h"
#include "nsIPrincipal.h"
#include "nsIXPConnect.h"
#include "nsDataHashtable.h"
class nsAXPCNativeCallContext;
struct JSContext;
@ -150,4 +153,26 @@ protected:
nsTArray<nsString> mPendingScripts;
};
struct nsFrameScriptExecutorJSObjectHolder
{
nsFrameScriptExecutorJSObjectHolder(JSObject* aObject) : mObject(aObject) {}
JSObject* mObject;
};
class nsFrameScriptExecutor
{
public:
static void Shutdown();
protected:
nsFrameScriptExecutor() : mCx(nsnull) {}
void DidCreateCx();
// Call this when you want to destroy mCx.
void DestroyCx();
void LoadFrameScriptInternal(const nsAString& aURL);
nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
JSContext* mCx;
nsCOMPtr<nsIPrincipal> mPrincipal;
static nsDataHashtable<nsStringHashKey, nsFrameScriptExecutorJSObjectHolder*>* sCachedScripts;
};
#endif

View File

@ -110,7 +110,7 @@ bool SendAsyncMessageToParent(void* aCallbackData,
nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
nsIContent* aOwner,
nsFrameMessageManager* aChrome)
: mCx(nsnull), mDocShell(aShell), mInitialized(PR_FALSE), mLoadingScript(PR_FALSE),
: mDocShell(aShell), mInitialized(PR_FALSE), mLoadingScript(PR_FALSE),
mDelayedDisconnect(PR_FALSE), mOwner(aOwner), mChromeMessageManager(aChrome)
{
}
@ -196,8 +196,7 @@ nsInProcessTabChildGlobal::Disconnect()
}
if (!mLoadingScript) {
if (mCx) {
JS_DestroyContext(mCx);
mCx = nsnull;
DestroyCx();
}
} else {
mDelayedDisconnect = PR_TRUE;
@ -296,7 +295,7 @@ nsInProcessTabChildGlobal::InitTabChildGlobal()
NS_ENSURE_SUCCESS(rv, false);
JS_SetGlobalObject(cx, global);
DidCreateCx();
return NS_OK;
}
@ -307,69 +306,10 @@ nsInProcessTabChildGlobal::LoadFrameScript(const nsAString& aURL)
mInitialized = PR_TRUE;
Init();
}
if (!mGlobal || !mCx) {
return;
}
nsCString url = NS_ConvertUTF16toUTF8(aURL);
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
if (NS_FAILED(rv)) {
return;
}
nsCOMPtr<nsIChannel> channel;
NS_NewChannel(getter_AddRefs(channel), uri);
if (!channel) {
return;
}
nsCOMPtr<nsIInputStream> input;
channel->Open(getter_AddRefs(input));
nsString dataString;
if (input) {
const PRUint32 bufferSize = 256;
char buffer[bufferSize];
nsCString data;
PRUint32 avail = 0;
input->Available(&avail);
PRUint32 read = 0;
if (avail) {
while (NS_SUCCEEDED(input->Read(buffer, bufferSize, &read)) && read) {
data.Append(buffer, read);
read = 0;
}
}
nsScriptLoader::ConvertToUTF16(channel, (PRUint8*)data.get(), data.Length(),
EmptyString(), nsnull, dataString);
}
if (!dataString.IsEmpty()) {
nsContentUtils::ThreadJSContextStack()->Push(mCx);
{
// Need to scope JSAutoRequest to happen after Push but before Pop,
// at least for now. See bug 584673.
JSAutoRequest ar(mCx);
jsval retval;
JSObject* global = nsnull;
mGlobal->GetJSObject(&global);
if (global) {
JSPrincipals* jsprin = nsnull;
mPrincipal->GetJSPrincipals(mCx, &jsprin);
nsContentUtils::XPConnect()->FlagSystemFilenamePrefix(url.get(), PR_TRUE);
PRBool tmp = mLoadingScript;
mLoadingScript = PR_TRUE;
JS_EvaluateUCScriptForPrincipals(mCx, global, jsprin,
(jschar*)dataString.get(),
dataString.Length(),
url.get(), 1, &retval);
//XXX Argh, JSPrincipals are manually refcounted!
JSPRINCIPALS_DROP(mCx, jsprin);
mLoadingScript = tmp;
}
}
JSContext* unused;
nsContentUtils::ThreadJSContextStack()->Pop(&unused);
}
PRBool tmp = mLoadingScript;
mLoadingScript = PR_TRUE;
LoadFrameScriptInternal(aURL);
mLoadingScript = tmp;
if (!mLoadingScript && mDelayedDisconnect) {
mDelayedDisconnect = PR_FALSE;
Disconnect();

View File

@ -43,18 +43,17 @@
#include "nsFrameMessageManager.h"
#include "nsIScriptContext.h"
#include "nsDOMEventTargetHelper.h"
#include "nsIPrincipal.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptContext.h"
#include "nsIClassInfo.h"
#include "jsapi.h"
#include "nsIDocShell.h"
#include "nsIXPConnect.h"
#include "nsIDOMElement.h"
#include "nsCOMArray.h"
#include "nsThreadUtils.h"
class nsInProcessTabChildGlobal : public nsDOMEventTargetHelper,
public nsFrameScriptExecutor,
public nsIInProcessContentFrameMessageManager,
public nsIScriptObjectPrincipal,
public nsIScriptContextPrincipal
@ -126,9 +125,6 @@ protected:
nsresult Init();
nsresult InitTabChildGlobal();
nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
JSContext* mCx;
nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIDocShell> mDocShell;
PRPackedBool mInitialized;
PRPackedBool mLoadingScript;

View File

@ -42,7 +42,6 @@
*/
#include "nsTextFragment.h"
#include "nsString.h"
#include "nsCRT.h"
#include "nsReadableUtils.h"
#include "nsMemory.h"
@ -241,27 +240,6 @@ nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength)
mState.mLength = aLength;
}
void
nsTextFragment::AppendTo(nsAString& aString) const
{
if (mState.mIs2b) {
aString.Append(m2b, mState.mLength);
} else {
AppendASCIItoUTF16(Substring(m1b, m1b + mState.mLength),
aString);
}
}
void
nsTextFragment::AppendTo(nsAString& aString, PRInt32 aOffset, PRInt32 aLength) const
{
if (mState.mIs2b) {
aString.Append(m2b + aOffset, aLength);
} else {
AppendASCIItoUTF16(Substring(m1b + aOffset, m1b + aOffset + aLength), aString);
}
}
void
nsTextFragment::CopyTo(PRUnichar *aDest, PRInt32 aOffset, PRInt32 aCount)
{

View File

@ -44,7 +44,7 @@
#ifndef nsTextFragment_h___
#define nsTextFragment_h___
#include "nsAString.h"
#include "nsString.h"
#include "nsTraceRefcnt.h"
class nsString;
class nsCString;
@ -165,14 +165,27 @@ public:
/**
* Append the contents of this string fragment to aString
*/
void AppendTo(nsAString& aString) const;
void AppendTo(nsAString& aString) const {
if (mState.mIs2b) {
aString.Append(m2b, mState.mLength);
} else {
AppendASCIItoUTF16(Substring(m1b, m1b + mState.mLength),
aString);
}
}
/**
* Append a substring of the contents of this string fragment to aString.
* @param aOffset where to start the substring in this text fragment
* @param aLength the length of the substring
*/
void AppendTo(nsAString& aString, PRInt32 aOffset, PRInt32 aLength) const;
void AppendTo(nsAString& aString, PRInt32 aOffset, PRInt32 aLength) const {
if (mState.mIs2b) {
aString.Append(m2b + aOffset, aLength);
} else {
AppendASCIItoUTF16(Substring(m1b + aOffset, m1b + aOffset + aLength), aString);
}
}
/**
* Make a copy of the fragments contents starting at offset for

View File

@ -339,17 +339,6 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
printf_stderr ("--- WebGL context created: %p\n", gl.get());
if (gl->IsGLES2()) {
// On native GLES2, no need to validate, the compiler will do it
mShaderValidation = PR_FALSE;
} else {
// Otherwise, check the shader validator pref
nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
prefService->GetBoolPref("webgl.shader_validator", &mShaderValidation);
}
mWidth = width;
mHeight = height;
mResetLayer = PR_TRUE;

View File

@ -56,7 +56,7 @@
#include "jstypedarray.h"
#if !defined(USE_GLES2) && defined(USE_ANGLE)
#if defined(USE_ANGLE)
// shader translator
#include "angle/ShaderLang.h"
#endif
@ -2840,7 +2840,7 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
return NS_OK;
MakeContextCurrent();
#if !defined(USE_GLES2) && defined(USE_ANGLE)
#if defined(USE_ANGLE)
if (shader->NeedsTranslation() && mShaderValidation) {
ShHandle compiler = 0;
int debugFlags = 0;
@ -2864,7 +2864,12 @@ WebGLContext::CompileShader(nsIWebGLShader *sobj)
const char *s = src.get();
if (!ShCompile(compiler, &s, 1, EShOptSimple, debugFlags)) {
shader->SetTranslationFailure(nsDependentCString(ShGetInfoLog(compiler)));
const char* info = ShGetInfoLog(compiler);
if (info) {
shader->SetTranslationFailure(nsDependentCString(info));
} else {
shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
}
ShDestruct(compiler);
return NS_OK;
}

View File

@ -39,9 +39,12 @@
#include "WebGLContext.h"
#include "nsIPrefService.h"
#include "nsServiceManagerUtils.h"
#include "CheckedInt.h"
#if !defined(USE_GLES2) && defined(USE_ANGLE)
#if defined(USE_ANGLE)
#include "angle/ShaderLang.h"
#endif
@ -444,17 +447,26 @@ WebGLContext::InitAndValidateGL()
gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
}
#if !defined(USE_GLES2) && defined(USE_ANGLE)
// initialize shader translator
static bool didTranslatorInit = false;
if (!didTranslatorInit && mShaderValidation) {
if (!ShInitialize()) {
LogMessage("GLSL translator initialization failed!");
return PR_FALSE;
static bool didTranslatorCheck = false;
if (!didTranslatorCheck) {
// Check the shader validator pref
nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
NS_ENSURE_TRUE(prefService != nsnull, NS_ERROR_FAILURE);
prefService->GetBoolPref("webgl.shader_validator", &mShaderValidation);
#if defined(USE_ANGLE)
// initialize shader translator
if (mShaderValidation) {
if (!ShInitialize()) {
LogMessage("GLSL translator initialization failed!");
return PR_FALSE;
}
}
didTranslatorInit = true;
}
#endif
didTranslatorCheck = true;
}
return PR_TRUE;
}

View File

@ -260,7 +260,7 @@ nsHTMLButtonElement::IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PR
*aIsFocusable =
#ifdef XP_MACOSX
!aWithMouse &&
(!aWithMouse || nsFocusManager::sMouseFocusesFormControl) &&
#endif
!HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);

View File

@ -58,6 +58,7 @@
#include "nsGUIEvent.h"
#include "nsContentPolicyUtils.h"
#include "nsIDOMWindow.h"
#include "nsFocusManager.h"
#include "imgIContainer.h"
#include "imgILoader.h"
@ -480,7 +481,7 @@ nsHTMLImageElement::IsHTMLFocusable(PRBool aWithMouse,
*aIsFocusable =
#ifdef XP_MACOSX
!aWithMouse &&
(!aWithMouse || nsFocusManager::sMouseFocusesFormControl) &&
#endif
(tabIndex >= 0 || HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex));

View File

@ -2880,7 +2880,7 @@ nsHTMLInputElement::IsHTMLFocusable(PRBool aWithMouse, PRBool *aIsFocusable, PRI
}
#ifdef XP_MACOSX
const PRBool defaultFocusable = !aWithMouse;
const PRBool defaultFocusable = !aWithMouse || nsFocusManager::sMouseFocusesFormControl;
#else
const PRBool defaultFocusable = PR_TRUE;
#endif

View File

@ -221,18 +221,6 @@ nsXULPopupListener::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
return NS_OK;
}
// Get the document with the popup.
nsCOMPtr<nsIContent> content = do_QueryInterface(mElement);
// Turn the document into a XUL document so we can use SetPopupNode.
nsCOMPtr<nsIDOMXULDocument> xulDocument = do_QueryInterface(content->GetDocument());
if (!xulDocument) {
return NS_ERROR_FAILURE;
}
// Store clicked-on node in xul document for context menus and menu popups.
xulDocument->SetPopupNode(targetNode);
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aMouseEvent));
if (mIsContext) {

View File

@ -378,7 +378,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
cb.NoteXPCOMChild(static_cast<nsIScriptGlobalObjectOwner*>(tmp->mPrototypes[i]));
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTooltipNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLocalStore)
if (tmp->mOverlayLoadObservers.IsInitialized())
@ -388,7 +387,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTooltipNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(nsXULDocument, nsXMLDocument)
@ -1527,26 +1525,23 @@ nsXULDocument::GetHeight(PRInt32* aHeight)
NS_IMETHODIMP
nsXULDocument::GetPopupNode(nsIDOMNode** aNode)
{
// Get popup node.
nsresult rv = TrustedGetPopupNode(aNode); // addref happens here
if (NS_SUCCEEDED(rv) && *aNode && !nsContentUtils::CanCallerAccess(*aNode)) {
NS_RELEASE(*aNode);
return NS_ERROR_DOM_SECURITY_ERR;
}
return rv;
}
NS_IMETHODIMP
nsXULDocument::TrustedGetPopupNode(nsIDOMNode** aNode)
{
*aNode = nsnull;
nsCOMPtr<nsIDOMNode> node;
nsCOMPtr<nsPIWindowRoot> rootWin = GetWindowRoot();
if (rootWin)
rootWin->GetPopupNode(aNode); // addref happens here
node = rootWin->GetPopupNode(); // addref happens here
if (!node) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) {
node = pm->GetLastTriggerPopupNode(this);
}
}
if (node && nsContentUtils::CanCallerAccess(node))
node.swap(*aNode);
return NS_OK;
}
@ -1615,25 +1610,22 @@ nsXULDocument::GetPopupRangeOffset(PRInt32* aRangeOffset)
NS_IMETHODIMP
nsXULDocument::GetTooltipNode(nsIDOMNode** aNode)
{
if (mTooltipNode && !nsContentUtils::CanCallerAccess(mTooltipNode)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
*aNode = mTooltipNode;
NS_IF_ADDREF(*aNode);
return NS_OK;
}
*aNode = nsnull;
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) {
nsCOMPtr<nsIDOMNode> node = pm->GetLastTriggerTooltipNode(this);
if (node && nsContentUtils::CanCallerAccess(node))
node.swap(*aNode);
}
NS_IMETHODIMP
nsXULDocument::TrustedGetTooltipNode(nsIDOMNode** aNode)
{
NS_IF_ADDREF(*aNode = mTooltipNode);
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::SetTooltipNode(nsIDOMNode* aNode)
{
mTooltipNode = aNode;
// do nothing
return NS_OK;
}

View File

@ -19,7 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=449457
<script type="application/javascript"><![CDATA[
/** Test for Bug 449457 **/
document.tooltipNode = document;
document.popupNode = document;
ok(true, "This is just a leak test");
]]></script>

View File

@ -1,6 +1,6 @@
This is sqlite 3.6.23.1
This is sqlite 3.7.0.1
-- Shawn Wilsher <me@shawnwilsher.com>, 03/2010
-- Shawn Wilsher <me@shawnwilsher.com>, 08/2010
See http://www.sqlite.org/ for more info.

File diff suppressed because it is too large Load Diff

View File

@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.6.23.1"
#define SQLITE_VERSION_NUMBER 3006023
#define SQLITE_SOURCE_ID "2010-03-26 22:28:06 b078b588d617e07886ad156e9f54ade6d823568e"
#define SQLITE_VERSION "3.7.0.1"
#define SQLITE_VERSION_NUMBER 3007000
#define SQLITE_SOURCE_ID "2010-08-04 12:31:11 042a1abb030a0711386add7eb6e10832cc8b0f57"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -146,7 +146,6 @@ SQLITE_API const char *sqlite3_libversion(void);
SQLITE_API const char *sqlite3_sourceid(void);
SQLITE_API int sqlite3_libversion_number(void);
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
**
@ -169,9 +168,10 @@ SQLITE_API int sqlite3_libversion_number(void);
** See also: SQL functions [sqlite_compileoption_used()] and
** [sqlite_compileoption_get()] and the [compile_options pragma].
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
SQLITE_API const char *sqlite3_compileoption_get(int N);
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
#endif
/*
** CAPI3REF: Test To See If The Library Is Threadsafe
@ -393,7 +393,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
#define SQLITE_EMPTY 16 /* Database is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
@ -449,7 +449,12 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8) )
#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8))
#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8))
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
/*
** CAPI3REF: Flags For File Open Operations
@ -476,11 +481,12 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
/*
** CAPI3REF: Device Characteristics
**
** The xDeviceCapabilities method of the [sqlite3_io_methods]
** The xDeviceCharacteristics method of the [sqlite3_io_methods]
** object returns an integer which is a vector of the these
** bit values expressing I/O characteristics of the mass storage
** device that holds the file that the [sqlite3_io_methods]
@ -497,17 +503,18 @@ SQLITE_API int sqlite3_exec(
** information is written to disk in the same order as calls
** to xWrite().
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
#define SQLITE_IOCAP_ATOMIC1K 0x00000004
#define SQLITE_IOCAP_ATOMIC2K 0x00000008
#define SQLITE_IOCAP_ATOMIC4K 0x00000010
#define SQLITE_IOCAP_ATOMIC8K 0x00000020
#define SQLITE_IOCAP_ATOMIC16K 0x00000040
#define SQLITE_IOCAP_ATOMIC32K 0x00000080
#define SQLITE_IOCAP_ATOMIC64K 0x00000100
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
#define SQLITE_IOCAP_ATOMIC1K 0x00000004
#define SQLITE_IOCAP_ATOMIC2K 0x00000008
#define SQLITE_IOCAP_ATOMIC4K 0x00000010
#define SQLITE_IOCAP_ATOMIC8K 0x00000020
#define SQLITE_IOCAP_ATOMIC16K 0x00000040
#define SQLITE_IOCAP_ATOMIC32K 0x00000080
#define SQLITE_IOCAP_ATOMIC64K 0x00000100
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
/*
** CAPI3REF: File Locking Levels
@ -658,6 +665,12 @@ struct sqlite3_io_methods {
int (*xFileControl)(sqlite3_file*, int op, void *pArg);
int (*xSectorSize)(sqlite3_file*);
int (*xDeviceCharacteristics)(sqlite3_file*);
/* Methods above are valid for version 1 */
int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
int (*xShmLock)(sqlite3_file*, int offset, int n, int flags);
void (*xShmBarrier)(sqlite3_file*);
int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
/* Methods above are valid for version 2 */
/* Additional methods may be added in future releases */
};
@ -675,11 +688,19 @@ struct sqlite3_io_methods {
** into an integer that the pArg argument points to. This capability
** is used during testing and only needs to be supported when SQLITE_TEST
** is defined.
**
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
** layer a hint of how large the database file will grow to be during the
** current transaction. This hint is not guaranteed to be accurate but it
** is often close. The underlying VFS might choose to preallocate database
** file space based on this hint in order to help writes to the database
** file run faster.
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2
#define SQLITE_SET_LOCKPROXYFILE 3
#define SQLITE_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5
/*
** CAPI3REF: Mutex Handle
@ -811,20 +832,27 @@ typedef struct sqlite3_mutex sqlite3_mutex;
** handled as a fatal error by SQLite, vfs implementations should endeavor
** to prevent this by setting mxPathname to a sufficiently large value.
**
** The xRandomness(), xSleep(), and xCurrentTime() interfaces
** are not strictly a part of the filesystem, but they are
** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64()
** interfaces are not strictly a part of the filesystem, but they are
** included in the VFS structure for completeness.
** The xRandomness() function attempts to return nBytes bytes
** of good-quality randomness into zOut. The return value is
** the actual number of bytes of randomness obtained.
** The xSleep() method causes the calling thread to sleep for at
** least the number of microseconds given. The xCurrentTime()
** method returns a Julian Day Number for the current date and time.
**
** method returns a Julian Day Number for the current date and time as
** a floating point value.
** The xCurrentTimeInt64() method returns, as an integer, the Julian
** Day Number multipled by 86400000 (the number of milliseconds in
** a 24-hour day).
** ^SQLite will use the xCurrentTimeInt64() method to get the current
** date and time if that method is available (if iVersion is 2 or
** greater and the function pointer is not NULL) and will fall back
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
*/
typedef struct sqlite3_vfs sqlite3_vfs;
struct sqlite3_vfs {
int iVersion; /* Structure version number */
int iVersion; /* Structure version number (currently 2) */
int szOsFile; /* Size of subclassed sqlite3_file */
int mxPathname; /* Maximum file pathname length */
sqlite3_vfs *pNext; /* Next registered VFS */
@ -843,8 +871,16 @@ struct sqlite3_vfs {
int (*xSleep)(sqlite3_vfs*, int microseconds);
int (*xCurrentTime)(sqlite3_vfs*, double*);
int (*xGetLastError)(sqlite3_vfs*, int, char *);
/* New fields may be appended in figure versions. The iVersion
** value will increment whenever this happens. */
/*
** The methods above are in version 1 of the sqlite_vfs object
** definition. Those that follow are added in version 2 or later
*/
int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
/*
** The methods above are in versions 1 and 2 of the sqlite_vfs object.
** New fields may be appended in figure versions. The iVersion
** value will increment whenever this happens.
*/
};
/*
@ -856,13 +892,58 @@ struct sqlite3_vfs {
** With SQLITE_ACCESS_EXISTS, the xAccess method
** simply checks whether the file exists.
** With SQLITE_ACCESS_READWRITE, the xAccess method
** checks whether the file is both readable and writable.
** checks whether the named directory is both readable and writable
** (in other words, if files can be added, removed, and renamed within
** the directory).
** The SQLITE_ACCESS_READWRITE constant is currently used only by the
** [temp_store_directory pragma], though this could change in a future
** release of SQLite.
** With SQLITE_ACCESS_READ, the xAccess method
** checks whether the file is readable.
** checks whether the file is readable. The SQLITE_ACCESS_READ constant is
** currently unused, though it might be used in a future release of
** SQLite.
*/
#define SQLITE_ACCESS_EXISTS 0
#define SQLITE_ACCESS_READWRITE 1
#define SQLITE_ACCESS_READ 2
#define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */
#define SQLITE_ACCESS_READ 2 /* Unused */
/*
** CAPI3REF: Flags for the xShmLock VFS method
**
** These integer constants define the various locking operations
** allowed by the xShmLock method of [sqlite3_io_methods]. The
** following are the only legal combinations of flags to the
** xShmLock method:
**
** <ul>
** <li> SQLITE_SHM_LOCK | SQLITE_SHM_SHARED
** <li> SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE
** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED
** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE
** </ul>
**
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
** was given no the corresponding lock.
**
** The xShmLock method can transition between unlocked and SHARED or
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
** and EXCLUSIVE.
*/
#define SQLITE_SHM_UNLOCK 1
#define SQLITE_SHM_LOCK 2
#define SQLITE_SHM_SHARED 4
#define SQLITE_SHM_EXCLUSIVE 8
/*
** CAPI3REF: Maximum xShmLock index
**
** The xShmLock method on [sqlite3_io_methods] may use values
** between 0 and this upper bound as its "offset" argument.
** The SQLite core will never attempt to acquire or release a
** lock outside of this range
*/
#define SQLITE_SHM_NLOCK 8
/*
** CAPI3REF: Initialize The SQLite Library
@ -973,11 +1054,10 @@ SQLITE_API int sqlite3_os_end(void);
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
SQLITE_API int sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
** EXPERIMENTAL
**
** The sqlite3_db_config() interface is used to make configuration
** changes to a [database connection]. The interface is similar to
@ -997,11 +1077,10 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
** EXPERIMENTAL
**
** An instance of this object defines the interface between SQLite
** and low-level memory allocation routines.
@ -1083,7 +1162,6 @@ struct sqlite3_mem_methods {
/*
** CAPI3REF: Configuration Options
** EXPERIMENTAL
**
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
@ -1269,6 +1347,24 @@ struct sqlite3_mem_methods {
** [sqlite3_pcache_methods] object. SQLite copies of the current
** page cache implementation into that object.)^ </dd>
**
** <dt>SQLITE_CONFIG_LOG</dt>
** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
** function with a call signature of void(*)(void*,int,const char*),
** and a pointer to void. ^If the function pointer is not NULL, it is
** invoked by [sqlite3_log()] to process each logging event. ^If the
** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is
** passed through as the first parameter to the application-defined logger
** function whenever that function is invoked. ^The second parameter to
** the logger function is a copy of the first parameter to the corresponding
** [sqlite3_log()] call and is intended to be a [result code] or an
** [extended result code]. ^The third parameter passed to the logger is
** log message after formatting via [sqlite3_snprintf()].
** The SQLite logging interface is not reentrant; the logger function
** supplied by the application must not invoke any SQLite interface.
** In a multi-threaded application, the application-defined logger
** function must be threadsafe. </dd>
**
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@ -1289,8 +1385,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
/*
** CAPI3REF: Configuration Options
** EXPERIMENTAL
** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
** can be passed as the second argument to the [sqlite3_db_config()] interface.
@ -2066,7 +2161,6 @@ SQLITE_API int sqlite3_set_authorizer(
/*
** CAPI3REF: Tracing And Profiling Functions
** EXPERIMENTAL
**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
@ -2084,7 +2178,7 @@ SQLITE_API int sqlite3_set_authorizer(
** the original statement text and an estimate of wall-clock time
** of how long that statement took to run.
*/
SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
@ -2877,6 +2971,14 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** be the case that the same database connection is being used by two or
** more threads at the same moment in time.
**
** For all versions of SQLite up to and including 3.6.23.1, it was required
** after sqlite3_step() returned anything other than [SQLITE_ROW] that
** [sqlite3_reset()] be called before any subsequent invocation of
** sqlite3_step(). Failure to invoke [sqlite3_reset()] in this way would
** result in an [SQLITE_MISUSE] return from sqlite3_step(). But after
** version 3.6.23.1, sqlite3_step() began calling [sqlite3_reset()]
** automatically in this circumstance rather than returning [SQLITE_MISUSE].
**
** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
** API always returns a generic error code, [SQLITE_ERROR], following any
** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call
@ -3689,7 +3791,7 @@ SQLITE_API int sqlite3_collation_needed16(
void(*)(void*,sqlite3*,int eTextRep,const void*)
);
#if SQLITE_HAS_CODEC
#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database. This routine should be
** called right after sqlite3_open().
@ -3872,8 +3974,6 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
** an error or constraint causes an implicit rollback to occur.
** ^The rollback callback is not invoked if a transaction is
** automatically rolled back because the database connection is closed.
** ^The rollback callback is not invoked if a transaction is
** rolled back because a commit callback returned non-zero.
**
** See also the [sqlite3_update_hook()] interface.
*/
@ -4159,8 +4259,6 @@ SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void));
SQLITE_API void sqlite3_reset_auto_extension(void);
/*
****** EXPERIMENTAL - subject to change without notice **************
**
** The interface to the virtual-table mechanism is currently considered
** to be experimental. The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
@ -4180,7 +4278,6 @@ typedef struct sqlite3_module sqlite3_module;
/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
** EXPERIMENTAL
**
** This structure, sometimes called a a "virtual table module",
** defines the implementation of a [virtual tables].
@ -4227,7 +4324,6 @@ struct sqlite3_module {
/*
** CAPI3REF: Virtual Table Indexing Information
** KEYWORDS: sqlite3_index_info
** EXPERIMENTAL
**
** The sqlite3_index_info structure and its substructures is used to
** pass information into and receive the reply from the [xBestIndex]
@ -4309,7 +4405,6 @@ struct sqlite3_index_info {
/*
** CAPI3REF: Register A Virtual Table Implementation
** EXPERIMENTAL
**
** ^These routines are used to register a new [virtual table module] name.
** ^Module names must be registered before
@ -4331,13 +4426,13 @@ struct sqlite3_index_info {
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module(
SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@ -4348,7 +4443,6 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass
** of this object to describe a particular instance
@ -4374,7 +4468,6 @@ struct sqlite3_vtab {
/*
** CAPI3REF: Virtual Table Cursor Object
** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass of the
** following structure to describe cursors that point into the
@ -4396,18 +4489,16 @@ struct sqlite3_vtab_cursor {
/*
** CAPI3REF: Declare The Schema Of A Virtual Table
** EXPERIMENTAL
**
** ^The [xCreate] and [xConnect] methods of a
** [virtual table module] call this interface
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
** EXPERIMENTAL
**
** ^(Virtual tables can provide alternative implementations of functions
** using the [xFindFunction] method of the [virtual table module].
@ -4422,7 +4513,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zS
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@ -4432,8 +4523,6 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const cha
**
** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
**
****** EXPERIMENTAL - subject to change without notice **************
*/
/*
@ -4776,7 +4865,6 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
/*
** CAPI3REF: Mutex Methods Object
** EXPERIMENTAL
**
** An instance of this structure defines the low-level routines
** used to allocate and use mutexes.
@ -4989,11 +5077,11 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_RESERVE 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16
#define SQLITE_TESTCTRL_LAST 16
#define SQLITE_TESTCTRL_PGHDRSZ 17
#define SQLITE_TESTCTRL_LAST 17
/*
** CAPI3REF: SQLite Runtime Status
** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about the preformance of SQLite, and optionally to reset various
@ -5021,12 +5109,11 @@ SQLITE_API int sqlite3_test_control(int op, ...);
**
** See also: [sqlite3_db_status()]
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
/*
** CAPI3REF: Status Parameters
** EXPERIMENTAL
**
** These integer constants designate various run-time status parameters
** that can be returned by [sqlite3_status()].
@ -5113,14 +5200,15 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pH
/*
** CAPI3REF: Database Connection Status
** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about a single [database connection]. ^The first argument is the
** database connection object to be interrogated. ^The second argument
** is the parameter to interrogate. ^Currently, the only allowed value
** for the second parameter is [SQLITE_DBSTATUS_LOOKASIDE_USED].
** Additional options will likely appear in future releases of SQLite.
** is an integer constant, taken from the set of
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
** determiness the parameter to interrogate. The set of
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
** to grow in future releases of SQLite.
**
** ^The current value of the requested parameter is written into *pCur
** and the highest instantaneous value is written into *pHiwtr. ^If
@ -5129,11 +5217,10 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pH
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
** EXPERIMENTAL
**
** These constants are the available integer "verbs" that can be passed as
** the second argument to the [sqlite3_db_status()] interface.
@ -5148,14 +5235,21 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
**
** <dt>SQLITE_DBSTATUS_CACHE_USED</dt>
** <dd>^This parameter returns the approximate number of of bytes of heap
** memory used by all pager caches associated with the database connection.
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
** </dd>
** </dl>
*/
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
#define SQLITE_DBSTATUS_CACHE_USED 1
#define SQLITE_DBSTATUS_MAX 1 /* Largest defined DBSTATUS */
/*
** CAPI3REF: Prepared Statement Status
** EXPERIMENTAL
**
** ^(Each prepared statement maintains various
** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
@ -5177,11 +5271,10 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
** EXPERIMENTAL
**
** These preprocessor macros define integer codes that name counter
** values associated with the [sqlite3_stmt_status()] interface.
@ -5199,14 +5292,21 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int
** A non-zero value in this counter may indicate an opportunity to
** improvement performance through careful use of indices.</dd>
**
** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
** <dd>^This is the number of rows inserted into transient indices that
** were created automatically in order to help joins run faster.
** A non-zero value in this counter may indicate an opportunity to
** improvement performance by adding permanent indices that do not
** need to be reinitialized each time the statement is run.</dd>
**
** </dl>
*/
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
#define SQLITE_STMTSTATUS_AUTOINDEX 3
/*
** CAPI3REF: Custom Page Cache Object
** EXPERIMENTAL
**
** The sqlite3_pcache type is opaque. It is implemented by
** the pluggable module. The SQLite core has no knowledge of
@ -5221,7 +5321,6 @@ typedef struct sqlite3_pcache sqlite3_pcache;
/*
** CAPI3REF: Application Defined Page Cache.
** KEYWORDS: {page cache}
** EXPERIMENTAL
**
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
** register an alternative page cache implementation by passing in an
@ -5363,7 +5462,6 @@ struct sqlite3_pcache_methods {
/*
** CAPI3REF: Online Backup Object
** EXPERIMENTAL
**
** The sqlite3_backup object records state information about an ongoing
** online backup operation. ^The sqlite3_backup object is created by
@ -5376,7 +5474,6 @@ typedef struct sqlite3_backup sqlite3_backup;
/*
** CAPI3REF: Online Backup API.
** EXPERIMENTAL
**
** The backup API copies the content of one database into another.
** It is useful either for creating backups of databases or
@ -5445,10 +5542,14 @@ typedef struct sqlite3_backup sqlite3_backup;
** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code.
**
** ^The sqlite3_backup_step() might return [SQLITE_READONLY] if the destination
** database was opened read-only or if
** the destination is an in-memory database with a different page size
** from the source database.
** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if
** <ol>
** <li> the destination database was opened read-only, or
** <li> the destination database is using write-ahead-log journaling
** and the destination and source page sizes differ, or
** <li> The destination database is an in-memory database and the
** destination and source page sizes differ.
** </ol>)^
**
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
** the [sqlite3_busy_handler | busy-handler function]
@ -5564,7 +5665,6 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
/*
** CAPI3REF: Unlock Notification
** EXPERIMENTAL
**
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
@ -5686,7 +5786,6 @@ SQLITE_API int sqlite3_unlock_notify(
/*
** CAPI3REF: String Comparison
** EXPERIMENTAL
**
** ^The [sqlite3_strnicmp()] API allows applications and extensions to
** compare the contents of two buffers containing UTF-8 strings in a
@ -5697,12 +5796,11 @@ SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: Error Logging Interface
** EXPERIMENTAL
**
** ^The [sqlite3_log()] interface writes a message into the error log
** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
** ^If logging is enabled, the zFormat string and subsequent arguments are
** passed through to [sqlite3_vmprintf()] to generate the final output string.
** used with [sqlite3_snprintf()] to generate the final output string.
**
** The sqlite3_log() interface is intended for use by extensions such as
** virtual tables, collating functions, and SQL functions. While there is
@ -5719,6 +5817,89 @@ SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
*/
SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
** CAPI3REF: Write-Ahead Log Commit Hook
**
** ^The [sqlite3_wal_hook()] function is used to register a callback that
** will be invoked each time a database connection commits data to a
** [write-ahead log] (i.e. whenever a transaction is committed in
** [journal_mode | journal_mode=WAL mode]).
**
** ^The callback is invoked by SQLite after the commit has taken place and
** the associated write-lock on the database released, so the implementation
** may read, write or [checkpoint] the database as required.
**
** ^The first parameter passed to the callback function when it is invoked
** is a copy of the third parameter passed to sqlite3_wal_hook() when
** registering the callback. ^The second is a copy of the database handle.
** ^The third parameter is the name of the database that was written to -
** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter
** is the number of pages currently in the write-ahead log file,
** including those that were just committed.
**
** The callback function should normally return [SQLITE_OK]. ^If an error
** code is returned, that error will propagate back up through the
** SQLite code base to cause the statement that provoked the callback
** to report an error, though the commit will have still occurred. If the
** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value
** that does not correspond to any valid SQLite error code, the results
** are undefined.
**
** A single database handle may have at most a single write-ahead log callback
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
** previously registered write-ahead log callback. ^Note that the
** [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
** those overwrite any prior [sqlite3_wal_hook()] settings.
*/
SQLITE_API void *sqlite3_wal_hook(
sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
);
/*
** CAPI3REF: Configure an auto-checkpoint
**
** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
** [sqlite3_wal_hook()] that causes any database on [database connection] D
** to automatically [checkpoint]
** after committing a transaction if there are N or
** more frames in the [write-ahead log] file. ^Passing zero or
** a negative value as the nFrame parameter disables automatic
** checkpoints entirely.
**
** ^The callback registered by this function replaces any existing callback
** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback
** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism
** configured by this function.
**
** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
** from SQL.
**
** ^Every new [database connection] defaults to having the auto-checkpoint
** enabled with a threshold of 1000 pages. The use of this interface
** is only necessary if the default setting is found to be suboptimal
** for a particular application.
*/
SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
/*
** CAPI3REF: Checkpoint a database
**
** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
** on [database connection] D to be [checkpointed]. ^If X is NULL or an
** empty string, then a checkpoint is run on all databases of
** connection D. ^If the database connection D is not in
** [WAL | write-ahead log mode] then this interface is a harmless no-op.
**
** ^The [wal_checkpoint pragma] can be used to invoke this interface
** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] can be used to cause this interface to be
** run whenever the WAL reaches a certain size threshold.
*/
SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.

View File

@ -68,5 +68,22 @@ _TEST_FILES = \
blank.html \
$(NULL)
ifneq (mobile,$(MOZ_BUILD_APP))
_BROWSER_TEST_FILES = \
browser_bug343515.js \
bug343515_pg1.html \
bug343515_pg2.html \
bug343515_pg3.html \
bug343515_pg3_1.html \
bug343515_pg3_2.html \
bug343515_pg3_1_1.html \
$(NULL)
endif
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
ifneq (mobile,$(MOZ_BUILD_APP))
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
endif

View File

@ -0,0 +1,248 @@
// Test for bug 343515 - Need API for tabbrowsers to tell docshells they're visible/hidden
// Globals
var testPath = "http://mochi.test:8888/browser/docshell/test/navigation/";
var Ci = Components.interfaces;
var Cc = Components.classes;
var ctx = {};
// Helper function to check if a window is active
function isActive(aWindow) {
var docshell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
return docshell.isActive;
}
// Returns a closure that will remove itself as a listener from
// aElem and then call aCallback. aCallback is executed asynchronously,
// which is handy because load events fire before mIsDocumentLoaded is actually
// set to true. :(
function autoRemovedListener(aElem, aType, aCallback) {
var elem = aElem;
var type = aType;
var callback = aCallback;
function remover() {
elem.removeEventListener(type, remover, true);
executeSoon(callback);
}
return remover;
}
// Returns a closure that iteratively (BFS) waits for all
// of the descendant frames of aInitialWindow to finish loading,
// then calls aFinalCallback.
function frameLoadWaiter(aInitialWindow, aFinalCallback) {
// The window we're currently waiting on
var curr = aInitialWindow;
// The windows we need to wait for
var waitQueue = [];
// The callback to call when we're all done
var finalCallback = aFinalCallback;
function frameLoadCallback() {
// Push any subframes of what we just got
for (var i = 0; i < curr.frames.length; ++i)
waitQueue.push(curr.frames[i]);
// Handle the next window in the queue
if (waitQueue.length >= 1) {
curr = waitQueue.shift();
if (curr.document.readyState == "complete")
frameLoadCallback();
else
curr.addEventListener("load", autoRemovedListener(curr, "load", frameLoadCallback), true);
return;
}
// Otherwise, we're all done. Call the final callback
finalCallback();
}
return frameLoadCallback;
}
// Entry point from Mochikit
function test() {
// Lots of callbacks going on here
waitForExplicitFinish();
// Begin the test
step1();
}
function step1() {
// Get a handle on the initial tab
ctx.tab0 = gBrowser.selectedTab;
ctx.tab0Browser = gBrowser.getBrowserForTab(ctx.tab0);
ctx.tab0Window = ctx.tab0Browser.contentWindow;
// Our current tab should be active
ok(isActive(ctx.tab0Window), "Tab 0 should be active at test start");
// Open a New Tab
ctx.tab1 = gBrowser.addTab(testPath + "bug343515_pg1.html");
ctx.tab1Browser = gBrowser.getBrowserForTab(ctx.tab1);
ctx.tab1Window = ctx.tab1Browser.contentWindow;
ctx.tab1Browser.addEventListener("load",
autoRemovedListener(ctx.tab1Browser, "load", step2),
true);
}
function step2() {
// Our current tab should still be active
ok(isActive(ctx.tab0Window), "Tab 0 should still be active");
ok(!isActive(ctx.tab1Window), "Tab 1 should not be active");
// Switch to tab 1
gBrowser.selectedTab = ctx.tab1;
// Tab 1 should now be active
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
// Open another tab
ctx.tab2 = gBrowser.addTab(testPath + "bug343515_pg2.html");
ctx.tab2Browser = gBrowser.getBrowserForTab(ctx.tab2);
ctx.tab2Window = ctx.tab2Browser.contentWindow;
ctx.tab2Browser.addEventListener("load",
autoRemovedListener(ctx.tab2Browser, "load",
frameLoadWaiter(ctx.tab2Window, step3)),
true);
}
function step3() {
// Tab 0 should be inactive, Tab 1 should be active
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
// Tab 2's window _and_ its iframes should be inactive
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
is(ctx.tab2Window.frames.length, 2, "Tab 2 should have 2 iframes");
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
// Navigate tab 2 to a different page
ctx.tab2Window.location = testPath + "bug343515_pg3.html";
ctx.tab2Browser.addEventListener("load",
autoRemovedListener(ctx.tab2Browser, "load",
frameLoadWaiter(ctx.tab2Window, step4)),
true);
}
function step4() {
// Tab 0 should be inactive, Tab 1 should be active
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
// Tab2 and all descendants should be inactive
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
is(ctx.tab2Window.frames.length, 2, "Tab 2 should have 2 iframes");
is(ctx.tab2Window.frames[0].frames.length, 1, "Tab 2 iframe 0 should have 1 iframes");
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[0].frames[0]), "Tab2 iframe 0 subiframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
// Switch to Tab 2
gBrowser.selectedTab = ctx.tab2;
// Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(!isActive(ctx.tab1Window), "Tab 1 should be inactive");
ok(isActive(ctx.tab2Window), "Tab 2 should be active");
ok(isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be active");
ok(isActive(ctx.tab2Window.frames[0].frames[0]), "Tab2 iframe 0 subiframe 0 should be active");
ok(isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be active");
// Go back
ctx.tab2Browser.addEventListener("pageshow",
autoRemovedListener(ctx.tab2Browser, "pageshow",
frameLoadWaiter(ctx.tab2Window, step5)),
true);
ctx.tab2Browser.goBack();
}
function step5() {
// Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(!isActive(ctx.tab1Window), "Tab 1 should be inactive");
ok(isActive(ctx.tab2Window), "Tab 2 should be active");
ok(isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be active");
ok(isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be active");
// Switch to tab 1
gBrowser.selectedTab = ctx.tab1;
// Navigate to page 3
ctx.tab1Window.location = testPath + "bug343515_pg3.html";
ctx.tab1Browser.addEventListener("load",
autoRemovedListener(ctx.tab1Browser, "load",
frameLoadWaiter(ctx.tab1Window, step6)),
true);
}
function step6() {
// Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
ok(isActive(ctx.tab1Window.frames[0]), "Tab1 iframe 0 should be active");
ok(isActive(ctx.tab1Window.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active");
ok(isActive(ctx.tab1Window.frames[1]), "Tab1 iframe 1 should be active");
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
// Go forward on tab 2
ctx.tab2Browser.addEventListener("pageshow",
autoRemovedListener(ctx.tab2Browser, "pageshow",
frameLoadWaiter(ctx.tab2Window, step7)),
true);
var tab2docshell = ctx.tab2Window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation);
tab2docshell.goForward();
}
function step7() {
ctx.tab2Window = ctx.tab2Browser.contentWindow;
// Check everything
ok(!isActive(ctx.tab0Window), "Tab 0 should be inactive");
ok(isActive(ctx.tab1Window), "Tab 1 should be active");
ok(isActive(ctx.tab1Window.frames[0]), "Tab1 iframe 0 should be active");
ok(isActive(ctx.tab1Window.frames[0].frames[0]), "Tab1 iframe 0 subiframe 0 should be active");
ok(isActive(ctx.tab1Window.frames[1]), "Tab1 iframe 1 should be active");
ok(!isActive(ctx.tab2Window), "Tab 2 should be inactive");
ok(!isActive(ctx.tab2Window.frames[0]), "Tab2 iframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[0].frames[0]), "Tab2 iframe 0 subiframe 0 should be inactive");
ok(!isActive(ctx.tab2Window.frames[1]), "Tab2 iframe 1 should be inactive");
// That's probably enough
allDone();
}
function allDone() {
// Close the tabs we made
gBrowser.removeCurrentTab();
gBrowser.tabContainer.advanceSelectedTab(1, true);
gBrowser.removeCurrentTab();
// Tell the framework we're done
finish();
}

View File

@ -0,0 +1,5 @@
<html>
<head></head>
<body>Page 1
</body>
</html>

View File

@ -0,0 +1,7 @@
<html>
<head></head>
<body>Page 2
<iframe src="data:text/html,<html><head></head><body>pg2 iframe 0</body></html>"></iframe>
<iframe src="data:text/html,<html><head></head><body>pg2 iframe 1</body></html>"></iframe>
</body>
</html>

View File

@ -0,0 +1,7 @@
<html>
<head></head>
<body>Page 3
<iframe src="bug343515_pg3_1.html"></iframe>
<iframe src="bug343515_pg3_2.html"></iframe>
</body>
</html>

View File

@ -0,0 +1,6 @@
<html>
<head></head>
<body>pg3 - iframe 0
<iframe src="bug343515_pg3_1_1.html"></iframe>
</body>
</html>

View File

@ -0,0 +1 @@
<html><head></head><body>How far does the rabbit hole go?</body></html>

View File

@ -0,0 +1 @@
<html><head></head><body>pg3 iframe 1</body></html>

View File

@ -495,19 +495,25 @@ static const char kDOMStringBundleURL[] =
// NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
// are defined in nsIDOMClassInfo.h.
#define WINDOW_SCRIPTABLE_FLAGS \
#define COMMON_WINDOW_SCRIPTABLE_FLAGS \
(nsIXPCScriptable::WANT_GETPROPERTY | \
nsIXPCScriptable::WANT_SETPROPERTY | \
nsIXPCScriptable::WANT_PRECREATE | \
nsIXPCScriptable::WANT_ADDPROPERTY | \
nsIXPCScriptable::WANT_DELPROPERTY | \
nsIXPCScriptable::WANT_NEWENUMERATE | \
nsIXPCScriptable::WANT_FINALIZE | \
nsIXPCScriptable::WANT_EQUALITY | \
nsIXPCScriptable::WANT_OUTER_OBJECT | \
nsIXPCScriptable::WANT_INNER_OBJECT | \
nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE)
#define INNER_WINDOW_SCRIPTABLE_FLAGS \
(COMMON_WINDOW_SCRIPTABLE_FLAGS | \
nsIXPCScriptable::WANT_OUTER_OBJECT) \
#define OUTER_WINDOW_SCRIPTABLE_FLAGS \
(COMMON_WINDOW_SCRIPTABLE_FLAGS | \
nsIXPCScriptable::WANT_INNER_OBJECT | \
nsIXPCScriptable::WANT_NEWENUMERATE)
#define NODE_SCRIPTABLE_FLAGS \
((DOM_DEFAULT_SCRIPTABLE_FLAGS | \
nsIXPCScriptable::WANT_GETPROPERTY | \
@ -633,11 +639,11 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(Window, nsOuterWindowSH,
DEFAULT_SCRIPTABLE_FLAGS |
WINDOW_SCRIPTABLE_FLAGS)
OUTER_WINDOW_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(InnerWindow, nsInnerWindowSH,
DEFAULT_SCRIPTABLE_FLAGS |
WINDOW_SCRIPTABLE_FLAGS)
INNER_WINDOW_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(Location, nsLocationSH,
(DOM_DEFAULT_SCRIPTABLE_FLAGS &
@ -928,11 +934,11 @@ static nsDOMClassInfoData sClassInfoData[] = {
// DOM Chrome Window class.
NS_DEFINE_CLASSINFO_DATA(ChromeWindow, nsOuterWindowSH,
DEFAULT_SCRIPTABLE_FLAGS |
WINDOW_SCRIPTABLE_FLAGS)
OUTER_WINDOW_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(InnerChromeWindow, nsInnerWindowSH,
DEFAULT_SCRIPTABLE_FLAGS |
WINDOW_SCRIPTABLE_FLAGS)
INNER_WINDOW_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(CSSRGBColor, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -1315,11 +1321,11 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(ModalContentWindow, nsOuterWindowSH,
DEFAULT_SCRIPTABLE_FLAGS |
WINDOW_SCRIPTABLE_FLAGS)
OUTER_WINDOW_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(InnerModalContentWindow, nsInnerWindowSH,
DEFAULT_SCRIPTABLE_FLAGS |
WINDOW_SCRIPTABLE_FLAGS)
INNER_WINDOW_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(DataContainerEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
@ -5379,34 +5385,15 @@ nsCommonWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
NS_IMETHODIMP
nsCommonWindowSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp,
PRBool *_retval)
nsOuterWindowSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp,
PRBool *_retval)
{
nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper);
#ifdef DEBUG_SH_FORWARDING
{
nsDependentJSString str(::JS_ValueToString(cx, id));
if (win->IsInnerWindow()) {
#ifdef DEBUG_PRINT_INNER
printf("Property '%s' add on inner window %p\n",
NS_ConvertUTF16toUTF8(str).get(), (void *)win);
#endif
} else {
printf("Property '%s' add on outer window %p\n",
NS_ConvertUTF16toUTF8(str).get(), (void *)win);
}
}
#endif
JSObject *realObj;
wrapper->GetJSObject(&realObj);
if (win->IsOuterWindow() && obj == realObj) {
// XXXjst: Do security checks here when we remove the security
// checks on the inner window.
if (obj == realObj) {
nsGlobalWindow *innerWin = win->GetCurrentInnerWindowInternal();
JSObject *innerObj;
@ -6523,38 +6510,22 @@ ContentWindowGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
}
PRBool
nsCommonWindowSH::sResolving = PR_FALSE;
nsOuterWindowSH::sResolving = PR_FALSE;
NS_IMETHODIMP
nsCommonWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
JSObject **objp, PRBool *_retval)
nsOuterWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
JSObject **objp, PRBool *_retval)
{
nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper);
#ifdef DEBUG_SH_FORWARDING
{
nsDependentJSString str(::JS_ValueToString(cx, id));
if (win->IsInnerWindow()) {
#ifdef DEBUG_PRINT_INNER
printf("Property '%s' resolve on inner window %p\n",
NS_ConvertUTF16toUTF8(str).get(), (void *)win);
#endif
} else {
printf("Property '%s' resolve on outer window %p\n",
NS_ConvertUTF16toUTF8(str).get(), (void *)win);
}
}
#endif
// Note, we won't forward resolve of the location property to the
// inner window, we need to deal with that one for the outer too
// since we've got special security protection code for that
// property. Also note that we want to enter this block even for
// native wrappers, so that we'll ensure an inner window to wrap
// against for the result of whatever we're getting.
if (win->IsOuterWindow() && id != sLocation_id) {
if (id != sLocation_id) {
// XXXjst: Do security checks here when we remove the security
// checks on the inner window.
@ -6635,6 +6606,17 @@ nsCommonWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
}
return nsCommonWindowSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
}
NS_IMETHODIMP
nsCommonWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
JSObject **objp, PRBool *_retval)
{
nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper);
if (!JSID_IS_STRING(id)) {
if (JSID_IS_INT(id) && !(flags & JSRESOLVE_ASSIGNING)) {
// If we're resolving a numeric property, treat that as if
@ -7159,32 +7141,30 @@ nsCommonWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
NS_IMETHODIMP
nsCommonWindowSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 enum_op, jsval *statep,
jsid *idp, PRBool *_retval)
nsOuterWindowSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 enum_op, jsval *statep,
jsid *idp, PRBool *_retval)
{
switch ((JSIterateOp)enum_op) {
/* FIXME bug 576449: non-enumerable property support */
case JSENUMERATE_INIT_ALL:
case JSENUMERATE_INIT:
{
#ifdef DEBUG
// First, do the security check that nsDOMClassInfo does to see
// if we need to do any work at all.
nsDOMClassInfo::Enumerate(wrapper, cx, obj, _retval);
if (!*_retval) {
NS_ERROR("security wrappers failed us");
return NS_OK;
}
#endif
// The security check passed, let's see if we need to get the inner
// window's JS object or if we can just start enumerating.
nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper);
JSObject *enumobj = win->GetGlobalJSObject();
if (win->IsOuterWindow()) {
nsGlobalWindow *inner = win->GetCurrentInnerWindowInternal();
if (inner) {
enumobj = inner->GetGlobalJSObject();
}
}
nsGlobalWindow *win =
nsGlobalWindow::FromWrapper(wrapper)->GetCurrentInnerWindowInternal();
JSObject *enumobj = win->FastGetGlobalJSObject();
// Great, we have the js object, now let's enumerate it.
JSObject *iterator = JS_NewPropertyIterator(cx, enumobj);
@ -7272,8 +7252,8 @@ nsCommonWindowSH::Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
}
NS_IMETHODIMP
nsCommonWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval)
nsInnerWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval)
{
nsGlobalWindow *origWin = nsGlobalWindow::FromWrapper(wrapper);
nsGlobalWindow *win = origWin->GetOuterWindowInternal();
@ -7300,12 +7280,12 @@ nsCommonWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx
}
NS_IMETHODIMP
nsCommonWindowSH::InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval)
nsOuterWindowSH::InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval)
{
nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper);
if (win->IsInnerWindow() || win->IsFrozen()) {
if (win->IsFrozen()) {
// Return the inner window, or the outer if we're dealing with a
// frozen outer.
@ -7317,7 +7297,7 @@ nsCommonWindowSH::InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx
if (!inner) {
// Yikes! No inner window! Instead of leaking the outer window into the
// scope chain, let's return an error.
NS_ERROR("using an outer that doesn't have an inner?");
*_retval = nsnull;
return NS_ERROR_UNEXPECTED;

View File

@ -513,8 +513,6 @@ protected:
JSObject *obj, JSString *str,
PRBool *did_resolve);
static PRBool sResolving;
public:
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj);
@ -544,24 +542,15 @@ public:
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
NS_IMETHOD DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
JSObject **objp, PRBool *_retval);
NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 enum_op, jsval *statep,
jsid *idp, PRBool *_retval);
NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj);
NS_IMETHOD Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, const jsval &val, PRBool *bp);
NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval);
NS_IMETHOD InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval);
static JSBool GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
jsid id, uintN flags,
@ -586,7 +575,20 @@ protected:
{
}
static PRBool sResolving;
public:
NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
JSObject **objp, PRBool *_retval);
NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRUint32 enum_op, jsval *statep,
jsid *idp, PRBool *_retval);
NS_IMETHOD InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsOuterWindowSH(aData);
@ -605,6 +607,10 @@ protected:
}
public:
// We WANT_ADDPROPERTY, but are content to inherit it from nsEventReceiverSH.
NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
JSObject * obj, JSObject * *_retval);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsInnerWindowSH(aData);

View File

@ -157,6 +157,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
nsFocusManager* nsFocusManager::sInstance = nsnull;
PRBool nsFocusManager::sMouseFocusesFormControl = PR_FALSE;
nsFocusManager::nsFocusManager()
{ }
@ -168,6 +169,7 @@ nsFocusManager::~nsFocusManager()
if (prefBranch) {
prefBranch->RemoveObserver("accessibility.browsewithcaret", this);
prefBranch->RemoveObserver("accessibility.tabfocus_applies_to_xul", this);
prefBranch->RemoveObserver("accessibility.mouse_focuses_formcontrol", this);
}
}
@ -184,9 +186,13 @@ nsFocusManager::Init()
nsContentUtils::GetBoolPref("accessibility.tabfocus_applies_to_xul",
nsIContent::sTabFocusModelAppliesToXUL);
sMouseFocusesFormControl =
nsContentUtils::GetBoolPref("accessibility.mouse_focuses_formcontrol", PR_FALSE);
nsIPrefBranch2* prefBranch = nsContentUtils::GetPrefBranch();
prefBranch->AddObserver("accessibility.browsewithcaret", fm, PR_TRUE);
prefBranch->AddObserver("accessibility.tabfocus_applies_to_xul", fm, PR_TRUE);
prefBranch->AddObserver("accessibility.mouse_focuses_formcontrol", fm, PR_TRUE);
return NS_OK;
}
@ -213,6 +219,10 @@ nsFocusManager::Observe(nsISupports *aSubject,
nsContentUtils::GetBoolPref("accessibility.tabfocus_applies_to_xul",
nsIContent::sTabFocusModelAppliesToXUL);
}
else if (data.EqualsLiteral("accessibility.mouse_focuses_formcontrol")) {
sMouseFocusesFormControl =
nsContentUtils::GetBoolPref("accessibility.mouse_focuses_formcontrol", PR_FALSE);
}
}
return NS_OK;

View File

@ -113,6 +113,8 @@ public:
*/
static nsIContent* GetRedirectedFocus(nsIContent* aContent);
static PRBool sMouseFocusesFormControl;
protected:
nsFocusManager();

View File

@ -926,7 +926,7 @@ nsGlobalWindow::CleanUp(PRBool aIgnoreModalDialog)
if (mCleanedUp)
return;
mCleanedUp = PR_TRUE;
mNavigator = nsnull;
mScreen = nsnull;
mHistory = nsnull;
@ -1077,6 +1077,8 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
mListenerManager = nsnull;
}
mLocation = nsnull;
if (mDocument) {
NS_ASSERTION(mDoc, "Why is mDoc null?");
@ -1510,7 +1512,6 @@ public:
WindowStateHolder(nsGlobalWindow *aWindow,
nsIXPConnectJSObjectHolder *aHolder,
nsNavigator *aNavigator,
nsLocation *aLocation,
nsIXPConnectJSObjectHolder *aOuterProto);
nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
@ -1518,7 +1519,6 @@ public:
{ return mInnerWindowHolder; }
nsNavigator* GetNavigator() { return mNavigator; }
nsLocation* GetLocation() { return mLocation; }
nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
void DidRestoreWindow()
@ -1527,7 +1527,6 @@ public:
mInnerWindowHolder = nsnull;
mNavigator = nsnull;
mLocation = nsnull;
mOuterProto = nsnull;
}
@ -1539,7 +1538,6 @@ protected:
// window ends up recalculating it anyway.
nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
nsRefPtr<nsNavigator> mNavigator;
nsRefPtr<nsLocation> mLocation;
nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
};
@ -1548,11 +1546,9 @@ NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
nsIXPConnectJSObjectHolder *aHolder,
nsNavigator *aNavigator,
nsLocation *aLocation,
nsIXPConnectJSObjectHolder *aOuterProto)
: mInnerWindow(aWindow),
mNavigator(aNavigator),
mLocation(aLocation),
mOuterProto(aOuterProto)
{
NS_PRECONDITION(aWindow, "null window");
@ -1754,7 +1750,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
// These assignments addref.
mNavigator = wsh->GetNavigator();
mLocation = wsh->GetLocation();
if (mNavigator) {
// Update mNavigator's docshell pointer now.
@ -1773,8 +1768,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
newInnerWindow = new nsGlobalWindow(this);
}
}
mLocation = nsnull;
}
if (!newInnerWindow) {
@ -2191,8 +2184,6 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
if (mNavigator)
mNavigator->SetDocShell(aDocShell);
if (mLocation)
mLocation->SetDocShell(aDocShell);
if (mHistory)
mHistory->SetDocShell(aDocShell);
if (mFrames)
@ -6811,12 +6802,13 @@ nsGlobalWindow::GetPrivateRoot()
NS_IMETHODIMP
nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation)
{
FORWARD_TO_OUTER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
FORWARD_TO_INNER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED);
*aLocation = nsnull;
if (!mLocation && mDocShell) {
mLocation = new nsLocation(mDocShell);
nsIDocShell *docShell = GetDocShell();
if (!mLocation && docShell) {
mLocation = new nsLocation(docShell);
if (!mLocation) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -9093,7 +9085,6 @@ nsGlobalWindow::SaveWindowState(nsISupports **aState)
nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
mInnerWindowHolder,
mNavigator,
mLocation,
proto);
NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);

View File

@ -786,7 +786,6 @@ protected:
nsRefPtr<nsBarProp> mStatusbar;
nsRefPtr<nsBarProp> mScrollbars;
nsCOMPtr<nsIWeakReference> mWindowUtils;
nsRefPtr<nsLocation> mLocation;
nsString mStatus;
nsString mDefaultStatus;
// index 0->language_id 1, so index MAX-1 == language_id MAX
@ -808,6 +807,7 @@ protected:
nsTimeout* mTimeoutInsertionPoint;
PRUint32 mTimeoutPublicIdCounter;
PRUint32 mTimeoutFiringDepth;
nsRefPtr<nsLocation> mLocation;
// Holder of the dummy java plugin, used to expose window.java and
// window.packages.

View File

@ -48,10 +48,10 @@ class nsIControllers;
class nsIController;
struct JSContext;
// 2e26a297-6e40-41c1-81c9-7306571f955e
// 426C1B56-E38A-435E-B291-BE1557F2A0A2
#define NS_IWINDOWROOT_IID \
{ 0x2e26a297, 0x6e40, 0x41c1, \
{ 0x81, 0xc9, 0x73, 0x06, 0x57, 0x1f, 0x95, 0x5e } }
{ 0x426c1b56, 0xe38a, 0x435e, \
{ 0xb2, 0x91, 0xbe, 0x15, 0x57, 0xf2, 0xa0, 0xa2 } }
class nsPIWindowRoot : public nsPIDOMEventTarget {
public:
@ -59,7 +59,8 @@ public:
virtual nsPIDOMWindow* GetWindow()=0;
virtual void GetPopupNode(nsIDOMNode** aNode) = 0;
// get and set the node that is the context of a popup menu
virtual nsIDOMNode* GetPopupNode() = 0;
virtual void SetPopupNode(nsIDOMNode* aNode) = 0;
virtual nsresult GetControllerForCommand(const char *aCommand,

View File

@ -355,10 +355,10 @@ nsWindowRoot::GetControllerForCommand(const char * aCommand,
return NS_OK;
}
void
nsWindowRoot::GetPopupNode(nsIDOMNode** aNode)
nsIDOMNode*
nsWindowRoot::GetPopupNode()
{
NS_IF_ADDREF(*aNode = mPopupNode);
return mPopupNode;
}
void

View File

@ -95,7 +95,7 @@ public:
virtual nsresult GetControllerForCommand(const char * aCommand,
nsIController** _retval);
virtual void GetPopupNode(nsIDOMNode** aNode);
virtual nsIDOMNode* GetPopupNode();
virtual void SetPopupNode(nsIDOMNode* aNode);
virtual void SetParentTarget(nsPIDOMEventTarget* aTarget)

View File

@ -43,7 +43,7 @@ interface nsIDOMXULCommandDispatcher;
interface nsIObserver;
interface nsIBoxObject;
[scriptable, uuid(d55c39B4-b54a-4df5-9e68-09919e4538f9)]
[scriptable, uuid(b16d13c3-837d-445d-8f56-05d83d9b9eae)]
interface nsIDOMXULDocument : nsISupports
{
attribute nsIDOMNode popupNode;
@ -101,16 +101,4 @@ interface nsIDOMXULDocument : nsISupports
* - Ben Goodger (8/23/2005)
*/
void loadOverlay(in DOMString url, in nsIObserver aObserver);
/**
* Get the popup node from this XUL document without doing a security check to
* make sure that the caller has access to this node. This is for use from C++
* callers that can indirectly be called from content.
*/
[noscript] nsIDOMNode trustedGetPopupNode();
/**
* Like trustedGetPopupNode, but gets the tooltip node instead.
*/
[noscript] nsIDOMNode trustedGetTooltipNode();
};

View File

@ -54,6 +54,7 @@
#include "mozilla/plugins/BrowserStreamParent.h"
#include "PluginIdentifierParent.h"
#include "nsAutoPtr.h"
#include "nsContentUtils.h"
#include "nsCRT.h"
#ifdef MOZ_CRASHREPORTER
@ -69,6 +70,7 @@ using mozilla::ipc::SyncChannel;
using namespace mozilla::plugins;
static const char kTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
template<>
struct RunnableMethodTraits<mozilla::plugins::PluginModuleParent>
@ -84,15 +86,21 @@ PluginModuleParent::LoadModule(const char* aFilePath)
{
PLUGIN_LOG_DEBUG_FUNCTION;
PRInt32 prefSecs = nsContentUtils::GetIntPref(kLaunchTimeoutPref, 0);
// Block on the child process being launched and initialized.
PluginModuleParent* parent = new PluginModuleParent(aFilePath);
parent->mSubprocess->Launch();
nsAutoPtr<PluginModuleParent> parent(new PluginModuleParent(aFilePath));
bool launched = parent->mSubprocess->Launch(prefSecs * 1000);
if (!launched) {
// Need to set this so the destructor doesn't complain.
parent->mShutdown = true;
return nsnull;
}
parent->Open(parent->mSubprocess->GetChannel(),
parent->mSubprocess->GetChildProcessHandle());
TimeoutChanged(kTimeoutPref, parent);
return parent;
return parent.forget();
}

View File

@ -68,11 +68,11 @@ PluginProcessParent::~PluginProcessParent()
}
bool
PluginProcessParent::Launch()
PluginProcessParent::Launch(PRInt32 timeoutMs)
{
vector<string> args;
args.push_back(MungePluginDsoPath(mPluginFilePath));
return SyncLaunch(args);
return SyncLaunch(args, timeoutMs);
}
void

View File

@ -61,9 +61,10 @@ public:
~PluginProcessParent();
/**
* Synchronously launch the plugin process.
* Synchronously launch the plugin process. If the process fails to launch
* after timeoutMs, this method will return false.
*/
bool Launch();
bool Launch(PRInt32 timeoutMs);
void Delete();

View File

@ -51,6 +51,8 @@ _TEST_FILES = \
child_ip_address.html \
test_setting_document.domain_idn.html \
idn_child.html \
file_location.html \
test_location.html \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,10 @@
<html>
<script>
try {
top.SimpleTest.ok(!("existingprop" in location), "got a new location object in the iframe");
} catch (e) {
}
location.iframeprop = 42;
</script>
</html>

View File

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for location object behaviors</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<iframe id="ifr" onload="runTest()"></iframe>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
var count = 0;
var firstlocation;
var lastlocation;
function runTest() {
++count;
if (count == 1) {
firstlocation = $('ifr').contentWindow.location;
firstlocation.existingprop = 'fail';
firstlocation.href = 'file_location.html';
return;
}
if (count == 2) {
lastlocation = $('ifr').contentWindow.location;
is(lastlocation.iframeprop, 42, 'can read the new prop');
ok(firstlocation !== lastlocation, 'got a new location object');
// firstlocation should still work.
firstlocation.href = 'http://example.com/tests/dom/tests/mochitest/dom-level0/file_location.html';
return;
}
if (count == 3) {
try {
isnot($('ifr').contentWindow.location.iframeprop, 42, "shouldn't see this");
} catch (e) {
ok(/Permission denied/.test(e), "correctly threw a security error");
}
// XXX this doesn't work - file a bug on me!
//firstlocation.href = 'http://mochi.test:8888/tests/dom/tests/mochitest/dom-level0/file_location.html';
todo(false, 'can use old same-origin location object to set cross-origin frame');
$('ifr').contentWindow.location = 'file_location.html';
return;
}
is(lastlocation.iframeprop, 42, 'can still read old values of the location object');
ok(lastlocation !== $('ifr').contentWindow.location, 'location objects are distinct');
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -79,7 +79,19 @@ function runTest()
// the test regardless of which user input last occurred.
$("l1").focus();
var expectedVisible = (!isWin || getComputedStyle($("l1"), "").outlineWidth == "2px");
testHTMLElements(isMac, isWin && !expectedVisible);
testHTMLElements(htmlElements, isMac, isWin && !expectedVisible);
if (isMac) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
prefs.setBoolPref("accessibility.mouse_focuses_formcontrol", true);
testHTMLElements(htmlElementsMacPrefSet, true, false);
prefs.setBoolPref("accessibility.mouse_focuses_formcontrol", false);
}
$("l1").focus();
checkFocus($("l1"), expectedVisible, "appearance on list after focus() with :moz-focusring");
@ -117,6 +129,7 @@ var htmlElements = [
"<input id='elem' class='canfocus'>",
"<input id='elem' type='password' class='canfocus'>",
"<input id='elem' type='button'>",
"<input id='elem' type='checkbox'>",
"<textarea id='elem' class='canfocus'></textarea>",
"<select id='elem' class='canfocus'><option>One</select>",
"<select id='elem' rows='5' class='canfocus'><option>One</select>",
@ -124,13 +137,20 @@ var htmlElements = [
"<a href='about:blank' class='canfocus' onclick='return false;'>about:blank</a>",
];
function testHTMLElements(isMac, expectedNoRingsOnWin)
var htmlElementsMacPrefSet = [
"<button id='elem' class='canfocus'>Button</button>",
"<input id='elem' class='canfocus'>",
"<input id='elem' type='button' class='canfocus'>",
"<input id='elem' type='checkbox' class='canfocus'>",
];
function testHTMLElements(list, isMac, expectedNoRingsOnWin)
{
var childwin = frames[0];
var childdoc = childwin.document;
var container = childdoc.getElementById("container");
for (var e = 0; e < htmlElements.length; e++) {
container.innerHTML = htmlElements[e];
for (var e = 0; e < list.length; e++) {
container.innerHTML = list[e];
var elem = container.firstChild;
@ -140,8 +160,8 @@ function testHTMLElements(isMac, expectedNoRingsOnWin)
ringSize = "0px";
synthesizeMouse(elem, 8, 8, { }, childwin);
is(childdoc.activeElement, shouldFocus ? elem : childdoc.body, "mouse click on " + htmlElements[e]);
is(childwin.getComputedStyle(elem, "").outlineWidth, ringSize, "mouse click on " + htmlElements[e] + " ring");
is(childdoc.activeElement, shouldFocus ? elem : childdoc.body, "mouse click on " + list[e]);
is(childwin.getComputedStyle(elem, "").outlineWidth, ringSize, "mouse click on " + list[e] + " ring");
if (childdoc.activeElement)
childdoc.activeElement.blur();
@ -149,9 +169,9 @@ function testHTMLElements(isMac, expectedNoRingsOnWin)
ringSize = (elem.localName == "a" ? "0" : (expectedNoRingsOnWin ? 2 : 1)) + "px";
elem.focus();
is(childdoc.activeElement, elem, "focus() on " + htmlElements[e]);
is(childdoc.activeElement, elem, "focus() on " + list[e]);
is(childwin.getComputedStyle(elem, "").outlineWidth, ringSize,
"focus() on " + htmlElements[e] + " ring");
"focus() on " + list[e] + " ring");
childdoc.activeElement.blur();
}

View File

@ -102,6 +102,7 @@ DIST_LINK_FILES = \
greprefs.js \
browserconfig.properties \
blocklist.xml \
chrome.manifest \
$(NULL)
ifdef MOZ_IPC

View File

@ -107,7 +107,7 @@ static JSContext *autoconfig_cx = nsnull;
static JSObject *autoconfig_glob;
static JSClass global_class = {
"autoconfig_global", 0,
"autoconfig_global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nsnull
};

View File

@ -51,6 +51,7 @@
#include "nsUnicharUtilCIID.h"
#include "nsServiceManagerUtils.h"
#include "nsIContent.h"
#include "nsTextFragment.h"
// IsIgnorableCharacter
//
@ -429,13 +430,6 @@ IsBRElement(nsIDOMNode* aNode)
return NS_SUCCEEDED(rv);
}
static void
GetNodeText(nsIDOMNode* aNode, nsAutoString& aText)
{
nsresult rv = aNode->GetNodeValue(aText);
NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to get node text");
}
// Find the previous node in the DOM tree in preorder. This isn't fast because
// one call to GetPrevSibling can be O(N) in the number of siblings...
static nsIDOMNode*
@ -480,10 +474,12 @@ ContainsDOMWordSeparator(nsIDOMNode* aNode, PRInt32 aBeforeOffset,
if (!IsTextNode(aNode))
return PR_FALSE;
nsAutoString str;
GetNodeText(aNode, str);
for (PRInt32 i = NS_MIN(aBeforeOffset, PRInt32(str.Length())) - 1; i >= 0; --i) {
if (IsDOMWordSeparator(str.CharAt(i))) {
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
NS_ASSERTION(content, "Where is our content?");
const nsTextFragment* textFragment = content->GetText();
NS_ASSERTION(textFragment, "Where is our text?");
for (PRInt32 i = NS_MIN(aBeforeOffset, PRInt32(textFragment->GetLength())) - 1; i >= 0; --i) {
if (IsDOMWordSeparator(textFragment->CharAt(i))) {
*aSeparatorOffset = i;
return PR_TRUE;
}
@ -584,7 +580,6 @@ mozInlineSpellWordUtil::BuildSoftText()
PRBool seenSoftEnd = PR_FALSE;
// Leave this outside the loop so large heap string allocations can be reused
// across iterations
nsAutoString str;
while (node) {
if (node == mSoftEnd.mNode) {
seenSoftEnd = PR_TRUE;
@ -592,14 +587,17 @@ mozInlineSpellWordUtil::BuildSoftText()
PRBool exit = PR_FALSE;
if (IsTextNode(node)) {
GetNodeText(node, str);
PRInt32 lastOffsetInNode = str.Length();
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
NS_ASSERTION(content, "Where is our content?");
const nsTextFragment* textFragment = content->GetText();
NS_ASSERTION(textFragment, "Where is our text?");
PRInt32 lastOffsetInNode = textFragment->GetLength();
if (seenSoftEnd) {
// check whether we can stop after this
for (PRInt32 i = node == mSoftEnd.mNode ? mSoftEnd.mOffset : 0;
i < PRInt32(str.Length()); ++i) {
if (IsDOMWordSeparator(str.CharAt(i))) {
i < PRInt32(textFragment->GetLength()); ++i) {
if (IsDOMWordSeparator(textFragment->CharAt(i))) {
exit = PR_TRUE;
// stop at the first separator after the soft end point
lastOffsetInNode = i;
@ -612,7 +610,7 @@ mozInlineSpellWordUtil::BuildSoftText()
PRInt32 len = lastOffsetInNode - firstOffsetInNode;
mSoftTextDOMMapping.AppendElement(
DOMTextMapping(NodeOffset(node, firstOffsetInNode), mSoftText.Length(), len));
mSoftText.Append(Substring(str, firstOffsetInNode, len));
textFragment->AppendTo(mSoftText, firstOffsetInNode, len);
}
firstOffsetInNode = 0;

View File

@ -237,3 +237,16 @@
// Vista glass
#define NS_THEME_WIN_GLASS 230
// Windows themed window frame elements
#define NS_THEME_WINDOW_TITLEBAR 231
#define NS_THEME_WINDOW_TITLEBAR_MAXIMIZED 232
#define NS_THEME_WINDOW_FRAME_LEFT 233
#define NS_THEME_WINDOW_FRAME_RIGHT 234
#define NS_THEME_WINDOW_FRAME_BOTTOM 235
#define NS_THEME_WINDOW_BUTTON_CLOSE 236
#define NS_THEME_WINDOW_BUTTON_MINIMIZE 237
#define NS_THEME_WINDOW_BUTTON_MAXIMIZE 238
#define NS_THEME_WINDOW_BUTTON_RESTORE 239
#define NS_THEME_WINDOW_BUTTON_BOX 240
#define NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED 241

View File

@ -131,12 +131,14 @@ void GeckoChildProcessHost::InitWindowsGroupID()
#endif
bool
GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts)
GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTimeoutMs)
{
#ifdef XP_WIN
InitWindowsGroupID();
#endif
PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ?
PR_MillisecondsToInterval(aTimeoutMs) : PR_INTERVAL_NO_TIMEOUT;
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
NS_ASSERTION(MessageLoop::current() != ioLoop, "sync launch from the IO thread NYI");
@ -144,15 +146,29 @@ GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts)
NewRunnableMethod(this,
&GeckoChildProcessHost::PerformAsyncLaunch,
aExtraOpts));
// NB: this uses a different mechanism than the chromium parent
// class.
MonitorAutoEnter mon(mMonitor);
PRIntervalTime waitStart = PR_IntervalNow();
PRIntervalTime current;
// We'll receive several notifications, we need to exit when we
// have either successfully launched or have timed out.
while (!mLaunched) {
mon.Wait();
mon.Wait(timeoutTicks);
if (timeoutTicks != PR_INTERVAL_NO_TIMEOUT) {
current = PR_IntervalNow();
PRIntervalTime elapsed = current - waitStart;
if (elapsed > timeoutTicks) {
break;
}
timeoutTicks = timeoutTicks - elapsed;
waitStart = current;
}
}
return true;
return mLaunched;
}
bool

View File

@ -64,7 +64,7 @@ public:
~GeckoChildProcessHost();
bool SyncLaunch(std::vector<std::string> aExtraOpts=std::vector<std::string>());
bool SyncLaunch(std::vector<std::string> aExtraOpts=std::vector<std::string>(), int32 timeoutMs=0);
bool AsyncLaunch(std::vector<std::string> aExtraOpts=std::vector<std::string>());
bool PerformAsyncLaunch(std::vector<std::string> aExtraOpts=std::vector<std::string>());

View File

@ -486,7 +486,6 @@ def _cxxRefType(ipdltype, side):
def _cxxConstRefType(ipdltype, side):
t = _cxxBareType(ipdltype, side)
if ipdltype.isIPDL() and ipdltype.isActor():
t.const = 1 # const Actor*
return t
if ipdltype.isIPDL() and ipdltype.isShmem():
t.ref = 1
@ -508,8 +507,7 @@ def _cxxConstPtrToType(ipdltype, side):
t = _cxxBareType(ipdltype, side)
if ipdltype.isIPDL() and ipdltype.isActor():
t.ptr = 0
t.const = 1
t.ptrconstptr = 1 # const Actor* const*
t.ptrconstptr = 1
return t
t.const = 1
t.ptrconst = 1

View File

@ -78,6 +78,7 @@ IPDLTESTS = \
TestShutdown \
TestStackHooks \
TestSyncWakeup \
TestSyncHang \
$(NULL)
ifeq ($(OS_ARCH),Linux)

View File

@ -0,0 +1,15 @@
namespace mozilla {
namespace _ipdltest {
protocol PTestSyncHang {
child:
__delete__();
};
} // namespace mozilla
} // namespace _ipdltest

View File

@ -0,0 +1,71 @@
#include "TestSyncHang.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "IPDLUnitTests.h" // fail etc.
using std::vector;
using std::string;
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
mozilla::ipc::GeckoChildProcessHost* gSyncHangSubprocess;
TestSyncHangParent::TestSyncHangParent()
{
MOZ_COUNT_CTOR(TestSyncHangParent);
}
TestSyncHangParent::~TestSyncHangParent()
{
MOZ_COUNT_DTOR(TestSyncHangParent);
}
void
DeleteSyncHangSubprocess(MessageLoop* uiLoop)
{
delete gSyncHangSubprocess;
}
void
DeferredSyncHangParentShutdown()
{
// ping to DeleteSubprocess
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(DeleteSyncHangSubprocess, MessageLoop::current()));
}
void
TestSyncHangParent::Main()
{
vector<string> args;
args.push_back("fake/path");
gSyncHangSubprocess = new mozilla::ipc::GeckoChildProcessHost(GeckoProcessType_Plugin);
bool launched = gSyncHangSubprocess->SyncLaunch(args, 2);
if (launched)
fail("Calling SyncLaunch with an invalid path should return false");
MessageLoop::current()->PostTask(
FROM_HERE, NewRunnableFunction(DeferredSyncHangParentShutdown));
Close();
}
//-----------------------------------------------------------------------------
// child
TestSyncHangChild::TestSyncHangChild()
{
MOZ_COUNT_CTOR(TestSyncHangChild);
}
TestSyncHangChild::~TestSyncHangChild()
{
MOZ_COUNT_DTOR(TestSyncHangChild);
}
} // namespace _ipdltest
} // namespace mozilla

View File

@ -0,0 +1,56 @@
#ifndef mozilla__ipdltest_TestSyncHang_h
#define mozilla__ipdltest_TestSyncHang_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestSyncHangParent.h"
#include "mozilla/_ipdltest/PTestSyncHangChild.h"
namespace mozilla {
namespace _ipdltest {
class TestSyncHangParent :
public PTestSyncHangParent
{
public:
TestSyncHangParent();
virtual ~TestSyncHangParent();
void Main();
protected:
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
};
class TestSyncHangChild :
public PTestSyncHangChild
{
public:
TestSyncHangChild();
virtual ~TestSyncHangChild();
protected:
NS_OVERRIDE
virtual void ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestSyncHang_h

View File

@ -30,5 +30,6 @@ IPDLSRCS = \
PTestShutdownSubsub.ipdl \
PTestStackHooks.ipdl \
PTestSyncWakeup.ipdl \
PTestSyncHang.ipdl \
PTestSysVShmem.ipdl \
$(NULL)

View File

@ -48,6 +48,8 @@
#include "jsobj.h"
#include "jscntxt.h"
#include "mozilla/unused.h"
namespace mozilla {
namespace jetpack {
@ -62,7 +64,8 @@ class Handle
Handle(Handle* parent)
: mParent(parent)
, mObj(NULL)
, mRuntime(NULL)
, mCx(NULL)
, mRooted(false)
{}
BaseType* AllocPHandle() {
@ -79,7 +82,8 @@ public:
Handle()
: mParent(NULL)
, mObj(NULL)
, mRuntime(NULL)
, mCx(NULL)
, mRooted(false)
{}
~Handle() { TearDown(); }
@ -95,8 +99,28 @@ public:
return Unwrap(cx, JSVAL_TO_OBJECT(val));
}
JSObject* ToJSObject(JSContext* cx) const {
if (!mObj && !mRuntime) {
void Root() {
NS_ASSERTION(mObj && mCx, "Rooting with no object unexpected.");
if (mRooted)
return;
if (!JS_AddNamedObjectRoot(mCx, &mObj, "Jetpack Handle")) {
NS_RUNTIMEABORT("Failed to add root.");
}
mRooted = true;
}
void Unroot() {
NS_ASSERTION(mCx, "Unrooting with no JSContext unexpected.");
if (!mRooted)
return;
JS_RemoveObjectRoot(mCx, &mObj);
mRooted = false;
}
JSObject* ToJSObject(JSContext* cx) {
if (!mObj && !mCx) {
JSAutoRequest request(cx);
JSClass* clasp = const_cast<JSClass*>(&sHandle_JSClass);
@ -107,16 +131,13 @@ public:
JSPropertySpec* ps = const_cast<JSPropertySpec*>(sHandle_Properties);
JSFunctionSpec* fs = const_cast<JSFunctionSpec*>(sHandle_Functions);
JSRuntime* rt;
if (JS_SetPrivate(cx, obj, (void*)this) &&
JS_DefineProperties(cx, obj, ps) &&
JS_DefineFunctions(cx, obj, fs) &&
(rt = JS_GetRuntime(cx)) &&
JS_AddObjectRoot(cx, &mObj))
{
JS_DefineFunctions(cx, obj, fs)) {
mObj = obj;
mRuntime = rt;
mCx = cx;
Root();
}
}
return mObj;
@ -134,16 +155,33 @@ private:
static bool IsParent(const PHandleChild* handle) { return false; }
void TearDown() {
if (mObj) {
mObj->setPrivate(NULL);
mObj = NULL;
if (mCx) {
JSAutoRequest ar(mCx);
if (mObj) {
mObj->setPrivate(NULL);
js::AutoObjectRooter obj(mCx, mObj);
mObj = NULL;
JSBool hasOnInvalidate;
if (JS_HasProperty(mCx, obj.object(), "onInvalidate",
&hasOnInvalidate) && hasOnInvalidate) {
js::AutoValueRooter r(mCx);
JSBool ok = JS_CallFunctionName(mCx, obj.object(), "onInvalidate", 0,
NULL, r.jsval_addr());
if (!ok)
JS_ReportPendingException(mCx);
}
// By not nulling out mContext, we prevent ToJSObject from
// reviving an invalidated/destroyed handle.
}
// Nulling out mObj effectively unroots the object, but we still
// need to remove the root, else the JS engine will complain at
// shutdown.
NS_ASSERTION(mRuntime, "Should have a JSRuntime if we had an object");
js_RemoveRoot(mRuntime, (void*)&mObj);
// By not nulling out mRuntime, we prevent ToJSObject from
// reviving an invalidated/destroyed handle.
Unroot();
}
}
@ -155,8 +193,9 @@ private:
// Used to cache the JSObject returned by ToJSObject, which is
// otherwise a const method.
mutable JSObject* mObj;
mutable JSRuntime* mRuntime;
JSObject* mObj;
JSContext* mCx;
bool mRooted;
static Handle*
Unwrap(JSContext* cx, JSObject* obj) {
@ -199,6 +238,38 @@ private:
return JS_TRUE;
}
static JSBool
GetIsRooted(JSContext* cx, JSObject* obj, jsid, jsval* vp) {
Handle* self = Unwrap(cx, obj);
bool rooted = self ? self->mRooted : false;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(rooted));
return JS_TRUE;
}
static JSBool
SetIsRooted(JSContext* cx, JSObject* obj, jsid, jsval* vp) {
Handle* self = Unwrap(cx, obj);
JSBool v;
if (!JS_ValueToBoolean(cx, *vp, &v))
return JS_FALSE;
if (!self) {
if (v) {
JS_ReportError(cx, "Cannot root invalidated handle.");
return JS_FALSE;
}
return JS_TRUE;
}
if (v)
self->Root();
else
self->Unroot();
*vp = BOOLEAN_TO_JSVAL(v);
return JS_TRUE;
}
static JSBool
Invalidate(JSContext* cx, uintN argc, jsval* vp) {
if (argc > 0) {
@ -207,15 +278,10 @@ private:
}
Handle* self = Unwrap(cx, JS_THIS_OBJECT(cx, vp));
if (self) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_TRUE));
if (!Send__delete__(self)) {
JS_ReportError(cx, "Failed to send __delete__ while invalidating");
return JS_FALSE;
}
} else {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_FALSE));
}
if (self)
unused << Send__delete__(self);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}
@ -248,10 +314,13 @@ private:
static void
Finalize(JSContext* cx, JSObject* obj) {
Handle* self = Unwrap(cx, obj);
// Avoid warnings about unused return values:
self && Send__delete__(self);
if (self) {
NS_ASSERTION(!self->mRooted, "Finalizing a rooted object?");
self->mCx = NULL;
self->mObj = NULL;
unused << Send__delete__(self);
}
}
};
template <class BaseType>
@ -265,13 +334,14 @@ Handle<BaseType>::sHandle_JSClass = {
JSCLASS_NO_OPTIONAL_MEMBERS
};
#define HANDLE_PROP_FLAGS (JSPROP_READONLY | JSPROP_PERMANENT)
#define HANDLE_PROP_FLAGS (JSPROP_PERMANENT | JSPROP_SHARED)
template <class BaseType>
const JSPropertySpec
Handle<BaseType>::sHandle_Properties[] = {
{ "parent", 0, HANDLE_PROP_FLAGS, GetParent, NULL },
{ "isValid", 0, HANDLE_PROP_FLAGS, GetIsValid, NULL },
{ "parent", 0, HANDLE_PROP_FLAGS | JSPROP_READONLY, GetParent, NULL },
{ "isValid", 0, HANDLE_PROP_FLAGS | JSPROP_READONLY, GetIsValid, NULL },
{ "isRooted", 0, HANDLE_PROP_FLAGS, GetIsRooted, SetIsRooted },
{ 0, 0, 0, NULL, NULL }
};

View File

@ -298,7 +298,7 @@ JetpackActorCommon::jsval_from_PrimVariant(JSContext* cx,
case PrimVariant::TPHandleParent: {
JSObject* hobj =
static_cast<const HandleParent*>(from.get_PHandleParent())->ToJSObject(cx);
static_cast<HandleParent*>(from.get_PHandleParent())->ToJSObject(cx);
if (!hobj)
return false;
*to = OBJECT_TO_JSVAL(hobj);
@ -307,7 +307,7 @@ JetpackActorCommon::jsval_from_PrimVariant(JSContext* cx,
case PrimVariant::TPHandleChild: {
JSObject* hobj =
static_cast<const HandleChild*>(from.get_PHandleChild())->ToJSObject(cx);
static_cast<HandleChild*>(from.get_PHandleChild())->ToJSObject(cx);
if (!hobj)
return false;
*to = OBJECT_TO_JSVAL(hobj);

View File

@ -68,10 +68,13 @@ JetpackChild::sImplMethods[] = {
JS_FN("registerReceiver", RegisterReceiver, 2, IMPL_METHOD_FLAGS),
JS_FN("unregisterReceiver", UnregisterReceiver, 2, IMPL_METHOD_FLAGS),
JS_FN("unregisterReceivers", UnregisterReceivers, 1, IMPL_METHOD_FLAGS),
JS_FN("wrap", Wrap, 1, IMPL_METHOD_FLAGS),
JS_FN("createHandle", CreateHandle, 0, IMPL_METHOD_FLAGS),
JS_FN("createSandbox", CreateSandbox, 0, IMPL_METHOD_FLAGS),
JS_FN("evalInSandbox", EvalInSandbox, 2, IMPL_METHOD_FLAGS),
JS_FN("gc", GC, 0, IMPL_METHOD_FLAGS),
#ifdef JS_GC_ZEAL
JS_FN("gczeal", GCZeal, 1, IMPL_METHOD_FLAGS),
#endif
JS_FS_END
};
@ -362,13 +365,6 @@ JetpackChild::UnregisterReceivers(JSContext* cx, uintN argc, jsval* vp)
return JS_TRUE;
}
JSBool
JetpackChild::Wrap(JSContext* cx, uintN argc, jsval* vp)
{
NS_NOTYETIMPLEMENTED("wrap not yet implemented (depends on bug 563010)");
return JS_FALSE;
}
JSBool
JetpackChild::CreateHandle(JSContext* cx, uintN argc, jsval* vp)
{
@ -476,5 +472,27 @@ JetpackChild::ReportError(JSContext* cx, const char* message,
sReportingError = false;
}
JSBool
JetpackChild::GC(JSContext* cx, uintN argc, jsval *vp)
{
JS_GC(cx);
return JS_TRUE;
}
#ifdef JS_GC_ZEAL
JSBool
JetpackChild::GCZeal(JSContext* cx, uintN argc, jsval *vp)
{
jsval* argv = JS_ARGV(cx, vp);
uint32 zeal;
if (!JS_ValueToECMAUint32(cx, argv[0], &zeal))
return JS_FALSE;
JS_SetGCZeal(cx, PRUint8(zeal));
return JS_TRUE;
}
#endif
} // namespace jetpack
} // namespace mozilla

View File

@ -86,10 +86,13 @@ private:
static JSBool RegisterReceiver(JSContext* cx, uintN argc, jsval *vp);
static JSBool UnregisterReceiver(JSContext* cx, uintN argc, jsval *vp);
static JSBool UnregisterReceivers(JSContext* cx, uintN argc, jsval *vp);
static JSBool Wrap(JSContext* cx, uintN argc, jsval *vp);
static JSBool CreateHandle(JSContext* cx, uintN argc, jsval *vp);
static JSBool CreateSandbox(JSContext* cx, uintN argc, jsval *vp);
static JSBool EvalInSandbox(JSContext* cx, uintN argc, jsval *vp);
static JSBool GC(JSContext* cx, uintN argc, jsval *vp);
#ifdef JS_GC_ZEAL
static JSBool GCZeal(JSContext* cx, uintN argc, jsval *vp);
#endif
static void ReportError(JSContext* cx, const char* message,
JSErrorReport* report);

View File

@ -38,15 +38,17 @@ function test_local_invalidation() {
var parent = createHandle(),
child = parent.createHandle();
do_check_true(child.invalidate());
dump("test_local_invalidation\n");
child.invalidate();
do_check_false(child.isValid);
do_check_true(parent.isValid);
child = parent.createHandle();
do_check_true(child.isValid);
do_check_true(parent.invalidate());
do_check_false(parent.invalidate());
parent.invalidate();
parent.invalidate();
do_check_false(child.isValid);
do_check_false(parent.isValid);
@ -60,7 +62,7 @@ function test_local_invalidation() {
do_check_eq(child.parent.parent, parent);
do_check_true(child.parent.isValid);
do_check_true(child.parent.invalidate());
child.parent.invalidate();
do_check_false(child.isValid);
do_check_true(parent.isValid);
@ -80,7 +82,7 @@ function test_long_parent_chain(len) {
handle = handle.parent;
do_check_true(child.isValid);
do_check_true(ancestor.invalidate());
ancestor.invalidate();
do_check_false(child.isValid);
}

View File

@ -0,0 +1,46 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
function createJetpack(args)
{
var jp = Components.classes["@mozilla.org/jetpack/service;1"].
getService(Components.interfaces.nsIJetpackService).
createJetpack();
if (!args.skipRegisterCleanup)
do_register_cleanup(function() {
jp.destroy();
});
if (!args.skipRegisterError)
jp.registerReceiver("core:exception", function(msgName, e) {
dump("Received exception from remote code: " + e + "\n");
do_check_true(false);
});
if (args.scriptFile)
jp.evalScript(read_file(args.scriptFile));
return jp;
}
const PR_RDONLY = 0x1;
function read_file(f)
{
var fis = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
fis.init(f, PR_RDONLY, 0444, Ci.nsIFileInputStream.CLOSE_ON_EOF);
var lis = Cc["@mozilla.org/intl/converter-input-stream;1"]
.createInstance(Ci.nsIConverterInputStream);
lis.init(fis, "UTF-8", 1024, 0);
var data = "";
var r = {};
while (lis.readString(0x0FFFFFFF, r))
data += r.value;
return data;
}

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