зеркало из https://github.com/mozilla/pjs.git
Merge MC -> JM
This commit is contained in:
Коммит
5bf926fb84
|
@ -976,10 +976,12 @@ refRelationSetCB(AtkObject *aAtkObj)
|
|||
while ((tempAcc = rel.Next()))
|
||||
targets.AppendElement(nsAccessibleWrap::GetAtkObject(tempAcc));
|
||||
|
||||
if (targets.Length()) {
|
||||
atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType);
|
||||
atk_relation_set_add(relation_set, atkRelation);
|
||||
g_object_unref(atkRelation);
|
||||
}
|
||||
}
|
||||
|
||||
return relation_set;
|
||||
}
|
||||
|
|
|
@ -868,8 +868,11 @@ var InspectorUI = {
|
|||
delete this.treeBrowserDocument;
|
||||
}
|
||||
|
||||
if (this.treeIFrame)
|
||||
if (this.treeIFrame) {
|
||||
let parent = this.treeIFrame.parentNode;
|
||||
parent.removeChild(this.treeIFrame);
|
||||
delete this.treeIFrame;
|
||||
}
|
||||
delete this.ioBox;
|
||||
|
||||
if (this.domplate) {
|
||||
|
@ -893,6 +896,8 @@ var InspectorUI = {
|
|||
this.treeLoaded = false;
|
||||
|
||||
this.treePanel.addEventListener("popuphidden", function treePanelHidden() {
|
||||
this.removeEventListener("popuphidden", treePanelHidden, false);
|
||||
|
||||
InspectorUI.closing = false;
|
||||
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.CLOSED, null);
|
||||
}, false);
|
||||
|
|
|
@ -156,10 +156,9 @@ Sanitizer.prototype = {
|
|||
}
|
||||
|
||||
// Clear plugin data.
|
||||
let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
const phInterface = Ci.nsIPluginHost;
|
||||
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
|
||||
ph.QueryInterface(phInterface);
|
||||
let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface);
|
||||
|
||||
// Determine age range in seconds. (-1 means clear all.) We don't know
|
||||
// that this.range[1] is actually now, so we compute age range based
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* ***** 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 content.js.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Tim Taubert <ttaubert@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 ***** */
|
||||
|
||||
addEventListener("DOMWillOpenModalDialog", function (event) {
|
||||
// (event.isTrusted == true) when the event is generated by a user action
|
||||
// and does not originate from a script.
|
||||
if (event.isTrusted) {
|
||||
// we're intentionally sending a synchronous message to handle this event
|
||||
// as quick as possible, switch the selected tab and hide the tabview
|
||||
// before the modal dialog is shown
|
||||
sendSyncMessage("Panorama:DOMWillOpenModalDialog");
|
||||
}
|
||||
}, true);
|
|
@ -231,7 +231,7 @@ function GroupItem(listOfEls, options) {
|
|||
.appendTo(appTabTrayContainer);
|
||||
|
||||
AllTabs.tabs.forEach(function(xulTab) {
|
||||
if (xulTab.pinned && xulTab.ownerDocument.defaultView == gWindow)
|
||||
if (xulTab.pinned)
|
||||
self.addAppTab(xulTab, {dontAdjustTray: true});
|
||||
});
|
||||
|
||||
|
@ -744,9 +744,13 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
// ----------
|
||||
// Function: _unhide
|
||||
// Shows the hidden group.
|
||||
_unhide: function GroupItem__unhide() {
|
||||
let self = this;
|
||||
|
||||
//
|
||||
// Parameters:
|
||||
// options - various options (see below)
|
||||
//
|
||||
// Possible options:
|
||||
// immediately - true when no animations should be used
|
||||
_unhide: function GroupItem__unhide(options) {
|
||||
this._cancelFadeAwayUndoButtonTimer();
|
||||
this.hidden = false;
|
||||
this.$undoContainer.remove();
|
||||
|
@ -754,20 +758,31 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
this.droppable(true);
|
||||
this.setTrenches(this.bounds);
|
||||
|
||||
iQ(this.container).show().animate({
|
||||
"-moz-transform": "scale(1)",
|
||||
"opacity": 1
|
||||
}, {
|
||||
duration: 170,
|
||||
complete: function() {
|
||||
let self = this;
|
||||
|
||||
let finalize = function () {
|
||||
self._children.forEach(function(child) {
|
||||
iQ(child.container).show();
|
||||
});
|
||||
|
||||
UI.setActive(self);
|
||||
self._sendToSubscribers("groupShown", { groupItemId: self.id });
|
||||
}
|
||||
};
|
||||
|
||||
let $container = iQ(this.container).show();
|
||||
|
||||
if (!options || !options.immediately) {
|
||||
$container.animate({
|
||||
"-moz-transform": "scale(1)",
|
||||
"opacity": 1
|
||||
}, {
|
||||
duration: 170,
|
||||
complete: finalize
|
||||
});
|
||||
} else {
|
||||
$container.css({"-moz-transform": "none", opacity: 1});
|
||||
finalize();
|
||||
}
|
||||
|
||||
GroupItems.updateGroupCloseButtons();
|
||||
},
|
||||
|
@ -785,15 +800,29 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
let remainingGroups = GroupItems.groupItems.filter(function (groupItem) {
|
||||
return (groupItem != self && groupItem.getChildren().length);
|
||||
});
|
||||
|
||||
let tab = null;
|
||||
|
||||
if (!gBrowser._numPinnedTabs && !remainingGroups.length) {
|
||||
let emptyGroups = GroupItems.groupItems.filter(function (groupItem) {
|
||||
return (groupItem != self && !groupItem.getChildren().length);
|
||||
});
|
||||
let group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup());
|
||||
group.newTab(null, { closedLastTab: true });
|
||||
tab = group.newTab(null, {dontZoomIn: true});
|
||||
}
|
||||
|
||||
this.destroy();
|
||||
let closed = this.destroy();
|
||||
|
||||
if (!tab)
|
||||
return;
|
||||
|
||||
if (closed) {
|
||||
// Let's make the new tab the selected tab.
|
||||
UI.goToTab(tab);
|
||||
} else {
|
||||
// Remove the new tab and group, if this group is no longer closed.
|
||||
tab._tabViewTabItem.parent.destroy({immediately: true});
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -806,6 +835,10 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
//
|
||||
// Options:
|
||||
// immediately - (bool) if true, no animation will be used
|
||||
//
|
||||
// Returns true if the groupItem has been closed, or false otherwise. A group
|
||||
// could not have been closed due to a tab with an onUnload handler (that
|
||||
// waits for user interaction).
|
||||
destroy: function GroupItem_destroy(options) {
|
||||
let self = this;
|
||||
|
||||
|
@ -814,14 +847,11 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
// In other words, the group "close" event is fired before all browser
|
||||
// tabs in the group are closed. The below code would fire the group "close"
|
||||
// event only after all browser tabs in that group are closed.
|
||||
let shouldRemoveTabItems = [];
|
||||
let toClose = this._children.concat();
|
||||
toClose.forEach(function(child) {
|
||||
this._children.concat().forEach(function(child) {
|
||||
child.removeSubscriber("close", self._onChildClose);
|
||||
|
||||
let removed = child.close(true);
|
||||
if (removed) {
|
||||
shouldRemoveTabItems.push(child);
|
||||
if (child.close(true)) {
|
||||
self.remove(child, { dontArrange: true });
|
||||
} else {
|
||||
// child.removeSubscriber() must be called before child.close(),
|
||||
// therefore we call child.addSubscriber() if the tab is not removed.
|
||||
|
@ -829,15 +859,14 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
}
|
||||
});
|
||||
|
||||
if (shouldRemoveTabItems.length != toClose.length) {
|
||||
// remove children without the assiciated tab and show the group item
|
||||
shouldRemoveTabItems.forEach(function(child) {
|
||||
self.remove(child, { dontArrange: true });
|
||||
});
|
||||
|
||||
if (this._children.length) {
|
||||
if (this.hidden)
|
||||
this.$undoContainer.fadeOut(function() { self._unhide() });
|
||||
|
||||
return false;
|
||||
} else {
|
||||
this.close(options);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1818,13 +1847,16 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
// Parameters:
|
||||
// url - the new tab should open this url as well
|
||||
// options - the options object
|
||||
// dontZoomIn - set to true to not zoom into the newly created tab
|
||||
// closedLastTab - boolean indicates the last tab has just been closed
|
||||
newTab: function GroupItem_newTab(url, options) {
|
||||
if (options && options.closedLastTab)
|
||||
UI.closedLastTabInTabView = true;
|
||||
|
||||
UI.setActive(this, { dontSetActiveTabInGroup: true });
|
||||
gBrowser.loadOneTab(url || "about:blank", { inBackground: false });
|
||||
|
||||
let dontZoomIn = !!(options && options.dontZoomIn);
|
||||
return gBrowser.loadOneTab(url || "about:blank", { inBackground: dontZoomIn });
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -1926,13 +1958,13 @@ let GroupItems = {
|
|||
let self = this;
|
||||
|
||||
// setup attr modified handler, and prepare for its uninit
|
||||
function handleAttrModified(xulTab) {
|
||||
self._handleAttrModified(xulTab);
|
||||
function handleAttrModified(event) {
|
||||
self._handleAttrModified(event.target);
|
||||
}
|
||||
|
||||
// make sure any closed tabs are removed from the delay update list
|
||||
function handleClose(xulTab) {
|
||||
let idx = self._delayedModUpdates.indexOf(xulTab);
|
||||
function handleClose(event) {
|
||||
let idx = self._delayedModUpdates.indexOf(event.target);
|
||||
if (idx != -1)
|
||||
self._delayedModUpdates.splice(idx, 1);
|
||||
}
|
||||
|
@ -2040,7 +2072,7 @@ let GroupItems = {
|
|||
// Function: _updateAppTabIcons
|
||||
// Update images of any apptab icons that point to passed in xultab
|
||||
_updateAppTabIcons: function GroupItems__updateAppTabIcons(xulTab) {
|
||||
if (xulTab.ownerDocument.defaultView != gWindow || !xulTab.pinned)
|
||||
if (!xulTab.pinned)
|
||||
return;
|
||||
|
||||
let iconUrl = this.getAppTabFavIconUrl(xulTab);
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
/* ***** 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 ***** */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let EXPORTED_SYMBOLS = ["AllTabs"];
|
||||
|
||||
let AllTabs = {
|
||||
// ----------
|
||||
// Function: toString
|
||||
// Prints [AllTabs] for debug use
|
||||
toString: function AllTabs_toString() {
|
||||
return "[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.filter(browserWindow.gBrowser.tabs, function (tab) !tab.closing);
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach a callback for a given tab event.
|
||||
*
|
||||
* @param eventName
|
||||
* Name of the corresponding Tab* Event; one of "attrModified",
|
||||
* "close", "move", "open", "select", "pinned", "unpinned".
|
||||
* @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[events[eventName]];
|
||||
if (listeners)
|
||||
listeners.push(callback);
|
||||
else
|
||||
eventListeners[events[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", "pinned", "unpinned".
|
||||
* @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[events[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: "TabAttrModified",
|
||||
close: "TabClose",
|
||||
move: "TabMove",
|
||||
open: "TabOpen",
|
||||
select: "TabSelect",
|
||||
pinned: "TabPinned",
|
||||
unpinned: "TabUnpinned"
|
||||
};
|
||||
let eventListeners = {};
|
||||
|
||||
function registerBrowserWindow(browserWindow) {
|
||||
for each (let event in events)
|
||||
browserWindow.addEventListener(event, tabEventListener, true);
|
||||
|
||||
browserWindow.addEventListener("unload", unregisterBrowserWindow, false);
|
||||
}
|
||||
|
||||
function unregisterBrowserWindow(unloadEvent) {
|
||||
let browserWindow = unloadEvent.currentTarget;
|
||||
|
||||
for each (let event in events)
|
||||
browserWindow.removeEventListener(event, tabEventListener, true);
|
||||
|
||||
browserWindow.removeEventListener("unload", unregisterBrowserWindow, false);
|
||||
}
|
||||
|
||||
function tabEventListener(event) {
|
||||
// Make sure we've gotten listeners before trying to call
|
||||
let listeners = eventListeners[event.type];
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function observer(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "domwindowopened":
|
||||
subject.addEventListener("load", function onLoad() {
|
||||
subject.removeEventListener("load", onLoad, 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);
|
|
@ -520,6 +520,9 @@ function createSearchTabMacher() {
|
|||
}
|
||||
|
||||
function hideSearch(event) {
|
||||
if (!isSearchEnabled())
|
||||
return;
|
||||
|
||||
iQ("#searchbox").val("");
|
||||
iQ("#searchshade").hide();
|
||||
iQ("#search").hide();
|
||||
|
|
|
@ -79,9 +79,6 @@ let Storage = {
|
|||
|
||||
// ___ Tabs
|
||||
AllTabs.tabs.forEach(function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
return;
|
||||
|
||||
self.saveTab(tab, null);
|
||||
});
|
||||
|
||||
|
@ -184,6 +181,23 @@ let Storage = {
|
|||
return existingData;
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: readWindowBusyState
|
||||
// Returns the current busyState for the given window.
|
||||
readWindowBusyState: function Storage_readWindowBusyState(win) {
|
||||
let state;
|
||||
|
||||
try {
|
||||
let data = this._sessionStore.getWindowState(win);
|
||||
if (data)
|
||||
state = JSON.parse(data);
|
||||
} catch (e) {
|
||||
Utils.log("Error while parsing window state");
|
||||
}
|
||||
|
||||
return (state && state.windows[0].busy);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: saveGroupItemsData
|
||||
// Saves the global data for the <GroupItems> singleton for the given window.
|
||||
|
|
|
@ -478,29 +478,22 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
// closing tab doesn't belong to a group and no empty group, create a new
|
||||
// one for the new tab.
|
||||
if (!groupClose && gBrowser.tabs.length == 1) {
|
||||
let group;
|
||||
if (this.tab._tabViewTabItem.parent) {
|
||||
group = this.tab._tabViewTabItem.parent;
|
||||
} else {
|
||||
let emptyGroups = GroupItems.groupItems.filter(function (groupItem) {
|
||||
return (!groupItem.getChildren().length);
|
||||
});
|
||||
group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup());
|
||||
}
|
||||
let group = this.tab._tabViewTabItem.parent;
|
||||
group.newTab(null, { closedLastTab: true });
|
||||
}
|
||||
|
||||
// when "TabClose" event is fired, the browser tab is about to close and our
|
||||
// item "close" is fired before the browser tab actually get closed.
|
||||
// Therefore, we need "tabRemoved" event below.
|
||||
gBrowser.removeTab(this.tab);
|
||||
let tabNotClosed =
|
||||
Array.some(gBrowser.tabs, function(tab) { return tab == this.tab; }, this);
|
||||
if (!tabNotClosed)
|
||||
let tabClosed = !this.tab;
|
||||
|
||||
if (tabClosed)
|
||||
this._sendToSubscribers("tabRemoved");
|
||||
|
||||
// No need to explicitly delete the tab data, becasue sessionstore data
|
||||
// associated with the tab will automatically go away
|
||||
return !tabNotClosed;
|
||||
return tabClosed;
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -746,27 +739,26 @@ let TabItems = {
|
|||
this.tempCanvas.height = 112;
|
||||
|
||||
// When a tab is opened, create the TabItem
|
||||
this._eventListeners["open"] = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
||||
return;
|
||||
this._eventListeners.open = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
if (!tab.pinned)
|
||||
self.link(tab);
|
||||
}
|
||||
// When a tab's content is loaded, show the canvas and hide the cached data
|
||||
// if necessary.
|
||||
this._eventListeners["attrModified"] = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
||||
return;
|
||||
this._eventListeners.attrModified = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
if (!tab.pinned)
|
||||
self.update(tab);
|
||||
}
|
||||
// When a tab is closed, unlink.
|
||||
this._eventListeners["close"] = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
||||
return;
|
||||
this._eventListeners.close = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
// XXX bug #635975 - don't unlink the tab if the dom window is closing.
|
||||
if (!UI.isDOMWindowClosing)
|
||||
if (!tab.pinned && !UI.isDOMWindowClosing)
|
||||
self.unlink(tab);
|
||||
}
|
||||
for (let name in this._eventListeners) {
|
||||
|
@ -774,8 +766,8 @@ let TabItems = {
|
|||
}
|
||||
|
||||
// For each tab, create the link.
|
||||
AllTabs.tabs.forEach(function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow || tab.pinned)
|
||||
AllTabs.tabs.forEach(function (tab) {
|
||||
if (tab.pinned)
|
||||
return;
|
||||
|
||||
self.link(tab, {immediately: true});
|
||||
|
|
|
@ -5,7 +5,6 @@ const Ci = Components.interfaces;
|
|||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource:///modules/tabview/AllTabs.jsm");
|
||||
Cu.import("resource:///modules/tabview/utils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
@ -44,6 +43,30 @@ var gTabViewDeck = gWindow.document.getElementById("tab-view-deck");
|
|||
var gBrowserPanel = gWindow.document.getElementById("browser-panel");
|
||||
var gTabViewFrame = gWindow.document.getElementById("tab-view");
|
||||
|
||||
let AllTabs = {
|
||||
_events: {
|
||||
attrModified: "TabAttrModified",
|
||||
close: "TabClose",
|
||||
move: "TabMove",
|
||||
open: "TabOpen",
|
||||
select: "TabSelect",
|
||||
pinned: "TabPinned",
|
||||
unpinned: "TabUnpinned"
|
||||
},
|
||||
|
||||
get tabs() {
|
||||
return Array.filter(gBrowser.tabs, function (tab) !tab.closing);
|
||||
},
|
||||
|
||||
register: function AllTabs_register(eventName, callback) {
|
||||
gBrowser.tabContainer.addEventListener(this._events[eventName], callback, false);
|
||||
},
|
||||
|
||||
unregister: function AllTabs_unregister(eventName, callback) {
|
||||
gBrowser.tabContainer.removeEventListener(this._events[eventName], callback, false);
|
||||
}
|
||||
};
|
||||
|
||||
# NB: Certain files need to evaluate before others
|
||||
|
||||
#include iq.js
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
* Raymond Lee <raymond@appcoast.com>
|
||||
* Sean Dunn <seanedunn@yahoo.com>
|
||||
* Tim Taubert <tim.taubert@gmx.de>
|
||||
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -80,6 +81,10 @@ let UI = {
|
|||
// If true, a closed tab has just been restored.
|
||||
restoredClosedTab: false,
|
||||
|
||||
// Variable: _isChangingVisibility
|
||||
// Tracks whether we're currently in the process of showing/hiding the tabview.
|
||||
_isChangingVisibility: false,
|
||||
|
||||
// Variable: _reorderTabItemsOnShow
|
||||
// Keeps track of the <GroupItem>s which their tab items' tabs have been moved
|
||||
// and re-orders the tab items when switching to TabView.
|
||||
|
@ -123,9 +128,9 @@ let UI = {
|
|||
wasInTabView: false
|
||||
},
|
||||
|
||||
// Variable: _storageBusyCount
|
||||
// Used to keep track of how many calls to storageBusy vs storageReady.
|
||||
_storageBusyCount: 0,
|
||||
// Variable: _storageBusy
|
||||
// Tells whether the storage is currently busy or not.
|
||||
_storageBusy: false,
|
||||
|
||||
// Variable: isDOMWindowClosing
|
||||
// Tells wether the parent window is about to close
|
||||
|
@ -169,6 +174,10 @@ let UI = {
|
|||
|
||||
// ___ storage
|
||||
Storage.init();
|
||||
|
||||
if (Storage.readWindowBusyState(gWindow))
|
||||
this.storageBusy();
|
||||
|
||||
let data = Storage.readUIData(gWindow);
|
||||
this._storageSanity(data);
|
||||
this._pageBounds = data.pageBounds;
|
||||
|
@ -230,6 +239,15 @@ let UI = {
|
|||
self.uninit();
|
||||
});
|
||||
|
||||
// ___ setup DOMWillOpenModalDialog message handler
|
||||
let mm = gWindow.messageManager;
|
||||
let callback = this._onDOMWillOpenModalDialog.bind(this);
|
||||
mm.addMessageListener("Panorama:DOMWillOpenModalDialog", callback);
|
||||
|
||||
this._cleanupFunctions.push(function () {
|
||||
mm.removeMessageListener("Panorama:DOMWillOpenModalDialog", callback);
|
||||
});
|
||||
|
||||
// ___ setup key handlers
|
||||
this._setTabViewFrameKeyHandlers();
|
||||
|
||||
|
@ -272,6 +290,10 @@ let UI = {
|
|||
self._save();
|
||||
}, false);
|
||||
|
||||
// ___ load frame script
|
||||
let frameScript = "chrome://browser/content/tabview-content.js";
|
||||
gWindow.messageManager.loadFrameScript(frameScript, true);
|
||||
|
||||
// ___ Done
|
||||
this._frameInitialized = true;
|
||||
this._save();
|
||||
|
@ -477,9 +499,11 @@ let UI = {
|
|||
// Parameters:
|
||||
// zoomOut - true for zoom out animation, false for nothing.
|
||||
showTabView: function UI_showTabView(zoomOut) {
|
||||
if (this.isTabViewVisible())
|
||||
if (this.isTabViewVisible() || this._isChangingVisibility)
|
||||
return;
|
||||
|
||||
this._isChangingVisibility = true;
|
||||
|
||||
// initialize the direction of the page
|
||||
this._initPageDirection();
|
||||
|
||||
|
@ -522,6 +546,7 @@ let UI = {
|
|||
self.setActive(item);
|
||||
|
||||
self._resize(true);
|
||||
self._isChangingVisibility = false;
|
||||
dispatchEvent(event);
|
||||
|
||||
// Flush pending updates
|
||||
|
@ -531,6 +556,7 @@ let UI = {
|
|||
});
|
||||
} else {
|
||||
self.clearActiveTab();
|
||||
self._isChangingVisibility = false;
|
||||
dispatchEvent(event);
|
||||
|
||||
// Flush pending updates
|
||||
|
@ -547,9 +573,11 @@ let UI = {
|
|||
// Function: hideTabView
|
||||
// Hides TabView and shows the main browser UI.
|
||||
hideTabView: function UI_hideTabView() {
|
||||
if (!this.isTabViewVisible())
|
||||
if (!this.isTabViewVisible() || this._isChangingVisibility)
|
||||
return;
|
||||
|
||||
this._isChangingVisibility = true;
|
||||
|
||||
// another tab might be select if user decides to stay on a page when
|
||||
// a onclose confirmation prompts.
|
||||
GroupItems.removeHiddenGroups();
|
||||
|
@ -576,6 +604,8 @@ let UI = {
|
|||
#endif
|
||||
Storage.saveVisibilityData(gWindow, "false");
|
||||
|
||||
this._isChangingVisibility = false;
|
||||
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("tabviewhidden", true, false);
|
||||
dispatchEvent(event);
|
||||
|
@ -612,12 +642,13 @@ let UI = {
|
|||
// Pauses the storage activity that conflicts with sessionstore updates and
|
||||
// private browsing mode switches. Calls can be nested.
|
||||
storageBusy: function UI_storageBusy() {
|
||||
if (!this._storageBusyCount) {
|
||||
if (this._storageBusy)
|
||||
return;
|
||||
|
||||
this._storageBusy = true;
|
||||
|
||||
TabItems.pauseReconnecting();
|
||||
GroupItems.pauseAutoclose();
|
||||
}
|
||||
|
||||
this._storageBusyCount++;
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -625,8 +656,11 @@ let UI = {
|
|||
// Resumes the activity paused by storageBusy, and updates for any new group
|
||||
// information in sessionstore. Calls can be nested.
|
||||
storageReady: function UI_storageReady() {
|
||||
this._storageBusyCount--;
|
||||
if (!this._storageBusyCount) {
|
||||
if (!this._storageBusy)
|
||||
return;
|
||||
|
||||
this._storageBusy = false;
|
||||
|
||||
let hasGroupItemsData = GroupItems.load();
|
||||
if (!hasGroupItemsData)
|
||||
this.reset();
|
||||
|
@ -634,7 +668,6 @@ let UI = {
|
|||
TabItems.resumeReconnecting();
|
||||
GroupItems._updateTabBar();
|
||||
GroupItems.resumeAutoclose();
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -678,6 +711,7 @@ let UI = {
|
|||
}
|
||||
} else if (topic == "private-browsing-change-granted") {
|
||||
if (data == "enter" || data == "exit") {
|
||||
hideSearch();
|
||||
self._privateBrowsing.transitionMode = data;
|
||||
self.storageBusy();
|
||||
}
|
||||
|
@ -703,9 +737,8 @@ let UI = {
|
|||
});
|
||||
|
||||
// TabOpen
|
||||
this._eventListeners.open = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
return;
|
||||
this._eventListeners.open = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
// if it's an app tab, add it to all the group items
|
||||
if (tab.pinned)
|
||||
|
@ -715,9 +748,8 @@ let UI = {
|
|||
};
|
||||
|
||||
// TabClose
|
||||
this._eventListeners.close = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
return;
|
||||
this._eventListeners.close = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
// if it's an app tab, remove it from all the group items
|
||||
if (tab.pinned)
|
||||
|
@ -730,7 +762,7 @@ let UI = {
|
|||
} else {
|
||||
// If we're currently in the process of entering private browsing,
|
||||
// we don't want to go to the Tab View UI.
|
||||
if (self._storageBusyCount)
|
||||
if (self._storageBusy)
|
||||
return;
|
||||
|
||||
// if not closing the last tab
|
||||
|
@ -749,21 +781,14 @@ let UI = {
|
|||
groupItem._children.length == 1 &&
|
||||
groupItem._children[0].tab == tab);
|
||||
|
||||
// 2) Take care of the case where you've closed the last tab in
|
||||
// an un-named groupItem, which means that the groupItem is gone (null) and
|
||||
// there are no visible tabs.
|
||||
let closingUnnamedGroup = (groupItem == null &&
|
||||
gBrowser.visibleTabs.length <= 1);
|
||||
|
||||
// 3) When a blank tab is active while restoring a closed tab the
|
||||
// 2) When a blank tab is active while restoring a closed tab the
|
||||
// blank tab gets removed. The active group is not closed as this is
|
||||
// where the restored tab goes. So do not show the TabView.
|
||||
let tabItem = tab && tab._tabViewTabItem;
|
||||
let closingBlankTabAfterRestore =
|
||||
(tabItem && tabItem.isRemovedAfterRestore);
|
||||
|
||||
if ((closingLastOfGroup || closingUnnamedGroup) &&
|
||||
!closingBlankTabAfterRestore) {
|
||||
if (closingLastOfGroup && !closingBlankTabAfterRestore) {
|
||||
// for the tab focus event to pick up.
|
||||
self._closedLastVisibleTab = true;
|
||||
self.showTabView();
|
||||
|
@ -773,9 +798,8 @@ let UI = {
|
|||
};
|
||||
|
||||
// TabMove
|
||||
this._eventListeners.move = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
return;
|
||||
this._eventListeners.move = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
if (GroupItems.groupItems.length > 0) {
|
||||
if (tab.pinned) {
|
||||
|
@ -790,26 +814,21 @@ let UI = {
|
|||
};
|
||||
|
||||
// TabSelect
|
||||
this._eventListeners.select = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
return;
|
||||
|
||||
self.onTabSelect(tab);
|
||||
this._eventListeners.select = function (event) {
|
||||
self.onTabSelect(event.target);
|
||||
};
|
||||
|
||||
// TabPinned
|
||||
this._eventListeners.pinned = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
return;
|
||||
this._eventListeners.pinned = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
TabItems.handleTabPin(tab);
|
||||
GroupItems.addAppTab(tab);
|
||||
};
|
||||
|
||||
// TabUnpinned
|
||||
this._eventListeners.unpinned = function(tab) {
|
||||
if (tab.ownerDocument.defaultView != gWindow)
|
||||
return;
|
||||
this._eventListeners.unpinned = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
TabItems.handleTabUnpin(tab);
|
||||
GroupItems.removeAppTab(tab);
|
||||
|
@ -883,8 +902,14 @@ let UI = {
|
|||
|
||||
// if TabView is visible but we didn't just close the last tab or
|
||||
// selected tab, show chrome.
|
||||
if (this.isTabViewVisible())
|
||||
if (this.isTabViewVisible()) {
|
||||
// Unhide the group of the tab the user is activating.
|
||||
if (tab && tab._tabViewTabItem && tab._tabViewTabItem.parent &&
|
||||
tab._tabViewTabItem.parent.hidden)
|
||||
tab._tabViewTabItem.parent._unhide({immediately: true});
|
||||
|
||||
this.hideTabView();
|
||||
}
|
||||
|
||||
// another tab might be selected when hideTabView() is invoked so a
|
||||
// validation is needed.
|
||||
|
@ -918,6 +943,27 @@ let UI = {
|
|||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _onDOMWillOpenModalDialog
|
||||
// Called when a web page is about to show a modal dialog.
|
||||
_onDOMWillOpenModalDialog: function UI__onDOMWillOpenModalDialog(cx) {
|
||||
if (!this.isTabViewVisible())
|
||||
return;
|
||||
|
||||
let index = gBrowser.browsers.indexOf(cx.target);
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
let tab = gBrowser.tabs[index];
|
||||
|
||||
// When TabView is visible, we need to call onTabSelect to make sure that
|
||||
// TabView is hidden and that the correct group is activated. When a modal
|
||||
// dialog is shown for currently selected tab the onTabSelect event handler
|
||||
// is not called, so we need to do it.
|
||||
if (gBrowser.selectedTab == tab && this._currentTab == tab)
|
||||
this.onTabSelect(tab);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: setReorderTabsOnHide
|
||||
// Sets the groupItem which the tab items' tabs should be re-ordered when
|
||||
|
|
|
@ -111,6 +111,7 @@ _BROWSER_FILES = \
|
|||
browser_tabview_bug625269.js \
|
||||
browser_tabview_bug625424.js \
|
||||
browser_tabview_bug626368.js \
|
||||
browser_tabview_bug626455.js \
|
||||
browser_tabview_bug626525.js \
|
||||
browser_tabview_bug626791.js \
|
||||
browser_tabview_bug627239.js \
|
||||
|
@ -139,6 +140,7 @@ _BROWSER_FILES = \
|
|||
browser_tabview_bug649006.js \
|
||||
browser_tabview_bug649307.js \
|
||||
browser_tabview_bug649319.js \
|
||||
browser_tabview_bug650280.js \
|
||||
browser_tabview_bug650573.js \
|
||||
browser_tabview_bug651311.js \
|
||||
browser_tabview_bug654721.js \
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource:///modules/tabview/AllTabs.jsm");
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let AllTabs;
|
||||
let newTab = gBrowser.addTab();
|
||||
|
||||
// TabPinned
|
||||
let pinned = function(tab) {
|
||||
let pinned = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
is(tab, newTab, "The tabs are the same after the tab is pinned");
|
||||
ok(tab.pinned, "The tab gets pinned");
|
||||
|
||||
|
@ -17,7 +18,9 @@ function test() {
|
|||
};
|
||||
|
||||
// TabUnpinned
|
||||
let unpinned = function(tab) {
|
||||
let unpinned = function (event) {
|
||||
let tab = event.target;
|
||||
|
||||
AllTabs.unregister("pinned", pinned);
|
||||
AllTabs.unregister("unpinned", unpinned);
|
||||
|
||||
|
@ -26,13 +29,17 @@ function test() {
|
|||
|
||||
// clean up and finish
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
hideTabView(finish);
|
||||
};
|
||||
|
||||
showTabView(function () {
|
||||
AllTabs = TabView.getContentWindow().AllTabs;
|
||||
|
||||
AllTabs.register("pinned", pinned);
|
||||
AllTabs.register("unpinned", unpinned);
|
||||
|
||||
ok(!newTab.pinned, "The tab is not pinned");
|
||||
gBrowser.pinTab(newTab);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ function setupOne(win) {
|
|||
afterAllTabsLoaded(function () setupTwo(win), win);
|
||||
}
|
||||
|
||||
let restoreWin;
|
||||
let restoredWin;
|
||||
|
||||
function setupTwo(win) {
|
||||
let contentWindow = win.TabView.getContentWindow();
|
||||
|
@ -37,26 +37,20 @@ function setupTwo(win) {
|
|||
contentWindow.TabItems.update(tabItem.tab);
|
||||
tabItem.addSubscriber("savedCachedImageData", function onSaved(item) {
|
||||
item.removeSubscriber("savedCachedImageData", onSaved);
|
||||
--numTabsToSave;
|
||||
|
||||
if (!--numTabsToSave)
|
||||
restoreWindow();
|
||||
});
|
||||
});
|
||||
|
||||
// after the window is closed, restore it.
|
||||
let xulWindowDestory = function() {
|
||||
Services.obs.removeObserver(
|
||||
xulWindowDestory, "xul-window-destroyed", false);
|
||||
|
||||
// "xul-window-destroyed" is just fired just before a XUL window is
|
||||
// destroyed so restore window and test it after a delay
|
||||
let restoreWindow = function() {
|
||||
executeSoon(function() {
|
||||
restoredWin = undoCloseWindow();
|
||||
restoredWin.addEventListener("load", function onLoad(event) {
|
||||
restoredWin.removeEventListener("load", onLoad, false);
|
||||
|
||||
registerCleanupFunction(function() restoredWin.close());
|
||||
|
||||
// ensure that closed tabs have been saved
|
||||
is(numTabsToSave, 0, "All tabs were saved when window was closed.");
|
||||
is(restoredWin.gBrowser.tabs.length, 3, "The total number of tabs is 3");
|
||||
|
||||
// setup tab variables and listen to the tabs load progress
|
||||
|
@ -103,7 +97,6 @@ function setupTwo(win) {
|
|||
}, false);
|
||||
});
|
||||
};
|
||||
Services.obs.addObserver(xulWindowDestory, "xul-window-destroyed", false);
|
||||
|
||||
win.close();
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ function test() {
|
|||
function part1(win) {
|
||||
registerCleanupFunction(function() win.close());
|
||||
|
||||
let contentWindow = win.document.getElementById("tab-view").contentWindow;
|
||||
let contentWindow = win.TabView.getContentWindow();
|
||||
is(contentWindow.GroupItems.groupItems.length, 1, "Has only one group");
|
||||
|
||||
let originalTab = win.gBrowser.selectedTab;
|
||||
|
@ -71,15 +71,12 @@ function part2(win) {
|
|||
// switch the selected tab to new tab
|
||||
win.gBrowser.selectedTab = newTab;
|
||||
|
||||
whenTabViewIsHidden(function () {
|
||||
is(win.gBrowser.selectedTab, newTab, "The seleted tab should be the same as before (new tab)");
|
||||
win.close();
|
||||
finish();
|
||||
});
|
||||
|
||||
// show tabview
|
||||
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
|
||||
// hide tabview
|
||||
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
|
||||
})
|
||||
showTabView(function () {
|
||||
hideTabView(function () {
|
||||
is(win.gBrowser.selectedTab, newTab,
|
||||
"The selected tab should be the same as before (new tab)");
|
||||
waitForFocus(finish);
|
||||
}, win);
|
||||
}, win);
|
||||
}, win);
|
||||
}
|
||||
|
|
|
@ -21,9 +21,7 @@ function onTabViewShown() {
|
|||
|
||||
function testStayOnPage(contentWindow, groupItemOne, groupItemTwo) {
|
||||
whenDialogOpened(function (dialog) {
|
||||
groupItemTwo.addSubscriber("groupShown", function onShown() {
|
||||
groupItemTwo.removeSubscriber("groupShown", onShown);
|
||||
|
||||
executeSoon(function () {
|
||||
is(gBrowser.tabs.length, 2,
|
||||
"The total number of tab is 2 when staying on the page");
|
||||
is(contentWindow.TabItems.getItems().length, 2,
|
||||
|
|
|
@ -25,6 +25,7 @@ function test1() {
|
|||
is(groupItems.length, 1, "there is one groupItem");
|
||||
|
||||
whenTabViewIsHidden(function() {
|
||||
gBrowser.selectedTab = gBrowser.tabs[0];
|
||||
is(groupItems.length, 2, "there are two groupItems");
|
||||
closeGroupItem(groupItems[1], finish);
|
||||
});
|
||||
|
|
|
@ -18,6 +18,6 @@ function test() {
|
|||
cw.GroupItems.resumeArrange();
|
||||
ok(groupItem.isStacked(), 'groupItem is now stacked');
|
||||
|
||||
closeGroupItem(groupItem, finish);
|
||||
closeGroupItem(groupItem, function () hideTabView(finish));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ function test() {
|
|||
ok(!document.getElementById("context_openTabInWindow").disabled, "The 'Move to New Window' menu item is enabled");
|
||||
|
||||
let newTabTwo = gBrowser.selectedTab;
|
||||
gBrowser.selected = originalTab;
|
||||
gBrowser.selectedTab = originalTab;
|
||||
|
||||
gBrowser.removeTab(newTabOne);
|
||||
gBrowser.removeTab(newTabTwo);
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||
* Raymond Lee <raymond@appcoast.com>
|
||||
*/
|
||||
|
||||
const TEST_URL = 'data:text/html,<script>window.onbeforeunload=' +
|
||||
'function(e){e.returnValue="?"}</script><body ' +
|
||||
'onunload="alert(\'onunload\')" onpagehide="' +
|
||||
'alert(\'onpagehide\')"></body>';
|
||||
|
||||
let contentWindow;
|
||||
let activeGroup;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
showTabView(function () {
|
||||
contentWindow = TabView.getContentWindow();
|
||||
activeGroup = contentWindow.GroupItems.getActiveGroupItem();
|
||||
|
||||
gBrowser.browsers[0].contentWindow.location =
|
||||
"data:text/html,<p>test for bug 626455, tab1";
|
||||
gBrowser.addTab(TEST_URL);
|
||||
|
||||
afterAllTabsLoaded(testStayOnPage);
|
||||
});
|
||||
}
|
||||
|
||||
function testStayOnPage() {
|
||||
whenDialogOpened(function (dialog) {
|
||||
// stay on page
|
||||
dialog.cancelDialog();
|
||||
|
||||
executeSoon(function () {
|
||||
showTabView(function () {
|
||||
is(gBrowser.tabs.length, 1,
|
||||
"The total number of tab is 1 when staying on the page");
|
||||
|
||||
let location = gBrowser.browsers[0].contentWindow.location.toString();
|
||||
isnot(location.indexOf("onbeforeunload"), -1,
|
||||
"The open tab is the expected one");
|
||||
|
||||
is(contentWindow.GroupItems.getActiveGroupItem(), activeGroup,
|
||||
"Active group is still the same");
|
||||
|
||||
is(contentWindow.GroupItems.groupItems.length, 1,
|
||||
"Only one group is open");
|
||||
|
||||
// start the next test
|
||||
testLeavePage();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
closeGroupItem(activeGroup);
|
||||
}
|
||||
|
||||
function testLeavePage() {
|
||||
let dialogsAccepted = 0;
|
||||
|
||||
whenDialogOpened(function onDialogOpened(dialog) {
|
||||
if (++dialogsAccepted < 3)
|
||||
whenDialogOpened(onDialogOpened);
|
||||
|
||||
// Leave page
|
||||
dialog.acceptDialog();
|
||||
});
|
||||
|
||||
whenGroupClosed(activeGroup, finishTest);
|
||||
closeGroupItem(activeGroup);
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
is(gBrowser.tabs.length, 1,
|
||||
"The total number of tab is 1 after leaving the page");
|
||||
is(contentWindow.TabItems.getItems().length, 1,
|
||||
"The total number of tab items is 1 after leaving the page");
|
||||
|
||||
let location = gBrowser.browsers[0].contentWindow.location.toString();
|
||||
is(location, "about:blank", "The open tab is the expected one");
|
||||
|
||||
isnot(contentWindow.GroupItems.getActiveGroupItem(), activeGroup,
|
||||
"Active group is no longer the same");
|
||||
|
||||
is(contentWindow.GroupItems.groupItems.length, 1,
|
||||
"Only one group is open");
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
// ----------
|
||||
function whenGroupClosed(group, callback) {
|
||||
group.addSubscriber("close", function onClose() {
|
||||
group.removeSubscriber("close", onClose);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
// ----------
|
||||
function whenDialogOpened(callback) {
|
||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Ci.nsIWindowMediator);
|
||||
|
||||
let listener = {
|
||||
onCloseWindow: function () {},
|
||||
onWindowTitleChange: function () {},
|
||||
|
||||
onOpenWindow: function (xulWin) {
|
||||
let domWin = xulWin.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
|
||||
whenWindowLoaded(domWin, function () {
|
||||
let dialog = domWin.document.querySelector("dialog");
|
||||
if (dialog) {
|
||||
wm.removeListener(listener);
|
||||
callback(dialog);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
wm.addListener(listener);
|
||||
}
|
|
@ -15,7 +15,7 @@ function loadTabs (win) {
|
|||
function testTopOfStack(win) {
|
||||
registerCleanupFunction(function () { win.close(); });
|
||||
let cw = win.TabView.getContentWindow();
|
||||
groupItem = cw.GroupItems.getActiveGroupItem();
|
||||
let groupItem = cw.GroupItems.getActiveGroupItem();
|
||||
ok(!groupItem.isStacked(), 'groupItem is not stacked');
|
||||
groupItem.setSize(150, 150);
|
||||
groupItem.setUserSize();
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
|
||||
function test() {
|
||||
let cw;
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
if (cw)
|
||||
cw.hideSearch();
|
||||
|
||||
TabView.hide();
|
||||
pb.privateBrowsingEnabled = false;
|
||||
});
|
||||
|
||||
let enableSearch = function (callback) {
|
||||
if (cw.isSearchEnabled()) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
cw.addEventListener("tabviewsearchenabled", function onSearchEnabled() {
|
||||
cw.removeEventListener("tabviewsearchenabled", onSearchEnabled, false);
|
||||
executeSoon(callback);
|
||||
}, false);
|
||||
|
||||
cw.ensureSearchShown();
|
||||
};
|
||||
|
||||
let getSearchboxValue = function () {
|
||||
return cw.iQ("#searchbox").val();
|
||||
};
|
||||
|
||||
let prepareSearchbox = function (callback) {
|
||||
ok(!cw.isSearchEnabled(), "search is disabled");
|
||||
|
||||
enableSearch(function () {
|
||||
cw.iQ("#searchbox").val("moz");
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
let searchAndSwitchPBMode = function (callback) {
|
||||
prepareSearchbox(function () {
|
||||
togglePrivateBrowsing(function () {
|
||||
showTabView(function () {
|
||||
ok(!cw.isSearchEnabled(), "search is disabled");
|
||||
is(getSearchboxValue(), "", "search box is empty");
|
||||
callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
showTabView(function () {
|
||||
cw = TabView.getContentWindow();
|
||||
searchAndSwitchPBMode(function () {
|
||||
searchAndSwitchPBMode(function () {
|
||||
hideTabView(finish);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -67,7 +67,7 @@ function test() {
|
|||
EventUtils.synthesizeMouse(target, 600, 5, {type: "mouseup"}, cw);
|
||||
|
||||
checkNumberOfGroupItems(2);
|
||||
next();
|
||||
closeGroupItem(cw.GroupItems.groupItems[1], next);
|
||||
}, win);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,49 +3,32 @@
|
|||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
TabView.toggle();
|
||||
showTabView(onTabViewShown);
|
||||
}
|
||||
|
||||
function onTabViewWindowLoaded() {
|
||||
window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false);
|
||||
|
||||
function onTabViewShown() {
|
||||
ok(TabView.isVisible(), "Tab View is visible");
|
||||
|
||||
let contentWindow = document.getElementById("tab-view").contentWindow;
|
||||
let contentWindow = TabView.getContentWindow();
|
||||
let [originalTab] = gBrowser.visibleTabs;
|
||||
|
||||
let createGroupItem = function (left, top, width, height) {
|
||||
let box = new contentWindow.Rect(left, top, width, height);
|
||||
let groupItem = new contentWindow.GroupItem([], {bounds: box, immediately: true});
|
||||
|
||||
contentWindow.UI.setActive(groupItem);
|
||||
gBrowser.loadOneTab("about:blank", {inBackground: true});
|
||||
|
||||
return groupItem;
|
||||
};
|
||||
|
||||
// create group one and two
|
||||
let boxOne = new contentWindow.Rect(20, 20, 300, 300);
|
||||
let groupOne = new contentWindow.GroupItem([], { bounds: boxOne });
|
||||
ok(groupOne.isEmpty(), "This group is empty");
|
||||
let groupOne = createGroupItem(20, 20, 300, 300);
|
||||
let groupTwo = createGroupItem(20, 400, 300, 300);
|
||||
|
||||
let boxTwo = new contentWindow.Rect(20, 400, 300, 300);
|
||||
let groupTwo = new contentWindow.GroupItem([], { bounds: boxTwo });
|
||||
|
||||
groupOne.addSubscriber("childAdded", function onChildAdded() {
|
||||
groupOne.removeSubscriber("childAdded", onChildAdded);
|
||||
groupTwo.newTab();
|
||||
});
|
||||
|
||||
let count = 0;
|
||||
let onTabViewShown = function() {
|
||||
if (count == 2) {
|
||||
window.removeEventListener("tabviewshown", onTabViewShown, false);
|
||||
waitForFocus(function () {
|
||||
addTest(contentWindow, groupOne.id, groupTwo.id, originalTab);
|
||||
}
|
||||
};
|
||||
let onTabViewHidden = function() {
|
||||
TabView.toggle();
|
||||
if (++count == 2)
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
};
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
|
||||
// open tab in group
|
||||
groupOne.newTab();
|
||||
});
|
||||
}
|
||||
|
||||
function addTest(contentWindow, groupOneId, groupTwoId, originalTab) {
|
||||
|
@ -75,23 +58,12 @@ function addTest(contentWindow, groupOneId, groupTwoId, originalTab) {
|
|||
is(groupTwo.getChildren().length, ++groupTwoTabItemCount,
|
||||
"The number of children in group two is increased by 1");
|
||||
|
||||
let onTabViewHidden = function() {
|
||||
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
groupTwo.closeAll();
|
||||
// close undo group
|
||||
let closeButton = groupTwo.$undoContainer.find(".close");
|
||||
EventUtils.sendMouseEvent(
|
||||
{ type: "click" }, closeButton[0], contentWindow);
|
||||
};
|
||||
groupTwo.addSubscriber("close", function onClose() {
|
||||
groupTwo.removeSubscriber("close", onClose);
|
||||
finish();
|
||||
closeGroupItem(groupOne, function () {
|
||||
closeGroupItem(groupTwo, function () hideTabView(finish));
|
||||
});
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
gBrowser.selectedTab = originalTab;
|
||||
}
|
||||
groupTwo.addSubscriber("childAdded", endGame);
|
||||
|
||||
groupTwo.addSubscriber("childAdded", endGame);
|
||||
simulateDragDrop(tabItem.container, offsetX, offsetY, contentWindow);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let timerId;
|
||||
let newWin;
|
||||
|
||||
// ----------
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// launch tab view for the first time
|
||||
newWindowWithTabView(function() {}, function(win) {
|
||||
let panelSelected = false;
|
||||
registerCleanupFunction(function () ok(panelSelected, "panel is selected"));
|
||||
|
||||
let onLoad = function (win) {
|
||||
registerCleanupFunction(function () win.close());
|
||||
|
||||
newWin = win;
|
||||
|
||||
let onSelect = function(event) {
|
||||
|
@ -21,27 +24,26 @@ function test() {
|
|||
return;
|
||||
|
||||
deck.removeEventListener("select", onSelect, true);
|
||||
panelSelected = true;
|
||||
};
|
||||
|
||||
whenTabViewIsShown(function() {
|
||||
let deck = win.document.getElementById("tab-view-deck");
|
||||
deck.addEventListener("select", onSelect, true);
|
||||
};
|
||||
|
||||
let onShow = function (win) {
|
||||
executeSoon(function() {
|
||||
testMethodToHideAndShowTabView(function() {
|
||||
newWin.document.getElementById("menu_tabview").doCommand();
|
||||
}, function() {
|
||||
testMethodToHideAndShowTabView(function() {
|
||||
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, newWin);
|
||||
EventUtils.synthesizeKey("E", { accelKey: true, shiftKey: true }, newWin);
|
||||
}, finish);
|
||||
});
|
||||
});
|
||||
}, win);
|
||||
};
|
||||
|
||||
let deck = win.document.getElementById("tab-view-deck");
|
||||
deck.addEventListener("select", onSelect, true);
|
||||
});
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
newWin.close();
|
||||
});
|
||||
newWindowWithTabView(onShow, onLoad);
|
||||
}
|
||||
|
||||
function testMethodToHideAndShowTabView(executeFunc, callback) {
|
||||
|
|
|
@ -49,11 +49,15 @@ function onTabViewLoadedAndShown() {
|
|||
groupTitles[a] = gi.getTitle();
|
||||
}
|
||||
|
||||
contentWindow.gPrefBranch.setBoolPref("animate_zoom", false);
|
||||
|
||||
// Create a second tab
|
||||
gBrowser.addTab("about:robots");
|
||||
is(gBrowser.tabs.length, 2, "we now have 2 tabs");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
contentWindow.gPrefBranch.clearUserPref("animate_zoom");
|
||||
});
|
||||
|
||||
afterAllTabsLoaded(function() {
|
||||
|
|
|
@ -361,7 +361,10 @@ function togglePrivateBrowsing(callback) {
|
|||
|
||||
Services.obs.addObserver(function observe() {
|
||||
Services.obs.removeObserver(observe, topic);
|
||||
afterAllTabsLoaded(callback);
|
||||
|
||||
// use executeSoon() to let Panorama load its group data from the session
|
||||
// before we call afterAllTabsLoaded()
|
||||
executeSoon(function () afterAllTabsLoaded(callback));
|
||||
}, topic, false);
|
||||
|
||||
let pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
|
|
|
@ -53,6 +53,7 @@ browser.jar:
|
|||
content/browser/tabview.css (content/tabview/tabview.css)
|
||||
* content/browser/tabview.js (content/tabview/tabview.js)
|
||||
content/browser/tabview.html (content/tabview/tabview.html)
|
||||
content/browser/tabview-content.js (content/tabview/content.js)
|
||||
* content/browser/urlbarBindings.xml (content/urlbarBindings.xml)
|
||||
* content/browser/utilityOverlay.js (content/utilityOverlay.js)
|
||||
* content/browser/web-panels.js (content/web-panels.js)
|
||||
|
|
|
@ -256,7 +256,8 @@ FeedWriter.prototype = {
|
|||
__contentSandbox: null,
|
||||
get _contentSandbox() {
|
||||
if (!this.__contentSandbox)
|
||||
this.__contentSandbox = new Cu.Sandbox(this._window);
|
||||
this.__contentSandbox = new Cu.Sandbox(this._window,
|
||||
{sandboxName: 'FeedWriter'});
|
||||
|
||||
return this.__contentSandbox;
|
||||
},
|
||||
|
|
|
@ -619,11 +619,9 @@ PrivateBrowsingService.prototype = {
|
|||
}
|
||||
|
||||
// Plugin data
|
||||
let (ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost)) {
|
||||
const phInterface = Ci.nsIPluginHost;
|
||||
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
|
||||
ph.QueryInterface(phInterface);
|
||||
|
||||
let (ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface)) {
|
||||
let tags = ph.getPluginTags();
|
||||
for (let i = 0; i < tags.length; i++) {
|
||||
try {
|
||||
|
|
|
@ -59,7 +59,7 @@ window.onload = function() {
|
|||
gStateObject = JSON.parse(sessionData.value);
|
||||
}
|
||||
catch (exJSON) {
|
||||
var s = new Cu.Sandbox("about:blank");
|
||||
var s = new Cu.Sandbox("about:blank", {sandboxName: 'aboutSessionRestore'});
|
||||
gStateObject = Cu.evalInSandbox("(" + sessionData.value + ")", s);
|
||||
// If we couldn't parse the string with JSON.parse originally, make sure
|
||||
// that the value in the textbox will be parsable.
|
||||
|
|
|
@ -135,7 +135,7 @@ SessionStartup.prototype = {
|
|||
this._initialState = JSON.parse(iniString);
|
||||
}
|
||||
catch (exJSON) {
|
||||
var s = new Cu.Sandbox("about:blank");
|
||||
var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'});
|
||||
this._initialState = Cu.evalInSandbox("(" + iniString + ")", s);
|
||||
}
|
||||
|
||||
|
|
|
@ -785,7 +785,7 @@ SessionStoreService.prototype = {
|
|||
aWindow.__SSi = "window" + Date.now();
|
||||
|
||||
// and create its data object
|
||||
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [] };
|
||||
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
|
||||
if (!this._isWindowLoaded(aWindow))
|
||||
this._windows[aWindow.__SSi]._restoring = true;
|
||||
if (!aWindow.toolbar.visible)
|
||||
|
@ -969,6 +969,9 @@ SessionStoreService.prototype = {
|
|||
// save the window if it has multiple tabs or a single saveable tab
|
||||
if (winData.tabs.length > 1 ||
|
||||
(winData.tabs.length == 1 && this._shouldSaveTabState(winData.tabs[0]))) {
|
||||
// we don't want to save the busy state
|
||||
delete winData.busy;
|
||||
|
||||
this._closedWindows.unshift(winData);
|
||||
this._capClosedWindows();
|
||||
}
|
||||
|
@ -1265,7 +1268,7 @@ SessionStoreService.prototype = {
|
|||
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
var window = aTab.ownerDocument.defaultView;
|
||||
this._sendWindowStateEvent(window, "Busy");
|
||||
this._setWindowStateBusy(window);
|
||||
this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0);
|
||||
},
|
||||
|
||||
|
@ -1281,7 +1284,7 @@ SessionStoreService.prototype = {
|
|||
tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length));
|
||||
tabState.pinned = false;
|
||||
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
this._setWindowStateBusy(aWindow);
|
||||
let newTab = aTab == aWindow.gBrowser.selectedTab ?
|
||||
aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
|
||||
aWindow.gBrowser.addTab();
|
||||
|
@ -1324,7 +1327,7 @@ SessionStoreService.prototype = {
|
|||
let closedTab = closedTabs.splice(aIndex, 1).shift();
|
||||
let closedTabState = closedTab.state;
|
||||
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
this._setWindowStateBusy(aWindow);
|
||||
// create a new tab
|
||||
let browser = aWindow.gBrowser;
|
||||
let tab = browser.addTab();
|
||||
|
@ -2534,7 +2537,7 @@ SessionStoreService.prototype = {
|
|||
|
||||
// We're not returning from this before we end up calling restoreHistoryPrecursor
|
||||
// for this window, so make sure we send the SSWindowStateBusy event.
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
this._setWindowStateBusy(aWindow);
|
||||
|
||||
if (root._closedWindows)
|
||||
this._closedWindows = root._closedWindows;
|
||||
|
@ -2721,7 +2724,7 @@ SessionStoreService.prototype = {
|
|||
if (aTabs.length == 0) {
|
||||
// this is normally done in restoreHistory() but as we're returning early
|
||||
// here we need to take care of it.
|
||||
this._sendWindowStateEvent(aWindow, "Ready");
|
||||
this._setWindowStateReady(aWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2866,7 +2869,7 @@ SessionStoreService.prototype = {
|
|||
if (aTabs.length == 0) {
|
||||
// At this point we're essentially ready for consumers to read/write data
|
||||
// via the sessionstore API so we'll send the SSWindowStateReady event.
|
||||
this._sendWindowStateEvent(aWindow, "Ready");
|
||||
this._setWindowStateReady(aWindow);
|
||||
return; // no more tabs to restore
|
||||
}
|
||||
|
||||
|
@ -4011,6 +4014,42 @@ SessionStoreService.prototype = {
|
|||
this._restoreCount = -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the given window's busy state
|
||||
* @param aWindow the window
|
||||
* @param aValue the window's busy state
|
||||
*/
|
||||
_setWindowStateBusyValue:
|
||||
function sss__changeWindowStateBusyValue(aWindow, aValue) {
|
||||
|
||||
this._windows[aWindow.__SSi].busy = aValue;
|
||||
|
||||
// Keep the to-be-restored state in sync because that is returned by
|
||||
// getWindowState() as long as the window isn't loaded, yet.
|
||||
if (!this._isWindowLoaded(aWindow)) {
|
||||
let stateToRestore = this._statesToRestore[aWindow.__SS_restoreID].windows[0];
|
||||
stateToRestore.busy = aValue;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the given window's state to 'not busy'.
|
||||
* @param aWindow the window
|
||||
*/
|
||||
_setWindowStateReady: function sss__setWindowStateReady(aWindow) {
|
||||
this._setWindowStateBusyValue(aWindow, false);
|
||||
this._sendWindowStateEvent(aWindow, "Ready");
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the given window's state to 'busy'.
|
||||
* @param aWindow the window
|
||||
*/
|
||||
_setWindowStateBusy: function sss__setWindowStateBusy(aWindow) {
|
||||
this._setWindowStateBusyValue(aWindow, true);
|
||||
this._sendWindowStateEvent(aWindow, "Busy");
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatch an SSWindowState_____ event for the given window.
|
||||
* @param aWindow the window
|
||||
|
|
|
@ -151,6 +151,7 @@ _BROWSER_TEST_FILES = \
|
|||
browser_636279.js \
|
||||
browser_645428.js \
|
||||
browser_659591.js \
|
||||
browser_662812.js \
|
||||
$(NULL)
|
||||
|
||||
ifneq ($(OS_ARCH),Darwin)
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
const TAB_STATE_NEEDS_RESTORE = 1;
|
||||
const TAB_STATE_RESTORING = 2;
|
||||
|
||||
let stateBackup = ss.getBrowserState();
|
||||
|
||||
let state = {windows:[{tabs:[
|
||||
{entries:[{url:"http://example.com#1"}]},
|
||||
{entries:[{url:"http://example.com#2"}]},
|
||||
|
@ -22,20 +20,12 @@ function test() {
|
|||
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs");
|
||||
|
||||
TabsProgressListener.uninit();
|
||||
|
||||
ss.setBrowserState(stateBackup);
|
||||
});
|
||||
|
||||
TabsProgressListener.init();
|
||||
|
||||
// First stage: restoreHiddenTabs = true
|
||||
// Second stage: restoreHiddenTabs = false
|
||||
test_loadTabs(true, function () {
|
||||
test_loadTabs(false, function () {
|
||||
waitForFocus(finish);
|
||||
});
|
||||
test_loadTabs(false, finish);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -43,10 +33,9 @@ function test_loadTabs(restoreHiddenTabs, callback) {
|
|||
Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", restoreHiddenTabs);
|
||||
|
||||
let expectedTabs = restoreHiddenTabs ? 8 : 4;
|
||||
|
||||
let firstProgress = true;
|
||||
|
||||
TabsProgressListener.setCallback(function (needsRestore, isRestoring) {
|
||||
newWindowWithState(state, function (win, needsRestore, isRestoring) {
|
||||
if (firstProgress) {
|
||||
firstProgress = false;
|
||||
is(isRestoring, 3, "restoring 3 tabs concurrently");
|
||||
|
@ -54,60 +43,75 @@ function test_loadTabs(restoreHiddenTabs, callback) {
|
|||
ok(isRestoring < 4, "restoring max. 3 tabs concurrently");
|
||||
}
|
||||
|
||||
if (gBrowser.tabs.length - needsRestore == expectedTabs) {
|
||||
TabsProgressListener.unsetCallback();
|
||||
is(gBrowser.visibleTabs.length, 4, "only 4 visible tabs");
|
||||
if (win.gBrowser.tabs.length - needsRestore == expectedTabs) {
|
||||
is(win.gBrowser.visibleTabs.length, 4, "only 4 visible tabs");
|
||||
|
||||
TabsProgressListener.uninit();
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
ss.setBrowserState(JSON.stringify(state));
|
||||
}
|
||||
|
||||
function countTabs() {
|
||||
let needsRestore = 0, isRestoring = 0;
|
||||
let windowsEnum = Services.wm.getEnumerator("navigator:browser");
|
||||
|
||||
while (windowsEnum.hasMoreElements()) {
|
||||
let window = windowsEnum.getNext();
|
||||
if (window.closed)
|
||||
continue;
|
||||
|
||||
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
|
||||
let browser = window.gBrowser.tabs[i].linkedBrowser;
|
||||
if (browser.__SS_restoreState == TAB_STATE_RESTORING)
|
||||
isRestoring++;
|
||||
else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
|
||||
needsRestore++;
|
||||
}
|
||||
}
|
||||
|
||||
return [needsRestore, isRestoring];
|
||||
}
|
||||
|
||||
let TabsProgressListener = {
|
||||
init: function () {
|
||||
gBrowser.addTabsProgressListener(this);
|
||||
init: function (win) {
|
||||
this.window = win;
|
||||
|
||||
this.window.gBrowser.addTabsProgressListener(this);
|
||||
},
|
||||
|
||||
uninit: function () {
|
||||
this.unsetCallback();
|
||||
gBrowser.removeTabsProgressListener(this);
|
||||
this.window.gBrowser.removeTabsProgressListener(this);
|
||||
|
||||
delete this.window;
|
||||
delete this.callback;
|
||||
},
|
||||
|
||||
setCallback: function (callback) {
|
||||
this.callback = callback;
|
||||
},
|
||||
|
||||
unsetCallback: function () {
|
||||
delete this.callback;
|
||||
},
|
||||
|
||||
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
if (this.callback && aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
|
||||
this.callback.apply(null, countTabs());
|
||||
this.callback.apply(null, [this.window].concat(this.countTabs()));
|
||||
},
|
||||
|
||||
countTabs: function () {
|
||||
let needsRestore = 0, isRestoring = 0;
|
||||
|
||||
for (let i = 0; i < this.window.gBrowser.tabs.length; i++) {
|
||||
let browser = this.window.gBrowser.tabs[i].linkedBrowser;
|
||||
if (browser.__SS_restoreState == TAB_STATE_RESTORING)
|
||||
isRestoring++;
|
||||
else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
|
||||
needsRestore++;
|
||||
}
|
||||
|
||||
return [needsRestore, isRestoring];
|
||||
}
|
||||
}
|
||||
|
||||
// ----------
|
||||
function whenWindowLoaded(win, callback) {
|
||||
win.addEventListener("load", function onLoad() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
executeSoon(callback);
|
||||
}, false);
|
||||
}
|
||||
|
||||
// ----------
|
||||
function newWindowWithState(state, callback) {
|
||||
let opts = "chrome,all,dialog=no,height=800,width=800";
|
||||
let win = window.openDialog(getBrowserURL(), "_blank", opts);
|
||||
|
||||
registerCleanupFunction(function () win.close());
|
||||
|
||||
whenWindowLoaded(win, function () {
|
||||
TabsProgressListener.init(win);
|
||||
TabsProgressListener.setCallback(callback);
|
||||
|
||||
ss.setWindowState(win, JSON.stringify(state), true);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
window.addEventListener("SSWindowStateBusy", function onBusy() {
|
||||
window.removeEventListener("SSWindowStateBusy", onBusy, false);
|
||||
|
||||
let state = JSON.parse(ss.getWindowState(window));
|
||||
ok(state.windows[0].busy, "window is busy");
|
||||
|
||||
window.addEventListener("SSWindowStateReady", function onReady() {
|
||||
window.removeEventListener("SSWindowStateReady", onReady, false);
|
||||
|
||||
let state = JSON.parse(ss.getWindowState(window));
|
||||
ok(!state.windows[0].busy, "window is not busy");
|
||||
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
executeSoon(finish);
|
||||
}, false);
|
||||
}, false);
|
||||
|
||||
// create a new tab
|
||||
let tab = gBrowser.addTab("about:mozilla");
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
// close and restore it
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
gBrowser.removeTab(tab);
|
||||
ss.undoCloseTab(window, 0);
|
||||
}, true);
|
||||
}
|
|
@ -178,7 +178,8 @@ var Scratchpad = {
|
|||
this._previousLocation != this.gBrowser.contentWindow.location.href) {
|
||||
let contentWindow = this.gBrowser.selectedBrowser.contentWindow;
|
||||
this._contentSandbox = new Cu.Sandbox(contentWindow,
|
||||
{ sandboxPrototype: contentWindow, wantXrays: false });
|
||||
{ sandboxPrototype: contentWindow, wantXrays: false,
|
||||
sandboxName: 'scratchpad-content'});
|
||||
|
||||
this._previousBrowserWindow = this.browserWindow;
|
||||
this._previousBrowser = this.gBrowser.selectedBrowser;
|
||||
|
@ -211,7 +212,8 @@ var Scratchpad = {
|
|||
if (!this._chromeSandbox ||
|
||||
this.browserWindow != this._previousBrowserWindow) {
|
||||
this._chromeSandbox = new Cu.Sandbox(this.browserWindow,
|
||||
{ sandboxPrototype: this.browserWindow, wantXrays: false });
|
||||
{ sandboxPrototype: this.browserWindow, wantXrays: false,
|
||||
sandboxName: 'scratchpad-chrome'});
|
||||
|
||||
this._previousBrowserWindow = this.browserWindow;
|
||||
}
|
||||
|
|
|
@ -603,18 +603,37 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
|
|||
|
||||
#forward-button {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar");
|
||||
-moz-transition: 250ms ease-out;
|
||||
}
|
||||
#forward-button[disabled="true"] {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
|
||||
}
|
||||
|
||||
#forward-button:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar");
|
||||
}
|
||||
#forward-button[disabled="true"]:-moz-locale-dir(rtl) {
|
||||
|
||||
toolbar:not([mode=icons]) #forward-button[disabled="true"] {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
|
||||
}
|
||||
toolbar:not([mode=icons]) #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled");
|
||||
}
|
||||
|
||||
toolbar[mode=icons] #forward-button[disabled="true"] {
|
||||
-moz-transform: scale(0);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
toolbar[mode=icons] #forward-button[disabled="true"]:-moz-locale-dir(ltr) {
|
||||
margin-left: -36px;
|
||||
}
|
||||
toolbar[mode=icons] #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
|
||||
margin-right: -36px;
|
||||
}
|
||||
toolbar[mode=icons][iconsize=small] #forward-button[disabled="true"]:-moz-locale-dir(ltr) {
|
||||
margin-left: -28px;
|
||||
}
|
||||
toolbar[mode=icons][iconsize=small] #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
|
||||
margin-right: -28px;
|
||||
}
|
||||
|
||||
#reload-button {
|
||||
list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar");
|
||||
}
|
||||
|
@ -786,7 +805,7 @@ toolbar[iconsize="small"] #forward-button {
|
|||
.unified-nav-forward[_moz-menuactive] {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu") !important;
|
||||
}
|
||||
toolbar[iconsize="small"] #forward-button[disabled="true"] {
|
||||
toolbar[iconsize="small"]:not([mode=icons]) #forward-button[disabled="true"] {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu&state=disabled");
|
||||
}
|
||||
|
||||
|
@ -796,7 +815,7 @@ toolbar[iconsize="small"] #forward-button:-moz-locale-dir(rtl) {
|
|||
.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu") !important;
|
||||
}
|
||||
toolbar[iconsize="small"] #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
|
||||
toolbar[iconsize="small"]:not([mode=icons]) #forward-button[disabled="true"]:-moz-locale-dir(rtl) {
|
||||
list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled");
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,17 @@ import os
|
|||
|
||||
class DeviceManagerADB(DeviceManager):
|
||||
|
||||
def __init__(self, host = None, port = 20701, retrylimit = 5, packageName = "org.mozilla.fennec_unofficial"):
|
||||
def __init__(self, host = None, port = 20701, retrylimit = 5, packageName = None):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.retrylimit = retrylimit
|
||||
self.retries = 0
|
||||
self._sock = None
|
||||
if packageName == None:
|
||||
if os.getenv('USER'):
|
||||
packageName = 'org.mozilla.fennec_' + os.getenv('USER')
|
||||
else:
|
||||
packageName = 'org.mozilla.fennec_'
|
||||
self.Init(packageName)
|
||||
|
||||
def Init(self, packageName):
|
||||
|
@ -27,7 +32,11 @@ class DeviceManagerADB(DeviceManager):
|
|||
self.tmpDir = None
|
||||
try:
|
||||
# a test to see if we have root privs
|
||||
self.checkCmd(["shell", "ls", "/sbin"])
|
||||
files = self.listFiles("/data/data")
|
||||
if (len(files) == 1):
|
||||
if (files[0].find("Permission denied") != -1):
|
||||
print "NOT running as root"
|
||||
raise Exception("not running as root")
|
||||
except:
|
||||
try:
|
||||
self.checkCmd(["root"])
|
||||
|
@ -98,7 +107,7 @@ class DeviceManagerADB(DeviceManager):
|
|||
try:
|
||||
if (not self.dirExists(remoteDir)):
|
||||
self.mkDirs(remoteDir+"/x")
|
||||
for root, dirs, files in os.walk(localDir):
|
||||
for root, dirs, files in os.walk(localDir, followlinks='true'):
|
||||
relRoot = os.path.relpath(root, localDir)
|
||||
for file in files:
|
||||
localFile = os.path.join(root, file)
|
||||
|
@ -134,8 +143,12 @@ class DeviceManagerADB(DeviceManager):
|
|||
# success: True
|
||||
# failure: False
|
||||
def fileExists(self, filepath):
|
||||
self.checkCmd(["shell", "ls", filepath])
|
||||
p = self.runCmd(["shell", "ls", "-a", filepath])
|
||||
data = p.stdout.readlines()
|
||||
if (len(data) == 1):
|
||||
if (data[0].rstrip() == filepath):
|
||||
return True
|
||||
return False
|
||||
|
||||
def removeFile(self, filename):
|
||||
return self.runCmd(["shell", "rm", filename]).stdout.read()
|
||||
|
@ -381,18 +394,11 @@ class DeviceManagerADB(DeviceManager):
|
|||
return devroot + '/fennec'
|
||||
elif (self.dirExists(devroot + '/firefox')):
|
||||
return devroot + '/firefox'
|
||||
elif (self.dirExists('/data/data/org.mozilla.fennec')):
|
||||
return '/data/data/org.mozilla.fennec'
|
||||
elif (self.dirExists('/data/data/org.mozilla.firefox')):
|
||||
return '/data/data/org.mozilla.firefox'
|
||||
elif (self.dirExists('/data/data/org.mozilla.fennec_unofficial')):
|
||||
return '/data/data/org.mozilla.fennec_unofficial'
|
||||
elif (self.dirExists('/data/data/org.mozilla.fennec_aurora')):
|
||||
return '/data/data/org.mozilla.fennec_aurora'
|
||||
elif (self.dirExists('/data/data/org.mozilla.firefox_beta')):
|
||||
return '/data/data/org.mozilla.firefox_beta'
|
||||
elif (self.packageName and self.dirExists('/data/data/' + self.packageName)):
|
||||
return '/data/data/' + self.packageName
|
||||
|
||||
# Failure (either not installed or not a recognized platform)
|
||||
print "devicemanagerADB: getAppRoot failed"
|
||||
return None
|
||||
|
||||
# Gets the directory location on the device for a specific test type
|
||||
|
|
|
@ -43,7 +43,6 @@ USE_AUTOCONF = 1
|
|||
MOZILLA_CLIENT = 1
|
||||
target = @target@
|
||||
ac_configure_args = @ac_configure_args@
|
||||
BUILD_MODULES = @BUILD_MODULES@
|
||||
MOZILLA_VERSION = @MOZILLA_VERSION@
|
||||
FIREFOX_VERSION = @FIREFOX_VERSION@
|
||||
|
||||
|
|
|
@ -41,6 +41,38 @@ static BOOL sh_DoCopy(wchar_t *srcFileName, DWORD srcFileAttributes,
|
|||
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
|
||||
#define STR_LEN(a) (ARRAY_LEN(a) - 1)
|
||||
|
||||
#ifdef __MINGW32__
|
||||
|
||||
/* MingW currently does not implement a wide version of the
|
||||
startup routines. Workaround is to implement something like
|
||||
it ourselves. */
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
int wmain(int argc, WCHAR **argv);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
wchar_t *commandLine = GetCommandLineW();
|
||||
int argcw = 0;
|
||||
wchar_t **_argvw = CommandLineToArgvW( commandLine, &argcw );
|
||||
wchar_t *argvw[argcw + 1];
|
||||
int i;
|
||||
if (!_argvw)
|
||||
return 127;
|
||||
/* CommandLineToArgvW doesn't output the ending NULL so
|
||||
we have to manually add it on */
|
||||
for ( i = 0; i < argcw; i++ )
|
||||
argvw[i] = _argvw[i];
|
||||
argvw[argcw] = NULL;
|
||||
|
||||
result = wmain(argcw, argvw);
|
||||
LocalFree(_argvw);
|
||||
return result;
|
||||
}
|
||||
#endif /* __MINGW32__ */
|
||||
|
||||
/* changes all forward slashes in token to backslashes */
|
||||
void changeForwardSlashesToBackSlashes ( wchar_t *arg )
|
||||
{
|
||||
|
|
|
@ -153,6 +153,20 @@ xpcshell-tests:
|
|||
$(LIBXUL_DIST)/bin/xpcshell \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
|
||||
|
||||
xpcshell-tests-remote: DM_TRANS?=adb
|
||||
xpcshell-tests-remote:
|
||||
$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
|
||||
-I$(topsrcdir)/build \
|
||||
-I$(topsrcdir)/build/mobile \
|
||||
$(topsrcdir)/testing/xpcshell/remotexpcshelltests.py \
|
||||
--symbols-path=$(DIST)/crashreporter-symbols \
|
||||
--build-info-json=$(DEPTH)/mozinfo.json \
|
||||
$(EXTRA_TEST_ARGS) \
|
||||
--dm_trans=$(DM_TRANS) \
|
||||
--deviceIP=${TEST_DEVICE} \
|
||||
--objdir=$(DEPTH) \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
|
||||
|
||||
# Execute a single test, specified in $(SOLO_FILE), but don't automatically
|
||||
# start the test. Instead, present the xpcshell prompt so the user can
|
||||
# attach a debugger and then start the test.
|
||||
|
@ -182,6 +196,23 @@ check-one:
|
|||
$(LIBXUL_DIST)/bin/xpcshell \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
|
||||
|
||||
check-one-remote: DM_TRANS?=adb
|
||||
check-one-remote:
|
||||
$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
|
||||
-I$(topsrcdir)/build \
|
||||
-I$(topsrcdir)/build/mobile \
|
||||
$(testxpcsrcdir)/remotexpcshelltests.py \
|
||||
--symbols-path=$(DIST)/crashreporter-symbols \
|
||||
--build-info-json=$(DEPTH)/mozinfo.json \
|
||||
--test-path=$(SOLO_FILE) \
|
||||
--profile-name=$(MOZ_APP_NAME) \
|
||||
--verbose \
|
||||
$(EXTRA_TEST_ARGS) \
|
||||
--dm_trans=$(DM_TRANS) \
|
||||
--deviceIP=${TEST_DEVICE} \
|
||||
--objdir=$(DEPTH) \
|
||||
--noSetup \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
|
||||
endif # XPCSHELL_TESTS
|
||||
|
||||
ifdef CPP_UNIT_TESTS
|
||||
|
@ -1122,8 +1153,9 @@ ifdef HAVE_DTRACE
|
|||
ifndef XP_MACOSX
|
||||
ifdef DTRACE_PROBE_OBJ
|
||||
ifndef DTRACE_LIB_DEPENDENT
|
||||
$(DTRACE_PROBE_OBJ):
|
||||
dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ)
|
||||
NON_DTRACE_OBJS := $(filter-out $(DTRACE_PROBE_OBJ),$(OBJS))
|
||||
$(DTRACE_PROBE_OBJ): $(NON_DTRACE_OBJS)
|
||||
dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(NON_DTRACE_OBJS)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -1519,9 +1551,6 @@ export:: FORCE
|
|||
@echo; sleep 2; false
|
||||
endif
|
||||
|
||||
$(IDL_DIR)::
|
||||
$(NSINSTALL) -D $@
|
||||
|
||||
# generate .h files from into $(XPIDL_GEN_DIR), then export to $(DIST)/include;
|
||||
# warn against overriding existing .h file.
|
||||
$(XPIDL_GEN_DIR)/.done:
|
||||
|
@ -1592,14 +1621,8 @@ endif # XPIDLSRCS
|
|||
|
||||
|
||||
|
||||
#
|
||||
# General rules for exporting idl files.
|
||||
#
|
||||
# WORK-AROUND ONLY, for mozilla/tools/module-deps/bootstrap.pl build.
|
||||
# Bug to fix idl dependency problems w/o this extra build pass is
|
||||
# http://bugzilla.mozilla.org/show_bug.cgi?id=145777
|
||||
#
|
||||
$(IDL_DIR)::
|
||||
$(IDL_DIR):
|
||||
$(NSINSTALL) -D $@
|
||||
|
||||
export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS)
|
||||
|
@ -2066,7 +2089,6 @@ showhost:
|
|||
@echo "HOST_LIBRARY = $(HOST_LIBRARY)"
|
||||
|
||||
showbuildmods::
|
||||
@echo "Build Modules = $(BUILD_MODULES)"
|
||||
@echo "Module dirs = $(BUILD_MODULE_DIRS)"
|
||||
|
||||
documentation:
|
||||
|
|
|
@ -970,7 +970,6 @@ if test -n "$_WIN32_MSVC"; then
|
|||
AC_DEFINE(HAVE_IO_H)
|
||||
AC_DEFINE(HAVE_SETBUF)
|
||||
AC_DEFINE(HAVE_ISATTY)
|
||||
AC_DEFINE(HAVE_STDCALL)
|
||||
fi
|
||||
|
||||
fi # COMPILE_ENVIRONMENT
|
||||
|
@ -2482,6 +2481,8 @@ ia64*-hpux*)
|
|||
if test -n "$GNU_CC"; then
|
||||
CFLAGS="$CFLAGS -mstackrealign"
|
||||
CXXFLAGS="$CXXFLAGS -mstackrealign"
|
||||
else
|
||||
AC_DEFINE(HAVE_STDCALL)
|
||||
fi
|
||||
|
||||
MOZ_CHECK_HEADERS(mmintrin.h)
|
||||
|
|
|
@ -6125,7 +6125,7 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
|
|||
} while ((doc = doc->GetParentDocument()));
|
||||
|
||||
// Remove from parent.
|
||||
nsINode* parent = adoptedNode->GetNodeParent();
|
||||
nsCOMPtr<nsINode> parent = adoptedNode->GetNodeParent();
|
||||
if (parent) {
|
||||
rv = parent->RemoveChildAt(parent->IndexOf(adoptedNode), PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -620,7 +620,7 @@ nsINode::Normalize()
|
|||
}
|
||||
|
||||
// Remove node
|
||||
nsINode* parent = node->GetNodeParent();
|
||||
nsCOMPtr<nsINode> parent = node->GetNodeParent();
|
||||
NS_ASSERTION(parent || hasRemoveListeners,
|
||||
"Should always have a parent unless "
|
||||
"mutation events messed us up");
|
||||
|
@ -3945,7 +3945,7 @@ nsINode::ReplaceOrInsertBefore(PRBool aReplace, nsINode* aNewChild,
|
|||
}
|
||||
|
||||
// Remove the new child from the old parent if one exists
|
||||
nsINode* oldParent = newContent->GetNodeParent();
|
||||
nsCOMPtr<nsINode> oldParent = newContent->GetNodeParent();
|
||||
if (oldParent) {
|
||||
PRInt32 removeIndex = oldParent->IndexOf(newContent);
|
||||
if (removeIndex < 0) {
|
||||
|
|
|
@ -2510,12 +2510,12 @@ nsHTMLInputElement::SanitizeValue(nsAString& aValue)
|
|||
case NS_FORM_INPUT_SEARCH:
|
||||
case NS_FORM_INPUT_TEL:
|
||||
case NS_FORM_INPUT_PASSWORD:
|
||||
case NS_FORM_INPUT_EMAIL:
|
||||
{
|
||||
PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 };
|
||||
aValue.StripChars(crlf);
|
||||
}
|
||||
break;
|
||||
case NS_FORM_INPUT_EMAIL:
|
||||
case NS_FORM_INPUT_URL:
|
||||
{
|
||||
PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 };
|
||||
|
|
|
@ -75,8 +75,12 @@ var email = document.forms[0].elements[0];
|
|||
var values = [
|
||||
[ '', true ], // The empty string shouldn't be considered as invalid.
|
||||
[ 'foo@bar.com', true ],
|
||||
[ ' foo@bar.com', false ],
|
||||
[ 'foo@bar.com ', false ],
|
||||
[ ' foo@bar.com', true ],
|
||||
[ 'foo@bar.com ', true ],
|
||||
[ '\r\n foo@bar.com', true ],
|
||||
[ 'foo@bar.com \n\r', true ],
|
||||
[ '\n\n \r\rfoo@bar.com\n\n \r\r', true ],
|
||||
[ '\n\r \n\rfoo@bar.com\n\r \n\r', true ],
|
||||
[ 'tulip', false ],
|
||||
// Some checks on the user part of the address.
|
||||
[ '@bar.com', false ],
|
||||
|
@ -163,7 +167,7 @@ values.push(["foo@bar.com" + legalCharacters, true]);
|
|||
// Add domain illegal characters.
|
||||
illegalCharacters = "()<>[]:;@\\,!#$%&'*+/=?^_`{|}~ \t";
|
||||
for each (c in illegalCharacters) {
|
||||
values.push(['foo@foo.bar' + c, false]);
|
||||
values.push(['foo@foo.ba' + c + 'r', false]);
|
||||
}
|
||||
|
||||
values.forEach(function([value, valid]) {
|
||||
|
|
|
@ -47,9 +47,9 @@ function sanitizeValue(aType, aValue)
|
|||
case "password":
|
||||
case "search":
|
||||
case "tel":
|
||||
case "email":
|
||||
return aValue.replace(/[\n\r]/g, "");
|
||||
case "url":
|
||||
case "email":
|
||||
return aValue.replace(/[\n\r]/g, "").replace(/^\s+|\s+$/g, "");
|
||||
case "date":
|
||||
case "month":
|
||||
|
|
|
@ -32,7 +32,6 @@ function seekStarted(evt) {
|
|||
function seekEnded(evt) {
|
||||
var v = evt.target;
|
||||
v._gotSeekEnded = true;
|
||||
v.play();
|
||||
}
|
||||
|
||||
function loadedData(evt) {
|
||||
|
|
|
@ -146,8 +146,14 @@ nsSMILCSSProperty::GetBaseValue() const
|
|||
|
||||
// (4) Populate our nsSMILValue from the computed style
|
||||
if (didGetComputedVal) {
|
||||
// When we parse animation values we check if they are context-sensitive or
|
||||
// not so that we don't cache animation values whose meaning may change.
|
||||
// For base values however this is unnecessary since on each sample the
|
||||
// compositor will fetch the (computed) base value and compare it against
|
||||
// the cached (computed) value and detect changes for us.
|
||||
nsSMILCSSValueType::ValueFromString(mPropID, mElement,
|
||||
computedStyleVal, baseValue);
|
||||
computedStyleVal, baseValue,
|
||||
nsnull);
|
||||
}
|
||||
return baseValue;
|
||||
}
|
||||
|
@ -160,22 +166,17 @@ nsSMILCSSProperty::ValueFromString(const nsAString& aStr,
|
|||
{
|
||||
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
|
||||
|
||||
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
|
||||
if (aValue.IsNull()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue,
|
||||
&aPreventCachingOfSandwich);
|
||||
|
||||
// XXX Due to bug 536660 (or at least that seems to be the most likely
|
||||
// culprit), when we have animation setting display:none on a <use> element,
|
||||
// if we DON'T set the property every sample, chaos ensues.
|
||||
if (!aPreventCachingOfSandwich && mPropID == eCSSProperty_display) {
|
||||
aPreventCachingOfSandwich = PR_TRUE;
|
||||
}
|
||||
|
||||
// XXXdholbert: For simplicity, just assume that all CSS values have to
|
||||
// reparsed every sample. This prevents us from doing the "nothing's changed
|
||||
// so don't recompose" optimization (bug 533291) for CSS properties & mapped
|
||||
// attributes. If it ends up being expensive to always recompose those, we
|
||||
// can be a little smarter here. We really only need to set
|
||||
// aPreventCachingOfSandwich to true for "inherit" & "currentColor" (whose
|
||||
// values could change at any time), for length-valued types (particularly
|
||||
// those with em/ex/percent units, since their conversion ratios can change
|
||||
// at any time), and for any value for 'font-family'.
|
||||
aPreventCachingOfSandwich = PR_TRUE;
|
||||
return NS_OK;
|
||||
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -371,7 +371,8 @@ ValueFromStringHelper(nsCSSProperty aPropID,
|
|||
Element* aTargetElement,
|
||||
nsPresContext* aPresContext,
|
||||
const nsAString& aString,
|
||||
nsStyleAnimation::Value& aStyleAnimValue)
|
||||
nsStyleAnimation::Value& aStyleAnimValue,
|
||||
PRBool* aIsContextSensitive)
|
||||
{
|
||||
// If value is negative, we'll strip off the "-" so the CSS parser won't
|
||||
// barf, and then manually make the parsed value negative.
|
||||
|
@ -386,7 +387,8 @@ ValueFromStringHelper(nsCSSProperty aPropID,
|
|||
}
|
||||
nsDependentSubstring subString(aString, subStringBegin);
|
||||
if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString,
|
||||
PR_TRUE, aStyleAnimValue)) {
|
||||
PR_TRUE, aStyleAnimValue,
|
||||
aIsContextSensitive)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (isNegative) {
|
||||
|
@ -409,7 +411,8 @@ void
|
|||
nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
|
||||
Element* aTargetElement,
|
||||
const nsAString& aString,
|
||||
nsSMILValue& aValue)
|
||||
nsSMILValue& aValue,
|
||||
PRBool* aIsContextSensitive)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed");
|
||||
nsPresContext* presContext = GetPresContextForElement(aTargetElement);
|
||||
|
@ -420,7 +423,7 @@ nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
|
|||
|
||||
nsStyleAnimation::Value parsedValue;
|
||||
if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
|
||||
aString, parsedValue)) {
|
||||
aString, parsedValue, aIsContextSensitive)) {
|
||||
sSingleton.Init(aValue);
|
||||
aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
|
||||
}
|
||||
|
|
|
@ -100,13 +100,20 @@ public:
|
|||
* @param aString The string to be parsed as a CSS value.
|
||||
* @param [out] aValue The nsSMILValue to be populated. Should
|
||||
* initially be null-typed.
|
||||
* @param [out] aIsContextSensitive Set to PR_TRUE if |aString| may produce
|
||||
* a different |aValue| depending on other
|
||||
* CSS properties on |aTargetElement|
|
||||
* or its ancestors (e.g. 'inherit).
|
||||
* PR_FALSE otherwise. May be nsnull.
|
||||
* Not set if the method fails.
|
||||
* @pre aValue.IsNull()
|
||||
* @post aValue.IsNull() || aValue.mType == nsSMILCSSValueType::sSingleton
|
||||
*/
|
||||
static void ValueFromString(nsCSSProperty aPropID,
|
||||
Element* aTargetElement,
|
||||
const nsAString& aString,
|
||||
nsSMILValue& aValue);
|
||||
nsSMILValue& aValue,
|
||||
PRBool* aIsContextSensitive);
|
||||
|
||||
/**
|
||||
* Creates a string representation of the given nsSMILValue.
|
||||
|
|
|
@ -67,15 +67,9 @@ nsSMILMappedAttribute::ValueFromString(const nsAString& aStr,
|
|||
{
|
||||
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
|
||||
|
||||
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
|
||||
if (aValue.IsNull()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// XXXdholbert: For simplicity, just assume that all CSS values have to
|
||||
// reparsed every sample. See note in nsSMILCSSProperty::ValueFromString.
|
||||
aPreventCachingOfSandwich = PR_TRUE;
|
||||
return NS_OK;
|
||||
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue,
|
||||
&aPreventCachingOfSandwich);
|
||||
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
nsSMILValue
|
||||
|
@ -87,8 +81,12 @@ nsSMILMappedAttribute::GetBaseValue() const
|
|||
baseStringValue);
|
||||
nsSMILValue baseValue;
|
||||
if (success) {
|
||||
// For base values, we don't need to worry whether the value returned is
|
||||
// context-sensitive or not since the compositor will take care of comparing
|
||||
// the returned (computed) base value and its cached value and determining
|
||||
// if an update is required or not.
|
||||
nsSMILCSSValueType::ValueFromString(mPropID, mElement,
|
||||
baseStringValue, baseValue);
|
||||
baseStringValue, baseValue, nsnull);
|
||||
} else {
|
||||
// Attribute is unset -- use computed value.
|
||||
// FIRST: Temporarily clear animated value, to make sure it doesn't pollute
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=533291">Mozilla Bug 533291</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<!-- Bug 628848: The following should be display: none but we currently don't
|
||||
handle percentage lengths properly when the whole fragment is display: none
|
||||
-->
|
||||
<div id="content" style="visibility: hidden">
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px"
|
||||
onload="this.pauseAnimations()">
|
||||
<g id="circleParent">
|
||||
|
@ -19,68 +22,99 @@
|
|||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
/** Test for SMIL fill modes **/
|
||||
/** Test for SMIL values that are context-sensitive **/
|
||||
|
||||
/* See bugs 533291 and 562815.
|
||||
|
||||
The format of each test is basically:
|
||||
1) create some animated and frozen state
|
||||
2) test the animated values
|
||||
3) change the context
|
||||
4) test that context-sensitive animation values have changed
|
||||
|
||||
Ideally, after changing the context (3), the animated state would instantly
|
||||
update. However, this is not currently the case for many situations.
|
||||
|
||||
For CSS properties we have bug 545282 - In animations involving 'inherit'
|
||||
/ 'currentColor', changes to inherited value / 'color' don't show up in
|
||||
animated value immediately
|
||||
|
||||
For SVG lengths we have bug 508206 - Relative units used in
|
||||
animation don't update immediately
|
||||
|
||||
(There are a few of todo_is's in the following tests so that if those bugs
|
||||
are ever resolved we'll know to update this test case accordingly.)
|
||||
|
||||
So in between (3) and (4) we force a sample. This is currently done by
|
||||
calling SVGSVGElement.setCurrentTime with the same current time which has the
|
||||
side effect of forcing a sample.
|
||||
|
||||
What we *are* testing is that we're not too zealous with caching animation
|
||||
values whilst in the frozen state. Normally we'd say, "Hey, we're frozen,
|
||||
let's just use the same animation result as last time" but for some
|
||||
context-sensitive animation values that doesn't work.
|
||||
*/
|
||||
|
||||
/* Global Variables */
|
||||
const SVGNS = "http://www.w3.org/2000/svg";
|
||||
|
||||
// Animation parameters -- not used for <set> animation
|
||||
const ANIM_DUR = "4s";
|
||||
const TIME_ANIM_END = "4";
|
||||
const TIME_AFTER_ANIM_END = "5";
|
||||
|
||||
// SETTIMEOUT_INTERVAL: This value just needs to be at least as large as
|
||||
// nsSMILAnimationController::kTimerInterval, so we can queue up a callback
|
||||
// for this far in the future and be assured that an animation sample will
|
||||
// have happened before the callback fires (because we presumably already
|
||||
// have an animation sample in the setTimeout queue, with a lower timeout
|
||||
// value than this).
|
||||
// NOTE: We only need to use timeouts here because of Bug 545282.
|
||||
const SETTIMEOUT_INTERVAL = 60;
|
||||
|
||||
const gTestArray =
|
||||
[ testBaseValueChange,
|
||||
testCurrentColorChange,
|
||||
testCurrentColorChangeUsingStyle,
|
||||
testInheritChange,
|
||||
testInheritChangeUsingStyle
|
||||
];
|
||||
|
||||
// Index of current test in gTestArray
|
||||
var gNextTestIndex = 0;
|
||||
|
||||
const gSvg = document.getElementById("svg");
|
||||
const gCircle = document.getElementById("circle");
|
||||
const gCircleParent = document.getElementById("circleParent");
|
||||
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// MAIN FUNCTION
|
||||
// -------------
|
||||
|
||||
function main() {
|
||||
function main()
|
||||
{
|
||||
ok(gSvg.animationsPaused(), "should be paused by <svg> load handler");
|
||||
is(gSvg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
|
||||
|
||||
if (gNextTestIndex != 0) {
|
||||
ok(false, "expecting to start at first test in array.");
|
||||
const tests =
|
||||
[ testBaseValueChange,
|
||||
testCurrentColorChange,
|
||||
testCurrentColorChangeUsingStyle,
|
||||
testCurrentColorChangeOnFallback,
|
||||
testInheritChange,
|
||||
testInheritChangeUsingStyle,
|
||||
testEmUnitChangeOnProp,
|
||||
testEmUnitChangeOnPropBase,
|
||||
testEmUnitChangeOnLength,
|
||||
testPercentUnitChangeOnProp,
|
||||
testPercentUnitChangeOnLength,
|
||||
testRelativeFontSize,
|
||||
testRelativeFontWeight,
|
||||
testRelativeFont,
|
||||
testCalcFontSize,
|
||||
testDashArray,
|
||||
testClip
|
||||
];
|
||||
|
||||
while (tests.length) {
|
||||
tests.shift()();
|
||||
}
|
||||
// Kick off first test. (It will kick off the one after it, and so on.)
|
||||
runNextTest();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// HELPER FUNCTIONS
|
||||
// ----------------
|
||||
function createAnimFromTo(attrName, fromVal, toVal) {
|
||||
var anim = document.createElementNS(SVGNS,"animate");
|
||||
function createAnimSetTo(attrName, toVal)
|
||||
{
|
||||
var anim = document.createElementNS(SVGNS,"set");
|
||||
anim.setAttribute("attributeName", attrName);
|
||||
anim.setAttribute("dur", ANIM_DUR);
|
||||
anim.setAttribute("begin", "0s");
|
||||
anim.setAttribute("from", fromVal);
|
||||
anim.setAttribute("to", toVal);
|
||||
anim.setAttribute("fill", "freeze");
|
||||
return gCircle.appendChild(anim);
|
||||
}
|
||||
function createAnimBy(attrName, byVal) {
|
||||
|
||||
function createAnimBy(attrName, byVal)
|
||||
{
|
||||
var anim = document.createElementNS(SVGNS,"animate");
|
||||
anim.setAttribute("attributeName", attrName);
|
||||
anim.setAttribute("dur", ANIM_DUR);
|
||||
|
@ -90,6 +124,18 @@ function createAnimBy(attrName, byVal) {
|
|||
return gCircle.appendChild(anim);
|
||||
}
|
||||
|
||||
function createAnimFromTo(attrName, fromVal, toVal)
|
||||
{
|
||||
var anim = document.createElementNS(SVGNS,"animate");
|
||||
anim.setAttribute("attributeName", attrName);
|
||||
anim.setAttribute("dur", ANIM_DUR);
|
||||
anim.setAttribute("begin","0s");
|
||||
anim.setAttribute("from", fromVal);
|
||||
anim.setAttribute("to", toVal);
|
||||
anim.setAttribute("fill", "freeze");
|
||||
return gCircle.appendChild(anim);
|
||||
}
|
||||
|
||||
// Common setup code for each test function: seek to 0, and make sure
|
||||
// the previous test cleaned up its animations.
|
||||
function setupTest() {
|
||||
|
@ -99,17 +145,6 @@ function setupTest() {
|
|||
}
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (gNextTestIndex == gTestArray.length) {
|
||||
// No tests left! we're done.
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Call next test (and increment next-test index)
|
||||
gTestArray[gNextTestIndex++]();
|
||||
}
|
||||
|
||||
// THE TESTS
|
||||
// ---------
|
||||
|
||||
|
@ -130,106 +165,400 @@ function testBaseValueChange()
|
|||
"Checking animated cx after anim ends & after changing base val");
|
||||
|
||||
anim.parentNode.removeChild(anim); // clean up
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function testCurrentColorChange()
|
||||
{
|
||||
gCircle.setAttribute("color", "red"); // At first: currentColor=red
|
||||
var anim = createAnimFromTo("fill", "yellow", "currentColor");
|
||||
var anim = createAnimSetTo("fill", "currentColor");
|
||||
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
gSvg.setCurrentTime(0); // trigger synchronous sample
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
|
||||
"Checking animated fill=currentColor after anim ends");
|
||||
"Checking animated fill=currentColor after animating");
|
||||
|
||||
gCircle.setAttribute("color", "lime"); // Change: currentColor=lime
|
||||
setTimeout(testCurrentColorChange_final, SETTIMEOUT_INTERVAL);
|
||||
}
|
||||
|
||||
function testCurrentColorChange_final()
|
||||
{
|
||||
// Bug 545282: We should really detect this change and update immediately but
|
||||
// currently we don't until we get sampled again
|
||||
todo_is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
|
||||
"Checking animated fill=currentColor after updating context but before " +
|
||||
"sampling");
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
|
||||
"Checking animated fill=currentColor after anim ends and 'color' changes");
|
||||
"Checking animated fill=currentColor after updating context");
|
||||
|
||||
// Clean up
|
||||
gCircle.removeAttribute("color");
|
||||
gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
|
||||
|
||||
// Kick off next test
|
||||
runNextTest();
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testCurrentColorChangeUsingStyle()
|
||||
{
|
||||
setupTest();
|
||||
gCircle.setAttribute("style", "color: red"); // At first: currentColor=red
|
||||
var anim = createAnimFromTo("fill", "yellow", "currentColor");
|
||||
var anim = createAnimSetTo("fill", "currentColor");
|
||||
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
|
||||
"Checking animated fill=currentColor after anim ends (using style attr)");
|
||||
"Checking animated fill=currentColor after animating (using style attr)");
|
||||
|
||||
gCircle.setAttribute("style", "color: lime"); // Change: currentColor=lime
|
||||
setTimeout(testCurrentColorChangeUsingStyle_final, SETTIMEOUT_INTERVAL);
|
||||
}
|
||||
|
||||
function testCurrentColorChangeUsingStyle_final()
|
||||
{
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
|
||||
"Checking animated fill=currentColor after anim ends and 'color' changes "
|
||||
"Checking animated fill=currentColor after updating context "
|
||||
+ "(using style attr)");
|
||||
|
||||
// Clean up
|
||||
gCircle.removeAttribute("style");
|
||||
gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
|
||||
runNextTest();
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function getFallbackColor(pServerStr)
|
||||
{
|
||||
return pServerStr.substr(pServerStr.indexOf(" ")+1);
|
||||
}
|
||||
|
||||
function testCurrentColorChangeOnFallback()
|
||||
{
|
||||
setupTest();
|
||||
gCircle.setAttribute("color", "red"); // At first: currentColor=red
|
||||
var anim = createAnimSetTo("fill", "url(#missingGrad) currentColor");
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
var fallback =
|
||||
getFallbackColor(SMILUtil.getComputedStyleSimple(gCircle, "fill"));
|
||||
is(fallback, "rgb(255, 0, 0)",
|
||||
"Checking animated fallback fill=currentColor after animating");
|
||||
|
||||
gCircle.setAttribute("color", "lime"); // Change: currentColor=lime
|
||||
gSvg.setCurrentTime(0);
|
||||
fallback = getFallbackColor(SMILUtil.getComputedStyleSimple(gCircle, "fill"));
|
||||
is(fallback, "rgb(0, 255, 0)",
|
||||
"Checking animated fallback fill=currentColor after updating context");
|
||||
|
||||
gCircle.removeAttribute("style");
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testInheritChange()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("fill", "red"); // At first: inherit=red
|
||||
var anim = createAnimFromTo("fill", "yellow", "inherit");
|
||||
var anim = createAnimSetTo("fill", "inherit");
|
||||
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
|
||||
"Checking animated fill=inherit after anim ends");
|
||||
"Checking animated fill=inherit after animating");
|
||||
|
||||
gCircleParent.setAttribute("fill", "lime"); // Change: inherit=lime
|
||||
setTimeout(testInheritChange_final, SETTIMEOUT_INTERVAL);
|
||||
}
|
||||
|
||||
function testInheritChange_final() {
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
|
||||
"Checking animated fill=inherit after anim ends and parent val changes");
|
||||
"Checking animated fill=inherit after updating context");
|
||||
|
||||
gCircleParent.removeAttribute("fill");
|
||||
gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
|
||||
runNextTest();
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testInheritChangeUsingStyle()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("style", "fill: red"); // At first: inherit=red
|
||||
var anim = createAnimFromTo("fill", "yellow", "inherit");
|
||||
var anim = createAnimSetTo("fill", "inherit");
|
||||
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(255, 0, 0)",
|
||||
"Checking animated fill=inherit after anim ends (using style attr)");
|
||||
"Checking animated fill=inherit after animating (using style attr)");
|
||||
|
||||
gCircleParent.setAttribute("style", "fill: lime"); // Change: inherit=lime
|
||||
setTimeout(testInheritChangeUsingStyle_final, SETTIMEOUT_INTERVAL);
|
||||
}
|
||||
|
||||
function testInheritChangeUsingStyle_final() {
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "fill"), "rgb(0, 255, 0)",
|
||||
"Checking animated fill=inherit after anim ends and parent val changes "
|
||||
"Checking animated fill=inherit after updating context "
|
||||
+ "(using style attr)");
|
||||
|
||||
gCircleParent.removeAttribute("style");
|
||||
gCircle.firstChild.parentNode.removeChild(gCircle.firstChild);
|
||||
runNextTest();
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testEmUnitChangeOnProp()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
|
||||
var anim = createAnimSetTo("font-size", "2em");
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "20px",
|
||||
"Checking animated font-size=2em after animating ends");
|
||||
|
||||
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "40px",
|
||||
"Checking animated font-size=2em after updating context");
|
||||
|
||||
gCircleParent.removeAttribute("font-size");
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testEmUnitChangeOnPropBase()
|
||||
{
|
||||
// Test the case where the base value for our animation sandwich is
|
||||
// context-sensitive.
|
||||
// Currently, this is taken care of by the compositor which keeps a cached
|
||||
// base value and compares it with the current base value. This test then just
|
||||
// serves as a regression test in case the compositor's behaviour changes.
|
||||
setupTest();
|
||||
gSvg.setAttribute("font-size", "10px"); // At first: font-size: 10px
|
||||
gCircleParent.setAttribute("font-size", "1em"); // Base: 10px
|
||||
var anim = createAnimBy("font-size", "10px");
|
||||
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "20px",
|
||||
"Checking animated font-size=20px after anim ends");
|
||||
|
||||
gSvg.setAttribute("font-size", "20px"); // Change: font-size: 20px
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "30px",
|
||||
"Checking animated font-size=30px after updating context");
|
||||
|
||||
gCircleParent.removeAttribute("font-size");
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testEmUnitChangeOnLength()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
|
||||
var anim = createAnimSetTo("cx", "2em");
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
is(gCircle.cx.animVal.value, 20,
|
||||
"Checking animated length=2em after animating");
|
||||
|
||||
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
|
||||
// Bug 508206: We should really detect this change and update immediately but
|
||||
// currently we don't until we get sampled again
|
||||
todo_is(gCircle.cx.animVal.value, 40,
|
||||
"Checking animated length=2em after updating context but before sampling");
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
is(gCircle.cx.animVal.value, 40,
|
||||
"Checking animated length=2em after updating context and after " +
|
||||
"resampling");
|
||||
|
||||
gCircleParent.removeAttribute("font-size");
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testPercentUnitChangeOnProp()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
|
||||
var anim = createAnimSetTo("font-size", "150%");
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "15px",
|
||||
"Checking animated font-size=150% after animating");
|
||||
|
||||
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
|
||||
gSvg.setCurrentTime(0);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "font-size"), "30px",
|
||||
"Checking animated font-size=150% after updating context");
|
||||
|
||||
gCircleParent.removeAttribute("font-size");
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testPercentUnitChangeOnLength()
|
||||
{
|
||||
setupTest();
|
||||
var oldHeight = gSvg.getAttribute("height");
|
||||
gSvg.setAttribute("height", "100px"); // At first: viewport height: 100px
|
||||
var anim = createAnimSetTo("cy", "100%");
|
||||
|
||||
gSvg.setCurrentTime(0); // Force synchronous sample so animation takes effect
|
||||
// Due to bug 627594 (SVGLength.value for percent value lengths doesn't
|
||||
// reflect updated viewport until reflow) the following will fail.
|
||||
// Check that it does indeed fail so that when that bug is fixed this test
|
||||
// can be updated.
|
||||
todo_is(gCircle.cy.animVal.value, 100,
|
||||
"Checking animated length=100% after animating but before reflow");
|
||||
gSvg.forceRedraw();
|
||||
// Even after doing a reflow though we'll still fail due to bug 508206
|
||||
// (Relative units used in animation don't update immediately)
|
||||
todo_is(gCircle.cy.animVal.value, 100,
|
||||
"Checking animated length=100% after animating but before resampling");
|
||||
gSvg.setCurrentTime(0);
|
||||
// Now we should be up to date
|
||||
is(gCircle.cy.animVal.value, 100,
|
||||
"Checking animated length=100% after animating");
|
||||
|
||||
gSvg.setAttribute("height", "50px"); // Change: height: 50px
|
||||
gSvg.forceRedraw(); // Bug 627594
|
||||
gSvg.setCurrentTime(0); // Bug 508206
|
||||
is(gCircle.cy.animVal.value, 50,
|
||||
"Checking animated length=100% after updating context");
|
||||
|
||||
gSvg.setAttribute("height", oldHeight);
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testRelativeFontSize()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
|
||||
var anim = createAnimSetTo("font-size", "larger");
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
|
||||
// CSS 2 suggests a scaling factor of 1.2 so we should be looking at something
|
||||
// around about 12 or so
|
||||
ok(fsize > 10 && fsize < 20,
|
||||
"Checking animated font-size > 10px after animating");
|
||||
|
||||
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
|
||||
gSvg.setCurrentTime(0);
|
||||
fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
|
||||
ok(fsize > 20, "Checking animated font-size > 20px after updating context");
|
||||
|
||||
gCircleParent.removeAttribute("font-size");
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testRelativeFontWeight()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("font-weight", "100"); // At first: font-weight 100
|
||||
var anim = createAnimSetTo("font-weight", "bolder");
|
||||
// CSS 2: 'bolder': Specifies the next weight that is assigned to a font
|
||||
// that is darker than the inherited one. If there is no such weight, it
|
||||
// simply results in the next darker numerical value (and the font remains
|
||||
// unchanged), unless the inherited value was '900', in which case the
|
||||
// resulting weight is also '900'.
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
var weight =
|
||||
parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-weight"));
|
||||
ok(weight > 100, "Checking animated font-weight > 100 after animating");
|
||||
|
||||
gCircleParent.setAttribute("font-weight", "800"); // Change: font-weight 800
|
||||
gSvg.setCurrentTime(0);
|
||||
weight = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-weight"));
|
||||
is(weight, 900,
|
||||
"Checking animated font-weight = 900 after updating context");
|
||||
|
||||
gCircleParent.removeAttribute("font-weight");
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testRelativeFont()
|
||||
{
|
||||
// Test a relative font-size as part of a 'font' spec since the code path
|
||||
// is different in this case
|
||||
// It turns out that, due to the way we store shorthand font properties, we
|
||||
// don't need to worry about marking such values as context-sensitive since we
|
||||
// seem to store them in their relative form. If, however, we change the way
|
||||
// we store shorthand font properties in the future, this will serve as
|
||||
// a useful regression test.
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
|
||||
// We must be sure to set every part of the shorthand property to some
|
||||
// non-context sensitive value because we want to test that even if only the
|
||||
// font-size is relative we will update it appropriately.
|
||||
var anim =
|
||||
createAnimSetTo("font", "normal normal bold larger/normal sans-serif");
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
|
||||
ok(fsize > 10 && fsize < 20,
|
||||
"Checking size of shorthand 'font' > 10px after animating");
|
||||
|
||||
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
|
||||
gSvg.setCurrentTime(0);
|
||||
fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
|
||||
ok(fsize > 20,
|
||||
"Checking size of shorthand 'font' > 20px after updating context");
|
||||
|
||||
gCircleParent.removeAttribute("font-size");
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testCalcFontSize()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("font-size", "10px"); // At first: font-size: 10px
|
||||
var anim = createAnimSetTo("font-size", "-moz-calc(110% + 0.1em)");
|
||||
|
||||
gSvg.setCurrentTime(0);
|
||||
var fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
|
||||
// Font size should be 1.1 * 10px + 0.1 * 10px = 12
|
||||
is(fsize, 12, "Checking animated calc font-size == 12px after animating");
|
||||
|
||||
gCircleParent.setAttribute("font-size", "20px"); // Change: font-size: 20px
|
||||
gSvg.setCurrentTime(0);
|
||||
fsize = parseInt(SMILUtil.getComputedStyleSimple(gCircle, "font-size"));
|
||||
is(fsize, 24, "Checking animated calc font-size == 24px after updating " +
|
||||
"context");
|
||||
|
||||
gCircleParent.removeAttribute("font-size");
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testDashArray()
|
||||
{
|
||||
// stroke dasharrays don't currently convert units--but if someone ever fixes
|
||||
// that, hopefully this test will fail and remind us not to cache percentage
|
||||
// values in that case
|
||||
setupTest();
|
||||
var oldHeight = gSvg.getAttribute("height");
|
||||
var oldWidth = gSvg.getAttribute("width");
|
||||
gSvg.setAttribute("height", "100px"); // At first: viewport: 100x100px
|
||||
gSvg.setAttribute("width", "100px");
|
||||
var anim = createAnimFromTo("stroke-dasharray", "0 5", "0 50%");
|
||||
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
|
||||
// Now we should be up to date
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "stroke-dasharray"), "0, 50%",
|
||||
"Checking animated stroke-dasharray after animating");
|
||||
|
||||
gSvg.setAttribute("height", "50px"); // Change viewport: 50x50px
|
||||
gSvg.setAttribute("width", "50px");
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
is(SMILUtil.getComputedStyleSimple(gCircle, "stroke-dasharray"), "0, 50%",
|
||||
"Checking animated stroke-dasharray after updating context");
|
||||
|
||||
gSvg.setAttribute("height", oldHeight);
|
||||
gSvg.setAttribute("width", oldWidth);
|
||||
gCircle.removeChild(gCircle.firstChild);
|
||||
}
|
||||
|
||||
function testClip()
|
||||
{
|
||||
setupTest();
|
||||
gCircleParent.setAttribute("font-size", "20px"); // At first: font-size: 20px
|
||||
|
||||
// The clip property only applies to elements that establish a new
|
||||
// viewport so we need to create a nested svg and add animation to that
|
||||
var nestedSVG = document.createElementNS(SVGNS, "svg");
|
||||
nestedSVG.setAttribute("clip", "rect(0px 0px 0px 0px)");
|
||||
gCircleParent.appendChild(nestedSVG);
|
||||
|
||||
var anim = createAnimSetTo("clip", "rect(1em 1em 1em 1em)");
|
||||
// createAnimSetTo will make the animation a child of gCircle so we need to
|
||||
// move it so it targets nestedSVG instead
|
||||
nestedSVG.appendChild(anim);
|
||||
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
is(SMILUtil.getComputedStyleSimple(nestedSVG, "clip"),
|
||||
"rect(20px, 20px, 20px, 20px)",
|
||||
"Checking animated clip rect after animating");
|
||||
|
||||
gCircleParent.setAttribute("font-size", "10px"); // Change: font-size: 10px
|
||||
gSvg.setCurrentTime(TIME_AFTER_ANIM_END);
|
||||
is(SMILUtil.getComputedStyleSimple(nestedSVG, "clip"),
|
||||
"rect(10px, 10px, 10px, 10px)",
|
||||
"Checking animated clip rect after updating context");
|
||||
|
||||
gCircleParent.removeAttribute("font-size");
|
||||
gCircleParent.removeChild(nestedSVG);
|
||||
}
|
||||
|
||||
window.addEventListener("load", main, false);
|
||||
|
|
|
@ -57,7 +57,6 @@ _TEST_FILES = \
|
|||
a_href_helper_04.svg \
|
||||
test_animLengthObjectIdentity.xhtml \
|
||||
test_animLengthReadonly.xhtml \
|
||||
test_animLengthRelativeUnits.xhtml \
|
||||
test_animLengthUnits.xhtml \
|
||||
test_bbox.xhtml \
|
||||
test_bbox-with-invalid-viewBox.xhtml \
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=508206
|
||||
-->
|
||||
<head>
|
||||
<title>Test for liveness of relative units in animation</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=508206">Mozilla Bug 508206</a>
|
||||
<p id="display"></p>
|
||||
<!-- XXX The following should be display: none but that's broken by bug 413975
|
||||
where we don't handle percentage lengths when the whole fragment is
|
||||
display: none properly. -->
|
||||
<div id="content" style="visibility: hidden">
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px"
|
||||
onload="this.pauseAnimations()">
|
||||
<g font-size="10px">
|
||||
<circle cx="0" cy="0" r="15" fill="blue" id="circle">
|
||||
<animate attributeName="cx" from="0" to="10em" dur="10s" begin="0s"
|
||||
fill="freeze" id="animate"/>
|
||||
<animate attributeName="cy" from="0" to="100%" dur="10s" begin="0s"
|
||||
fill="freeze"/>
|
||||
</circle>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
/** Test liveness of relative units of animated lengths **/
|
||||
|
||||
/* Global Variables */
|
||||
const svgns="http://www.w3.org/2000/svg";
|
||||
var svg = document.getElementById("svg");
|
||||
var circle = document.getElementById('circle');
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function main() {
|
||||
ok(svg.animationsPaused(), "should be paused by <svg> load handler");
|
||||
is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
|
||||
|
||||
// Sample mid-way through the animation
|
||||
svg.setCurrentTime(5);
|
||||
|
||||
// (1) Check values mid-way
|
||||
is(circle.cx.animVal.value, 50,
|
||||
"(1) Unexpected animVal for cx before changing base length");
|
||||
is(circle.cy.animVal.value, 50,
|
||||
"(1) Unexpected animVal for cy before changing base length");
|
||||
|
||||
// (2) Change the frame of reference and check values are updated immediately
|
||||
|
||||
// Change font-size
|
||||
circle.parentNode.setAttribute('font-size', '5px');
|
||||
todo_is(circle.cx.animVal.value, 25,
|
||||
"(2) Unexpected animVal for cx after changing parent font-size");
|
||||
|
||||
// Change the viewport size
|
||||
svg.setAttribute('height', '50px');
|
||||
todo_is(circle.cy.animVal.value, 25,
|
||||
"(2) Unexpected animVal for cy after changing containing viewport size");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
var animate = document.getElementById('animate');
|
||||
if (animate && animate.targetElement) {
|
||||
window.addEventListener("load", main, false);
|
||||
} else {
|
||||
ok(true); // Skip tests but don't report 'todo' either
|
||||
SimpleTest.finish();
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -429,7 +429,7 @@ static PRBool IsChromeURI(nsIURI* aURI)
|
|||
|
||||
/* Implementation file */
|
||||
|
||||
static PRIntn
|
||||
static PRBool
|
||||
TraverseProtos(nsHashKey *aKey, void *aData, void* aClosure)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
|
@ -439,7 +439,7 @@ TraverseProtos(nsHashKey *aKey, void *aData, void* aClosure)
|
|||
return kHashEnumerateNext;
|
||||
}
|
||||
|
||||
static PRIntn
|
||||
static PRBool
|
||||
UnlinkProtoJSObjects(nsHashKey *aKey, void *aData, void* aClosure)
|
||||
{
|
||||
nsXBLPrototypeBinding *proto = static_cast<nsXBLPrototypeBinding*>(aData);
|
||||
|
@ -453,7 +453,7 @@ struct ProtoTracer
|
|||
void *mClosure;
|
||||
};
|
||||
|
||||
static PRIntn
|
||||
static PRBool
|
||||
TraceProtos(nsHashKey *aKey, void *aData, void* aClosure)
|
||||
{
|
||||
ProtoTracer* closure = static_cast<ProtoTracer*>(aClosure);
|
||||
|
|
|
@ -328,7 +328,7 @@ PRBool nsXBLPrototypeBinding::CompareBindingURI(nsIURI* aURI) const
|
|||
return equal;
|
||||
}
|
||||
|
||||
static PRIntn
|
||||
static PRBool
|
||||
TraverseInsertionPoint(nsHashKey* aKey, void* aData, void* aClosure)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback &cb =
|
||||
|
@ -1213,7 +1213,7 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent)
|
|||
PRInt32 i;
|
||||
for (i = 0; i < count; i++) {
|
||||
nsIContent* child = childrenElements[i];
|
||||
nsIContent* parent = child->GetParent();
|
||||
nsCOMPtr<nsIContent> parent = child->GetParent();
|
||||
|
||||
// Create an XBL insertion point entry.
|
||||
nsXBLInsertionPointEntry* xblIns = nsXBLInsertionPointEntry::Create(parent);
|
||||
|
|
|
@ -4047,7 +4047,8 @@ nsXULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
|
|||
if (attr == nsGkAtoms::removeelement &&
|
||||
value.EqualsLiteral("true")) {
|
||||
|
||||
rv = RemoveElement(aTargetNode->GetParent(), aTargetNode);
|
||||
nsCOMPtr<nsIContent> parent = aTargetNode->GetParent();
|
||||
rv = RemoveElement(parent, aTargetNode);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -1324,7 +1324,7 @@ nsXULContentBuilder::RemoveGeneratedContent(nsIContent* aElement)
|
|||
while (0 != (count = ungenerated.Length())) {
|
||||
// Pull the next "ungenerated" element off the queue.
|
||||
PRUint32 last = count - 1;
|
||||
nsIContent* element = ungenerated[last];
|
||||
nsCOMPtr<nsIContent> element = ungenerated[last];
|
||||
ungenerated.RemoveElementAt(last);
|
||||
|
||||
PRUint32 i = element->GetChildCount();
|
||||
|
|
|
@ -8452,13 +8452,13 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
GetCurScrollPos(ScrollOrientation_X, &cx);
|
||||
GetCurScrollPos(ScrollOrientation_Y, &cy);
|
||||
|
||||
// We scroll whenever we're not doing a history load. Note that
|
||||
// sometimes we might scroll even if we don't fire a hashchange
|
||||
// event! See bug 653741.
|
||||
if (!aSHEntry) {
|
||||
// ScrollToAnchor doesn't necessarily cause us to scroll the window;
|
||||
// the function decides whether a scroll is appropriate based on the
|
||||
// arguments it receives. But even if we don't end up scrolling,
|
||||
// ScrollToAnchor performs other important tasks, such as informing
|
||||
// the presShell that we have a new hash. See bug 680257.
|
||||
rv = ScrollToAnchor(curHash, newHash, aLoadType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mLoadType = aLoadType;
|
||||
mURIResultedInDocument = PR_TRUE;
|
||||
|
|
|
@ -120,6 +120,8 @@ _TEST_FILES = \
|
|||
file_bug669671.sjs \
|
||||
test_bug675587.html \
|
||||
test_bfcache_plus_hash.html \
|
||||
test_bug680257.html \
|
||||
file_bug680257.html \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<style type='text/css'>
|
||||
a { color: black; }
|
||||
a:target { color: red; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload='(opener || parent).popupLoaded()'>
|
||||
|
||||
<a id='a' href='#a'>link</a>
|
||||
<a id='b' href='#b'>link2</a>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,59 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=680257
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 680257</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=680257">Mozilla Bug 680257</a>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var popup = window.open('file_bug680257.html');
|
||||
|
||||
// The popup will call into popupLoaded() once it loads.
|
||||
function popupLoaded() {
|
||||
// runTests() needs to be called from outside popupLoaded's onload handler.
|
||||
// Otherwise, the navigations we do in runTests won't create new SHEntries.
|
||||
SimpleTest.executeSoon(runTests);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
checkPopupLinkStyle(false, 'Initial');
|
||||
|
||||
popup.location.hash = 'a';
|
||||
checkPopupLinkStyle(true, 'After setting hash');
|
||||
|
||||
popup.history.back();
|
||||
checkPopupLinkStyle(false, 'After going back');
|
||||
|
||||
popup.history.forward();
|
||||
checkPopupLinkStyle(true, 'After going forward');
|
||||
|
||||
popup.close();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function checkPopupLinkStyle(isTarget, desc) {
|
||||
var link = popup.document.getElementById('a');
|
||||
var style = popup.getComputedStyle(link);
|
||||
var color = style.getPropertyValue('color');
|
||||
|
||||
// Color is red if isTarget, black otherwise.
|
||||
if (isTarget) {
|
||||
is(color, 'rgb(255, 0, 0)', desc);
|
||||
}
|
||||
else {
|
||||
is(color, 'rgb(0, 0, 0)', desc);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -8220,6 +8220,7 @@ NS_IMETHODIMP
|
|||
nsGlobalWindow::GetMozIndexedDB(nsIIDBFactory** _retval)
|
||||
{
|
||||
if (!mIndexedDB) {
|
||||
if (!IsChromeWindow()) {
|
||||
nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
|
||||
do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
NS_ENSURE_TRUE(thirdPartyUtil, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
@ -8234,6 +8235,7 @@ nsGlobalWindow::GetMozIndexedDB(nsIIDBFactory** _retval)
|
|||
*_retval = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
mIndexedDB = indexedDB::IDBFactory::Create(this);
|
||||
NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
* http://www.w3.org/TR/DOM-Level-2-Style
|
||||
*/
|
||||
|
||||
[builtinclass, scriptable, uuid(10f43750-b379-11e0-aff2-0800200c9a66)]
|
||||
[builtinclass, scriptable, uuid(286466f1-4246-4574-afdb-2f8a03ad7cc8)]
|
||||
interface nsIDOMCSS2Properties : nsISupports
|
||||
{
|
||||
attribute DOMString background;
|
||||
|
@ -657,6 +657,9 @@ interface nsIDOMCSS2Properties : nsISupports
|
|||
attribute DOMString MozBorderImage;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
attribute DOMString MozColumns;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
attribute DOMString MozColumnRule;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
* For more information on this interface, please see
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/#messageevent
|
||||
*/
|
||||
[scriptable, uuid(dc8ec5c6-ebf2-4f95-be99-cd13e3c0d0c6)]
|
||||
[scriptable, uuid(9ac4fa26-4d19-4f4e-807e-b30cd0dbe56a)]
|
||||
interface nsIDOMMessageEvent : nsIDOMEvent
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -3,4 +3,8 @@ head = head_plugins.js
|
|||
tail =
|
||||
|
||||
[test_bug455213.js]
|
||||
# Bug 676953: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_bug471245.js]
|
||||
# Bug 676953: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
|
|
|
@ -421,6 +421,7 @@ abstract public class GeckoApp
|
|||
public void onStart()
|
||||
{
|
||||
Log.i(LOG_FILE_NAME, "start");
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_START));
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ public class GeckoEvent {
|
|||
public static final int SURFACE_CREATED = 13;
|
||||
public static final int SURFACE_DESTROYED = 14;
|
||||
public static final int GECKO_EVENT_SYNC = 15;
|
||||
public static final int ACTIVITY_START = 17;
|
||||
|
||||
public static final int IME_COMPOSITION_END = 0;
|
||||
public static final int IME_COMPOSITION_BEGIN = 1;
|
||||
|
|
|
@ -169,8 +169,30 @@ class GeckoSurfaceView
|
|||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
|
||||
// Force exactly one frame to render
|
||||
// because the surface change is only seen after we
|
||||
// have swapped the back buffer.
|
||||
// The buffer size only changes after the next swap buffer.
|
||||
// We need to make sure the Gecko's view resize when Android's
|
||||
// buffer resizes.
|
||||
if (mDrawMode == DRAW_GLES_2) {
|
||||
// When we get a surfaceChange event, we have 0 to n paint events
|
||||
// waiting in the Gecko event queue. We will make the first
|
||||
// succeed and the abort the others.
|
||||
mDrawSingleFrame = true;
|
||||
if (!mInDrawing) {
|
||||
// Queue at least one paint event in case none are queued.
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
}
|
||||
GeckoAppShell.geckoEventSync();
|
||||
mDrawSingleFrame = false;
|
||||
mAbortDraw = false;
|
||||
}
|
||||
|
||||
if (mShowingSplashScreen)
|
||||
drawSplashScreen(holder, width, height);
|
||||
|
||||
mSurfaceLock.lock();
|
||||
|
||||
try {
|
||||
|
@ -221,6 +243,12 @@ class GeckoSurfaceView
|
|||
}
|
||||
} finally {
|
||||
mSurfaceLock.unlock();
|
||||
if (mDrawMode == DRAW_GLES_2) {
|
||||
// Force a frame to be drawn before the surfaceChange returns,
|
||||
// otherwise we get artifacts.
|
||||
GeckoAppShell.scheduleRedraw();
|
||||
GeckoAppShell.geckoEventSync();
|
||||
}
|
||||
}
|
||||
|
||||
Object syncDrawObject = null;
|
||||
|
@ -293,6 +321,10 @@ class GeckoSurfaceView
|
|||
public static final int DRAW_ERROR = 0;
|
||||
public static final int DRAW_GLES_2 = 1;
|
||||
public static final int DRAW_2D = 2;
|
||||
// Drawing is disable when the surface buffer
|
||||
// has changed size but we haven't yet processed the
|
||||
// resize event.
|
||||
public static final int DRAW_DISABLED = 3;
|
||||
|
||||
public int beginDrawing() {
|
||||
if (mInDrawing) {
|
||||
|
@ -300,6 +332,12 @@ class GeckoSurfaceView
|
|||
return DRAW_ERROR;
|
||||
}
|
||||
|
||||
// Once we drawn our first frame after resize we can ignore
|
||||
// the other draw events until we handle the resize events.
|
||||
if (mAbortDraw) {
|
||||
return DRAW_DISABLED;
|
||||
}
|
||||
|
||||
/* Grab the lock, which we'll hold while we're drawing.
|
||||
* It gets released in endDrawing(), and is also used in surfaceChanged
|
||||
* to make sure that we don't change our surface details while
|
||||
|
@ -330,6 +368,9 @@ class GeckoSurfaceView
|
|||
return;
|
||||
}
|
||||
|
||||
if (mDrawSingleFrame)
|
||||
mAbortDraw = true;
|
||||
|
||||
try {
|
||||
if (!mSurfaceValid) {
|
||||
Log.e(LOG_FILE_NAME, "endDrawing with false mSurfaceValid");
|
||||
|
@ -657,6 +698,10 @@ class GeckoSurfaceView
|
|||
// Are we actively between beginDrawing/endDrawing?
|
||||
boolean mInDrawing;
|
||||
|
||||
// Used to finish the current buffer before changing the surface size
|
||||
boolean mDrawSingleFrame = false;
|
||||
boolean mAbortDraw = false;
|
||||
|
||||
// Are we waiting for a buffer to draw in surfaceChanged?
|
||||
boolean mSyncDraw;
|
||||
|
||||
|
|
|
@ -3,4 +3,8 @@ head =
|
|||
tail =
|
||||
|
||||
[test_wwauthpromptfactory.js]
|
||||
# Bug 676955: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_wwpromptfactory.js]
|
||||
# Bug 676955: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
|
|
|
@ -285,7 +285,7 @@ NS_IMETHODIMP nsSystemPrefService::GetBoolPref(const char *aPrefName, PRBool *_r
|
|||
}
|
||||
|
||||
/* void setBoolPref (in string aPrefName, in long aValue); */
|
||||
NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRInt32 aValue)
|
||||
NS_IMETHODIMP nsSystemPrefService::SetBoolPref(const char *aPrefName, PRBool aValue)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -41,10 +41,6 @@
|
|||
#include "nsICategoryManager.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
|
||||
// The number 130 more or less comes out of thin air.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=355178#c78 for a pseudo-rationale.
|
||||
#define UNREASONABLE_WORD_LENGTH 130
|
||||
|
||||
#define DEFAULT_SPELL_CHECKER "@mozilla.org/spellchecker/engine;1"
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozSpellChecker)
|
||||
|
@ -149,12 +145,6 @@ mozSpellChecker::CheckWord(const nsAString &aWord, PRBool *aIsMisspelled, nsTArr
|
|||
if(!mSpellCheckingEngine)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// don't bother to check crazy words
|
||||
if (aWord.Length() > UNREASONABLE_WORD_LENGTH) {
|
||||
*aIsMisspelled = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aIsMisspelled = PR_FALSE;
|
||||
result = mSpellCheckingEngine->Check(PromiseFlatString(aWord).get(), &correct);
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
|
|
|
@ -111,6 +111,8 @@ tail =
|
|||
[test_encode_CP852.js]
|
||||
[test_encode_CP855.js]
|
||||
[test_encode_CP857.js]
|
||||
# Bug 676958: test consistently hangs on Android
|
||||
skip-if = os == "android"
|
||||
[test_encode_CP862.js]
|
||||
[test_encode_CP864.js]
|
||||
[test_encode_CP874.js]
|
||||
|
|
|
@ -3,4 +3,6 @@ head =
|
|||
tail =
|
||||
|
||||
[test_ipcshell.js]
|
||||
# Bug 676963: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_ipcshell_child.js]
|
||||
|
|
|
@ -77,6 +77,36 @@ GRE_MODULE = 1
|
|||
|
||||
LIBS = $(NSPR_LIBS)
|
||||
|
||||
ifdef GNU_CXX
|
||||
ifdef INTEL_CXX
|
||||
# icc gets special optimize flags
|
||||
ifdef MOZ_PROFILE_GENERATE
|
||||
MODULE_OPTIMIZE_FLAGS = -O0
|
||||
else
|
||||
MODULE_OPTIMIZE_FLAGS = -O2 -ip
|
||||
endif
|
||||
else # not INTEL_CXX
|
||||
|
||||
MODULE_OPTIMIZE_FLAGS = -O3 -fstrict-aliasing -fno-stack-protector
|
||||
|
||||
# We normally want -fomit-frame-pointer, but we want an explicit
|
||||
# -fno-omit-frame-pointer if we're using a sampling profiler.
|
||||
ifndef MOZ_PROFILING
|
||||
MODULE_OPTIMIZE_FLAGS += -fomit-frame-pointer
|
||||
else
|
||||
MODULE_OPTIMIZE_FLAGS += -fno-omit-frame-pointer
|
||||
endif
|
||||
|
||||
endif
|
||||
else # not GNU_CXX
|
||||
ifeq ($(OS_ARCH),SunOS)
|
||||
MODULE_OPTIMIZE_FLAGS = -xO4
|
||||
endif
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
MODULE_OPTIMIZE_FLAGS = -O2
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
NO_PROFILE_GUIDED_OPTIMIZE = 1
|
||||
endif
|
||||
|
|
|
@ -43,7 +43,6 @@ USE_AUTOCONF = 1
|
|||
MOZILLA_CLIENT = 1
|
||||
target = @target@
|
||||
ac_configure_args = @ac_configure_args@
|
||||
BUILD_MODULES = @BUILD_MODULES@
|
||||
MOZILLA_VERSION = @MOZILLA_VERSION@
|
||||
|
||||
MOZ_BUILD_APP = @MOZ_BUILD_APP@
|
||||
|
|
|
@ -41,6 +41,38 @@ static BOOL sh_DoCopy(wchar_t *srcFileName, DWORD srcFileAttributes,
|
|||
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
|
||||
#define STR_LEN(a) (ARRAY_LEN(a) - 1)
|
||||
|
||||
#ifdef __MINGW32__
|
||||
|
||||
/* MingW currently does not implement a wide version of the
|
||||
startup routines. Workaround is to implement something like
|
||||
it ourselves. */
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
int wmain(int argc, WCHAR **argv);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int result;
|
||||
wchar_t *commandLine = GetCommandLineW();
|
||||
int argcw = 0;
|
||||
wchar_t **_argvw = CommandLineToArgvW( commandLine, &argcw );
|
||||
wchar_t *argvw[argcw + 1];
|
||||
int i;
|
||||
if (!_argvw)
|
||||
return 127;
|
||||
/* CommandLineToArgvW doesn't output the ending NULL so
|
||||
we have to manually add it on */
|
||||
for ( i = 0; i < argcw; i++ )
|
||||
argvw[i] = _argvw[i];
|
||||
argvw[argcw] = NULL;
|
||||
|
||||
result = wmain(argcw, argvw);
|
||||
LocalFree(_argvw);
|
||||
return result;
|
||||
}
|
||||
#endif /* __MINGW32__ */
|
||||
|
||||
/* changes all forward slashes in token to backslashes */
|
||||
void changeForwardSlashesToBackSlashes ( wchar_t *arg )
|
||||
{
|
||||
|
|
|
@ -153,6 +153,20 @@ xpcshell-tests:
|
|||
$(LIBXUL_DIST)/bin/xpcshell \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
|
||||
|
||||
xpcshell-tests-remote: DM_TRANS?=adb
|
||||
xpcshell-tests-remote:
|
||||
$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
|
||||
-I$(topsrcdir)/build \
|
||||
-I$(topsrcdir)/build/mobile \
|
||||
$(topsrcdir)/testing/xpcshell/remotexpcshelltests.py \
|
||||
--symbols-path=$(DIST)/crashreporter-symbols \
|
||||
--build-info-json=$(DEPTH)/mozinfo.json \
|
||||
$(EXTRA_TEST_ARGS) \
|
||||
--dm_trans=$(DM_TRANS) \
|
||||
--deviceIP=${TEST_DEVICE} \
|
||||
--objdir=$(DEPTH) \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
|
||||
|
||||
# Execute a single test, specified in $(SOLO_FILE), but don't automatically
|
||||
# start the test. Instead, present the xpcshell prompt so the user can
|
||||
# attach a debugger and then start the test.
|
||||
|
@ -182,6 +196,23 @@ check-one:
|
|||
$(LIBXUL_DIST)/bin/xpcshell \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
|
||||
|
||||
check-one-remote: DM_TRANS?=adb
|
||||
check-one-remote:
|
||||
$(PYTHON) -u $(topsrcdir)/config/pythonpath.py \
|
||||
-I$(topsrcdir)/build \
|
||||
-I$(topsrcdir)/build/mobile \
|
||||
$(testxpcsrcdir)/remotexpcshelltests.py \
|
||||
--symbols-path=$(DIST)/crashreporter-symbols \
|
||||
--build-info-json=$(DEPTH)/mozinfo.json \
|
||||
--test-path=$(SOLO_FILE) \
|
||||
--profile-name=$(MOZ_APP_NAME) \
|
||||
--verbose \
|
||||
$(EXTRA_TEST_ARGS) \
|
||||
--dm_trans=$(DM_TRANS) \
|
||||
--deviceIP=${TEST_DEVICE} \
|
||||
--objdir=$(DEPTH) \
|
||||
--noSetup \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(relativesrcdir)/$(dir))
|
||||
endif # XPCSHELL_TESTS
|
||||
|
||||
ifdef CPP_UNIT_TESTS
|
||||
|
@ -1122,8 +1153,9 @@ ifdef HAVE_DTRACE
|
|||
ifndef XP_MACOSX
|
||||
ifdef DTRACE_PROBE_OBJ
|
||||
ifndef DTRACE_LIB_DEPENDENT
|
||||
$(DTRACE_PROBE_OBJ):
|
||||
dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ)
|
||||
NON_DTRACE_OBJS := $(filter-out $(DTRACE_PROBE_OBJ),$(OBJS))
|
||||
$(DTRACE_PROBE_OBJ): $(NON_DTRACE_OBJS)
|
||||
dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(NON_DTRACE_OBJS)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -1519,9 +1551,6 @@ export:: FORCE
|
|||
@echo; sleep 2; false
|
||||
endif
|
||||
|
||||
$(IDL_DIR)::
|
||||
$(NSINSTALL) -D $@
|
||||
|
||||
# generate .h files from into $(XPIDL_GEN_DIR), then export to $(DIST)/include;
|
||||
# warn against overriding existing .h file.
|
||||
$(XPIDL_GEN_DIR)/.done:
|
||||
|
@ -1592,14 +1621,8 @@ endif # XPIDLSRCS
|
|||
|
||||
|
||||
|
||||
#
|
||||
# General rules for exporting idl files.
|
||||
#
|
||||
# WORK-AROUND ONLY, for mozilla/tools/module-deps/bootstrap.pl build.
|
||||
# Bug to fix idl dependency problems w/o this extra build pass is
|
||||
# http://bugzilla.mozilla.org/show_bug.cgi?id=145777
|
||||
#
|
||||
$(IDL_DIR)::
|
||||
$(IDL_DIR):
|
||||
$(NSINSTALL) -D $@
|
||||
|
||||
export-idl:: $(SUBMAKEFILES) $(MAKE_DIRS)
|
||||
|
@ -2066,7 +2089,6 @@ showhost:
|
|||
@echo "HOST_LIBRARY = $(HOST_LIBRARY)"
|
||||
|
||||
showbuildmods::
|
||||
@echo "Build Modules = $(BUILD_MODULES)"
|
||||
@echo "Module dirs = $(BUILD_MODULE_DIRS)"
|
||||
|
||||
documentation:
|
||||
|
|
|
@ -1992,14 +1992,11 @@ case "$target" in
|
|||
*-darwin*)
|
||||
MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
|
||||
MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@'
|
||||
|
||||
MOZ_OPTIMIZE_FLAGS="-O3 -fstrict-aliasing -fno-stack-protector"
|
||||
# We normally want -fomit-frame-pointer, but we want an explicit
|
||||
# -fno-omit-frame-pointer if we're using a sampling profiler.
|
||||
# If we're building with --enable-profiling, we need a frame pointer.
|
||||
if test -z "$MOZ_PROFILING"; then
|
||||
MOZ_OPTIMIZE_FLAGS="$MOZ_OPTIMIZE_FLAGS -fomit-frame-pointer"
|
||||
MOZ_OPTIMIZE_FLAGS="-O3 -fomit-frame-pointer"
|
||||
else
|
||||
MOZ_OPTIMIZE_FLAGS="$MOZ_OPTIMIZE_FLAGS -fno-omit-frame-pointer"
|
||||
MOZ_OPTIMIZE_FLAGS="-O3 -fno-omit-frame-pointer"
|
||||
fi
|
||||
_PEDANTIC=
|
||||
CFLAGS="$CFLAGS -fpascal-strings -fno-common"
|
||||
|
|
|
@ -2563,6 +2563,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
|||
JS_ASSERT(script->compartment != cx->compartment);
|
||||
JS_OPT_ASSERT(script->ownerObject == fun);
|
||||
|
||||
cfun->u.i.script = NULL;
|
||||
JSScript *cscript = js_CloneScript(cx, script);
|
||||
if (!cscript)
|
||||
return NULL;
|
||||
|
|
|
@ -1839,6 +1839,8 @@ main(int argc, char **argv, char **envp)
|
|||
XRE_GetFileFromPath(argv[4], getter_AddRefs(appOmni));
|
||||
argc-=2;
|
||||
argv+=2;
|
||||
} else {
|
||||
appOmni = greOmni;
|
||||
}
|
||||
|
||||
XRE_InitOmnijar(greOmni, appOmni);
|
||||
|
|
|
@ -46,17 +46,8 @@ include $(DEPTH)/config/autoconf.mk
|
|||
|
||||
MODULE = xpconnect
|
||||
|
||||
ifeq (xpconnect, $(findstring xpconnect, $(BUILD_MODULES)))
|
||||
LIBRARY_NAME = xpconnect
|
||||
EXPORT_LIBRARY = 1
|
||||
SHORT_LIBNAME = xpconect
|
||||
IS_COMPONENT = 1
|
||||
MODULE_NAME = xpconnect
|
||||
GRE_MODULE = 1
|
||||
else
|
||||
LIBRARY_NAME = xpconnect_s
|
||||
FORCE_STATIC_LIB = 1
|
||||
endif
|
||||
LIBXUL_LIBRARY = 1
|
||||
EXPORTS = xpcpublic.h
|
||||
|
||||
|
|
|
@ -2074,7 +2074,8 @@ nsXPConnect::CreateSandbox(JSContext *cx, nsIPrincipal *principal,
|
|||
jsval rval = JSVAL_VOID;
|
||||
AUTO_MARK_JSVAL(ccx, &rval);
|
||||
|
||||
nsresult rv = xpc_CreateSandboxObject(cx, &rval, principal, NULL, false);
|
||||
nsresult rv = xpc_CreateSandboxObject(cx, &rval, principal, NULL, false,
|
||||
EmptyCString());
|
||||
NS_ASSERTION(NS_FAILED(rv) || !JSVAL_IS_PRIMITIVE(rval),
|
||||
"Bad return value from xpc_CreateSandboxObject()!");
|
||||
|
||||
|
|
|
@ -3153,7 +3153,7 @@ NS_IMPL_ISUPPORTS0(Identity)
|
|||
|
||||
nsresult
|
||||
xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop, JSObject *proto,
|
||||
bool wantXrays)
|
||||
bool wantXrays, const nsACString &sandboxName)
|
||||
{
|
||||
// Create the sandbox global object
|
||||
nsresult rv;
|
||||
|
@ -3240,6 +3240,10 @@ xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop, JSOb
|
|||
}
|
||||
}
|
||||
|
||||
xpc::CompartmentPrivate *compartmentPrivate =
|
||||
static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(cx, compartment));
|
||||
compartmentPrivate->location = sandboxName;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3351,6 +3355,8 @@ nsXPCComponents_utils_Sandbox::CallOrConstruct(nsIXPConnectWrappedNative *wrappe
|
|||
|
||||
JSObject *proto = nsnull;
|
||||
bool wantXrays = true;
|
||||
nsCString sandboxName;
|
||||
|
||||
if (argc > 1) {
|
||||
if (!JSVAL_IS_OBJECT(argv[1]))
|
||||
return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
|
||||
|
@ -3382,9 +3388,26 @@ nsXPCComponents_utils_Sandbox::CallOrConstruct(nsIXPConnectWrappedNative *wrappe
|
|||
|
||||
wantXrays = JSVAL_TO_BOOLEAN(option);
|
||||
}
|
||||
|
||||
if (!JS_HasProperty(cx, optionsObject, "sandboxName", &found))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
if (found) {
|
||||
if (!JS_GetProperty(cx, optionsObject, "sandboxName", &option) ||
|
||||
!JSVAL_IS_STRING(option)) {
|
||||
return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
|
||||
}
|
||||
|
||||
rv = xpc_CreateSandboxObject(cx, vp, prinOrSop, proto, wantXrays);
|
||||
char *tmp = JS_EncodeString(cx, JSVAL_TO_STRING(option));
|
||||
if (!tmp) {
|
||||
return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
|
||||
}
|
||||
|
||||
sandboxName.Adopt(tmp, strlen(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
rv = xpc_CreateSandboxObject(cx, vp, prinOrSop, proto, wantXrays, sandboxName);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return ThrowAndFail(rv, cx, _retval);
|
||||
|
|
|
@ -1584,22 +1584,30 @@ CompartmentStats::CompartmentStats(JSContext *cx, JSCompartment *c)
|
|||
{
|
||||
if(c->principals->codebase)
|
||||
{
|
||||
// A hack: replace forward slashes with '\\' so they aren't
|
||||
// treated as path separators. Users of the reporters
|
||||
// (such as about:memory) have to undo this change.
|
||||
name.Assign(c->principals->codebase);
|
||||
name.ReplaceChar('/', '\\');
|
||||
|
||||
// If it's the system compartment, append the address.
|
||||
// This means that multiple system compartments (and there
|
||||
// can be many) can be distinguished.
|
||||
if(c->isSystemCompartment)
|
||||
{
|
||||
if (c->data &&
|
||||
!((xpc::CompartmentPrivate*)c->data)->location.IsEmpty())
|
||||
{
|
||||
name.AppendLiteral(", ");
|
||||
name.Append(((xpc::CompartmentPrivate*)c->data)->location);
|
||||
}
|
||||
|
||||
// ample; 64-bit address max is 18 chars
|
||||
static const int maxLength = 31;
|
||||
nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
|
||||
name.Append(address);
|
||||
}
|
||||
|
||||
// A hack: replace forward slashes with '\\' so they aren't
|
||||
// treated as path separators. Users of the reporters
|
||||
// (such as about:memory) have to undo this change.
|
||||
name.ReplaceChar('/', '\\');
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -4315,7 +4315,7 @@ xpc_GetJSPrivate(JSObject *obj)
|
|||
// and used.
|
||||
nsresult
|
||||
xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop,
|
||||
JSObject *proto, bool preferXray);
|
||||
JSObject *proto, bool preferXray, const nsACString &sandboxName);
|
||||
|
||||
// Helper for evaluating scripts in a sandbox object created with
|
||||
// xpc_CreateSandboxObject(). The caller is responsible of ensuring
|
||||
|
@ -4396,6 +4396,7 @@ struct CompartmentPrivate
|
|||
JSObject2JSObjectMap *waiverWrapperMap;
|
||||
// NB: we don't want this map to hold a strong reference to the wrapper.
|
||||
nsDataHashtable<nsPtrHashKey<XPCWrappedNative>, JSObject *> *expandoMap;
|
||||
nsCString location;
|
||||
|
||||
bool RegisterExpandoObject(XPCWrappedNative *wn, JSObject *expando) {
|
||||
if (!expandoMap) {
|
||||
|
|
|
@ -15,6 +15,8 @@ tail =
|
|||
[test_import.js]
|
||||
[test_js_weak_references.js]
|
||||
[test_localeCompare.js]
|
||||
# Bug 676965: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_recursive_import.js]
|
||||
[test_xpcomutils.js]
|
||||
[test_unload.js]
|
||||
|
|
|
@ -83,11 +83,7 @@
|
|||
#endif
|
||||
|
||||
// Size to use for PLArena block allocations.
|
||||
// XXX: This should be 8192; the subtracted elements are a hack that's
|
||||
// required to ensure the allocation requests are power-of-two-sized and thus
|
||||
// avoid lots of wasted memory caused by the heap allocator rounding up request
|
||||
// sizes. Bug 676457 will fix it properly.
|
||||
static const size_t ARENA_PAGE_SIZE = 8192 - sizeof(PLArena) - PL_ARENA_CONST_ALIGN_MASK;
|
||||
static const size_t ARENA_PAGE_SIZE = 8192;
|
||||
|
||||
// Freed memory is filled with a poison value, which we arrange to
|
||||
// form a pointer either to an always-unmapped region of the address
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
function test() {
|
||||
document.querySelector("div").focus();
|
||||
// type a character, then press backspace to delete it
|
||||
sendKey("X", window);
|
||||
sendKey("BACK_SPACE", window);
|
||||
sendKey("X", "div1");
|
||||
sendKey("BACK_SPACE", "div1");
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="test()">
|
||||
<div contenteditable></div>
|
||||
<div id="div1" contenteditable></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
function test() {
|
||||
document.querySelector("div").focus();
|
||||
// type a character, then press backspace to delete it
|
||||
sendKey("X", window);
|
||||
sendKey("BACK_SPACE", window);
|
||||
sendKey("X", "div1");
|
||||
sendKey("BACK_SPACE", "div1");
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="test()">
|
||||
<div contenteditable></div>
|
||||
<div id="div1" contenteditable></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
function test() {
|
||||
document.querySelector("div").focus();
|
||||
// type a character, then press backspace to delete it
|
||||
sendKey("X", window);
|
||||
sendKey("BACK_SPACE", window);
|
||||
sendKey("X", "div1");
|
||||
sendKey("BACK_SPACE", "div1");
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="test()">
|
||||
<div contenteditable></div>
|
||||
<div id="div1" contenteditable></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -249,6 +249,7 @@ nsProgressFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|||
NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!");
|
||||
PresContext()->PresShell()->FrameNeedsReflow(barFrame, nsIPresShell::eResize,
|
||||
NS_FRAME_IS_DIRTY);
|
||||
Invalidate(GetVisualOverflowRectRelativeToSelf());
|
||||
}
|
||||
|
||||
return nsHTMLContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
|
||||
|
@ -278,6 +279,28 @@ nsProgressFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
|
|||
return autoSize;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsProgressFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
|
||||
{
|
||||
nsRefPtr<nsFontMetrics> fontMet;
|
||||
NS_ENSURE_SUCCESS(
|
||||
nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet)), 0);
|
||||
|
||||
nscoord minWidth = fontMet->Font().size; // 1em
|
||||
|
||||
if (GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_HORIZONTAL) {
|
||||
minWidth *= 10; // 10em
|
||||
}
|
||||
|
||||
return minWidth;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsProgressFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
|
||||
{
|
||||
return GetMinWidth(aRenderingContext);
|
||||
}
|
||||
|
||||
bool
|
||||
nsProgressFrame::ShouldUseNativeStyle() const
|
||||
{
|
||||
|
|
|
@ -84,6 +84,9 @@ public:
|
|||
nsSize aMargin, nsSize aBorder,
|
||||
nsSize aPadding, PRBool aShrinkWrap);
|
||||
|
||||
virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
|
||||
virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
|
||||
|
||||
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
|
||||
{
|
||||
return nsHTMLContainerFrame::IsFrameOfType(aFlags &
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<link rel='stylesheet' type='text/css' href='style.css'>
|
||||
<style>
|
||||
progress { display: block; }
|
||||
</style>
|
||||
<body>
|
||||
<progress value='0.5'></progress>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html class='reftest-wait'>
|
||||
<link rel='stylesheet' type='text/css' href='style.css'>
|
||||
<style>
|
||||
progress { display: block; }
|
||||
</style>
|
||||
<script>
|
||||
function loadHandler() {
|
||||
setTimeout(function() {
|
||||
var p = document.getElementsByTagName('progress')[0];
|
||||
p.value = '0.5';
|
||||
document.documentElement.className = '';
|
||||
}, 0);
|
||||
}
|
||||
</script>
|
||||
<body onload="loadHandler();">
|
||||
<progress value='0'></progress>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<link rel='stylesheet' type='text/css' href='style.css'>
|
||||
<style>
|
||||
progress { width: 10em; height: 1em; }
|
||||
progress.vertical { -moz-orient: vertical; width: 1em; height: 10em; }
|
||||
</style>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td>foo</td>
|
||||
<td><progress value='0.5'></td>
|
||||
<td>bar</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>foo</td>
|
||||
<td><progress class='vertical' value='0.5'></td>
|
||||
<td>bar</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<link rel='stylesheet' type='text/css' href='style.css'>
|
||||
<style>
|
||||
progress.vertical { -moz-orient: vertical; }
|
||||
</style>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td>foo</td>
|
||||
<td><progress value='0.5'></td>
|
||||
<td>bar</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>foo</td>
|
||||
<td><progress class='vertical' value='0.5'></td>
|
||||
<td>bar</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -19,3 +19,7 @@
|
|||
# transformations will not behave exactly the same for <progress> and two divs.
|
||||
# However, it would be possible to manually check those.
|
||||
# == transformations.html transformations-ref.html
|
||||
|
||||
# Tests for bugs:
|
||||
== block-invalidate.html block-invalidate-ref.html
|
||||
== in-cells.html in-cells-ref.html
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче