--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -86,24 +86,16 @@ nsAccDocManager::FindAccessibleInCache(n
arg.mNode = aNode;
mDocAccessibleCache.EnumerateRead(SearchAccessibleInDocCache,
static_cast<void*>(&arg));
return arg.mAccessible;
}
-void
-nsAccDocManager::ShutdownDocAccessiblesInTree(nsIDocument *aDocument)
-{
- nsCOMPtr<nsISupports> container = aDocument->GetContainer();
- nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
- ShutdownDocAccessiblesInTree(treeItem, aDocument);
-}
-
////////////////////////////////////////////////////////////////////////////////
// nsAccDocManager protected
PRBool
nsAccDocManager::Init()
{
mDocAccessibleCache.Init(4);
@@ -127,31 +119,16 @@ nsAccDocManager::Shutdown()
do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
if (progress)
progress->RemoveProgressListener(static_cast<nsIWebProgressListener*>(this));
ClearDocCache();
}
-void
-nsAccDocManager::ShutdownDocAccessible(nsIDocument *aDocument)
-{
- nsDocAccessible* docAccessible = mDocAccessibleCache.GetWeak(aDocument);
- if (!docAccessible)
- return;
-
- // We're allowed to not remove listeners when accessible document is shutdown
- // since we don't keep strong reference on chrome event target and listeners
- // are removed automatically when chrome event target goes away.
-
- docAccessible->Shutdown();
- mDocAccessibleCache.Remove(aDocument);
-}
-
////////////////////////////////////////////////////////////////////////////////
// nsISupports
NS_IMPL_THREADSAFE_ISUPPORTS3(nsAccDocManager,
nsIWebProgressListener,
nsIDOMEventListener,
nsISupportsWeakReference)
@@ -311,17 +288,24 @@ nsAccDocManager::HandleEvent(nsIDOMEvent
NS_LOG_ACCDOCDESTROY("received 'pagehide' event", document)
// Ignore 'pagehide' on temporary documents since we ignore them entirely in
// accessibility.
if (document->IsInitialDocument())
return NS_OK;
// Shutdown this one and sub document accessibles.
- ShutdownDocAccessiblesInTree(document);
+
+ // We're allowed to not remove listeners when accessible document is
+ // shutdown since we don't keep strong reference on chrome event target and
+ // listeners are removed automatically when chrome event target goes away.
+ nsDocAccessible* docAccessible = mDocAccessibleCache.GetWeak(document);
+ if (docAccessible)
+ docAccessible->Shutdown();
+
return NS_OK;
}
// XXX: handle error pages loading separately since they get neither
// webprogress notifications nor 'pageshow' event.
if (type.EqualsLiteral("DOMContentLoaded") &&
nsCoreUtils::IsErrorPage(document)) {
NS_LOG_ACCDOCLOAD2("handled 'DOMContentLoaded' event", document)
@@ -495,45 +479,16 @@ nsAccDocManager::CreateDocOrRootAccessib
}
NS_LOG_ACCDOCCREATE("document creation finished", aDocument)
AddListeners(aDocument, isRootDoc);
return docAcc;
}
-void
-nsAccDocManager::ShutdownDocAccessiblesInTree(nsIDocShellTreeItem *aTreeItem,
- nsIDocument *aDocument)
-{
- nsCOMPtr<nsIDocShellTreeNode> treeNode(do_QueryInterface(aTreeItem));
-
- if (treeNode) {
- PRInt32 subDocumentsCount = 0;
- treeNode->GetChildCount(&subDocumentsCount);
- for (PRInt32 idx = 0; idx < subDocumentsCount; idx++) {
- nsCOMPtr<nsIDocShellTreeItem> treeItemChild;
- treeNode->GetChildAt(idx, getter_AddRefs(treeItemChild));
- NS_ASSERTION(treeItemChild, "No tree item when there should be");
- if (!treeItemChild)
- continue;
-
- nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(treeItemChild));
- nsCOMPtr<nsIContentViewer> contentViewer;
- docShell->GetContentViewer(getter_AddRefs(contentViewer));
- if (!contentViewer)
- continue;
-
- ShutdownDocAccessiblesInTree(treeItemChild, contentViewer->GetDocument());
- }
- }
-
- ShutdownDocAccessible(aDocument);
-}
-
////////////////////////////////////////////////////////////////////////////////
// nsAccDocManager static
PLDHashOperator
nsAccDocManager::ClearDocCacheEntry(const nsIDocument* aKey,
nsRefPtr<nsDocAccessible>& aDocAccessible,
void* aUserArg)
{
--- a/accessible/src/base/nsAccDocManager.h
+++ b/accessible/src/base/nsAccDocManager.h
@@ -71,48 +71,44 @@ public:
/**
* Search through all document accessibles for an accessible with the given
* unique id.
*/
nsAccessible* FindAccessibleInCache(nsINode* aNode) const;
/**
- * Shutdown document accessibles in the tree starting from the given one.
- *
- * @param aDocument [in] the DOM document of start document accessible
- */
- void ShutdownDocAccessiblesInTree(nsIDocument *aDocument);
-
- /**
* Return document accessible from the cache. Convenient method for testing.
*/
inline nsDocAccessible* GetDocAccessibleFromCache(nsIDocument* aDocument) const
{
return mDocAccessibleCache.GetWeak(aDocument);
}
+ /**
+ * Called by document accessible when it gets shutdown.
+ */
+ inline void NotifyOfDocumentShutdown(nsIDocument* aDocument)
+ {
+ mDocAccessibleCache.Remove(aDocument);
+ }
+
protected:
nsAccDocManager() { };
/**
* Initialize the manager.
*/
PRBool Init();
/**
* Shutdown the manager.
*/
void Shutdown();
- /**
- * Shutdown the document accessible.
- */
- void ShutdownDocAccessible(nsIDocument* aDocument);
-
private:
nsAccDocManager(const nsAccDocManager&);
nsAccDocManager& operator =(const nsAccDocManager&);
private:
/**
* Create an accessible document if it was't created and fire accessibility
* events if needed.
@@ -151,22 +147,16 @@ private:
*/
void AddListeners(nsIDocument *aDocument, PRBool aAddPageShowListener);
/**
* Create document or root accessible.
*/
nsDocAccessible *CreateDocOrRootAccessible(nsIDocument *aDocument);
- /**
- * Shutdown document accessibles in the tree starting from given tree item.
- */
- void ShutdownDocAccessiblesInTree(nsIDocShellTreeItem *aTreeItem,
- nsIDocument *aDocument);
-
typedef nsRefPtrHashtable<nsPtrHashKey<const nsIDocument>, nsDocAccessible>
nsDocAccessibleHashtable;
/**
* Shutdown and remove the document accessible from cache.
*/
static PLDHashOperator
ClearDocCacheEntry(const nsIDocument* aKey,
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -377,17 +377,18 @@ nsAccessNode::ScrollTo(PRUint32 aScrollT
nsIFrame *frame = GetFrame();
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
nsCOMPtr<nsIContent> content = frame->GetContent();
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
PRInt16 vPercent, hPercent;
nsCoreUtils::ConvertScrollTypeToPercents(aScrollType, &vPercent, &hPercent);
- return shell->ScrollContentIntoView(content, vPercent, hPercent);
+ return shell->ScrollContentIntoView(content, vPercent, hPercent,
+ nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
}
NS_IMETHODIMP
nsAccessNode::ScrollToPoint(PRUint32 aCoordinateType, PRInt32 aX, PRInt32 aY)
{
nsIFrame *frame = GetFrame();
if (!frame)
return NS_ERROR_FAILURE;
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -538,17 +538,20 @@ nsAccessibilityService::PresShellDestroy
// pagehide event for the iframe's underlying document and its presshell is
// destroyed before we're notified styles were changed. Shutdown the document
// accessible early.
nsIDocument* doc = aPresShell->GetDocument();
if (!doc)
return;
NS_LOG_ACCDOCDESTROY("presshell destroyed", doc)
- ShutdownDocAccessible(doc);
+
+ nsDocAccessible* docAccessible = GetDocAccessibleFromCache(doc);
+ if (docAccessible)
+ docAccessible->Shutdown();
}
void
nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell,
nsIContent* aContent)
{
nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
if (document)
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -2363,17 +2363,18 @@ nsAccessible::DispatchClickEvent(nsICont
{
if (IsDefunct())
return;
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
// Scroll into view.
presShell->ScrollContentIntoView(aContent, NS_PRESSHELL_SCROLL_ANYWHERE,
- NS_PRESSHELL_SCROLL_ANYWHERE);
+ NS_PRESSHELL_SCROLL_ANYWHERE,
+ nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
// Fire mouse down and mouse up events.
PRBool res = nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, presShell,
aContent);
if (!res)
return;
nsCoreUtils::DispatchMouseEvent(NS_MOUSE_BUTTON_UP, presShell, aContent);
@@ -2761,16 +2762,23 @@ nsAccessible::InsertChildAt(PRUint32 aIn
}
PRBool
nsAccessible::RemoveChild(nsAccessible* aChild)
{
if (aChild->mParent != this || aChild->mIndexInParent == -1)
return PR_FALSE;
+ if (aChild->mIndexInParent >= mChildren.Length() ||
+ mChildren[aChild->mIndexInParent] != aChild) {
+ NS_ERROR("Child is bound to parent but parent hasn't this child at its index!");
+ aChild->UnbindFromParent();
+ return PR_FALSE;
+ }
+
for (PRUint32 idx = aChild->mIndexInParent + 1; idx < mChildren.Length(); idx++)
mChildren[idx]->mIndexInParent--;
mChildren.RemoveElementAt(aChild->mIndexInParent);
mEmbeddedObjCollector = nsnull;
aChild->UnbindFromParent();
return PR_TRUE;
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -670,27 +670,33 @@ nsDocAccessible::Shutdown()
if (mParent) {
nsDocAccessible* parentDocument = mParent->GetDocAccessible();
if (parentDocument)
parentDocument->RemoveChildDocument(this);
mParent->RemoveChild(this);
}
+ PRUint32 childDocCount = mChildDocuments.Length();
+ for (PRUint32 idx = 0; idx < childDocCount; idx++)
+ mChildDocuments[idx]->Shutdown();
+
mChildDocuments.Clear();
mWeakShell = nsnull; // Avoid reentrancy
mNodeToAccessibleMap.Clear();
ClearCache(mAccessibleCache);
nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument;
mDocument = nsnull;
nsHyperTextAccessibleWrap::Shutdown();
+
+ GetAccService()->NotifyOfDocumentShutdown(kungFuDeathGripDoc);
}
nsIFrame*
nsDocAccessible::GetFrame()
{
nsCOMPtr<nsIPresShell> shell(do_QueryReferent(mWeakShell));
nsIFrame* root = nsnull;
--- a/accessible/src/base/nsOuterDocAccessible.cpp
+++ b/accessible/src/base/nsOuterDocAccessible.cpp
@@ -164,17 +164,17 @@ nsOuterDocAccessible::Shutdown()
// any to avoid hanging document accessible.
NS_LOG_ACCDOCDESTROY_MSG("A11y outerdoc shutdown")
NS_LOG_ACCDOCDESTROY_ACCADDRESS("outerdoc", this)
nsAccessible *childAcc = mChildren.SafeElementAt(0, nsnull);
if (childAcc) {
NS_LOG_ACCDOCDESTROY("outerdoc's child document shutdown",
childAcc->GetDocumentNode())
- GetAccService()->ShutdownDocAccessiblesInTree(childAcc->GetDocumentNode());
+ childAcc->Shutdown();
}
nsAccessibleWrap::Shutdown();
}
////////////////////////////////////////////////////////////////////////////////
// nsAccessible public
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -1533,17 +1533,17 @@ nsHyperTextAccessible::SetSelectionRange
domSel->RemoveRange(range);
}
}
if (selCon) {
// XXX I'm not sure this can do synchronous scrolling. If the last param is
// set to true, this calling might flush the pending reflow. See bug 418470.
selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
- nsISelectionController::SELECTION_FOCUS_REGION, PR_FALSE);
+ nsISelectionController::SELECTION_FOCUS_REGION, 0);
}
return NS_OK;
}
NS_IMETHODIMP
nsHyperTextAccessible::SetCaretOffset(PRInt32 aCaretOffset)
{
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -967,18 +967,19 @@ var PlacesStarButton = {
onBeginUpdateBatch: function PSB_onBeginUpdateBatch() {
this._batching = true;
},
onEndUpdateBatch: function PSB_onEndUpdateBatch() {
this.updateState();
this._batching = false;
},
-
- onItemAdded: function PSB_onItemAdded(aItemId, aFolder, aIndex, aItemType) {
+
+ onItemAdded: function PSB_onItemAdded(aItemId, aFolder, aIndex, aItemType,
+ aURI) {
if (!this._batching && !this._starred)
this.updateState();
},
onBeforeItemRemoved: function() {},
onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex,
aItemType) {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -814,18 +814,17 @@ const gFormSubmitObserver = {
if (!(element instanceof HTMLInputElement ||
element instanceof HTMLTextAreaElement ||
element instanceof HTMLSelectElement ||
element instanceof HTMLButtonElement)) {
return;
}
- // Limit the message to 256 characters.
- this.panel.firstChild.textContent = element.validationMessage.substring(0, 256);
+ this.panel.firstChild.textContent = element.validationMessage;
element.focus();
// If the user type something or blur the element, we want to remove the popup.
// We could check for clicks but a click is already removing the popup.
let eventHandler = function(e) {
gFormSubmitObserver.panel.hidePopup();
};
@@ -3981,16 +3980,37 @@ var XULBrowserWindow = {
setOverLink: function (link) {
// Encode bidirectional formatting characters.
// (RFC 3987 sections 3.2 and 4.1 paragraph 6)
link = link.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g,
encodeURIComponent);
gURLBar.setOverLink(link);
},
+
+ // Called before links are navigated to to allow us to retarget them if needed.
+ onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
+ // Don't modify non-default targets or targets that aren't in top-level app
+ // tab docshells (isAppTab will be false for app tab subframes).
+ if (originalTarget != "" || !isAppTab)
+ return originalTarget;
+
+ let docURI = linkNode.ownerDocument.documentURIObject;
+ try {
+ let docURIDomain = Services.eTLD.getBaseDomain(docURI, 0);
+ let linkURIDomain = Services.eTLD.getBaseDomain(linkURI, 0);
+ // External links from within app tabs should always open in new tabs
+ // instead of replacing the app tab's page (Bug 575561)
+ if (docURIDomain != linkURIDomain)
+ return "_blank";
+ } catch(e) {
+ // If getBaseDomain fails, we return originalTarget below.
+ }
+ return originalTarget;
+ },
onLinkIconAvailable: function (aIconURL) {
if (gProxyFavIcon && gBrowser.userTypedValue === null)
PageProxySetIcon(aIconURL); // update the favicon in the URL bar
},
onProgressChange: function (aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
@@ -7482,35 +7502,37 @@ let gPrivateBrowsingUI = {
this._setPBMenuTitle("stop");
document.getElementById("menu_import").setAttribute("disabled", "true");
// Disable the Clear Recent History... menu item when in PB mode
// temporary fix until bug 463607 is fixed
document.getElementById("Tools:Sanitize").setAttribute("disabled", "true");
+ let docElement = document.documentElement;
if (this._privateBrowsingService.autoStarted) {
// Disable the menu item in auto-start mode
document.getElementById("privateBrowsingItem")
.setAttribute("disabled", "true");
#ifdef MENUBAR_CAN_AUTOHIDE
document.getElementById("appmenu_privateBrowsing")
.setAttribute("disabled", "true");
#endif
document.getElementById("Tools:PrivateBrowsing")
.setAttribute("disabled", "true");
+ if (window.location.href == getBrowserURL())
+ docElement.setAttribute("privatebrowsingmode", "permanent");
}
else if (window.location.href == getBrowserURL()) {
// Adjust the window's title
- let docElement = document.documentElement;
docElement.setAttribute("title",
docElement.getAttribute("title_privatebrowsing"));
docElement.setAttribute("titlemodifier",
docElement.getAttribute("titlemodifier_privatebrowsing"));
- docElement.setAttribute("browsingmode", "private");
+ docElement.setAttribute("privatebrowsingmode", "temporary");
gBrowser.updateTitlebar();
}
if (!aOnWindowOpen && this._disableUIOnToggle)
document.getElementById("Tools:PrivateBrowsing")
.setAttribute("disabled", "true");
},
@@ -7547,17 +7569,17 @@ let gPrivateBrowsingUI = {
if (window.location.href == getBrowserURL()) {
// Adjust the window's title
let docElement = document.documentElement;
docElement.setAttribute("title",
docElement.getAttribute("title_normal"));
docElement.setAttribute("titlemodifier",
docElement.getAttribute("titlemodifier_normal"));
- docElement.setAttribute("browsingmode", "normal");
+ docElement.removeAttribute("privatebrowsingmode");
}
// Enable the menu item in after exiting the auto-start mode
document.getElementById("privateBrowsingItem")
.removeAttribute("disabled");
#ifdef MENUBAR_CAN_AUTOHIDE
document.getElementById("appmenu_privateBrowsing")
.removeAttribute("disabled");
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -821,22 +821,17 @@
<deck flex="1" id="tab-view-deck">
<vbox flex="1">
<toolbox id="navigator-toolbox"
defaultmode="icons" mode="icons"
#ifdef WINCE
defaulticonsize="small" iconsize="small"
#endif
-#ifdef XP_WIN
tabsontop="true"
-#endif
-#ifdef XP_MACOSX
- tabsontop="true"
-#endif
persist="tabsontop">
<!-- Menu -->
<toolbar type="menubar" id="toolbar-menubar" class="chromeclass-menubar" customizable="true"
defaultset="menubar-items"
mode="icons" iconsize="small" defaulticonsize="small"
lockiconsize="true"
#ifdef MENUBAR_CAN_AUTOHIDE
toolbarname="&menubarCmd.label;"
@@ -1009,17 +1004,19 @@
label="&viewBookmarksToolbar.label;"/>
<menuseparator/>
<menuitem id="BMB_bookmarksShowAll"
label="&showAllBookmarks.label;"
command="Browser:ShowAllBookmarks"
key="manBookmarkKb"/>
<menuseparator/>
<menuitem id="BMB_bookmarkThisPage"
+#ifndef XP_MACOSX
class="menuitem-iconic"
+#endif
label="&bookmarkThisPageCmd.label;"
command="Browser:AddBookmarkAs"
key="addBookmarkAsKb"/>
<menuitem id="BMB_subscribeToPageMenuitem"
label="&subscribeToPageMenuitem.label;"
oncommand="return FeedHandler.subscribeToFeed(null, event);"
onclick="checkForMiddleClick(this, event);"
observes="singleFeedMenuitemState"/>
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -953,24 +953,27 @@ nsContextMenu.prototype = {
onDataAvailable: function saveLinkAs_onDataAvailable(aRequest, aContext,
aInputStream,
aOffset, aCount) {
this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
aOffset, aCount);
}
}
- // in case we need to prompt the user for authentication
function callbacks() {}
callbacks.prototype = {
getInterface: function sLA_callbacks_getInterface(aIID) {
if (aIID.equals(Ci.nsIAuthPrompt) || aIID.equals(Ci.nsIAuthPrompt2)) {
- var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
- getService(Ci.nsIPromptFactory);
- return ww.getPrompt(doc.defaultView, aIID);
+ // If the channel demands authentication prompt, we must cancel it
+ // because the save-as-timer would expire and cancel the channel
+ // before we get credentials from user. Both authentication dialog
+ // and save as dialog would appear on the screen as we fall back to
+ // the old fashioned way after the timeout.
+ timer.cancel();
+ channel.cancel(NS_ERROR_SAVE_LINK_AS_TIMEOUT);
}
throw Cr.NS_ERROR_NO_INTERFACE;
}
}
// if it we don't have the headers after a short time, the user
// won't have received any feedback from their click. that's bad. so
// we give up waiting for the filename.
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -186,16 +186,18 @@
if (aTab.hidden)
this.showTab(aTab);
this.moveTabTo(aTab, this._numPinnedTabs);
aTab.setAttribute("pinned", "true");
this.tabContainer._positionPinnedTabs();
this.tabContainer.adjustTabstrip();
+ this.getBrowserForTab(aTab).docShell.isAppTab = true;
+
let event = document.createEvent("Events");
event.initEvent("TabPinned", true, false);
aTab.dispatchEvent(event);
]]></body>
</method>
<method name="unpinTab">
<parameter name="aTab"/>
@@ -205,16 +207,18 @@
this.moveTabTo(aTab, this._numPinnedTabs - 1);
aTab.setAttribute("fadein", "true");
aTab.removeAttribute("pinned");
aTab.style.MozMarginStart = "";
this.tabContainer._positionPinnedTabs();
this.tabContainer.adjustTabstrip();
+ this.getBrowserForTab(aTab).docShell.isAppTab = false;
+
let event = document.createEvent("Events");
event.initEvent("TabUnpinned", true, false);
aTab.dispatchEvent(event);
]]></body>
</method>
<method name="previewTab">
<parameter name="aTab"/>
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -65,16 +65,17 @@
// dontPush - true if this groupItem shouldn't push away on creation; default is false
// dontPush - true if this groupItem shouldn't push away or snap on creation; default is false
// immediately - true if we want all placement immediately, not with animation
function GroupItem(listOfEls, options) {
if (typeof options == 'undefined')
options = {};
this._inited = false;
+ this._uninited = false;
this._children = []; // an array of Items
this.defaultSize = new Point(TabItems.tabWidth * 1.5, TabItems.tabHeight * 1.5);
this.isAGroupItem = true;
this.id = options.id || GroupItems.getNextID();
this._isStacked = false;
this._stackAngles = [0];
this.expanded = null;
this.locked = (options.locked ? Utils.copy(options.locked) : {});
@@ -361,25 +362,33 @@ GroupItem.prototype = Utils.extend(new I
isEmpty: function GroupItem_isEmpty() {
return !this._children.length && !this.getTitle();
},
// ----------
// Function: save
// Saves this groupItem to persistent storage.
save: function GroupItem_save() {
- if (!this._inited) // too soon to save now
+ if (!this._inited || this._uninited) // too soon/late to save
return;
var data = this.getStorageData();
if (GroupItems.groupItemStorageSanity(data))
Storage.saveGroupItem(gWindow, data);
},
// ----------
+ // Function: deleteData
+ // Deletes the groupItem in the persistent storage.
+ deleteData: function GroupItem_deleteData() {
+ this._uninited = true;
+ Storage.deleteGroupItem(gWindow, this.id);
+ },
+
+ // ----------
// Function: getTitle
// Returns the title of this groupItem as a string.
getTitle: function GroupItem_getTitle() {
var value = (this.$title ? this.$title.val() : '');
return (value == this.defaultName ? '' : value);
},
// ----------
@@ -556,17 +565,17 @@ GroupItem.prototype = Utils.extend(new I
}, {
duration: 170,
complete: function() {
iQ(this).remove();
Items.unsquish();
}
});
- Storage.deleteGroupItem(gWindow, this.id);
+ this.deleteData();
},
// ----------
// Function: closeAll
// Closes the groupItem and all of its children.
closeAll: function GroupItem_closeAll() {
let closeCenter = this.getBounds().center();
if (this._children.length > 0) {
@@ -642,17 +651,17 @@ GroupItem.prototype = Utils.extend(new I
self._sendToSubscribers("close");
self.removeTrenches();
iQ(self.container).remove();
self.$undoContainer.remove();
self.$undoContainer = null;
Items.unsquish();
- Storage.deleteGroupItem(gWindow, self.id);
+ self.deleteData();
};
this.$undoContainer.click(function(e) {
// Only do this for clicks on this actual element.
if (e.target.nodeName != self.$undoContainer[0].nodeName)
return;
self.$undoContainer.fadeOut(function() {
@@ -2067,13 +2076,13 @@ let GroupItems = {
this.groupItems.forEach(function(groupItem) {
if (groupItem.hidden) {
let toClose = groupItem._children.concat();
toClose.forEach(function(child) {
child.removeSubscriber(groupItem, "close");
child.close();
});
- Storage.deleteGroupItem(gWindow, groupItem.id);
+ groupItem.deleteData();
}
});
}
};
--- a/browser/base/content/tabview/tabitems.js
+++ b/browser/base/content/tabview/tabitems.js
@@ -197,21 +197,20 @@ function TabItem(tab, options) {
iQ("<div>")
.addClass('expander')
.appendTo($div);
this._updateDebugBounds();
TabItems.register(this);
-
- if (!this.reconnected) {
+
+ if (!this.reconnected)
GroupItems.newTab(this, options);
- }
-
+
// tabs which were not reconnected at all or were not immediately added
// to a group get the same treatment.
if (!this.reconnected || (reconnected && !reconnected.addedToGroup) ) {
this.setResizable(true, options.immediately);
this.droppable(true);
}
};
@@ -799,17 +798,17 @@ let TabItems = {
tabItem.favEl.src = iconUrl;
// ___ URL
let tabUrl = tab.linkedBrowser.currentURI.spec;
if (tabUrl != tabItem.url) {
let oldURL = tabItem.url;
tabItem.url = tabUrl;
- if (!tabItem.reconnected && (oldURL == 'about:blank' || !oldURL))
+ if (!tabItem.reconnected)
this.reconnect(tabItem);
tabItem.save();
}
// ___ label
let label = tab.label;
let $name = iQ(tabItem.nameEl);
@@ -1052,20 +1051,20 @@ let TabItems = {
item.hideCachedData();
}
}, 15000);
}
item.reconnected = true;
found = {addedToGroup: tabData.groupID};
} else {
- // if it's not a blank tab or it belongs to a group, it would mean
- // the item is reconnected.
- item.reconnected =
- (item.tab.linkedBrowser.currentURI.spec != 'about:blank' || item.parent);
+ // We should never have any orphaned tabs. Therefore, item is not
+ // connected if it has no parent and GroupItems.newTab() would handle
+ // the group creation.
+ item.reconnected = (item.parent != null);
}
item.save();
if (item.reconnected)
item._sendToSubscribers("reconnected");
} catch(e) {
Utils.log(e);
}
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -140,16 +140,17 @@ endif
browser_bug555224.js \
browser_bug555767.js \
browser_bug556061.js \
browser_bug559991.js \
browser_bug561623.js \
browser_bug561636.js \
browser_bug562649.js \
browser_bug563588.js \
+ browser_bug575561.js \
browser_bug577121.js \
browser_bug579872.js \
browser_bug580956.js \
browser_bug581242.js \
browser_bug581253.js \
browser_bug581947.js \
browser_bug585785.js \
browser_bug585830.js \
@@ -213,16 +214,18 @@ endif
alltabslistener.html \
zoom_test.html \
dummy_page.html \
browser_tabMatchesInAwesomebar.js \
file_bug550565_popup.html \
file_bug550565_favicon.ico \
browser_overLinkInLocationBar.js \
browser_aboutHome.js \
+ app_bug575561.html \
+ app_subframe_bug575561.html \
$(NULL)
# compartment-disabled
# browser_popupUI.js \
# browser_tab_dragdrop.js \
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
_BROWSER_FILES += \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/app_bug575561.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=575561
+-->
+ <head>
+ <title>Test for links in app tabs</title>
+ </head>
+ <body>
+ <a href="http://example.com/browser/browser/base/content/test/dummy_page.html">same domain</a>
+ <a href="http://test1.example.com/browser/browser/base/content/test/dummy_page.html">same domain (different subdomain)</a>
+ <a href="http://example.org/browser/browser/base/content/test/dummy_page.html">different domain</a>
+ <a href="http://example.org/browser/browser/base/content/test/dummy_page.html" target="foo">different domain (with target)</a>
+ <iframe src="app_subframe_bug575561.html"></iframe>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/app_subframe_bug575561.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=575561
+-->
+ <head>
+ <title>Test for links in app tab subframes</title>
+ </head>
+ <body>
+ <a href="http://example.org/browser/browser/base/content/test/dummy_page.html">different domain</a>
+ </body>
+</html>
--- a/browser/base/content/test/browser_bug553455.js
+++ b/browser/base/content/test/browser_bug553455.js
@@ -603,16 +603,25 @@ function test() {
Services.prefs.setBoolPref("extensions.logging.enabled", true);
Services.obs.addObserver(XPInstallObserver, "addon-install-started", false);
Services.obs.addObserver(XPInstallObserver, "addon-install-blocked", false);
Services.obs.addObserver(XPInstallObserver, "addon-install-failed", false);
Services.obs.addObserver(XPInstallObserver, "addon-install-complete", false);
registerCleanupFunction(function() {
+ // Make sure no more test parts run in case we were timed out
+ TESTS = [];
+
+ AddonManager.getAllInstalls(function(aInstalls) {
+ aInstalls.forEach(function(aInstall) {
+ aInstall.cancel();
+ });
+ });
+
Services.prefs.clearUserPref("extensions.logging.enabled");
Services.obs.removeObserver(XPInstallObserver, "addon-install-started");
Services.obs.removeObserver(XPInstallObserver, "addon-install-blocked");
Services.obs.removeObserver(XPInstallObserver, "addon-install-failed");
Services.obs.removeObserver(XPInstallObserver, "addon-install-complete");
});
--- a/browser/base/content/test/browser_bug561636.js
+++ b/browser/base/content/test/browser_bug561636.js
@@ -12,18 +12,18 @@ function checkPopupHide()
{
ok(gInvalidFormPopup.state != 'showing' && gInvalidFormPopup.state != 'open',
"The invalid form popup should not be shown");
}
function checkPopupMessage(doc)
{
is(gInvalidFormPopup.firstChild.textContent,
- doc.getElementById('i').validationMessage.substring(0,256),
- "The panel should show the 256 first characters of the validationMessage");
+ doc.getElementById('i').validationMessage,
+ "The panel should show the message from validationMessage");
}
let gObserver = {
QueryInterface : XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]),
notifyInvalidSubmit : function (aFormElement, aInvalidElements)
{
}
@@ -128,74 +128,75 @@ function test3()
gBrowser.contentDocument.getElementById('s').click();
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedTab.linkedBrowser.loadURI(uri);
}
/**
- * In this test, we check that the validation message is correctly cut.
+ * In this test, we check that, we can hide the popup by interacting with the
+ * invalid element.
*/
function test4()
{
- let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i'><input id='s' type='submit'></form>";
+ let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
let tab = gBrowser.addTab();
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
checkPopupMessage(doc);
- // Clean-up and next test.
- gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
- executeSoon(test5);
+ EventUtils.synthesizeKey("a", {});
+
+ executeSoon(function () {
+ checkPopupHide();
+
+ // Clean-up and next test.
+ gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
+ executeSoon(test5);
+ });
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
- let msg = "";
- for (let i=0; i<50; ++i) {
- msg += "abcde ";
- }
- // msg has 300 characters
- gBrowser.contentDocument.getElementById('i').setCustomValidity(msg);
gBrowser.contentDocument.getElementById('s').click();
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedTab.linkedBrowser.loadURI(uri);
}
/**
- * In this test, we check that, we can hide the popup by interacting with the
- * invalid element.
+ * In this test, we check that we can hide the popup by blurring the invalid
+ * element.
*/
function test5()
{
let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
let tab = gBrowser.addTab();
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
checkPopupMessage(doc);
- EventUtils.synthesizeKey("a", {});
+ doc.getElementById('i').blur();
executeSoon(function () {
checkPopupHide();
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
executeSoon(test6);
});
@@ -207,35 +208,34 @@ function test5()
gBrowser.contentDocument.getElementById('s').click();
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedTab.linkedBrowser.loadURI(uri);
}
/**
- * In this test, we check that we can hide the popup by blurring the invalid
- * element.
+ * In this test, we check that we can hide the popup by pressing TAB.
*/
function test6()
{
let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
let tab = gBrowser.addTab();
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
checkPopupMessage(doc);
- doc.getElementById('i').blur();
+ EventUtils.synthesizeKey("VK_TAB", {});
executeSoon(function () {
checkPopupHide();
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
executeSoon(test7);
});
@@ -247,82 +247,43 @@ function test6()
gBrowser.contentDocument.getElementById('s').click();
}, true);
gBrowser.selectedTab = tab;
gBrowser.selectedTab.linkedBrowser.loadURI(uri);
}
/**
- * In this test, we check that we can hide the popup by pressing TAB.
+ * In this test, we check that the popup will hide if we move to another tab.
*/
function test7()
{
let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
let tab = gBrowser.addTab();
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let doc = gBrowser.contentDocument;
is(doc.activeElement, doc.getElementById('i'),
"First invalid element should be focused");
checkPopupShow();
checkPopupMessage(doc);
- EventUtils.synthesizeKey("VK_TAB", {});
-
- executeSoon(function () {
- checkPopupHide();
-
- // Clean-up and next test.
- gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
- executeSoon(test8);
- });
- }, false);
-
- tab.linkedBrowser.addEventListener("load", function(aEvent) {
- tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
-
- gBrowser.contentDocument.getElementById('s').click();
- }, true);
-
- gBrowser.selectedTab = tab;
- gBrowser.selectedTab.linkedBrowser.loadURI(uri);
-}
-
-/**
- * In this test, we check that the popup will hide if we move to another tab.
- */
-function test8()
-{
- let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
- let tab = gBrowser.addTab();
-
- gInvalidFormPopup.addEventListener("popupshown", function() {
- gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
-
- let doc = gBrowser.contentDocument;
- is(doc.activeElement, doc.getElementById('i'),
- "First invalid element should be focused");
-
- checkPopupShow();
- checkPopupMessage(doc);
-
// Create a new tab and move to it.
gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true});
executeSoon(function() {
checkPopupHide();
// Clean-up and next test.
gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
- executeSoon(test9);
+ executeSoon(test8);
});
}, false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
gBrowser.contentDocument.getElementById('s').click();
}, true);
@@ -331,17 +292,17 @@ function test8()
gBrowser.selectedTab.linkedBrowser.loadURI(uri);
}
/**
* In this test, we check that nothing happen (no focus nor popup) if the
* invalid form is submitted in another tab than the current focused one
* (submitted in background).
*/
-function test9()
+function test8()
{
let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input id='i' required><input id='s' type='submit'></form>";
let tab = gBrowser.addTab();
gObserver.notifyInvalidSubmit = function() {
executeSoon(function() {
let doc = tab.linkedBrowser.contentDocument;
isnot(doc.activeElement, doc.getElementById('i'),
@@ -350,17 +311,17 @@ function test9()
checkPopupHide();
// Clean-up
Services.obs.removeObserver(gObserver, "invalidformsubmit");
gObserver.notifyInvalidSubmit = function () {};
gBrowser.removeTab(tab, {animate: false});
// Next test
- executeSoon(test10);
+ executeSoon(test9);
});
};
Services.obs.addObserver(gObserver, "invalidformsubmit", false);
tab.linkedBrowser.addEventListener("load", function(aEvent) {
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
@@ -371,17 +332,17 @@ function test9()
}, true);
tab.linkedBrowser.loadURI(uri);
}
/**
* In this test, we check that the author defined error message is shown.
*/
-function test10()
+function test9()
{
let uri = "data:text/html,<iframe name='t'></iframe><form target='t' action='data:text/html,'><input x-moz-errormessage='foo' required id='i'><input id='s' type='submit'></form>";
let tab = gBrowser.addTab();
gInvalidFormPopup.addEventListener("popupshown", function() {
gInvalidFormPopup.removeEventListener("popupshown", arguments.callee, false);
let doc = gBrowser.contentDocument;
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug575561.js
@@ -0,0 +1,77 @@
+function test() {
+ waitForExplicitFinish();
+
+ // Pinned: Link to the same domain should not open a new tab
+ // Tests link to http://example.com/browser/browser/base/content/test/dummy_page.html
+ testLink(0, true, false, function() {
+ // Pinned: Link to the same domain should not open a new tab
+ // Tests link to http://test1.example.com/browser/browser/base/content/test/dummy_page.html
+ testLink(1, true, false, function() {
+ // Pinned: Link to a different domain should open a new tab
+ // Tests link to http://example.org/browser/browser/base/content/test/dummy_page.html
+ testLink(2, true, true, function() {
+ // Not Pinned: Link to a different domain should not open a new tab
+ // Tests link to http://example.org/browser/browser/base/content/test/dummy_page.html
+ testLink(2, false, false, function() {
+ // Pinned: Targetted link should open a new tab
+ // Tests link to http://example.org/browser/browser/base/content/test/dummy_page.html with target="foo"
+ testLink(3, true, true, function() {
+ // Pinned: Link in a subframe should not open a new tab
+ // Tests link to http://example.org/browser/browser/base/content/test/dummy_page.html in subframe
+ testLink(0, true, false, finish, true);
+ });
+ });
+ });
+ });
+ });
+}
+
+function testLink(aLinkIndex, pinTab, expectNewTab, nextTest, testSubFrame) {
+ let appTab = gBrowser.addTab("http://example.com/browser/browser/base/content/test/app_bug575561.html", {skipAnimation: true});
+ if (pinTab)
+ gBrowser.pinTab(appTab);
+ gBrowser.selectedTab = appTab;
+ appTab.linkedBrowser.addEventListener("load", onLoad, true);
+
+ let loadCount = 0;
+ function onLoad() {
+ loadCount++;
+ if (loadCount < 2)
+ return;
+
+ appTab.linkedBrowser.removeEventListener("load", onLoad, true);
+
+ let browser = gBrowser.getBrowserForTab(appTab);
+ if (testSubFrame)
+ browser = browser.contentDocument.getElementsByTagName("iframe")[0];
+
+ let links = browser.contentDocument.getElementsByTagName("a");
+
+ if (expectNewTab)
+ gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true);
+ else
+ browser.addEventListener("load", onPageLoad, true);
+
+ info("Clicking " + links[aLinkIndex].textContent);
+ EventUtils.sendMouseEvent({type:"click"}, links[aLinkIndex], browser.contentWindow);
+
+ function onPageLoad() {
+ browser.removeEventListener("load", onPageLoad, true);
+ is(browser.contentDocument.location.href, links[aLinkIndex].href, "Link should not open in a new tab");
+ executeSoon(function(){
+ gBrowser.removeTab(appTab);
+ nextTest();
+ });
+ }
+
+ function onTabOpen(event) {
+ gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true);
+ ok(true, "Link should open a new tab");
+ executeSoon(function(){
+ gBrowser.removeTab(appTab);
+ gBrowser.removeCurrentTab();
+ nextTest();
+ });
+ }
+ }
+}
--- a/browser/base/content/test/browser_bug585785.js
+++ b/browser/base/content/test/browser_bug585785.js
@@ -1,31 +1,36 @@
var tab;
-var performedTest = false;
function test() {
waitForExplicitFinish();
tab = gBrowser.addTab();
isnot(tab.getAttribute("fadein"), "true", "newly opened tab is yet to fade in");
- // Remove the tab right before the opening animation's first frame
+ // Try to remove the tab right before the opening animation's first frame
window.mozRequestAnimationFrame(checkAnimationState);
- executeSoon(checkAnimationState);
}
function checkAnimationState() {
- if (performedTest)
- return;
-
if (tab.getAttribute("fadein") != "true") {
window.mozRequestAnimationFrame(checkAnimationState);
- executeSoon(checkAnimationState);
return;
}
- performedTest = true;
+ info(window.getComputedStyle(tab).maxWidth);
+ gBrowser.removeTab(tab, { animate: true });
+ if (!tab.parentNode) {
+ ok(true, "tab removed synchronously since the opening animation hasn't moved yet");
+ finish();
+ return;
+ }
- info(window.getComputedStyle(tab).maxWidth);
- gBrowser.removeTab(tab, {animate:true});
- ok(!tab.parentNode, "tab successfully removed");
- finish();
+ info("tab didn't close immediately, so the tab opening animation must have started moving");
+ info("waiting for the tab to close asynchronously");
+ tab.addEventListener("transitionend", function (event) {
+ if (event.propertyName == "max-width")
+ executeSoon(function () {
+ ok(!tab.parentNode, "tab removed asynchronously");
+ finish();
+ });
+ }, false);
}
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -51,27 +51,29 @@ include $(topsrcdir)/config/rules.mk
browser_tabview_bug590606.js \
browser_tabview_bug591706.js \
browser_tabview_bug594176.js \
browser_tabview_bug595191.js \
browser_tabview_bug595518.js \
browser_tabview_bug595804.js \
browser_tabview_bug595930.js \
browser_tabview_bug595943.js \
+ browser_tabview_bug598600.js \
browser_tabview_dragdrop.js \
browser_tabview_exit_button.js \
browser_tabview_group.js \
browser_tabview_launch.js \
browser_tabview_orphaned_tabs.js \
browser_tabview_privatebrowsing.js \
browser_tabview_search.js \
browser_tabview_snapping.js \
browser_tabview_startup_transitions.js \
browser_tabview_undo_group.js \
browser_tabview_firstrun_pref.js \
+ head.js \
search1.html \
search2.html \
$(NULL)
# compartments: test disabled
# browser_tabview_multiwindow_search.js \
libs:: $(_BROWSER_FILES)
--- a/browser/base/content/test/tabview/browser_tabview_bug590606.js
+++ b/browser/base/content/test/tabview/browser_tabview_bug590606.js
@@ -54,17 +54,17 @@ function test() {
"There is one group item on startup");
let groupItemOne = contentWindow.GroupItems.groupItems[0];
is(groupItemOne.getChildren().length, 2,
"There should be two tab items in that group.");
is(gBrowser.selectedTab, groupItemOne.getChild(0).tab,
"The currently selected tab should be the first tab in the groupItemOne");
// create another group with a tab.
- let groupItemTwo = createEmptyGroupItem(contentWindow, 200);
+ let groupItemTwo = createEmptyGroupItem(contentWindow, 300, 300, 200);
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
// start the test
testGroupSwitch(contentWindow, groupItemOne, groupItemTwo);
};
window.addEventListener("tabviewhidden", onTabViewHidden, false);
@@ -106,21 +106,8 @@ function testGroupSwitch(contentWindow,
"The currently selected tab should be the second tab in the groupItemOne");
// cleanup.
gBrowser.removeTab(groupItemTwo.getChild(0).tab);
gBrowser.removeTab(newTabOne);
finish();
}
-
-function createEmptyGroupItem(contentWindow, padding) {
- let pageBounds = contentWindow.Items.getPageBounds();
- pageBounds.inset(padding, padding);
-
- let box = new contentWindow.Rect(pageBounds);
- box.width = 300;
- box.height = 300;
-
- let emptyGroupItem = new contentWindow.GroupItem([], { bounds: box });
-
- return emptyGroupItem;
-}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug598600.js
@@ -0,0 +1,115 @@
+/* ***** 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 bug598600 test.
+ *
+ * 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):
+ * Raymond Lee <raymond@appcoast.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+let newWin;
+let prefService;
+
+function test() {
+ let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+ prefService =
+ Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).
+ getBranch("browser.panorama.");
+ // make sure we don't trigger the 'first run' behavior
+ prefService.setBoolPref("experienced_first_run", true);
+
+ waitForExplicitFinish();
+
+ // open a new window and setup the window state.
+ newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
+ newWin.addEventListener("load", function(event) {
+ this.removeEventListener("load", arguments.callee, false);
+
+ let newState = {
+ windows: [{
+ tabs: [{
+ entries: [{ "url": "about:blank" }],
+ hidden: true,
+ attributes: {},
+ extData: {
+ "tabview-tab":
+ '{"bounds":{"left":20,"top":35,"width":280,"height":210},' +
+ '"userSize":null,"url":"about:blank","groupID":1,' +
+ '"imageData":null,"title":null}'
+ }
+ },{
+ entries: [{ url: "about:blank" }],
+ index: 1,
+ hidden: false,
+ attributes: {},
+ extData: {
+ "tabview-tab":
+ '{"bounds":{"left":375,"top":35,"width":280,"height":210},' +
+ '"userSize":null,"url":"about:blank","groupID":2,' +
+ '"imageData":null,"title":null}'
+ }
+ }],
+ selected:2,
+ _closedTabs: [],
+ extData: {
+ "tabview-groups": '{"nextID":3,"activeGroupId":2}',
+ "tabview-group":
+ '{"1":{"bounds":{"left":15,"top":10,"width":320,"height":375},' +
+ '"userSize":null,"locked":{},"title":"","id":1},' +
+ '"2":{"bounds":{"left":380,"top":5,"width":320,"height":375},' +
+ '"userSize":null,"locked":{},"title":"","id":2}}',
+ "tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":875,"height":650}}'
+ }, sizemode:"normal"
+ }]
+ };
+ ss.setWindowState(newWin, JSON.stringify(newState), true);
+
+ // add a new tab.
+ newWin.gBrowser.addTab();
+ is(newWin.gBrowser.tabs.length, 3, "There are 3 browser tabs");
+
+ let onTabViewShow = function() {
+ newWin.removeEventListener("tabviewshown", onTabViewShow, false);
+
+ let contentWindow = newWin.document.getElementById("tab-view").contentWindow;
+
+ is(contentWindow.GroupItems.groupItems.length, 2, "Has two group items");
+ is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphan tabs");
+
+ // clean up and finish
+ prefService.setBoolPref("experienced_first_run", false);
+ newWin.close();
+
+ finish();
+ }
+ newWin.addEventListener("tabviewshown", onTabViewShow, false);
+ newWin.TabView.toggle();
+ }, false);
+}
--- a/browser/base/content/test/tabview/browser_tabview_dragdrop.js
+++ b/browser/base/content/test/tabview/browser_tabview_dragdrop.js
@@ -90,20 +90,18 @@ function addTest(contentWindow, groupOne
let groupTwoTabItemCount = groupTwo.getChildren().length;
is(groupOneTabItemCount, 1, "GroupItem one has one tab");
is(groupTwoTabItemCount, 1, "GroupItem two has one tab as well");
let tabItem = groupOne.getChild(0);
ok(tabItem, "The tab item exists");
// calculate the offsets
- let groupTwoRect = groupTwo.getBounds();
- let groupTwoRectCenter = groupTwoRect.center();
- let tabItemRect = tabItem.getBounds();
- let tabItemRectCenter = tabItemRect.center();
+ let groupTwoRectCenter = groupTwo.getBounds().center();
+ let tabItemRectCenter = tabItem.getBounds().center();
let offsetX =
Math.round(groupTwoRectCenter.x - tabItemRectCenter.x);
let offsetY =
Math.round(groupTwoRectCenter.y - tabItemRectCenter.y);
function endGame() {
groupTwo.removeSubscriber(groupTwo, "childAdded");
@@ -127,46 +125,28 @@ function addTest(contentWindow, groupOne
window.addEventListener("tabviewhidden", onTabViewHidden, false);
gBrowser.selectedTab = originalTab;
}
groupTwo.addSubscriber(groupTwo, "childAdded", endGame);
simulateDragDrop(tabItem.container, offsetX, offsetY, contentWindow);
}
-function simulateDragDrop(tabItem, offsetX, offsetY, contentWindow) {
- // enter drag mode
- let dataTransfer;
+function simulateDragDrop(element, offsetX, offsetY, contentWindow) {
+ let rect = element.getBoundingClientRect();
+ let startX = (rect.right - rect.left)/2;
+ let startY = (rect.bottom - rect.top)/2;
+ let incrementX = offsetX / 2;
+ let incrementY = offsetY / 2;
EventUtils.synthesizeMouse(
- tabItem, 1, 1, { type: "mousedown" }, contentWindow);
- event = contentWindow.document.createEvent("DragEvents");
- event.initDragEvent(
- "dragenter", true, true, contentWindow, 0, 0, 0, 0, 0,
- false, false, false, false, 1, null, dataTransfer);
- tabItem.dispatchEvent(event);
+ element, startX, startY, { type: "mousedown" });
+
+ for (let i = 1; i <= 2; i++) {
+ EventUtils.synthesizeMouse(
+ element, (startX + incrementX * i), (startY + incrementY * i),
+ { type: "mousemove" });
+ }
- // drag over
- if (offsetX || offsetY) {
- let Ci = Components.interfaces;
- let utils = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).
- getInterface(Ci.nsIDOMWindowUtils);
- let rect = tabItem.getBoundingClientRect();
- for (let i = 1; i <= 5; i++) {
- let left = rect.left + Math.round(i * offsetX / 5);
- let top = rect.top + Math.round(i * offsetY / 5);
- utils.sendMouseEvent("mousemove", left, top, 0, 1, 0);
- }
- event = contentWindow.document.createEvent("DragEvents");
- event.initDragEvent(
- "dragover", true, true, contentWindow, 0, 0, 0, 0, 0,
- false, false, false, false, 0, null, dataTransfer);
- tabItem.dispatchEvent(event);
- }
-
- // drop
- EventUtils.synthesizeMouse(tabItem, 0, 0, { type: "mouseup" }, contentWindow);
- event = contentWindow.document.createEvent("DragEvents");
- event.initDragEvent(
- "drop", true, true, contentWindow, 0, 0, 0, 0, 0,
- false, false, false, false, 0, null, dataTransfer);
- tabItem.dispatchEvent(event);
+ EventUtils.synthesizeMouse(
+ element, (startX + incrementX * 2), (startY + incrementY * 2),
+ { type: "mouseup" });
}
--- a/browser/base/content/test/tabview/browser_tabview_group.js
+++ b/browser/base/content/test/tabview/browser_tabview_group.js
@@ -60,17 +60,17 @@ function onTabViewWindowLoaded() {
testEmptyGroupItem(contentWindow);
}
function testEmptyGroupItem(contentWindow) {
let groupItemCount = contentWindow.GroupItems.groupItems.length;
// create empty group item
- let emptyGroupItem = createEmptyGroupItem(contentWindow, 100);
+ let emptyGroupItem = createEmptyGroupItem(contentWindow, 300, 300, 100, true);
ok(emptyGroupItem.isEmpty(), "This group is empty");
is(contentWindow.GroupItems.groupItems.length, ++groupItemCount,
"The number of groups is increased by 1");
emptyGroupItem.addSubscriber(emptyGroupItem, "close", function() {
emptyGroupItem.removeSubscriber(emptyGroupItem, "close");
@@ -84,17 +84,17 @@ function testEmptyGroupItem(contentWindo
let closeButton = emptyGroupItem.container.getElementsByClassName("close");
ok(closeButton[0], "Group close button exists");
// click the close button
EventUtils.synthesizeMouse(closeButton[0], 1, 1, {}, contentWindow);
}
function testGroupItemWithTabItem(contentWindow) {
- let groupItem = createEmptyGroupItem(contentWindow, 200);
+ let groupItem = createEmptyGroupItem(contentWindow, 300, 300, 200, true);
let tabItemCount = 0;
let onTabViewHidden = function() {
window.removeEventListener("tabviewhidden", onTabViewHidden, false);
is(groupItem.getChildren().length, ++tabItemCount,
"The number of children in new tab group is increased by 1");
@@ -156,22 +156,8 @@ function testGroupItemWithTabItem(conten
window.addEventListener("tabviewshown", onTabViewShown, false);
// click on the + button
let newTabButton = groupItem.container.getElementsByClassName("newTabButton");
ok(newTabButton[0], "New tab button exists");
EventUtils.synthesizeMouse(newTabButton[0], 1, 1, {}, contentWindow);
}
-
-function createEmptyGroupItem(contentWindow, padding) {
- let pageBounds = contentWindow.Items.getPageBounds();
- pageBounds.inset(padding, padding);
-
- let box = new contentWindow.Rect(pageBounds);
- box.width = 300;
- box.height = 300;
-
- let emptyGroupItem = new contentWindow.GroupItem([], { bounds: box,
- immediately: true });
-
- return emptyGroupItem;
-}
--- a/browser/base/content/test/tabview/browser_tabview_orphaned_tabs.js
+++ b/browser/base/content/test/tabview/browser_tabview_orphaned_tabs.js
@@ -62,17 +62,17 @@ function onTabViewWindowLoaded() {
let contentWindow = newWin.document.getElementById("tab-view").contentWindow;
// 1) the tab should belong to a group, and no orphan tabs
ok(tabOne.tabItem.parent, "Tab one belongs to a group");
is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphaned tabs");
// 2) create a group, add a blank tab
- let groupItem = createEmptyGroupItem(contentWindow, 200);
+ let groupItem = createEmptyGroupItem(contentWindow, 300, 300, 200);
let onTabViewHidden = function() {
newWin.removeEventListener("tabviewhidden", onTabViewHidden, false);
// 3) the new group item should have one child and no orphan tab
is(groupItem.getChildren().length, 1, "The group item has an item");
is(contentWindow.GroupItems.getOrphanedTabs().length, 0, "No orphaned tabs");
@@ -105,29 +105,16 @@ function onTabViewWindowLoaded() {
// click on the + button
let newTabButton = groupItem.container.getElementsByClassName("newTabButton");
ok(newTabButton[0], "New tab button exists");
EventUtils.sendMouseEvent({ type: "click" }, newTabButton[0], contentWindow);
}
-function createEmptyGroupItem(contentWindow, padding) {
- let pageBounds = contentWindow.Items.getPageBounds();
- pageBounds.inset(padding, padding);
-
- let box = new contentWindow.Rect(pageBounds);
- box.width = 300;
- box.height = 300;
-
- let emptyGroupItem = new contentWindow.GroupItem([], { bounds: box });
-
- return emptyGroupItem;
-}
-
function whenWindowObservesOnce(win, topic, callback) {
let windowWatcher =
Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
function windowObserver(subject, topicName, aData) {
if (win == subject.QueryInterface(Ci.nsIDOMWindow) && topic == topicName) {
windowWatcher.unregisterNotification(windowObserver);
callback();
}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/head.js
@@ -0,0 +1,51 @@
+/* ***** 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 the utilities for tabview.
+ *
+ * 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):
+ * Raymond Lee <raymond@appcoast.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 ***** */
+
+function createEmptyGroupItem(contentWindow, width, height, padding, noAnimation) {
+ let pageBounds = contentWindow.Items.getPageBounds();
+ pageBounds.inset(padding, padding);
+
+ let box = new contentWindow.Rect(pageBounds);
+ box.width = width;
+ box.height = height;
+
+ let immediately = noAnimation ? true: false;
+ let emptyGroupItem =
+ new contentWindow.GroupItem([], { bounds: box, immediately: immediately });
+
+ return emptyGroupItem;
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -125,34 +125,48 @@
"anonid", "textbox-input-box");
var cxmenu = document.getAnonymousElementByAttribute(textBox,
"anonid", "input-box-contextmenu");
var pasteAndGo;
cxmenu.addEventListener("popupshowing", function() {
if (!pasteAndGo)
return;
var controller = document.commandDispatcher.getControllerForCommand("cmd_paste");
- var enabled = controller.isCommandEnabled("cmd_paste");
- if (enabled)
- pasteAndGo.removeAttribute("disabled");
- else
- pasteAndGo.setAttribute("disabled", "true");
+ var couldBeURL = controller.isCommandEnabled("cmd_paste");
+ if (couldBeURL) {
+ let cbSvc = Cc["@mozilla.org/widget/clipboard;1"].
+ getService(Ci.nsIClipboard);
+ let xferable = Cc["@mozilla.org/widget/transferable;1"].
+ createInstance(Ci.nsITransferable);
+ xferable.addDataFlavor("text/unicode");
+ cbSvc.getData(xferable, cbSvc.kGlobalClipboard);
+ let data = {};
+ xferable.getTransferData("text/unicode", data, {});
+ data = data.value.QueryInterface(Ci.nsISupportsString).data;
+ try {
+ makeURI(data);
+ } catch (ex) { // clipboard data is not a URL
+ couldBeURL = false;
+ }
+ }
+ pasteAndGo.hidden = !couldBeURL;
}, false);
var insertLocation = cxmenu.firstChild;
while (insertLocation.nextSibling &&
insertLocation.getAttribute("cmd") != "cmd_paste")
insertLocation = insertLocation.nextSibling;
if (insertLocation) {
pasteAndGo = document.createElement("menuitem");
let label = Services.strings.createBundle("chrome://browser/locale/browser.properties").
GetStringFromName("pasteAndGo.label");
pasteAndGo.setAttribute("label", label);
pasteAndGo.setAttribute("anonid", "paste-and-go");
- pasteAndGo.setAttribute("oncommand", "goDoCommand('cmd_paste'); gURLBar.handleCommand();");
+ pasteAndGo.setAttribute("oncommand",
+ "gURLBar.value = ''; goDoCommand('cmd_paste'); gURLBar.handleCommand();");
cxmenu.insertBefore(pasteAndGo, insertLocation.nextSibling);
}
]]></constructor>
<destructor><![CDATA[
this._prefs.removeObserver("", this);
this._prefs = null;
this.inputField.controllers.removeController(this._copyCutController);
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -478,17 +478,17 @@ function openTroubleshootingPage()
openUILinkIn("about:support", "tab");
}
/**
* Opens the feedback page for this version of the application.
*/
function openFeedbackPage()
{
- openUILinkIn("http://input.mozilla.com/sad", "tab");
+ openUILinkIn("http://input.mozilla.com/feedback", "tab");
}
#ifdef MOZ_UPDATER
/**
* Opens the update manager and checks for updates to the application.
*/
function checkForUpdates()
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -1156,17 +1156,18 @@ var gEditItemOverlay = {
var folderItem = this._getFolderMenuItem(aNewParent);
// just setting selectItem _does not_ trigger oncommand, so we don't
// recurse
this._folderMenuList.selectedItem = folderItem;
},
- onItemAdded: function EIO_onItemAdded(aItemId, aFolder, aIndex, aItemType) {
+ onItemAdded: function EIO_onItemAdded(aItemId, aFolder, aIndex, aItemType,
+ aURI) {
this._lastNewItem = aItemId;
},
onBeginUpdateBatch: function() { },
onEndUpdateBatch: function() { },
onBeforeItemRemoved: function() { },
onItemRemoved: function() { },
onItemVisited: function() { },
--- a/browser/components/places/content/history-panel.xul
+++ b/browser/components/places/content/history-panel.xul
@@ -41,18 +41,16 @@
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
<!DOCTYPE page [
-<!ENTITY % historyDTD SYSTEM "chrome://browser/locale/history/history.dtd">
-%historyDTD;
<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/places.dtd">
%placesDTD;
]>
<!-- we need to keep id="history-panel" for upgrade and switching
between versions of the browser -->
<page id="history-panel" orient="vertical"
--- a/browser/components/places/content/places.xul
+++ b/browser/components/places/content/places.xul
@@ -386,17 +386,17 @@
<treechildren flex="1"/>
</tree>
<splitter collapse="none" persist="state"></splitter>
<vbox id="contentView" flex="4">
<deck id="contentDeck" flex="1">
<vbox id="defaultView" flex="1">
<vbox id="searchModifiers" hidden="true">
<toolbar id="organizerScopeBar" class="chromeclass-toolbar" align="center">
- <label id="scopeBarTitle" value="&search.label;"/>
+ <label id="scopeBarTitle" value="&search.in.label;"/>
<toolbarbutton id="scopeBarAll" type="radio" group="scopeBar"
oncommand="PlacesQueryBuilder.onScopeSelected(this);"
label="&search.scopeBookmarks.label;"
accesskey="&search.scopeBookmarks.accesskey;"/>
<!--
<toolbarbutton id="scopeBarDownloads" type="radio" group="scopeBar"
oncommand="PlacesQueryBuilder.onScopeSelected(this);"
label="&search.scopeDownloads.label;"
--- a/browser/components/places/tests/browser/browser_library_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_library_views_liveupdate.js
@@ -199,17 +199,17 @@ var bookmarksObserver = {
QueryInterface: function PSB_QueryInterface(aIID) {
if (aIID.equals(Ci.nsINavBookmarkObserver) ||
aIID.equals(Ci.nsISupports))
return this;
throw Cr.NS_NOINTERFACE;
},
// nsINavBookmarkObserver
- onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex) {
+ onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex, aURI) {
var node = null;
var index = null;
[node, index] = getNodeForTreeItem(aItemId, gLibrary.PlacesOrganizer._places);
// Left pane should not be updated for normal bookmarks or separators.
var type = PlacesUtils.bookmarks.getItemType(aItemId);
switch (type) {
case PlacesUtils.bookmarks.TYPE_BOOKMARK:
var uriString = PlacesUtils.bookmarks.getBookmarkURI(aItemId).spec;
--- a/browser/components/places/tests/browser/browser_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_views_liveupdate.js
@@ -218,17 +218,17 @@ var bookmarksObserver = {
if (aIID.equals(Ci.nsINavBookmarkObserver) ||
aIID.equals(Ci.nsISupports))
return this;
throw Cr.NS_NOINTERFACE;
},
// nsINavBookmarkObserver
onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex,
- aItemType) {
+ aItemType, aURI) {
var views = getViewsForFolder(aFolderId);
ok(views.length > 0, "Found affected views (" + views.length + "): " + views);
// Check that item has been added in the correct position.
for (var i = 0; i < views.length; i++) {
var [node, index] = searchItemInView(aItemId, views[i]);
isnot(node, null, "Found new Places node in " + views[i]);
is(index, aIndex, "Node is at index " + index);
--- a/browser/components/places/tests/unit/test_placesTxn.js
+++ b/browser/components/places/tests/unit/test_placesTxn.js
@@ -48,17 +48,17 @@ var annosvc = PlacesUtils.annotations;
// create and add bookmarks observer
var observer = {
onBeginUpdateBatch: function() {
this._beginUpdateBatch = true;
},
onEndUpdateBatch: function() {
this._endUpdateBatch = true;
},
- onItemAdded: function(id, folder, index, itemType) {
+ onItemAdded: function(id, folder, index, itemType, uri) {
this._itemAddedId = id;
this._itemAddedParent = folder;
this._itemAddedIndex = index;
this._itemAddedType = itemType;
},
onBeforeItemRemoved: function(id) {
},
onItemRemoved: function(id, folder, index, itemType) {
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_theming.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_theming.js
@@ -30,36 +30,36 @@
* 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 ***** */
-// This test makes sure that browsingmode attribute of the window is correctly
+// This test makes sure that privatebrowsingmode attribute of the window is correctly
// switched with private browsing mode changes.
function test() {
// initialization
gPrefService.setBoolPref("browser.privatebrowsing.keep_current_session", true);
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
let docRoot = document.documentElement;
- is(docRoot.getAttribute("browsingmode"), "normal",
- "browsingmode should be \"normal\" initially");
+ ok(!docRoot.hasAttribute("privatebrowsingmode"),
+ "privatebrowsingmode should not be present in normal mode");
// enter private browsing mode
pb.privateBrowsingEnabled = true;
- is(docRoot.getAttribute("browsingmode"), "private",
- "browsingmode should be \"private\" inside the private browsing mode");
+ is(docRoot.getAttribute("privatebrowsingmode"), "temporary",
+ "privatebrowsingmode should be \"temporary\" inside the private browsing mode");
// leave private browsing mode
pb.privateBrowsingEnabled = false;
- is(docRoot.getAttribute("browsingmode"), "normal",
- "browsingmode should be \"normal\" outside the private browsing mode");
+ ok(!docRoot.hasAttribute("privatebrowsingmode"),
+ "privatebrowsingmode should not be present in normal mode");
// cleanup
gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
}
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -599,17 +599,18 @@
while (insertLocation.nextSibling &&
insertLocation.getAttribute("cmd") != "cmd_paste")
insertLocation = insertLocation.nextSibling;
if (insertLocation) {
element = document.createElementNS(kXULNS, "menuitem");
label = this._stringBundle.getString("cmd_pasteAndSearch");
element.setAttribute("label", label);
element.setAttribute("anonid", "paste-and-search");
- element.setAttribute("oncommand", "goDoCommand('cmd_paste'); document.getElementById('searchbar').handleSearchCommand();");
+ element.setAttribute("oncommand",
+ "BrowserSearch.searchBar.value = ''; goDoCommand('cmd_paste'); BrowserSearch.searchBar.handleSearchCommand();");
cxmenu.insertBefore(element, insertLocation.nextSibling);
pasteAndSearch = element;
}
element = document.createElementNS(kXULNS, "menuitem");
label = this._stringBundle.getString("cmd_clearHistory");
akey = this._stringBundle.getString("cmd_clearHistory_accesskey");
element.setAttribute("label", label);
--- a/browser/components/search/test/Makefile.in
+++ b/browser/components/search/test/Makefile.in
@@ -40,18 +40,19 @@ topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/components/search/test
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = browser_405664.js \
- browser_415700.js \
+ browser_addEngine.js \
testEngine.xml \
+ testEngine.src \
browser_426329.js \
426329.xml \
browser_483086.js \
483086-1.xml \
483086-2.xml \
test.html \
$(NULL)
rename from browser/components/search/test/browser_415700.js
rename to browser/components/search/test/browser_addEngine.js
--- a/browser/components/search/test/browser_415700.js
+++ b/browser/components/search/test/browser_addEngine.js
@@ -30,56 +30,139 @@
* 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 ***** */
var gSS = Services.search;
-function observers(aSubject, aTopic, aData) {
+function observer(aSubject, aTopic, aData) {
+ if (!gCurrentTest) {
+ info("Observer called with no test active");
+ return;
+ }
+
+ let engine = aSubject.QueryInterface(Ci.nsISearchEngine);
+ info("Observer: " + aData + " for " + engine.name);
+ let method;
switch (aData) {
case "engine-added":
- test2();
+ if (gCurrentTest.added)
+ method = "added"
break;
case "engine-current":
- test3();
+ if (gCurrentTest.current)
+ method = "current";
break;
case "engine-removed":
- test4();
+ if (gCurrentTest.removed)
+ method = "removed";
break;
}
+
+ if (method)
+ gCurrentTest[method](engine);
+}
+
+function checkEngine(checkObj, engineObj) {
+ info("Checking engine");
+ for (var prop in checkObj)
+ is(checkObj[prop], engineObj[prop], prop + " is correct");
+}
+
+var gTests = [
+ {
+ name: "opensearch install",
+ engine: {
+ name: "Foo",
+ alias: null,
+ description: "Foo Search",
+ searchForm: "http://mochi.test:8888/browser/browser/components/search/test/",
+ type: Ci.nsISearchEngine.TYPE_OPENSEARCH
+ },
+ run: function () {
+ gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/testEngine.xml",
+ Ci.nsISearchEngine.DATA_XML, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC",
+ false);
+ },
+ added: function (engine) {
+ ok(engine, "engine was added.");
+
+ checkEngine(this.engine, engine);
+
+ let engineFromSS = gSS.getEngineByName(this.engine.name);
+ is(engine, engineFromSS, "engine is obtainable via getEngineByName");
+
+ let aEngine = gSS.getEngineByAlias("fooalias");
+ ok(!aEngine, "Alias was not parsed from engine description");
+
+ gSS.currentEngine = engine;
+ },
+ current: function (engine) {
+ let currentEngine = gSS.currentEngine;
+ is(engine, currentEngine, "engine is current");
+ is(engine.name, this.engine.name, "current engine was changed successfully");
+
+ gSS.removeEngine(engine);
+ },
+ removed: function (engine) {
+ let currentEngine = gSS.currentEngine;
+ ok(currentEngine, "An engine is present.");
+ isnot(currentEngine.name, this.engine.name, "Current engine reset after removal");
+
+ nextTest();
+ }
+ },
+ {
+ name: "sherlock install",
+ engine: {
+ name: "Test Sherlock",
+ alias: null,
+ description: "Test Description",
+ searchForm: "http://example.com/searchform",
+ type: Ci.nsISearchEngine.TYPE_SHERLOCK
+ },
+ run: function () {
+ gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/testEngine.src",
+ Ci.nsISearchEngine.DATA_TEXT, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC",
+ false);
+ },
+ added: function (engine) {
+ ok(engine, "engine was added.");
+ checkEngine(this.engine, engine);
+
+ let engineFromSS = gSS.getEngineByName(this.engine.name);
+ is(engineFromSS, engine, "engine is obtainable via getEngineByName");
+
+ gSS.removeEngine(engine);
+ },
+ removed: function (engine) {
+ let currentEngine = gSS.currentEngine;
+ ok(currentEngine, "An engine is present.");
+ isnot(currentEngine.name, this.engine.name, "Current engine reset after removal");
+
+ nextTest();
+ }
+ }
+];
+
+var gCurrentTest = null;
+function nextTest() {
+ if (gTests.length) {
+ gCurrentTest = gTests.shift();
+ info("Running " + gCurrentTest.name);
+ gCurrentTest.run();
+ } else
+ executeSoon(finish);
}
function test() {
waitForExplicitFinish();
- Services.obs.addObserver(observers, "browser-search-engine-modified", false);
+ Services.obs.addObserver(observer, "browser-search-engine-modified", false);
+ registerCleanupFunction(cleanup);
- gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/testEngine.xml",
- Ci.nsISearchEngine.DATA_XML, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC",
- false);
+ nextTest();
}
-function test2() {
- var engine = gSS.getEngineByName("Foo");
- ok(engine, "Engine was added.");
-
- var aEngine = gSS.getEngineByAlias("fooalias");
- ok(!aEngine, "Alias was not parsed from engine description");
-
- gSS.currentEngine = engine;
+function cleanup() {
+ Services.obs.removeObserver(observer, "browser-search-engine-modified");
}
-
-function test3() {
- var engine = gSS.currentEngine;
- is(engine.name, "Foo", "Current engine was changed successfully");
-
- gSS.removeEngine(engine);
-}
-
-function test4() {
- var engine = gSS.currentEngine;
- ok(engine, "An engine is present.");
- isnot(engine.name, "Foo", "Current engine reset after removal");
-
- Services.obs.removeObserver(observers, "browser-search-engine-modified");
- finish();
-}
new file mode 100644
--- /dev/null
+++ b/browser/components/search/test/testEngine.src
@@ -0,0 +1,11 @@
+<search
+ name="Test Sherlock"
+ description="Test Description"
+ method="GET"
+ searchform="http://example.com/searchform"
+ action="http://example.com/action"
+ queryCharset="UTF-8"
+>
+ <input name="userParam" user>
+ <input name="param" value="value">
+</search>
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -31,16 +31,17 @@
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
+const Cu = Components.utils;
var gStateObject;
var gTreeData;
// Page initialization
window.onload = function() {
// the crashed session state is kept inside a textbox so that SessionStore picks it up
@@ -49,23 +50,36 @@ window.onload = function() {
if (!sessionData.value) {
var ss = Cc["@mozilla.org/browser/sessionstartup;1"].getService(Ci.nsISessionStartup);
sessionData.value = ss.state;
if (!sessionData.value) {
document.getElementById("errorTryAgain").disabled = true;
return;
}
}
+
+ // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
+ if (sessionData.value.charAt(0) == '(')
+ sessionData.value = sessionData.value.slice(1, -1);
+ try {
+ gStateObject = JSON.parse(sessionData.value);
+ }
+ catch (exJSON) {
+ var s = new Cu.Sandbox("about:blank");
+ 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.
+ sessionData.value = JSON.stringify(gStateObject);
+ }
+
// make sure the data is tracked to be restored in case of a subsequent crash
var event = document.createEvent("UIEvents");
event.initUIEvent("input", true, true, window, 0);
sessionData.dispatchEvent(event);
-
- gStateObject = JSON.parse(sessionData.value);
-
+
initTreeView();
document.getElementById("errorTryAgain").focus();
};
function initTreeView() {
var tabList = document.getElementById("tabList");
var winLabel = tabList.getAttribute("_window_label");
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -1263,25 +1263,42 @@ SessionStoreService.prototype = {
if (aWindow.__SSi && this._windows[aWindow.__SSi].extData &&
this._windows[aWindow.__SSi].extData[aKey])
delete this._windows[aWindow.__SSi].extData[aKey];
else
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
},
getTabValue: function sss_getTabValue(aTab, aKey) {
- var data = aTab.__SS_extdata || {};
+ let data = {};
+ if (aTab.__SS_extdata) {
+ data = aTab.__SS_extdata;
+ }
+ else if (aTab.linkedBrowser.__SS_data && aTab.linkedBrowser.__SS_data.extData) {
+ // If the tab hasn't been fully restored, get the data from the to-be-restored data
+ data = aTab.linkedBrowser.__SS_data.extData;
+ }
return data[aKey] || "";
},
setTabValue: function sss_setTabValue(aTab, aKey, aStringValue) {
- if (!aTab.__SS_extdata) {
+ // If the tab hasn't been restored, then set the data there, otherwise we
+ // could lose newly added data.
+ let saveTo;
+ if (aTab.__SS_extdata) {
+ saveTo = aTab.__SS_extdata;
+ }
+ else if (aTab.linkedBrowser.__SS_data && aTab.linkedBrowser.__SS_data.extData) {
+ saveTo = aTab.linkedBrowser.__SS_data.extData;
+ }
+ else {
aTab.__SS_extdata = {};
+ saveTo = aTab.__SS_extdata;
}
- aTab.__SS_extdata[aKey] = aStringValue;
+ saveTo[aKey] = aStringValue;
this.saveStateDelayed(aTab.ownerDocument.defaultView);
},
deleteTabValue: function sss_deleteTabValue(aTab, aKey) {
if (aTab.__SS_extdata && aTab.__SS_extdata[aKey])
delete aTab.__SS_extdata[aKey];
else
throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -112,18 +112,20 @@ include $(topsrcdir)/config/rules.mk
browser_500328.js \
browser_514751.js \
browser_522545.js \
browser_524745.js \
browser_528776.js \
browser_579868.js \
browser_579879.js \
browser_580512.js \
+ browser_581593.js \
browser_586147.js \
browser_586068-cascaded_restore.js \
+ browser_590268.js \
browser_600545.js \
$(NULL)
ifneq ($(OS_ARCH),Darwin)
_BROWSER_TEST_FILES += \
browser_597071.js \
$(NULL)
endif
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_581593.js
@@ -0,0 +1,90 @@
+/* ***** 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 sessionstore test code.
+ *
+ * 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):
+ * Paul O’Shannessy <paul@oshannessy.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 ***** */
+
+Cu.import("resource://gre/modules/Services.jsm");
+let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+ getService(Ci.nsISessionStore);
+
+let stateBackup = ss.getBrowserState();
+
+
+function test() {
+ /** Test for bug 581593 **/
+ waitForExplicitFinish();
+
+ let oldState = { windows: [{ tabs: [{ entries: [{ url: "example.com" }] }] }]};
+ let pageData = {
+ url: "about:sessionrestore",
+ formdata: { "#sessionData": "(" + JSON.stringify(oldState) + ")" }
+ };
+ let state = { windows: [{ tabs: [{ entries: [pageData] }] }] };
+
+ // The form data will be restored before SSTabRestored, so we want to listen
+ // for that on the currently selected tab (it will be reused)
+ gBrowser.selectedTab.addEventListener("SSTabRestored", onSSTabRestored, true);
+
+ ss.setBrowserState(JSON.stringify(state));
+}
+
+function onSSTabRestored(aEvent) {
+ info("SSTabRestored event");
+ gBrowser.selectedTab.removeEventListener("SSTabRestored", onSSTabRestored, true);
+ gBrowser.selectedBrowser.addEventListener("input", onInput, true);
+}
+
+function onInput(aEvent) {
+ info("input event");
+ gBrowser.selectedBrowser.removeEventListener("input", onInput, true);
+
+ // This is an ok way to check this because we will make sure that the text
+ // field is parsable.
+ let val = gBrowser.selectedBrowser.contentDocument.getElementById("sessionData").value;
+ try {
+ JSON.parse(val);
+ ok(true, "JSON.parse succeeded");
+ }
+ catch (e) {
+ ok(false, "JSON.parse failed");
+ }
+ cleanup();
+}
+
+function cleanup() {
+ ss.setBrowserState(stateBackup);
+ executeSoon(finish);
+}
+
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_590268.js
@@ -0,0 +1,148 @@
+/* ***** 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 sessionstore test code.
+ *
+ * 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):
+ * Paul O’Shannessy <paul@oshannessy.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const NUM_TABS = 12;
+
+Cu.import("resource://gre/modules/Services.jsm");
+let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+ getService(Ci.nsISessionStore);
+
+let stateBackup = ss.getBrowserState();
+
+
+function test() {
+ /** Test for Bug 590268 - Provide access to sessionstore tab data sooner **/
+ waitForExplicitFinish();
+
+ let startedTest = false;
+
+ // wasLoaded will be used to keep track of tabs that have already had SSTabRestoring
+ // fired for them.
+ let wasLoaded = { };
+ let restoringTabsCount = 0;
+ let uniq2 = { };
+ let uniq2Count = 0;
+ let state = { windows: [{ tabs: [] }] };
+ // We're going to put a bunch of tabs into this state
+ for (let i = 0; i < NUM_TABS; i++) {
+ let uniq = r();
+ let tabData = {
+ entries: [{ url: "http://example.com/#" + i }],
+ extData: { "uniq": uniq }
+ };
+ state.windows[0].tabs.push(tabData);
+ wasLoaded[uniq] = false;
+ }
+
+
+ function onSSTabRestoring(aEvent) {
+ restoringTabsCount++;
+ let uniq = ss.getTabValue(aEvent.originalTarget, "uniq");
+ wasLoaded[uniq] = true;
+
+ // On the first SSTabRestoring we're going to run the the real test.
+ // We'll keep this listener around so we can keep marking tabs as restored.
+ if (restoringTabsCount == 1)
+ onFirstSSTabRestoring();
+ else if (restoringTabsCount == NUM_TABS)
+ onLastSSTabRestoring();
+ }
+
+ // This does the actual testing. SSTabRestoring should be firing on tabs from
+ // left to right, so we're going to start with the rightmost tab.
+ function onFirstSSTabRestoring() {
+ info("onFirstSSTabRestoring...");
+ for (let i = gBrowser.tabs.length - 1; i >= 0; i--) {
+ let tab = gBrowser.tabs[i];
+ let actualUniq = ss.getTabValue(tab, "uniq");
+ let expectedUniq = state.windows[0].tabs[i].extData["uniq"];
+
+ if (wasLoaded[actualUniq]) {
+ info("tab " + i + ": already restored");
+ continue;
+ }
+ is(actualUniq, expectedUniq, "tab " + i + ": extData was correct");
+
+ // Now we're going to set a piece of data back on the tab so it can be read
+ // to test setting a value "early".
+ uniq2[actualUniq] = r();
+ ss.setTabValue(tab, "uniq2", uniq2[actualUniq]);
+ // This will be used in the final comparison to make sure we checked the
+ // same number as we set.
+ uniq2Count++;
+ }
+ }
+
+ function onLastSSTabRestoring() {
+ let checked = 0;
+ for (let i = 0; i < gBrowser.tabs.length; i++) {
+ let tab = gBrowser.tabs[i];
+ let uniq = ss.getTabValue(tab, "uniq");
+
+ // Look to see if we set a uniq2 value for this uniq value
+ if (uniq in uniq2) {
+ is(ss.getTabValue(tab, "uniq2"), uniq2[uniq], "tab " + i + " has correct uniq2 value");
+ checked++;
+ }
+ }
+ is(checked, uniq2Count, "checked the same number of uniq2 as we set");
+ cleanup();
+ }
+
+ function cleanup() {
+ // remove the event listener and clean up before finishing
+ gBrowser.tabContainer.removeEventListener("SSTabRestoring", onSSTabRestoring, false);
+ // Put this in an executeSoon because we still haven't called restoreNextTab
+ // in sessionstore for the last tab (we'll call it after this). We end up
+ // trying to restore the tab (since we then add a closed tab to the array).
+ executeSoon(function() {
+ ss.setBrowserState(stateBackup);
+ executeSoon(finish);
+ });
+ }
+
+ // Add the event listener
+ gBrowser.tabContainer.addEventListener("SSTabRestoring", onSSTabRestoring, false);
+ // Restore state
+ ss.setBrowserState(JSON.stringify(state));
+}
+
+// Helper function to create a random value
+function r() {
+ return "" + Date.now() + Math.random();
+}
+
--- a/browser/fuel/src/fuelApplication.js
+++ b/browser/fuel/src/fuelApplication.js
@@ -389,17 +389,17 @@ Bookmark.prototype = {
// observer
onBeginUpdateBatch : function bm_obub() {
},
onEndUpdateBatch : function bm_oeub() {
},
- onItemAdded : function bm_oia(aId, aFolder, aIndex) {
+ onItemAdded : function bm_oia(aId, aFolder, aIndex, aItemType, aURI) {
// bookmark object doesn't exist at this point
},
onBeforeItemRemoved : function bm_obir(aId) {
},
onItemRemoved : function bm_oir(aId, aFolder, aIndex) {
if (this._id == aId)
@@ -542,17 +542,17 @@ BookmarkFolder.prototype = {
// observer
onBeginUpdateBatch : function bmf_obub() {
},
onEndUpdateBatch : function bmf_oeub() {
},
- onItemAdded : function bmf_oia(aId, aFolder, aIndex) {
+ onItemAdded : function bmf_oia(aId, aFolder, aIndex, aItemType, aURI) {
// handle root folder events
if (!this._parent)
this._events.dispatch("add", aId);
// handle this folder events
if (this._id == aFolder)
this._events.dispatch("addchild", aId);
},
deleted file mode 100644
--- a/browser/locales/en-US/chrome/browser/history/history.dtd
+++ /dev/null
@@ -1,26 +0,0 @@
-<!ENTITY find.label "Search:">
-<!ENTITY find.accesskey "S">
-<!ENTITY expand.label "Expand">
-<!ENTITY expand.accesskey "E">
-<!ENTITY collapse.label "Collapse">
-<!ENTITY collapse.accesskey "C">
-<!ENTITY byDate.label "By Date">
-<!ENTITY byDate.accesskey "D">
-<!ENTITY bySite.label "By Site">
-<!ENTITY bySite.accesskey "S">
-<!ENTITY view.label "View">
-<!ENTITY view.accesskey "w">
-<!ENTITY byMostVisited.label "By Most Visited">
-<!ENTITY byMostVisited.accesskey "V">
-<!ENTITY byLastVisited.label "By Last Visited">
-<!ENTITY byLastVisited.accesskey "L">
-<!ENTITY byDayAndSite.label "By Date and Site">
-<!ENTITY byDayAndSite.accesskey "t">
-<!ENTITY openLinkInWindow.label "Open">
-<!ENTITY openLinkInWindow.accesskey "O">
-<!ENTITY openInNewTab.label "Open in New Tab">
-<!ENTITY openInNewTab.accesskey "T">
-<!ENTITY openInNewWindow.label "Open in New Window">
-<!ENTITY openInNewWindow.accesskey "W">
-<!ENTITY copyLink.label "Copy Link Location">
-<!ENTITY copyLink.accesskey "C">
--- a/browser/locales/en-US/chrome/browser/places/places.dtd
+++ b/browser/locales/en-US/chrome/browser/places/places.dtd
@@ -89,16 +89,18 @@
<!ENTITY col.visitcount.label "Visit Count">
<!ENTITY col.keyword.label "Keyword">
<!ENTITY col.description.label "Description">
<!ENTITY col.dateadded.label "Added">
<!ENTITY col.lastmodified.label "Last Modified">
<!ENTITY search.label "Search:">
<!ENTITY search.accesskey "S">
+
+<!ENTITY search.in.label "Search in:">
<!ENTITY search.scopeFolder.label "Selected Folder">
<!ENTITY search.scopeFolder.accesskey "r">
<!ENTITY search.scopeBookmarks.label "Bookmarks">
<!ENTITY search.scopeBookmarks.accesskey "k">
<!ENTITY search.scopeDownloads.label "Downloads">
<!ENTITY search.scopeDownloads.accesskey "D">
<!ENTITY search.scopeHistory.label "History">
<!ENTITY search.scopeHistory.accesskey "H">
@@ -118,8 +120,23 @@
<!ENTITY forwardButton.tooltip "Go forward">
<!ENTITY detailsPane.more.label "More">
<!ENTITY detailsPane.more.accesskey "e">
<!ENTITY detailsPane.less.label "Less">
<!ENTITY detailsPane.less.accesskey "e">
<!ENTITY detailsPane.noPreviewAvailable.label "Preview">
<!ENTITY detailsPane.selectAnItemText.description "Select an item to view and edit its properties">
+
+<!ENTITY find.label "Search:">
+<!ENTITY find.accesskey "S">
+<!ENTITY view.label "View">
+<!ENTITY view.accesskey "w">
+<!ENTITY byDate.label "By Date">
+<!ENTITY byDate.accesskey "D">
+<!ENTITY bySite.label "By Site">
+<!ENTITY bySite.accesskey "S">
+<!ENTITY byMostVisited.label "By Most Visited">
+<!ENTITY byMostVisited.accesskey "V">
+<!ENTITY byLastVisited.label "By Last Visited">
+<!ENTITY byLastVisited.accesskey "L">
+<!ENTITY byDayAndSite.label "By Date and Site">
+<!ENTITY byDayAndSite.accesskey "t">
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -40,17 +40,16 @@
locale/browser/preferences/selectBookmark.dtd (%chrome/browser/preferences/selectBookmark.dtd)
locale/browser/places/moveBookmarks.dtd (%chrome/browser/places/moveBookmarks.dtd)
#ifdef MOZ_SAFE_BROWSING
locale/browser/safebrowsing/phishing-afterload-warning-message.dtd (%chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd)
locale/browser/safebrowsing/report-phishing.dtd (%chrome/browser/safebrowsing/report-phishing.dtd)
#endif
locale/browser/feeds/subscribe.dtd (%chrome/browser/feeds/subscribe.dtd)
locale/browser/feeds/subscribe.properties (%chrome/browser/feeds/subscribe.properties)
- locale/browser/history/history.dtd (%chrome/browser/history/history.dtd)
locale/browser/migration/migration.dtd (%chrome/browser/migration/migration.dtd)
locale/browser/migration/migration.properties (%chrome/browser/migration/migration.properties)
locale/browser/preferences/advanced.dtd (%chrome/browser/preferences/advanced.dtd)
* locale/browser/preferences/advanced-scripts.dtd (%chrome/browser/preferences/advanced-scripts.dtd)
locale/browser/preferences/applicationManager.dtd (%chrome/browser/preferences/applicationManager.dtd)
locale/browser/preferences/applicationManager.properties (%chrome/browser/preferences/applicationManager.properties)
locale/browser/preferences/colors.dtd (%chrome/browser/preferences/colors.dtd)
locale/browser/preferences/cookies.dtd (%chrome/browser/preferences/cookies.dtd)
--- a/browser/locales/shipped-locales
+++ b/browser/locales/shipped-locales
@@ -41,13 +41,14 @@ nso
pa-IN
pl
pt-BR
pt-PT
ro
ru
sk
son
+sq
sv-SE
tr
uk
zh-CN
zh-TW
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -469,21 +469,25 @@ menuitem:not([type]) {
#bookmarksShowAll {
list-style-image: url("chrome://browser/skin/Toolbar-small.png");
-moz-image-region: rect(0px 48px 16px 32px);
}
#bookmarksToolbarFolderMenu,
#BMB_bookmarksToolbar {
- list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
+ list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
+}
+
+#BMB_bookmarkThisPage {
+ list-style-image: url("chrome://browser/skin/places/starPage.png");
}
#BMB_unsortedBookmarks {
- list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
+ list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
}
#menu_openDownloads {
list-style-image: url("chrome://browser/skin/Toolbar-small.png");
-moz-image-region: rect(0px 16px 16px 0px);
}
#menu_pageInfo,
--- a/browser/themes/winstripe/browser/browser-aero.css
+++ b/browser/themes/winstripe/browser/browser-aero.css
@@ -1,14 +1,16 @@
%define WINSTRIPE_AERO
%include browser.css
%undef WINSTRIPE_AERO
%define customToolbarColor hsl(214,44%,87%)
%define glassToolbarBorderColor rgb(40%,40%,40%)
+%define glassActiveBorderColor rgb(37, 44, 51)
+%define glassInactiveBorderColor rgb(102, 102, 102)
@media all and (-moz-windows-default-theme) {
#navigator-toolbox > toolbar:not(:-moz-lwtheme) {
background-color: @customToolbarColor@;
}
.tabbrowser-tab[selected="true"]:not(:-moz-lwtheme) {
background-image: -moz-linear-gradient(white, @toolbarHighlight@ 30%),
@@ -26,16 +28,22 @@
border-top: none;
-moz-border-left-colors: rgba(255,255,255,.5) rgba(83,42,6,.9);
-moz-border-bottom-colors: rgba(255,255,255,.5) rgba(83,42,6,.9);
-moz-border-right-colors: rgba(255,255,255,.5) rgba(83,42,6,.9);
box-shadow: 0 1px 0 rgba(255,255,255,.25) inset,
0 0 2px 1px rgba(255,255,255,.25) inset;
}
+ #main-window[privatebrowsingmode=temporary] #appmenu-button:not(:-moz-window-inactive) {
+ -moz-border-left-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
+ -moz-border-bottom-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
+ -moz-border-right-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
+ }
+
#appmenu-button:-moz-window-inactive {
-moz-border-left-colors: rgba(255,255,255,.4) rgba(0,0,0,.5);
-moz-border-bottom-colors: rgba(255,255,255,.4) rgba(0,0,0,.5);
-moz-border-right-colors: rgba(255,255,255,.4) rgba(0,0,0,.5);
box-shadow: 0 0 0 1px rgba(255,255,255,.25) inset;
}
/* Bug 413060, comment 16: Vista Aero is a special case where we use a
@@ -80,16 +88,34 @@
-moz-appearance: -moz-win-borderless-glass;
background: transparent;
}
#main-window[chromemargin^="0,"][sizemode="normal"]:not([inFullscreen="true"]) #navigator-toolbox {
margin-top: -7px;
}
+ /* Artificially draw window borders that are covered by lwtheme, see bug 591930. */
+ #main-window[sizemode="normal"] > #titlebar > #titlebar-content:-moz-lwtheme {
+ border-top: 2px solid;
+ -moz-border-top-colors: @glassActiveBorderColor@ rgba(255,255,255,.6);
+ }
+
+ #main-window[sizemode="normal"] > #titlebar > #titlebar-content:-moz-lwtheme:-moz-window-inactive {
+ -moz-border-top-colors: @glassInactiveBorderColor@ rgba(255,255,255,.6);
+ }
+
+ #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #appmenu-button-container:-moz-lwtheme {
+ margin-top: -1px;
+ }
+
+ #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #titlebar-buttonbox:-moz-lwtheme {
+ margin-top: -2px;
+ }
+
#main-window:not(:-moz-lwtheme)[inFullscreen="true"] {
-moz-appearance: none;
background-color: #556;
}
#toolbar-menubar:not(:-moz-lwtheme),
#TabsToolbar[tabsontop="true"]:not(:-moz-lwtheme),
#navigator-toolbox[tabsontop="false"] > #nav-bar:not(:-moz-lwtheme),
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -121,39 +121,59 @@
color: white;
text-shadow: 0 0 1px rgba(0,0,0,.7),
0 1px 1.5px rgba(0,0,0,.5);
font-weight: bold;
padding: .1em 1.5em .15em;
margin: 0;
}
+#main-window[privatebrowsingmode=temporary] #appmenu-button:not(:-moz-window-inactive) {
+ background-image: -moz-linear-gradient(rgb(153,38,211), rgb(105,19,163) 95%);
+ border-color: rgba(43,8,65,.9);
+}
+
#appmenu-button:-moz-window-inactive {
background-image: none;
border-color: rgba(0,0,0,.4);
}
#appmenu-button:hover:not(:active):not([open]) {
background-image: -moz-radial-gradient(center bottom, farthest-side, rgba(252,240,89,.5) 10%, rgba(252,240,89,0) 70%),
-moz-radial-gradient(center bottom, farthest-side, rgb(236,133,0), rgba(255,229,172,0)),
-moz-linear-gradient(rgb(246,170,69), rgb(209,74,0) 95%);
border-color: rgba(83,42,6,.9);
box-shadow: 0 1px 0 rgba(255,255,255,.1) inset,
0 0 1.5px 1px rgba(250,234,169,.7) inset,
0 -1px 0 rgba(250,234,169,.5) inset;
}
+#main-window[privatebrowsingmode=temporary] #appmenu-button:hover:not(:active):not([open]) {
+ background-image: -moz-radial-gradient(center bottom, farthest-side, rgba(240,193,255,.5) 10%, rgba(240,193,255,0) 70%),
+ -moz-radial-gradient(center bottom, farthest-side, rgb(192,81,247), rgba(236,172,255,0)),
+ -moz-linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%);
+ border-color: rgba(43,8,65,.9);
+ box-shadow: 0 1px 0 rgba(255,255,255,.1) inset,
+ 0 0 2px 1px rgba(240,193,255,.7) inset,
+ 0 -1px 0 rgba(240,193,255,.5) inset;
+}
+
#appmenu-button:hover:active,
#appmenu-button[open] {
background-image: -moz-linear-gradient(rgb(246,170,69), rgb(209,74,0) 95%);
border-radius: 0;
box-shadow: 0 2px 3px rgba(0,0,0,.4) inset,
0 1px 1px rgba(0,0,0,.2) inset;
}
+#main-window[privatebrowsingmode=temporary] #appmenu-button:hover:active,
+#main-window[privatebrowsingmode=temporary] #appmenu-button[open] {
+ background-image: -moz-linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%);
+}
+
#appmenu-button > .button-box {
border-style: none;
padding: 0;
}
#appmenu-button > .button-box > .button-menu-dropmarker {
list-style-image: url(appmenu-dropmarker.png);
width: auto;
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -346,16 +346,17 @@ user_pref("shell.checkDefaultClient", fa
user_pref("browser.warnOnQuit", false);
user_pref("accessibility.typeaheadfind.autostart", false);
user_pref("javascript.options.showInConsole", true);
user_pref("devtools.errorconsole.enabled", true);
user_pref("layout.debug.enable_data_xbl", true);
user_pref("browser.EULA.override", true);
user_pref("javascript.options.tracejit.content", true);
user_pref("javascript.options.methodjit.content", true);
+user_pref("javascript.options.jitprofiling.content", true);
user_pref("gfx.color_management.force_srgb", true);
user_pref("network.manage-offline-status", false);
user_pref("test.mousescroll", true);
user_pref("security.default_personal_cert", "Select Automatically"); // Need to client auth test be w/o any dialogs
user_pref("network.http.prompt-temp-redirect", false);
user_pref("media.cache_size", 100);
user_pref("security.warn_viewing_mixed", false);
user_pref("app.update.enabled", false);
--- a/configure.in
+++ b/configure.in
@@ -5001,18 +5001,18 @@ NECKO_WIFI=1
NECKO_COOKIES=1
NECKO_DISK_CACHE=1
NECKO_PROTOCOLS_DEFAULT="about data file ftp http res viewsource wyciwyg"
USE_ARM_KUSER=
BUILD_CTYPES=1
XPC_IDISPATCH_SUPPORT=
-case "$target_os" in
-darwin*|*wince*|*winmo*)
+case "${target}" in
+*android*|*darwin*|*wince*|*winmo*)
ACCESSIBILITY=
;;
*)
ACCESSIBILITY=1
;;
esac
case "$target_os" in
@@ -8507,41 +8507,16 @@ if test "$MOZ_TREE_CAIRO"; then
AC_CHECK_HEADER(d3d9.h, MOZ_ENABLE_D3D9_LAYER=1)
dnl D3D10 Layers depend on D2D Surfaces.
if test -n "$WIN32_D2D_SURFACE_FEATURE"; then
AC_CHECK_HEADER(d3d10.h, MOZ_ENABLE_D3D10_LAYER=1)
fi
- AC_TRY_COMPILE([#include <ddraw.h>], [int foo = DDLOCK_WAITNOTBUSY;], HAS_DDRAW=1, HAS_DDRAW=)
- if test -z "$HAS_DDRAW"; then
- AC_MSG_WARN([DirectDraw ddraw.h header not found or it's missing DDLOCK_WAITNOTBUSY, disabling DirectDraw surface. If you have an older SDK (such as the CE5 SDK), try copying in ddraw.lib and ddraw.h from the WM6 SDK.])
- DDRAW_SURFACE_FEATURE=
- else
- DDRAW_SURFACE_FEATURE="#define CAIRO_HAS_DDRAW_SURFACE 1"
- fi
-
- if test -z "$OGLES_SDK_DIR"; then
- OGLES_SURFACE_FEATURE=
- else
- AC_TRY_COMPILE([
- #include <EGL/egl.h>
- #include <EGL/eglext.h>
- #include <GLES2/gl2.h>
- #include <GLES2/gl2ext.h>
- ], [ EGLDisplay _cairo_ddraw_egl_dpy = EGL_NO_DISPLAY;], HAS_OGLES=1, HAS_OGLES=)
- if test -z "$HAS_OGLES"; then
- AC_MSG_WARN([OpenGL ES2 headers not found, disabling OpenGL acceleration surfaces.])
- OGLES_SURFACE_FEATURE=
- else
- OGLES_SURFACE_FEATURE="#define CAIRO_DDRAW_USE_GL 1"
- fi
- fi
-
PDF_SURFACE_FEATURE="#define CAIRO_HAS_PDF_SURFACE 1"
fi
if test "$MOZ_WIDGET_TOOLKIT" = "os2"; then
OS2_SURFACE_FEATURE="#define CAIRO_HAS_OS2_SURFACE 1"
FT_FONT_FEATURE="#define CAIRO_HAS_FT_FONT 1"
PDF_SURFACE_FEATURE="#define CAIRO_HAS_PDF_SURFACE 1"
MOZ_ENABLE_CAIRO_FT=1
CAIRO_FT_CFLAGS="-I${MZFTCFGFT2}/include"
@@ -8576,18 +8551,16 @@ if test "$MOZ_TREE_CAIRO"; then
AC_SUBST(PDF_SURFACE_FEATURE)
AC_SUBST(SVG_SURFACE_FEATURE)
AC_SUBST(XLIB_SURFACE_FEATURE)
AC_SUBST(XLIB_XRENDER_SURFACE_FEATURE)
AC_SUBST(QUARTZ_SURFACE_FEATURE)
AC_SUBST(QUARTZ_IMAGE_SURFACE_FEATURE)
AC_SUBST(XCB_SURFACE_FEATURE)
AC_SUBST(WIN32_SURFACE_FEATURE)
- AC_SUBST(DDRAW_SURFACE_FEATURE)
- AC_SUBST(OGLES_SURFACE_FEATURE)
AC_SUBST(OS2_SURFACE_FEATURE)
AC_SUBST(BEOS_SURFACE_FEATURE)
AC_SUBST(DIRECTFB_SURFACE_FEATURE)
AC_SUBST(FT_FONT_FEATURE)
AC_SUBST(FC_FONT_FEATURE)
AC_SUBST(WIN32_FONT_FEATURE)
AC_SUBST(WIN32_DWRITE_FONT_FEATURE)
AC_SUBST(WIN32_D2D_SURFACE_FEATURE)
--- a/content/base/public/nsISelectionController.idl
+++ b/content/base/public/nsISelectionController.idl
@@ -46,17 +46,17 @@
typedef short SelectionType;
typedef short SelectionRegion;
%}
interface nsIDOMNode;
interface nsISelection;
interface nsISelectionDisplay;
-[scriptable, uuid(bc5795ab-bcb5-448b-b3c7-a111bead7c26)]
+[scriptable, uuid(ff11fa25-788f-444f-8f69-dcdf14348fb3)]
interface nsISelectionController : nsISelectionDisplay
{
const short SELECTION_NONE=0;
const short SELECTION_NORMAL=1;
const short SELECTION_SPELLCHECK=2;
const short SELECTION_IME_RAWINPUT=4;
const short SELECTION_IME_SELECTEDRAWTEXT=8;
const short SELECTION_IME_CONVERTEDTEXT=16;
@@ -89,30 +89,37 @@ interface nsISelectionController : nsISe
* GetSelection will return the selection that the presentation
* shell may implement.
*
* @param aType will hold the type of selection //SelectionType
* @param _return will hold the return value
*/
nsISelection getSelection(in short type);
+ const short SCROLL_SYNCHRONOUS = 1<<1;
+ const short SCROLL_FIRST_ANCESTOR_ONLY = 1<<2;
+
/**
* ScrollSelectionIntoView scrolls a region of the selection,
* so that it is visible in the scrolled view.
*
* @param aType the selection to scroll into view. //SelectionType
* @param aRegion the region inside the selection to scroll into view. //SelectionRegion
- * @param aIsSynchronous when true, scrolls the selection into view
- * before returning. If false, posts a request which is processed
+ * @param aFlags the scroll flags. Valid bits include:
+ * SCROLL_SYNCHRONOUS: when set, scrolls the selection into view
+ * before returning. If not set, posts a request which is processed
* at some point after the method returns.
+ * SCROLL_FIRST_ANCESTOR_ONLY: if set, only the first ancestor will be scrolled
+ * into view.
*
* Note that if isSynchronous is true, then this might flush the pending
* reflow. It's dangerous for some objects. See bug 418470 comment 12.
*/
- void scrollSelectionIntoView(in short type, in short region, in boolean isSynchronous);
+ void scrollSelectionIntoView(in short type, in short region, in short flags);
+
/**
* RepaintSelection repaints the selection specified by aType.
*
* @param aType specifies the selection to repaint.
*/
void repaintSelection(in short type);
/**
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -375,18 +375,17 @@ CSPRep.prototype = {
return false;
}
}
return (this.allowsInlineScripts === that.allowsInlineScripts)
&& (this.allowsEvalInScripts === that.allowsEvalInScripts);
},
/**
- * Generates string representation of the policy. Should be fairly similar
- * to the original.
+ * Generates canonical string representation of the policy.
*/
toString:
function csp_toString() {
var dirs = [];
if (this._allowEval || this._allowInlineScripts) {
dirs.push("options " + (this._allowEval ? "eval-script" : "")
+ (this._allowInlineScripts ? "inline-script" : ""));
@@ -602,18 +601,17 @@ CSPSourceList.prototype = {
if (!a_sorted[i].equals(b_sorted[i])) {
return false;
}
}
return true;
},
/**
- * Generates string representation of the Source List.
- * Should be fairly similar to the original.
+ * Generates canonical string representation of the Source List.
*/
toString:
function() {
if (this.isNone()) {
return "'none'";
}
if (this._permitAllSources) {
return "*";
@@ -634,17 +632,17 @@ CSPSourceList.prototype = {
* Returns whether or not this source list permits all sources (*).
*/
isAll:
function() {
return this._permitAllSources;
},
/**
- * Makes a new instance that resembles this object.
+ * Makes a new deep copy of this object.
* @returns
* a new CSPSourceList
*/
clone:
function() {
var aSL = new CSPSourceList();
aSL._permitAllSources = this._permitAllSources;
for (var i in this._sources) {
@@ -946,17 +944,17 @@ CSPSource.fromString = function(aStr, se
// is the first bit a scheme?
else if (CSPSource.validSchemeName(chunks[0])) {
sObj._scheme = chunks[0];
// then the second bit *must* be a host or empty
if (chunks[1] === "") {
// Allow scheme-only sources! These default to wildcard host/port,
// especially since host and port don't always matter.
// Example: "javascript:" and "data:"
- if (!sObj._host) sObj._host = "*";
+ if (!sObj._host) sObj._host = CSPHost.fromString("*");
if (!sObj._port) sObj._port = "*";
} else {
// some host was defined.
// ... remove <= 3 leading slashes (from the scheme) and parse
var cleanHost = chunks[1].replace(/^\/{0,3}/,"");
// ... and parse
sObj._host = CSPHost.fromString(cleanHost);
if (!sObj._host) {
@@ -1045,18 +1043,17 @@ CSPSource.prototype = {
}
// if there was no scheme (and thus no default scheme), return self.port
if (this._self && this._self.port) return this._self.port;
return undefined;
},
/**
- * Generates string representation of the Source.
- * Should be fairly similar to the original.
+ * Generates canonical string representation of the Source.
*/
toString:
function() {
if (this._isSelf)
return this._self.toString();
var s = "";
if (this._scheme)
@@ -1064,17 +1061,17 @@ CSPSource.prototype = {
if (this._host)
s = s + this._host;
if (this._port)
s = s + ":" + this._port;
return s;
},
/**
- * Makes a new instance that resembles this object.
+ * Makes a new deep copy of this object.
* @returns
* a new CSPSource
*/
clone:
function() {
var aClone = new CSPSource();
aClone._self = this._self ? this._self.clone() : undefined;
aClone._scheme = this._scheme;
@@ -1167,23 +1164,38 @@ CSPSource.prototype = {
else if (that._scheme === this._scheme)
newSource._scheme = this._scheme;
else {
CSPError("Could not intersect " + this + " with " + that
+ " due to scheme problems.");
return null;
}
+ // NOTE: Both sources must have a host, if they don't, something funny is
+ // going on. The fromString() factory method should have set the host to
+ // * if there's no host specified in the input. Regardless, if a host is
+ // not present either the scheme is hostless or any host should be allowed.
+ // This means we can use the other source's host as the more restrictive
+ // host expression, or if neither are present, we can use "*", but the
+ // error should still be reported.
+
// host
- if (!this._host)
- newSource._host = that._host;
- else if (!that._host)
- newSource._host = this._host;
- else // both this and that have hosts
+ if (this._host && that._host) {
newSource._host = this._host.intersectWith(that._host);
+ } else if (this._host) {
+ CSPError("intersecting source with undefined host: " + that.toString());
+ newSource._host = this._host.clone();
+ } else if (that._host) {
+ CSPError("intersecting source with undefined host: " + this.toString());
+ newSource._host = that._host.clone();
+ } else {
+ CSPError("intersecting two sources with undefined hosts: " +
+ this.toString() + " and " + that.toString());
+ newSource._host = CSPHost.fromString("*");
+ }
return newSource;
},
/**
* Compares one CSPSource to another.
*
* @param that
@@ -1261,26 +1273,25 @@ CSPHost.fromString = function(aStr) {
return null;
}
}
return hObj;
};
CSPHost.prototype = {
/**
- * Generates string representation of the Source.
- * Should be fairly similar to the original.
+ * Generates canonical string representation of the Host.
*/
toString:
function() {
return this._segments.join(".");
},
/**
- * Makes a new instance that resembles this object.
+ * Makes a new deep copy of this object.
* @returns
* a new CSPHost
*/
clone:
function() {
var aHost = new CSPHost();
for (var i in this._segments) {
aHost._segments[i] = this._segments[i];
@@ -1292,17 +1303,17 @@ CSPHost.prototype = {
* Returns true if this host accepts the provided host (or the other way
* around).
* @param aHost
* the FQDN in question (CSPHost or String)
* @returns
*/
permits:
function(aHost) {
- if (!aHost) return false;
+ if (!aHost) aHost = CSPHost.fromString("*");
if (!(aHost instanceof CSPHost)) {
// -- compare CSPHost to String
return this.permits(CSPHost.fromString(aHost));
}
var thislen = this._segments.length;
var thatlen = aHost._segments.length;
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5849,17 +5849,17 @@ CloneSimpleValues(JSContext* cx,
// Do we support FileList?
// Function objects don't get cloned.
if (JS_ObjectIsFunction(cx, obj)) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
// Security wrapped objects are not allowed either.
- if (obj->getClass()->ext.wrappedObject)
+ if (obj->isWrapper() && !obj->getClass()->ext.innerObject)
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
// See if this JSObject is backed by some C++ object. If it is then we assume
// that it is inappropriate to clone.
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrapper));
if (wrapper) {
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -3563,28 +3563,28 @@ nsINode::doInsertChildAt(nsIContent* aKi
nsCOMPtr<nsIDOMNode> adoptedKid;
rv = domDoc->AdoptNode(kid, getter_AddRefs(adoptedKid));
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(adoptedKid == kid, "Uh, adopt node changed nodes?");
}
}
- PRUint32 childCount = aChildArray.ChildCount();
- NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE);
-
// The id-handling code, and in the future possibly other code, need to
// react to unexpected attribute changes.
nsMutationGuard::DidMutate();
- PRBool isAppend = (aIndex == childCount);
-
+ // Do this before checking the child-count since this could cause mutations
nsIDocument* doc = GetCurrentDoc();
mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
+ PRUint32 childCount = aChildArray.ChildCount();
+ NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE);
+ PRBool isAppend = (aIndex == childCount);
+
rv = aChildArray.InsertChildAt(aKid, aIndex);
NS_ENSURE_SUCCESS(rv, rv);
if (aIndex == 0) {
mFirstChild = aKid;
}
nsIContent* parent =
IsNodeOfType(eDOCUMENT) ? nsnull : static_cast<nsIContent*>(this);
@@ -4014,16 +4014,18 @@ nsINode::ReplaceOrInsertBefore(PRBool aR
if (IsNodeOfType(eATTRIBUTE)) {
return NS_ERROR_NOT_IMPLEMENTED;
}
nsIContent* refContent;
nsresult res = NS_OK;
PRInt32 insPos;
+ mozAutoDocConditionalContentUpdateBatch batch(GetCurrentDoc(), PR_TRUE);
+
// Figure out which index to insert at
if (aRefChild) {
insPos = IndexOf(aRefChild);
if (insPos < 0) {
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
if (aRefChild == aNewChild) {
@@ -4075,21 +4077,16 @@ nsINode::ReplaceOrInsertBefore(PRBool aR
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(adoptedKid == newChild, "Uh, adopt node changed nodes?");
NS_ASSERTION(HasSameOwnerDoc(newContent) && doc == GetOwnerDoc(),
"ownerDocument changed again after adopting!");
}
}
- // We want an update batch when we expect several mutations to be performed,
- // which is when we're replacing a node, or when we're inserting a fragment.
- mozAutoDocConditionalContentUpdateBatch batch(GetCurrentDoc(),
- aReplace || nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE);
-
// If we're replacing
if (aReplace) {
refContent = GetChildAt(insPos + 1);
nsMutationGuard guard;
res = RemoveChildAt(insPos, PR_TRUE);
NS_ENSURE_SUCCESS(res, res);
@@ -5323,17 +5320,17 @@ nsGenericElement::PostHandleEventForLink
if (fm) {
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOUSE |
nsIFocusManager::FLAG_NOSCROLL);
}
nsIEventStateManager* esm =
aVisitor.mPresContext->EventStateManager();
- nsEventStateManager::SetGlobalActiveContent(
+ nsEventStateManager::SetActiveManager(
static_cast<nsEventStateManager*>(esm), this);
}
}
}
break;
case NS_MOUSE_CLICK:
if (NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent)) {
--- a/content/base/test/test_bug373181.xhtml
+++ b/content/base/test/test_bug373181.xhtml
@@ -1,20 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Testcase for bug 373181</title>
<script type="text/javascript" src="/MochiKit/packed.js"/>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/x-javascript">
- var bodyOnLoad = false;
- function checkOnLoad()
+ function onLoadFired()
{
- ok(bodyOnLoad, "Body onload event should fire");
+ ok(true, "Body onload event should fire");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
- setTimeout(checkOnLoad, 500);
</script>
</head>
- <body onload="bodyOnLoad = true;"/>
+ <body onload="onLoadFired();"/>
</html>
--- a/content/base/test/unit/test_csputils.js
+++ b/content/base/test/unit/test_csputils.js
@@ -30,16 +30,17 @@
* 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 ***** */
//load('CSPUtils.jsm');
Components.utils.import('resource://gre/modules/CSPUtils.jsm');
+Components.utils.import('resource://gre/modules/NetUtil.jsm');
// load the HTTP server
do_load_httpd_js();
var httpServer = new nsHttpServer();
const POLICY_FROM_URI = "allow 'self'; img-src *";
const POLICY_PORT = 9000;
@@ -185,16 +186,17 @@ test(
do_check_neq(null, CSPSource.fromString("*.a.com"));
//print(" --- Ignore the following two errors if they print ---");
//"wildcard should not work in non-first token for host.");
do_check_eq(null, CSPSource.fromString("x.*.a.com"));
//"funny characters (#) should not work for host.");
do_check_eq(null, CSPSource.fromString("a#2-c.com"));
+
//print(" --- Stop ignoring errors that print ---\n");
//"failed to parse host with port.");
do_check_neq(null, CSPSource.create("a.com:23"));
//"failed to parse host with scheme.");
do_check_neq(null, CSPSource.create("https://a.com"));
//"failed to parse host with scheme and port.");
do_check_neq(null, CSPSource.create("https://a.com:200"));
@@ -224,16 +226,26 @@ test(
//"src should inherit port *
do_check_true(src.permits("https://foobar.com:443"));
//"src should inherit and require https scheme
do_check_false(src.permits("http://foobar.com"));
//"src should inherit scheme 'https'"
do_check_true(src.permits("https://foobar.com"));
//"src should reject other hosts"
do_check_false(src.permits("https://a.com"));
+
+ src = CSPSource.create("javascript:", "https://foobar.com:443");
+ //"hostless schemes should be parseable."
+ var aUri = NetUtil.newURI("javascript:alert('foo');");
+ do_check_true(src.permits(aUri));
+ //"src should reject other hosts"
+ do_check_false(src.permits("https://a.com"));
+ //"nothing else should be allowed"
+ do_check_false(src.permits("https://foobar.com"));
+
});
///////////////////// Test the source list //////////////////////
test(
function test_CSPSourceList_fromString() {
var sd = CSPSourceList.fromString("'none'");
//"'none' -- should parse"
--- a/content/canvas/public/DocumentRendererChild.h
+++ b/content/canvas/public/DocumentRendererChild.h
@@ -48,19 +48,21 @@ namespace mozilla {
namespace ipc {
class DocumentRendererChild : public PDocumentRendererChild
{
public:
DocumentRendererChild();
virtual ~DocumentRendererChild();
- bool RenderDocument(nsIDOMWindow *window, const PRInt32& x, const PRInt32& y, const PRInt32& w, const PRInt32& h,
- const nsString& bgcolor, const PRUint32& flags, const PRBool& flush,
- PRUint32& _width, PRUint32& _height, nsCString& data);
+ bool RenderDocument(nsIDOMWindow *window,
+ const nsRect& documentRect, const gfxMatrix& transform,
+ const nsString& bgcolor,
+ PRUint32 renderFlags, PRBool flushLayout,
+ const nsIntSize& renderSize, nsCString& data);
private:
DISALLOW_EVIL_CONSTRUCTORS(DocumentRendererChild);
};
}
}
--- a/content/canvas/public/DocumentRendererParent.h
+++ b/content/canvas/public/DocumentRendererParent.h
@@ -49,20 +49,20 @@ namespace ipc {
class DocumentRendererParent : public PDocumentRendererParent
{
public:
DocumentRendererParent();
virtual ~DocumentRendererParent();
void SetCanvasContext(nsICanvasRenderingContextInternal* aCanvas,
gfxContext* ctx);
- void DrawToCanvas(PRUint32 aWidth, PRUint32 aHeight,
+ void DrawToCanvas(const nsIntSize& renderedSize,
const nsCString& aData);
- virtual bool Recv__delete__(const PRUint32& w, const PRUint32& h,
+ virtual bool Recv__delete__(const nsIntSize& renderedSize,
const nsCString& data);
private:
nsCOMPtr<nsICanvasRenderingContextInternal> mCanvas;
nsRefPtr<gfxContext> mCanvasContext;
DISALLOW_EVIL_CONSTRUCTORS(DocumentRendererParent);
};
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h
+++ b/content/canvas/public/nsICanvasRenderingContextInternal.h
@@ -115,24 +115,14 @@ public:
// Redraw the dirty rectangle of this canvas.
NS_IMETHOD Redraw(const gfxRect &dirty) = 0;
// If this context can be set to use Mozilla's Shmem segments as its backing
// store, this will set it to that state. Note that if you have drawn
// anything into this canvas before changing the shmem state, it will be
// lost.
NS_IMETHOD SetIsIPC(PRBool isIPC) = 0;
-
- // Swap this back buffer with the front, and copy its contents to the new
- // back. x, y, w, and h specify the area of |back| that is dirty.
- NS_IMETHOD Swap(mozilla::ipc::Shmem& back,
- PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h) = 0;
-
- // Sync back and front buffer, move ownership of back buffer to parent
- NS_IMETHOD Swap(PRUint32 nativeID,
- PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h) = 0;
-
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasRenderingContextInternal,
NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
#endif /* nsICanvasRenderingContextInternal_h___ */
--- a/content/canvas/src/DocumentRendererChild.cpp
+++ b/content/canvas/src/DocumentRendererChild.cpp
@@ -94,51 +94,55 @@ FlushLayoutForTree(nsIDOMWindow* aWindow
if (win) {
FlushLayoutForTree(win);
}
}
}
}
bool
-DocumentRendererChild::RenderDocument(nsIDOMWindow *window, const PRInt32& x, const PRInt32& y, const PRInt32& w, const PRInt32& h,
- const nsString& aBGColor, const PRUint32& flags, const PRBool& flush,
- PRUint32& _width, PRUint32& _height, nsCString& data)
+DocumentRendererChild::RenderDocument(nsIDOMWindow *window,
+ const nsRect& documentRect,
+ const gfxMatrix& transform,
+ const nsString& bgcolor,
+ PRUint32 renderFlags,
+ PRBool flushLayout,
+ const nsIntSize& renderSize,
+ nsCString& data)
{
- if (flush)
+ if (flushLayout)
FlushLayoutForTree(window);
nsCOMPtr<nsPresContext> presContext;
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(window);
if (win) {
nsIDocShell* docshell = win->GetDocShell();
if (docshell) {
docshell->GetPresContext(getter_AddRefs(presContext));
}
}
if (!presContext)
return false;
nscolor bgColor;
nsCSSParser parser;
- nsresult rv = parser.ParseColorString(PromiseFlatString(aBGColor),
+ nsresult rv = parser.ParseColorString(PromiseFlatString(bgcolor),
nsnull, 0, &bgColor);
if (NS_FAILED(rv))
return false;
nsIPresShell* presShell = presContext->PresShell();
- nsRect r(x, y, w, h);
-
- _width = nsPresContext::AppUnitsToIntCSSPixels(w);
- _height = nsPresContext::AppUnitsToIntCSSPixels(h);
+ // Draw directly into the output array.
+ data.SetLength(renderSize.width * renderSize.height * 4);
- // Draw directly into the output array.
- data.SetLength(_width * _height * 4);
- nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(reinterpret_cast<PRUint8*>(const_cast<char*>(data.get())),
- gfxIntSize(_width, _height),
- 4 * _width, gfxASurface::ImageFormatARGB32);
+ nsRefPtr<gfxImageSurface> surf =
+ new gfxImageSurface(reinterpret_cast<uint8*>(data.BeginWriting()),
+ gfxIntSize(renderSize.width, renderSize.height),
+ 4 * renderSize.width,
+ gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> ctx = new gfxContext(surf);
+ ctx->SetMatrix(transform);
- presShell->RenderDocument(r, flags, bgColor, ctx);
+ presShell->RenderDocument(documentRect, renderFlags, bgColor, ctx);
return true;
}
deleted file mode 100644
--- a/content/canvas/src/DocumentRendererNativeIDChild.cpp
+++ /dev/null
@@ -1,185 +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/
- *