mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Merge tracemonkey -> mozilla-central
This commit is contained in:
commit
9893654539
@ -213,6 +213,7 @@ ACCESSIBILITY_ATOM(aria_flowto, "aria-flowto")
|
||||
ACCESSIBILITY_ATOM(aria_grab, "aria-grab")
|
||||
ACCESSIBILITY_ATOM(aria_haspopup, "aria-haspopup")
|
||||
ACCESSIBILITY_ATOM(aria_invalid, "aria-invalid")
|
||||
ACCESSIBILITY_ATOM(aria_label, "aria-label")
|
||||
ACCESSIBILITY_ATOM(aria_labelledby, "aria-labelledby")
|
||||
ACCESSIBILITY_ATOM(aria_level, "aria-level")
|
||||
ACCESSIBILITY_ATOM(aria_live, "aria-live")
|
||||
|
@ -1628,6 +1628,7 @@ nsAccessibilityService::HasUniversalAriaProperty(nsIContent *aContent,
|
||||
aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_grab) ||
|
||||
aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_haspopup) ||
|
||||
aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_invalid) ||
|
||||
aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label) ||
|
||||
aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_labelledby) ||
|
||||
aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_live) ||
|
||||
aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_owns) ||
|
||||
|
@ -1706,7 +1706,11 @@ nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
|
||||
// Append all the text into one flat string
|
||||
PRUint32 numChildren = 0;
|
||||
nsCOMPtr<nsIDOMXULSelectControlElement> selectControlEl(do_QueryInterface(aContent));
|
||||
if (!selectControlEl) { // Don't walk children of elements with options, just get label directly
|
||||
|
||||
if (!selectControlEl && aContent->Tag() != nsAccessibilityAtoms::textarea) {
|
||||
// Don't walk children of elements with options, just get label directly.
|
||||
// Don't traverse the children of a textarea, we want the value, not the
|
||||
// static text node.
|
||||
numChildren = aContent->GetChildCount();
|
||||
}
|
||||
|
||||
@ -1843,8 +1847,14 @@ nsresult nsAccessible::GetHTMLName(nsAString& aLabel, PRBool aCanAggregateSubtre
|
||||
return NS_ERROR_FAILURE; // Node shut down
|
||||
}
|
||||
|
||||
// Check for DHTML accessibility labelledby relationship property
|
||||
// Check for aria-label property
|
||||
nsAutoString label;
|
||||
if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label, label)) {
|
||||
aLabel = label;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check for aria-labelledby relationship property
|
||||
nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_labelledby, label);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aLabel = label;
|
||||
@ -1894,8 +1904,14 @@ nsresult nsAccessible::GetXULName(nsAString& aLabel, PRBool aCanAggregateSubtree
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
|
||||
NS_ASSERTION(content, "No nsIContent for DOM node");
|
||||
|
||||
// First check for label override via accessibility labelledby relationship
|
||||
// First check for label override via aria-label property
|
||||
nsAutoString label;
|
||||
if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label, label)) {
|
||||
aLabel = label;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Second check for label override via aria-labelledby relationship
|
||||
nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_labelledby, label);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aLabel = label;
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
#include "nsAccessibleEventData.h"
|
||||
#include "nsAccessibilityAtoms.h"
|
||||
#include "nsAccessibilityUtils.h"
|
||||
#include "nsIAccessibilityService.h"
|
||||
#include "nsIAccessNode.h"
|
||||
#include "nsIDocument.h"
|
||||
|
@ -71,7 +71,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsApplicationAccessible,
|
||||
enumerator->GetNext(getter_AddRefs(childWeakRef));
|
||||
accessible = do_QueryReferent(childWeakRef);
|
||||
if (accessible) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, accessible);
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "nsApplicationAccessible child");
|
||||
cb.NoteXPCOMChild(accessible);
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ ElementTraverser(const void *aKey, nsIAccessNode *aAccessNode,
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aUserArg);
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, aAccessNode);
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mAccessNodeCache entry");
|
||||
cb->NoteXPCOMChild(aAccessNode);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
@ -1094,6 +1094,7 @@ NS_IMETHODIMP nsRootAccessible::FireDocLoadEvents(PRUint32 aEventType)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsresult
|
||||
nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
|
||||
nsIAccessibleTreeCache *aAccessible)
|
||||
@ -1157,4 +1158,5 @@ nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
|
||||
|
||||
return aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -42,7 +42,9 @@
|
||||
#include "nsDocAccessibleWrap.h"
|
||||
|
||||
#include "nsIAccessibleDocument.h"
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsIAccessibleTreeCache.h"
|
||||
#endif
|
||||
|
||||
#include "nsHashtable.h"
|
||||
#include "nsCaretAccessible.h"
|
||||
@ -131,6 +133,7 @@ class nsRootAccessible : public nsDocAccessibleWrap,
|
||||
/**
|
||||
* Handles 'TreeRowCountChanged' event. Used in HandleEventWithTarget().
|
||||
*/
|
||||
#ifdef MOZ_XUL
|
||||
nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
|
||||
nsIAccessibleTreeCache *aAccessible);
|
||||
|
||||
@ -140,7 +143,6 @@ class nsRootAccessible : public nsDocAccessibleWrap,
|
||||
nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
|
||||
nsIAccessibleTreeCache *aAccessible);
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
PRUint32 GetChromeFlags();
|
||||
#endif
|
||||
already_AddRefed<nsIDocShellTreeItem>
|
||||
|
@ -288,6 +288,8 @@ nsHTMLButtonAccessible::GetName(nsAString& aName)
|
||||
nsAutoString name;
|
||||
// Prefer aria-labelledby attribute for name
|
||||
if (content->HasAttr(kNameSpaceID_None,
|
||||
nsAccessibilityAtoms::aria_label) ||
|
||||
content->HasAttr(kNameSpaceID_None,
|
||||
nsAccessibilityAtoms::aria_labelledby)) {
|
||||
GetHTMLName(name, PR_FALSE);
|
||||
}
|
||||
|
@ -143,8 +143,9 @@ NS_IMETHODIMP nsHTMLImageAccessible::GetName(nsAString& aName)
|
||||
PRBool hasAltAttrib =
|
||||
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::alt, aName);
|
||||
if (aName.IsEmpty()) {
|
||||
if (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_labelledby)) {
|
||||
// Use HTML label or DHTML accessibility's labelledby attribute for name
|
||||
if (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label) ||
|
||||
content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_labelledby)) {
|
||||
// Use HTML label or DHTML accessibility's label or labelledby attribute for name
|
||||
// GetHTMLName will also try title attribute as a last resort
|
||||
GetHTMLName(aName, PR_FALSE);
|
||||
}
|
||||
|
@ -224,7 +224,19 @@ nsXFormsAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
|
||||
NS_IMETHODIMP
|
||||
nsXFormsAccessible::GetName(nsAString& aName)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
|
||||
if (!content) {
|
||||
return NS_ERROR_FAILURE; // Node shut down
|
||||
}
|
||||
|
||||
// Check for ARIA label property
|
||||
nsAutoString name;
|
||||
if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label, name)) {
|
||||
aName = name;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check for ARIA labelledby relationship property
|
||||
nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_labelledby, name);
|
||||
if (NS_SUCCEEDED(rv) && !name.IsEmpty()) {
|
||||
aName = name;
|
||||
|
@ -58,6 +58,7 @@ nsXFormsLabelAccessible::GetRole(PRUint32 *aRole)
|
||||
NS_IMETHODIMP
|
||||
nsXFormsLabelAccessible::GetName(nsAString& aName)
|
||||
{
|
||||
// XXX Correct name calculation for this, see bug 453594.
|
||||
nsAutoString name;
|
||||
nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_labelledby, name);
|
||||
aName = name;
|
||||
|
@ -45,7 +45,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = test_accessibility
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += mochitest
|
||||
endif
|
||||
|
||||
|
@ -51,6 +51,7 @@ _TEST_FILES =\
|
||||
common.js \
|
||||
nsIAccessible_actions.js \
|
||||
nsIAccessible_name.css \
|
||||
nsIAccessible_name.js \
|
||||
nsIAccessible_name.xbl \
|
||||
nsIAccessibleEditableText.js \
|
||||
test_aria_activedescendant.html \
|
||||
|
10
accessible/tests/mochitest/nsIAccessible_name.js
Normal file
10
accessible/tests/mochitest/nsIAccessible_name.js
Normal file
@ -0,0 +1,10 @@
|
||||
function testName(aID, aName)
|
||||
{
|
||||
var acc = getAccessible(aID);
|
||||
if (!acc) {
|
||||
ok(false, "No accessible for " + aID + "!");
|
||||
}
|
||||
|
||||
is(acc.name, aName, "Wrong name of the accessible for " + aID);
|
||||
return acc;
|
||||
}
|
@ -4,42 +4,25 @@
|
||||
<title>nsIAccessible::name calculation</title>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/nsIAccessible_name.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
|
||||
const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
|
||||
|
||||
var gAccRetrieval = null;
|
||||
|
||||
function testName(aID, aName)
|
||||
{
|
||||
var elm = document.getElementById(aID);
|
||||
if (!elm) {
|
||||
ok(false, "There is no element with ID " + aID);
|
||||
return;
|
||||
}
|
||||
|
||||
var acc = null;
|
||||
try {
|
||||
acc = gAccRetrieval.getAccessibleFor(elm);
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
if (!acc) {
|
||||
ok(false, "There is no accessible for " + aID);
|
||||
return;
|
||||
}
|
||||
|
||||
is(acc.name, aName, "Wrong name of the accessible for " + aID);
|
||||
}
|
||||
|
||||
function doTest()
|
||||
{
|
||||
gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
|
||||
getService(nsIAccessibleRetrieval);
|
||||
// aria-label
|
||||
|
||||
// Simple label provided via ARIA
|
||||
testName("btn_simple_aria_label", "I am a button");
|
||||
|
||||
// aria-label and aria-labelledby, expect aria-label
|
||||
testName("btn_both_aria_labels", "I am a button, two");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// aria-labelledby
|
||||
@ -132,6 +115,19 @@
|
||||
// If nothing is left. Let's try title attribute.
|
||||
testName("btn_title", "title");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// textarea name
|
||||
|
||||
// textarea's name should have the value, which initially is specified by
|
||||
// a text child.
|
||||
testName("textareawithchild", "Story: Foo");
|
||||
|
||||
// new textarea name should reflect the value change.
|
||||
var elem = document.getElementById("textareawithchild");
|
||||
elem.value = "Bar";
|
||||
|
||||
testName("textareawithchild", "Story: Bar");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
@ -153,6 +149,14 @@
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<!-- aria-label, simple label -->
|
||||
<span id="btn_simple_aria_label" role="button" aria-label="I am a button"/>
|
||||
<br/>
|
||||
<!-- aria-label plus aria-labelledby -->
|
||||
<span id="btn_both_aria_labels" role="button" aria-label="I am a button, two"
|
||||
aria-labelledby="labelledby_text"/>
|
||||
<br/>
|
||||
|
||||
<!-- aria-labelledby, single relation -->
|
||||
<span id="labelledby_text">text</span>
|
||||
<button id="btn_labelledby_text"
|
||||
@ -269,5 +273,13 @@
|
||||
|
||||
<!-- name from title attribute -->
|
||||
<span id="btn_title" role="group" title="title">15</span>
|
||||
|
||||
<!-- A textarea nested in a label with a text child (bug #453371). -->
|
||||
<form>
|
||||
<label>Story:
|
||||
<textarea id="textareawithchild" name="name">Foo</textarea>
|
||||
</label>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -13,41 +13,21 @@
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/a11y/accessible/nsIAccessible_name.js"></script>
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
|
||||
const nsIAccessibleRole = Components.interfaces.nsIAccessibleRole;
|
||||
|
||||
var gAccRetrieval = null;
|
||||
|
||||
function testName(aID, aName)
|
||||
{
|
||||
var elm = document.getElementById(aID);
|
||||
if (!elm) {
|
||||
ok(false, "There is no element with ID " + aID);
|
||||
return null;
|
||||
}
|
||||
|
||||
var acc = null;
|
||||
try {
|
||||
acc = gAccRetrieval.getAccessibleFor(elm);
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
if (!acc) {
|
||||
ok(false, "There is no accessible for " + aID);
|
||||
return null;
|
||||
}
|
||||
|
||||
is(acc.name, aName, "Wrong name of the accessible for " + aID);
|
||||
return acc;
|
||||
}
|
||||
|
||||
function doTest()
|
||||
{
|
||||
gAccRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
|
||||
getService(nsIAccessibleRetrieval);
|
||||
// aria-label
|
||||
|
||||
// Simple label provided via ARIA
|
||||
testName("btn_simple_aria_label", "I am a button");
|
||||
|
||||
// aria-label and aria-labelledby, expect aria-label
|
||||
testName("btn_both_aria_labels", "I am a button, two");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// aria-labelledby
|
||||
@ -198,6 +178,12 @@
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<!-- aria-label, simple label -->
|
||||
<button id="btn_simple_aria_label" aria-label="I am a button"/>
|
||||
<!-- aria-label plus aria-labelledby -->
|
||||
<button id="btn_both_aria_labels" aria-label="I am a button, two"
|
||||
aria-labelledby="labelledby_text"/>
|
||||
|
||||
<!-- aria-labelledby, single relation -->
|
||||
<description id="labelledby_text">text</description>
|
||||
<button id="btn_labelledby_text"
|
||||
|
@ -117,18 +117,11 @@ ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
|
||||
TK_LIBS := $(TK_LIBS)
|
||||
endif
|
||||
|
||||
ifdef MOZ_ENABLE_LIBXUL
|
||||
APP_XPCOM_LIBS = $(XPCOM_GLUE_LDOPTS)
|
||||
else
|
||||
MOZILLA_INTERNAL_API = 1
|
||||
APP_XPCOM_LIBS = $(XPCOM_LIBS)
|
||||
endif
|
||||
|
||||
LIBS += \
|
||||
$(STATIC_COMPONENTS_LINKER_PATH) \
|
||||
$(EXTRA_DSO_LIBS) \
|
||||
$(MOZ_JS_LIBS) \
|
||||
$(APP_XPCOM_LIBS) \
|
||||
$(XPCOM_GLUE_LDOPTS) \
|
||||
$(NSPR_LIBS) \
|
||||
$(TK_LIBS) \
|
||||
$(NULL)
|
||||
|
@ -535,9 +535,6 @@ pref("browser.backspace_action", 0);
|
||||
// 2 = check multi/single line controls
|
||||
pref("layout.spellcheckDefault", 1);
|
||||
|
||||
pref("view_source.editor.path", "");
|
||||
pref("view_source.editor.external", false);
|
||||
|
||||
pref("browser.send_pings", false);
|
||||
|
||||
/* initial web feed readers list */
|
||||
|
@ -48,7 +48,7 @@ abs_srcdir = $(shell cd $(srcdir) && pwd)
|
||||
|
||||
CHROME_DEPS += $(abs_srcdir)/content/overrides/app-license.html
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += content/test
|
||||
endif
|
||||
|
||||
|
@ -73,7 +73,12 @@ function init(aEvent)
|
||||
button.setAttribute("accesskey", document.documentElement.getAttribute("creditsaccesskey"));
|
||||
button.addEventListener("command", switchPage, false);
|
||||
|
||||
document.documentElement.getButton("accept").focus();
|
||||
var acceptButton = document.documentElement.getButton("accept");
|
||||
#ifdef XP_UNIX
|
||||
acceptButton.setAttribute("icon", "close");
|
||||
#endif
|
||||
acceptButton.focus();
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// it may not be sized at this point, and we need its width to calculate its position
|
||||
window.sizeToContent();
|
||||
|
@ -62,9 +62,17 @@
|
||||
#else
|
||||
title="&aboutDialog.title;"
|
||||
buttons="accept,extra2"
|
||||
#ifdef XP_UNIX
|
||||
buttonlabelaccept="&closeCmdGNOME.label;"
|
||||
buttonaccesskeyaccept="&closeCmdGNOME.accesskey;"
|
||||
#endif
|
||||
#endif
|
||||
creditslabel="©right;"
|
||||
#ifdef XP_UNIX
|
||||
creditsaccesskey="©rightGNOME.accesskey;"
|
||||
#else
|
||||
creditsaccesskey="©right.accesskey;"
|
||||
#endif
|
||||
aboutlabel="&aboutLink;"
|
||||
aboutaccesskey="&aboutLink.accesskey;">
|
||||
|
||||
|
@ -862,7 +862,7 @@ function prepareForStartup() {
|
||||
|
||||
// initialize observers and listeners
|
||||
// and give C++ access to gBrowser
|
||||
window.XULBrowserWindow = new nsBrowserStatusHandler();
|
||||
XULBrowserWindow.init();
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
|
||||
@ -1896,18 +1896,7 @@ function BrowserViewSourceOfDocument(aDocument)
|
||||
// If no page descriptor is available, just use the view-source URL...
|
||||
}
|
||||
|
||||
ViewSourceOfURL(webNav.currentURI.spec, pageCookie, aDocument);
|
||||
}
|
||||
|
||||
function ViewSourceOfURL(aURL, aPageDescriptor, aDocument)
|
||||
{
|
||||
var utils = window.top.gViewSourceUtils;
|
||||
if (getBoolPref("view_source.editor.external", false)) {
|
||||
utils.openInExternalEditor(aURL, aPageDescriptor, aDocument);
|
||||
}
|
||||
else {
|
||||
utils.openInInternalViewer(aURL, aPageDescriptor, aDocument);
|
||||
}
|
||||
top.gViewSourceUtils.viewSource(webNav.currentURI.spec, pageCookie, aDocument);
|
||||
}
|
||||
|
||||
// doc - document to use for source, or null for this window's document
|
||||
@ -2825,9 +2814,8 @@ const DOMLinkHandler = {
|
||||
if (!rels.feed && rels.alternate && rels.stylesheet)
|
||||
break;
|
||||
|
||||
var feed = { title: link.title, href: link.href, type: link.type };
|
||||
if (isValidFeed(feed, link.ownerDocument.nodePrincipal, rels.feed)) {
|
||||
FeedHandler.addFeed(feed, link.ownerDocument);
|
||||
if (isValidFeed(link, link.ownerDocument.nodePrincipal, rels.feed)) {
|
||||
FeedHandler.addFeed(link, link.ownerDocument);
|
||||
feedAdded = true;
|
||||
}
|
||||
}
|
||||
@ -3725,27 +3713,20 @@ function mimeTypeIsTextBased(aMimeType)
|
||||
aMimeType == "mozilla.application/cached-xul";
|
||||
}
|
||||
|
||||
function nsBrowserStatusHandler()
|
||||
{
|
||||
this.init();
|
||||
}
|
||||
|
||||
nsBrowserStatusHandler.prototype =
|
||||
{
|
||||
var XULBrowserWindow = {
|
||||
// Stored Status, Link and Loading values
|
||||
status : "",
|
||||
defaultStatus : "",
|
||||
jsStatus : "",
|
||||
jsDefaultStatus : "",
|
||||
overLink : "",
|
||||
startTime : 0,
|
||||
status: "",
|
||||
defaultStatus: "",
|
||||
jsStatus: "",
|
||||
jsDefaultStatus: "",
|
||||
overLink: "",
|
||||
startTime: 0,
|
||||
statusText: "",
|
||||
lastURI: null,
|
||||
|
||||
statusTimeoutInEffect : false,
|
||||
statusTimeoutInEffect: false,
|
||||
|
||||
QueryInterface : function(aIID)
|
||||
{
|
||||
QueryInterface: function (aIID) {
|
||||
if (aIID.equals(Ci.nsIWebProgressListener) ||
|
||||
aIID.equals(Ci.nsIWebProgressListener2) ||
|
||||
aIID.equals(Ci.nsISupportsWeakReference) ||
|
||||
@ -3755,16 +3736,33 @@ nsBrowserStatusHandler.prototype =
|
||||
throw Cr.NS_NOINTERFACE;
|
||||
},
|
||||
|
||||
init : function()
|
||||
{
|
||||
get statusMeter () {
|
||||
delete this.statusMeter;
|
||||
return this.statusMeter = document.getElementById("statusbar-icon");
|
||||
},
|
||||
get stopCommand () {
|
||||
delete this.stopCommand;
|
||||
return this.stopCommand = document.getElementById("Browser:Stop");
|
||||
},
|
||||
get reloadCommand () {
|
||||
delete this.reloadCommand;
|
||||
return this.reloadCommand = document.getElementById("Browser:Reload");
|
||||
},
|
||||
get statusTextField () {
|
||||
delete this.statusTextField;
|
||||
return this.statusTextField = document.getElementById("statusbar-display");
|
||||
},
|
||||
get securityButton () {
|
||||
delete this.securityButton;
|
||||
return this.securityButton = document.getElementById("security-button");
|
||||
},
|
||||
get isImage () {
|
||||
delete this.isImage;
|
||||
return this.isImage = document.getElementById("isImage");
|
||||
},
|
||||
|
||||
init: function () {
|
||||
this.throbberElement = document.getElementById("navigator-throbber");
|
||||
this.statusMeter = document.getElementById("statusbar-icon");
|
||||
this.stopCommand = document.getElementById("Browser:Stop");
|
||||
this.reloadCommand = document.getElementById("Browser:Reload");
|
||||
this.statusTextField = document.getElementById("statusbar-display");
|
||||
this.securityButton = document.getElementById("security-button");
|
||||
this.urlBar = document.getElementById("urlbar");
|
||||
this.isImage = document.getElementById("isImage");
|
||||
|
||||
// Initialize the security button's state and tooltip text. Remember to reset
|
||||
// _hostChanged, otherwise onSecurityChange will short circuit.
|
||||
@ -3773,40 +3771,34 @@ nsBrowserStatusHandler.prototype =
|
||||
this.onSecurityChange(null, null, securityUI.state);
|
||||
},
|
||||
|
||||
destroy : function()
|
||||
{
|
||||
destroy: function () {
|
||||
// XXXjag to avoid leaks :-/, see bug 60729
|
||||
this.throbberElement = null;
|
||||
this.statusMeter = null;
|
||||
this.stopCommand = null;
|
||||
this.reloadCommand = null;
|
||||
this.statusTextField = null;
|
||||
this.securityButton = null;
|
||||
this.urlBar = null;
|
||||
this.statusText = null;
|
||||
this.lastURI = null;
|
||||
delete this.throbberElement;
|
||||
delete this.statusMeter;
|
||||
delete this.stopCommand;
|
||||
delete this.reloadCommand;
|
||||
delete this.statusTextField;
|
||||
delete this.securityButton;
|
||||
delete this.statusText;
|
||||
delete this.lastURI;
|
||||
},
|
||||
|
||||
setJSStatus : function(status)
|
||||
{
|
||||
setJSStatus: function (status) {
|
||||
this.jsStatus = status;
|
||||
this.updateStatusField();
|
||||
},
|
||||
|
||||
setJSDefaultStatus : function(status)
|
||||
{
|
||||
setJSDefaultStatus: function (status) {
|
||||
this.jsDefaultStatus = status;
|
||||
this.updateStatusField();
|
||||
},
|
||||
|
||||
setDefaultStatus : function(status)
|
||||
{
|
||||
setDefaultStatus: function (status) {
|
||||
this.defaultStatus = status;
|
||||
this.updateStatusField();
|
||||
},
|
||||
|
||||
setOverLink : function(link, b)
|
||||
{
|
||||
setOverLink: function (link, b) {
|
||||
// Encode bidirectional formatting characters.
|
||||
// (RFC 3987 sections 3.2 and 4.1 paragraph 6)
|
||||
this.overLink = link.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g,
|
||||
@ -3814,8 +3806,7 @@ nsBrowserStatusHandler.prototype =
|
||||
this.updateStatusField();
|
||||
},
|
||||
|
||||
updateStatusField : function()
|
||||
{
|
||||
updateStatusField: function () {
|
||||
var text = this.overLink || this.status || this.jsStatus || this.jsDefaultStatus || this.defaultStatus;
|
||||
|
||||
// check the current value so we don't trigger an attribute change
|
||||
@ -3826,17 +3817,15 @@ nsBrowserStatusHandler.prototype =
|
||||
}
|
||||
},
|
||||
|
||||
onLinkIconAvailable : function(aBrowser)
|
||||
{
|
||||
onLinkIconAvailable: function (aBrowser) {
|
||||
if (gProxyFavIcon && gBrowser.mCurrentBrowser == aBrowser &&
|
||||
gBrowser.userTypedValue === null)
|
||||
PageProxySetIcon(aBrowser.mIconURL); // update the favicon in the URL bar
|
||||
},
|
||||
|
||||
onProgressChange : function (aWebProgress, aRequest,
|
||||
aCurSelfProgress, aMaxSelfProgress,
|
||||
aCurTotalProgress, aMaxTotalProgress)
|
||||
{
|
||||
onProgressChange: function (aWebProgress, aRequest,
|
||||
aCurSelfProgress, aMaxSelfProgress,
|
||||
aCurTotalProgress, aMaxTotalProgress) {
|
||||
if (aMaxTotalProgress > 0) {
|
||||
// This is highly optimized. Don't touch this code unless
|
||||
// you are intimately familiar with the cost of setting
|
||||
@ -3846,59 +3835,55 @@ nsBrowserStatusHandler.prototype =
|
||||
}
|
||||
},
|
||||
|
||||
onProgressChange64 : function (aWebProgress, aRequest,
|
||||
aCurSelfProgress, aMaxSelfProgress,
|
||||
aCurTotalProgress, aMaxTotalProgress)
|
||||
{
|
||||
onProgressChange64: function (aWebProgress, aRequest,
|
||||
aCurSelfProgress, aMaxSelfProgress,
|
||||
aCurTotalProgress, aMaxTotalProgress) {
|
||||
return this.onProgressChange(aWebProgress, aRequest,
|
||||
aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress,
|
||||
aMaxTotalProgress);
|
||||
},
|
||||
|
||||
onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
|
||||
{
|
||||
onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
|
||||
const nsIChannel = Components.interfaces.nsIChannel;
|
||||
if (aStateFlags & nsIWebProgressListener.STATE_START) {
|
||||
// This (thanks to the filter) is a network start or the first
|
||||
// stray request (the first request outside of the document load),
|
||||
// initialize the throbber and his friends.
|
||||
// This (thanks to the filter) is a network start or the first
|
||||
// stray request (the first request outside of the document load),
|
||||
// initialize the throbber and his friends.
|
||||
|
||||
// Call start document load listeners (only if this is a network load)
|
||||
if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aRequest && aWebProgress.DOMWindow == content)
|
||||
this.startDocumentLoad(aRequest);
|
||||
// Call start document load listeners (only if this is a network load)
|
||||
if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aRequest && aWebProgress.DOMWindow == content)
|
||||
this.startDocumentLoad(aRequest);
|
||||
|
||||
if (this.throbberElement) {
|
||||
// Turn the throbber on.
|
||||
this.throbberElement.setAttribute("busy", "true");
|
||||
}
|
||||
if (this.throbberElement) {
|
||||
// Turn the throbber on.
|
||||
this.throbberElement.setAttribute("busy", "true");
|
||||
}
|
||||
|
||||
// Turn the status meter on.
|
||||
this.statusMeter.value = 0; // be sure to clear the progress bar
|
||||
if (gProgressCollapseTimer) {
|
||||
window.clearTimeout(gProgressCollapseTimer);
|
||||
gProgressCollapseTimer = null;
|
||||
}
|
||||
else
|
||||
this.statusMeter.parentNode.collapsed = false;
|
||||
// Turn the status meter on.
|
||||
this.statusMeter.value = 0; // be sure to clear the progress bar
|
||||
if (gProgressCollapseTimer) {
|
||||
window.clearTimeout(gProgressCollapseTimer);
|
||||
gProgressCollapseTimer = null;
|
||||
}
|
||||
else
|
||||
this.statusMeter.parentNode.collapsed = false;
|
||||
|
||||
// XXX: This needs to be based on window activity...
|
||||
this.stopCommand.removeAttribute("disabled");
|
||||
// XXX: This needs to be based on window activity...
|
||||
this.stopCommand.removeAttribute("disabled");
|
||||
}
|
||||
else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
|
||||
if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
|
||||
if (aWebProgress.DOMWindow == content) {
|
||||
if (aRequest)
|
||||
this.endDocumentLoad(aRequest, aStatus);
|
||||
var browser = gBrowser.mCurrentBrowser;
|
||||
if (!gBrowser.mTabbedMode && !browser.mIconURL)
|
||||
if (!gBrowser.mTabbedMode && !gBrowser.mCurrentBrowser.mIconURL)
|
||||
gBrowser.useDefaultIcon(gBrowser.mCurrentTab);
|
||||
|
||||
if (Components.isSuccessCode(aStatus) &&
|
||||
content.document.documentElement.getAttribute("manifest")) {
|
||||
content.document.documentElement.getAttribute("manifest"))
|
||||
OfflineApps.offlineAppRequested(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3906,59 +3891,55 @@ nsBrowserStatusHandler.prototype =
|
||||
// request stop outside of loading the document, stop throbbers
|
||||
// and progress bars and such
|
||||
if (aRequest) {
|
||||
var msg = "";
|
||||
// Get the URI either from a channel or a pseudo-object
|
||||
if (aRequest instanceof nsIChannel || "URI" in aRequest) {
|
||||
var location = aRequest.URI;
|
||||
let msg = "";
|
||||
// Get the URI either from a channel or a pseudo-object
|
||||
if (aRequest instanceof nsIChannel || "URI" in aRequest) {
|
||||
let location = aRequest.URI;
|
||||
|
||||
// For keyword URIs clear the user typed value since they will be changed into real URIs
|
||||
if (location.scheme == "keyword" && aWebProgress.DOMWindow == content)
|
||||
gBrowser.userTypedValue = null;
|
||||
// For keyword URIs clear the user typed value since they will be changed into real URIs
|
||||
if (location.scheme == "keyword" && aWebProgress.DOMWindow == content)
|
||||
gBrowser.userTypedValue = null;
|
||||
|
||||
if (location.spec != "about:blank") {
|
||||
const kErrorBindingAborted = 0x804B0002;
|
||||
const kErrorNetTimeout = 0x804B000E;
|
||||
switch (aStatus) {
|
||||
case kErrorBindingAborted:
|
||||
msg = gNavigatorBundle.getString("nv_stopped");
|
||||
break;
|
||||
case kErrorNetTimeout:
|
||||
msg = gNavigatorBundle.getString("nv_timeout");
|
||||
break;
|
||||
}
|
||||
if (location.spec != "about:blank") {
|
||||
switch (aStatus) {
|
||||
case Components.results.NS_BINDING_ABORTED:
|
||||
msg = gNavigatorBundle.getString("nv_stopped");
|
||||
break;
|
||||
case Components.results.NS_ERROR_NET_TIMEOUT:
|
||||
msg = gNavigatorBundle.getString("nv_timeout");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If msg is false then we did not have an error (channel may have
|
||||
// been null, in the case of a stray image load).
|
||||
if (!msg && (!location || location.spec != "about:blank")) {
|
||||
msg = gNavigatorBundle.getString("nv_done");
|
||||
}
|
||||
this.status = "";
|
||||
this.setDefaultStatus(msg);
|
||||
|
||||
// Disable menu entries for images, enable otherwise
|
||||
if (content.document && mimeTypeIsTextBased(content.document.contentType))
|
||||
this.isImage.removeAttribute('disabled');
|
||||
else
|
||||
this.isImage.setAttribute('disabled', 'true');
|
||||
}
|
||||
// If msg is false then we did not have an error (channel may have
|
||||
// been null, in the case of a stray image load).
|
||||
if (!msg && (!location || location.spec != "about:blank"))
|
||||
msg = gNavigatorBundle.getString("nv_done");
|
||||
|
||||
// Turn the progress meter and throbber off.
|
||||
gProgressCollapseTimer = window.setTimeout(
|
||||
function() {
|
||||
gProgressMeterPanel.collapsed = true;
|
||||
gProgressCollapseTimer = null;
|
||||
}, 100);
|
||||
this.status = "";
|
||||
this.setDefaultStatus(msg);
|
||||
|
||||
if (this.throbberElement)
|
||||
this.throbberElement.removeAttribute("busy");
|
||||
// Disable menu entries for images, enable otherwise
|
||||
if (content.document && mimeTypeIsTextBased(content.document.contentType))
|
||||
this.isImage.removeAttribute('disabled');
|
||||
else
|
||||
this.isImage.setAttribute('disabled', 'true');
|
||||
}
|
||||
|
||||
this.stopCommand.setAttribute("disabled", "true");
|
||||
// Turn the progress meter and throbber off.
|
||||
gProgressCollapseTimer = window.setTimeout(function () {
|
||||
gProgressMeterPanel.collapsed = true;
|
||||
gProgressCollapseTimer = null;
|
||||
}, 100);
|
||||
|
||||
if (this.throbberElement)
|
||||
this.throbberElement.removeAttribute("busy");
|
||||
|
||||
this.stopCommand.setAttribute("disabled", "true");
|
||||
}
|
||||
},
|
||||
|
||||
onLocationChange : function(aWebProgress, aRequest, aLocationURI)
|
||||
{
|
||||
onLocationChange: function (aWebProgress, aRequest, aLocationURI) {
|
||||
var location = aLocationURI ? aLocationURI.spec : "";
|
||||
this._hostChanged = true;
|
||||
|
||||
@ -3969,7 +3950,7 @@ nsBrowserStatusHandler.prototype =
|
||||
document.tooltipNode = null;
|
||||
}
|
||||
else {
|
||||
for (var tooltipWindow =
|
||||
for (let tooltipWindow =
|
||||
document.tooltipNode.ownerDocument.defaultView;
|
||||
tooltipWindow != tooltipWindow.parent;
|
||||
tooltipWindow = tooltipWindow.parent) {
|
||||
@ -3992,18 +3973,18 @@ nsBrowserStatusHandler.prototype =
|
||||
// - which fires a onLocationChange message to uri + '#'...
|
||||
var selectedBrowser = gBrowser.selectedBrowser;
|
||||
if (selectedBrowser.lastURI) {
|
||||
var oldSpec = selectedBrowser.lastURI.spec;
|
||||
var oldIndexOfHash = oldSpec.indexOf("#");
|
||||
let oldSpec = selectedBrowser.lastURI.spec;
|
||||
let oldIndexOfHash = oldSpec.indexOf("#");
|
||||
if (oldIndexOfHash != -1)
|
||||
oldSpec = oldSpec.substr(0, oldIndexOfHash);
|
||||
var newSpec = location;
|
||||
var newIndexOfHash = newSpec.indexOf("#");
|
||||
let newSpec = location;
|
||||
let newIndexOfHash = newSpec.indexOf("#");
|
||||
if (newIndexOfHash != -1)
|
||||
newSpec = newSpec.substr(0, newSpec.indexOf("#"));
|
||||
if (newSpec != oldSpec) {
|
||||
// Remove all the notifications, except for those which want to
|
||||
// persist across the first location change.
|
||||
var nBox = gBrowser.getNotificationBox(selectedBrowser);
|
||||
let nBox = gBrowser.getNotificationBox(selectedBrowser);
|
||||
nBox.removeTransientNotifications();
|
||||
}
|
||||
}
|
||||
@ -4024,10 +4005,9 @@ nsBrowserStatusHandler.prototype =
|
||||
|
||||
var browser = gBrowser.selectedBrowser;
|
||||
if (aWebProgress.DOMWindow == content) {
|
||||
|
||||
if ((location == "about:blank" && !content.opener) ||
|
||||
location == "") { // Second condition is for new tabs, otherwise
|
||||
// reload function is enabled until tab is refreshed.
|
||||
location == "") { // Second condition is for new tabs, otherwise
|
||||
// reload function is enabled until tab is refreshed.
|
||||
this.reloadCommand.setAttribute("disabled", "true");
|
||||
} else {
|
||||
this.reloadCommand.removeAttribute("disabled");
|
||||
@ -4038,9 +4018,7 @@ nsBrowserStatusHandler.prototype =
|
||||
|
||||
if (gURLBar) {
|
||||
URLBarSetURI(aLocationURI);
|
||||
|
||||
// Update starring UI
|
||||
PlacesStarButton.updateState();
|
||||
PlacesStarButton.updateState(); // Update starring UI
|
||||
}
|
||||
|
||||
FullZoom.onLocationChange(aLocationURI);
|
||||
@ -4060,73 +4038,62 @@ nsBrowserStatusHandler.prototype =
|
||||
|
||||
// See bug 358202, when tabs are switched during a drag operation,
|
||||
// timers don't fire on windows (bug 203573)
|
||||
if (aRequest) {
|
||||
var self = this;
|
||||
setTimeout(function() { self.asyncUpdateUI(); }, 0);
|
||||
}
|
||||
if (aRequest)
|
||||
setTimeout(function () { XULBrowserWindow.asyncUpdateUI(); }, 0);
|
||||
else
|
||||
this.asyncUpdateUI();
|
||||
},
|
||||
|
||||
asyncUpdateUI : function () {
|
||||
asyncUpdateUI: function () {
|
||||
FeedHandler.updateFeeds();
|
||||
BrowserSearch.updateSearchButton();
|
||||
},
|
||||
|
||||
onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
|
||||
{
|
||||
onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
|
||||
this.status = aMessage;
|
||||
this.updateStatusField();
|
||||
},
|
||||
|
||||
onRefreshAttempted : function(aWebProgress, aURI, aDelay, aSameURI)
|
||||
{
|
||||
onRefreshAttempted: function (aWebProgress, aURI, aDelay, aSameURI) {
|
||||
if (gPrefService.getBoolPref("accessibility.blockautorefresh")) {
|
||||
var brandBundle = document.getElementById("bundle_brand");
|
||||
var brandShortName = brandBundle.getString("brandShortName");
|
||||
var refreshButtonText =
|
||||
let brandBundle = document.getElementById("bundle_brand");
|
||||
let brandShortName = brandBundle.getString("brandShortName");
|
||||
let refreshButtonText =
|
||||
gNavigatorBundle.getString("refreshBlocked.goButton");
|
||||
var refreshButtonAccesskey =
|
||||
let refreshButtonAccesskey =
|
||||
gNavigatorBundle.getString("refreshBlocked.goButton.accesskey");
|
||||
var message;
|
||||
if (aSameURI)
|
||||
message = gNavigatorBundle.getFormattedString(
|
||||
"refreshBlocked.refreshLabel", [brandShortName]);
|
||||
else
|
||||
message = gNavigatorBundle.getFormattedString(
|
||||
"refreshBlocked.redirectLabel", [brandShortName]);
|
||||
var topBrowser = getBrowserFromContentWindow(aWebProgress.DOMWindow.top);
|
||||
var docShell = aWebProgress.DOMWindow
|
||||
let message =
|
||||
gNavigatorBundle.getFormattedString(aSameURI ? "refreshBlocked.refreshLabel"
|
||||
: "refreshBlocked.redirectLabel",
|
||||
[brandShortName]);
|
||||
let topBrowser = getBrowserFromContentWindow(aWebProgress.DOMWindow.top);
|
||||
let docShell = aWebProgress.DOMWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
var notificationBox = gBrowser.getNotificationBox(topBrowser);
|
||||
var notification = notificationBox.getNotificationWithValue(
|
||||
"refresh-blocked");
|
||||
let notificationBox = gBrowser.getNotificationBox(topBrowser);
|
||||
let notification = notificationBox.getNotificationWithValue("refresh-blocked");
|
||||
if (notification) {
|
||||
notification.label = message;
|
||||
notification.refreshURI = aURI;
|
||||
notification.delay = aDelay;
|
||||
notification.docShell = docShell;
|
||||
}
|
||||
else {
|
||||
var buttons = [{
|
||||
} else {
|
||||
let buttons = [{
|
||||
label: refreshButtonText,
|
||||
accessKey: refreshButtonAccesskey,
|
||||
callback: function(aNotification, aButton) {
|
||||
callback: function (aNotification, aButton) {
|
||||
var refreshURI = aNotification.docShell
|
||||
.QueryInterface(Ci.nsIRefreshURI);
|
||||
refreshURI.forceRefreshURI(aNotification.refreshURI,
|
||||
aNotification.delay, true);
|
||||
}
|
||||
}];
|
||||
const priority = notificationBox.PRIORITY_INFO_MEDIUM;
|
||||
notification = notificationBox.appendNotification(
|
||||
message,
|
||||
"refresh-blocked",
|
||||
"chrome://browser/skin/Info.png",
|
||||
priority,
|
||||
buttons);
|
||||
notification =
|
||||
notificationBox.appendNotification(message, "refresh-blocked",
|
||||
"chrome://browser/skin/Info.png",
|
||||
notificationBox.PRIORITY_INFO_MEDIUM,
|
||||
buttons);
|
||||
notification.refreshURI = aURI;
|
||||
notification.delay = aDelay;
|
||||
notification.docShell = docShell;
|
||||
@ -4142,9 +4109,7 @@ nsBrowserStatusHandler.prototype =
|
||||
_tooltipText: null,
|
||||
_hostChanged: false, // onLocationChange will flip this bit
|
||||
|
||||
onSecurityChange : function browser_onSecChange(aWebProgress,
|
||||
aRequest, aState)
|
||||
{
|
||||
onSecurityChange: function (aWebProgress, aRequest, aState) {
|
||||
// Don't need to do anything if the data we use to update the UI hasn't
|
||||
// changed
|
||||
if (this._state == aState &&
|
||||
@ -4183,7 +4148,7 @@ nsBrowserStatusHandler.prototype =
|
||||
wpl.STATE_SECURE_HIGH |
|
||||
wpl.STATE_SECURE_MED |
|
||||
wpl.STATE_SECURE_LOW;
|
||||
var level = null;
|
||||
var level;
|
||||
var setHost = false;
|
||||
|
||||
switch (this._state & wpl_security_bits) {
|
||||
@ -4203,12 +4168,10 @@ nsBrowserStatusHandler.prototype =
|
||||
|
||||
if (level) {
|
||||
this.securityButton.setAttribute("level", level);
|
||||
if (this.urlBar)
|
||||
this.urlBar.setAttribute("level", level);
|
||||
this.securityButton.hidden = false;
|
||||
} else {
|
||||
this.securityButton.hidden = true;
|
||||
this.securityButton.removeAttribute("level");
|
||||
if (this.urlBar)
|
||||
this.urlBar.removeAttribute("level");
|
||||
}
|
||||
|
||||
if (setHost && this._host)
|
||||
@ -4236,8 +4199,7 @@ nsBrowserStatusHandler.prototype =
|
||||
},
|
||||
|
||||
// simulate all change notifications after switching tabs
|
||||
onUpdateCurrentBrowser : function(aStateFlags, aStatus, aMessage, aTotalProgress)
|
||||
{
|
||||
onUpdateCurrentBrowser: function (aStateFlags, aStatus, aMessage, aTotalProgress) {
|
||||
var nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
|
||||
var loadingDone = aStateFlags & nsIWebProgressListener.STATE_STOP;
|
||||
// use a pseudo-object instead of a (potentially non-existing) channel for getting
|
||||
@ -4256,8 +4218,7 @@ nsBrowserStatusHandler.prototype =
|
||||
this.onProgressChange(gBrowser.webProgress, 0, 0, aTotalProgress, 1);
|
||||
},
|
||||
|
||||
startDocumentLoad : function(aRequest)
|
||||
{
|
||||
startDocumentLoad: function (aRequest) {
|
||||
// clear out feed data
|
||||
gBrowser.mCurrentBrowser.feeds = null;
|
||||
|
||||
@ -4274,8 +4235,7 @@ nsBrowserStatusHandler.prototype =
|
||||
}
|
||||
},
|
||||
|
||||
endDocumentLoad : function(aRequest, aStatus)
|
||||
{
|
||||
endDocumentLoad: function (aRequest, aStatus) {
|
||||
const nsIChannel = Components.interfaces.nsIChannel;
|
||||
var urlStr = aRequest.QueryInterface(nsIChannel).originalURI.spec;
|
||||
|
||||
|
@ -99,19 +99,15 @@
|
||||
<tooltip id="aHTMLTooltip" onpopupshowing="return FillInHTMLTooltip(document.tooltipNode);"/>
|
||||
|
||||
<!-- for search and content formfill/pw manager -->
|
||||
<panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete" noautofocus="true" hidden="true"/>
|
||||
<panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete" noautofocus="true" hidden="true" level="top"/>
|
||||
|
||||
<!-- for url bar autocomplete -->
|
||||
<panel type="autocomplete-richlistbox" chromedir="&locale.dir;" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true"/>
|
||||
<panel type="autocomplete-richlistbox" chromedir="&locale.dir;" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true" level="top"/>
|
||||
|
||||
<!-- XXX panel element that has one or more text fields should not be
|
||||
top-most panel, for IME users. See bug 433340 comment 100. -->
|
||||
<panel id="editBookmarkPanel"
|
||||
orient="vertical"
|
||||
ignorekeys="true"
|
||||
hidden="true"
|
||||
noautohide="true"
|
||||
onpopupshowing="this.removeAttribute('noautohide');"
|
||||
onpopupshown="StarUI.panelShown(event);"
|
||||
aria-labelledby="editBookmarkPanelTitle">
|
||||
<hbox flex="1" align="top">
|
||||
@ -197,7 +193,7 @@
|
||||
<!-- Popup for site identity information -->
|
||||
<panel id="identity-popup" position="after_start" hidden="true" noautofocus="true"
|
||||
onpopupshown="document.getElementById('identity-popup-more-info-button').focus();"
|
||||
onpopuphidden="focusAndSelectUrlBar();" norestorefocus="true"
|
||||
onpopuphidden="focusAndSelectUrlBar();" norestorefocus="true" level="top"
|
||||
chromedir="&locale.dir;">
|
||||
<hbox id="identity-popup-container" align="top">
|
||||
<image id="identity-popup-icon"/>
|
||||
@ -234,7 +230,7 @@
|
||||
<label crop="center" flex="1"/>
|
||||
</tooltip>
|
||||
|
||||
<panel id="ctrlTab-panel" class="KUI-panel" hidden="true" noautofocus="true">
|
||||
<panel id="ctrlTab-panel" class="KUI-panel" hidden="true" noautofocus="true" level="top">
|
||||
<label id="ctrlTab-label" flex="1"/>
|
||||
<svg:svg id="ctrlTab-svgRoot">
|
||||
<svg:defs>
|
||||
@ -565,6 +561,7 @@
|
||||
tooltiptext="&downloadMonitor2.tooltip;" hidden="true"
|
||||
command="Tools:Downloads"/>
|
||||
<statusbarpanel id="security-button" class="statusbarpanel-iconic-text"
|
||||
hidden="true"
|
||||
ondblclick="if (event.button == 0) displaySecurityInfo();"/>
|
||||
<statusbarpanel id="page-report-button" type="menu"
|
||||
class="statusbarpanel-menu-iconic"
|
||||
|
@ -62,9 +62,9 @@ function initFeedTab()
|
||||
}
|
||||
|
||||
if (rels.feed || (link.type && rels.alternate && !rels.stylesheet)) {
|
||||
var feed = { title: link.title, href: link.href, type: link.type || "" };
|
||||
if (isValidFeed(feed, gDocument.nodePrincipal, rels.feed)) {
|
||||
var type = feedTypes[feed.type] || feedTypes["application/rss+xml"];
|
||||
var type = isValidFeed(link, gDocument.nodePrincipal, rels.feed);
|
||||
if (type) {
|
||||
type = feedTypes[type] || feedTypes["application/rss+xml"];
|
||||
addRow(feed.title, type, feed.href);
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ _TEST_FILES = test_feed_discovery.html \
|
||||
_BROWSER_FILES = browser_bug321000.js \
|
||||
browser_bug405137.js \
|
||||
browser_bug409481.js \
|
||||
browser_bug413915.js \
|
||||
browser_autodiscovery.js \
|
||||
browser_bug420160.js \
|
||||
browser_bug441778.js \
|
||||
|
62
browser/base/content/test/browser_bug413915.js
Normal file
62
browser/base/content/test/browser_bug413915.js
Normal file
@ -0,0 +1,62 @@
|
||||
function test() {
|
||||
var ioserv = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var exampleUri = ioserv.newURI("http://example.com/", null, null);
|
||||
var secman = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
|
||||
getService(Components.interfaces.nsIScriptSecurityManager);
|
||||
var principal = secman.getCodebasePrincipal(exampleUri);
|
||||
|
||||
function testIsFeed(aTitle, aHref, aType, aKnown) {
|
||||
var link = { title: aTitle, href: aHref, type: aType };
|
||||
return isValidFeed(link, principal, aKnown);
|
||||
}
|
||||
|
||||
var href = "http://example.com/feed/";
|
||||
var atomType = "application/atom+xml";
|
||||
var funkyAtomType = " aPPLICAtion/Atom+XML ";
|
||||
var rssType = "application/rss+xml";
|
||||
var funkyRssType = " Application/RSS+XML ";
|
||||
var rdfType = "application/rdf+xml";
|
||||
var texmlType = "text/xml";
|
||||
var appxmlType = "application/xml";
|
||||
var noRss = "Foo";
|
||||
var rss = "RSS";
|
||||
|
||||
// things that should be valid
|
||||
ok(testIsFeed(noRss, href, atomType, false) == atomType,
|
||||
"detect Atom feed");
|
||||
ok(testIsFeed(noRss, href, funkyAtomType, false) == atomType,
|
||||
"clean up and detect Atom feed");
|
||||
ok(testIsFeed(noRss, href, rssType, false) == rssType,
|
||||
"detect RSS feed");
|
||||
ok(testIsFeed(noRss, href, funkyRssType, false) == rssType,
|
||||
"clean up and detect RSS feed");
|
||||
|
||||
// things that should not be feeds
|
||||
ok(testIsFeed(noRss, href, rdfType, false) == null,
|
||||
"should not detect RDF non-feed");
|
||||
ok(testIsFeed(rss, href, rdfType, false) == null,
|
||||
"should not detect RDF feed from type and title");
|
||||
ok(testIsFeed(noRss, href, texmlType, false) == null,
|
||||
"should not detect text/xml non-feed");
|
||||
ok(testIsFeed(rss, href, texmlType, false) == null,
|
||||
"should not detect text/xml feed from type and title");
|
||||
ok(testIsFeed(noRss, href, appxmlType, false) == null,
|
||||
"should not detect application/xml non-feed");
|
||||
ok(testIsFeed(rss, href, appxmlType, false) == null,
|
||||
"should not detect application/xml feed from type and title");
|
||||
|
||||
// security check only, returns cleaned up type or "application/rss+xml"
|
||||
ok(testIsFeed(noRss, href, atomType, true) == atomType,
|
||||
"feed security check should return Atom type");
|
||||
ok(testIsFeed(noRss, href, funkyAtomType, true) == atomType,
|
||||
"feed security check should return cleaned up Atom type");
|
||||
ok(testIsFeed(noRss, href, rssType, true) == rssType,
|
||||
"feed security check should return RSS type");
|
||||
ok(testIsFeed(noRss, href, funkyRssType, true) == rssType,
|
||||
"feed security check should return cleaned up RSS type");
|
||||
ok(testIsFeed(noRss, href, "", true) == rssType,
|
||||
"feed security check without type should return RSS type");
|
||||
ok(testIsFeed(noRss, href, "garbage", true) == "garbage",
|
||||
"feed security check with garbage type should return garbage");
|
||||
}
|
@ -28,17 +28,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=377611
|
||||
<!-- type is case-insensitive -->
|
||||
<link rel="alternate" type="aPPliCAtion/ATom+xML" title="12" href="/12.atom" />
|
||||
|
||||
<!-- tolerate application/rdf+xml if the title includes 'rss' -->
|
||||
<link rel="alternate" type="application/rdf+xml" title="13 rss" href="/13.rdf" />
|
||||
|
||||
<!-- tolerate application/xml if the title includes 'rss' -->
|
||||
<link rel="alternate" type="application/xml" title="14 rss" href="/14.xml" />
|
||||
|
||||
<!-- tolerate text/xml if the title includes 'rss' -->
|
||||
<link rel="alternate" type="text/xml" title="15 rss" href="/15.xml" />
|
||||
|
||||
<!-- "feed stylesheet" is a feed, though "alternate stylesheet" isn't -->
|
||||
<link rel="feed stylesheet" title="16" href="/16.atom" />
|
||||
<link rel="feed stylesheet" title="13" href="/13.atom" />
|
||||
|
||||
<!-- hyphens or letters around rel not allowed -->
|
||||
<link rel="disabled-alternate" type="application/atom+xml" title="Bogus1" href="/Bogus1" />
|
||||
@ -63,8 +54,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=377611
|
||||
<!-- don't find application/rss+xml by title -->
|
||||
<link rel="goats" type="application/rss+xml" title="Bogus9 RSS and Atom" href="/Bogus9" />
|
||||
|
||||
<!-- don't find application/rdf+xml by title -->
|
||||
<link rel="alternate" type="application/rdf+xml" title="Bogus10 RSS and Atom" href="/Bogus10" />
|
||||
|
||||
<!-- don't find application/xml by title -->
|
||||
<link rel="alternate" type="application/xml" title="Bogus11 RSS and Atom" href="/Bogus11" />
|
||||
|
||||
<!-- don't find text/xml by title -->
|
||||
<link rel="alternate" type="text/xml" title="Bogus12 RSS and Atom" href="/Bogus12" />
|
||||
|
||||
<!-- alternate and stylesheet isn't a feed -->
|
||||
<link rel="alternate stylesheet" type="application/rss+xml" title="Bogus10 RSS" href="/Bogus10" />
|
||||
<link rel="alternate stylesheet" type="application/rss+xml" title="Bogus13 RSS" href="/Bogus13" />
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
|
@ -25,8 +25,8 @@ addLoadEvent(function() {
|
||||
// Need privs because the feed seems to have an about:feeds principal or some
|
||||
// such. It's not same-origin with us in any case.
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
|
||||
is($("testFrame").contentDocument.documentElement.id, "feedHandler",
|
||||
"Text didn't get sniffed as a feed?");
|
||||
is($("testFrame").contentDocument.documentElement.id, "",
|
||||
"Text got sniffed as a feed?");
|
||||
});
|
||||
addLoadEvent(SimpleTest.finish);
|
||||
|
||||
|
@ -631,7 +631,7 @@ function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup,
|
||||
/**
|
||||
* isValidFeed: checks whether the given data represents a valid feed.
|
||||
*
|
||||
* @param aData
|
||||
* @param aLink
|
||||
* An object representing a feed with title, href and type.
|
||||
* @param aPrincipal
|
||||
* The principal of the document, used for security check.
|
||||
@ -639,40 +639,28 @@ function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup,
|
||||
* Whether this is already a known feed or not, if true only a security
|
||||
* check will be performed.
|
||||
*/
|
||||
function isValidFeed(aData, aPrincipal, aIsFeed)
|
||||
function isValidFeed(aLink, aPrincipal, aIsFeed)
|
||||
{
|
||||
if (!aData || !aPrincipal)
|
||||
if (!aLink || !aPrincipal)
|
||||
return false;
|
||||
|
||||
var type = aLink.type.toLowerCase().replace(/^\s+|\s*(?:;.*)?$/g, "");
|
||||
if (!aIsFeed) {
|
||||
var type = aData.type && aData.type.toLowerCase();
|
||||
type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
|
||||
|
||||
aIsFeed = (type == "application/rss+xml" ||
|
||||
type == "application/atom+xml");
|
||||
|
||||
if (!aIsFeed) {
|
||||
// really slimy: general XML types with magic letters in the title
|
||||
const titleRegex = /(^|\s)rss($|\s)/i;
|
||||
aIsFeed = ((type == "text/xml" || type == "application/rdf+xml" ||
|
||||
type == "application/xml") && titleRegex.test(aData.title));
|
||||
}
|
||||
}
|
||||
|
||||
if (aIsFeed) {
|
||||
try {
|
||||
urlSecurityCheck(aData.href, aPrincipal,
|
||||
urlSecurityCheck(aLink.href, aPrincipal,
|
||||
Components.interfaces.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
|
||||
return type || "application/rss+xml";
|
||||
}
|
||||
catch(ex) {
|
||||
aIsFeed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (type)
|
||||
aData.type = type;
|
||||
|
||||
return aIsFeed;
|
||||
return null;
|
||||
}
|
||||
|
||||
// aCalledFromModal is optional
|
||||
|
@ -43,7 +43,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = public src
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
|
@ -60,6 +60,8 @@
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIMIMEHeaderParam.h"
|
||||
|
||||
#include "nsMimeTypes.h"
|
||||
|
||||
#define TYPE_ATOM "application/atom+xml"
|
||||
#define TYPE_RSS "application/rss+xml"
|
||||
#define TYPE_MAYBE_FEED "application/vnd.mozilla.maybe.feed"
|
||||
@ -331,6 +333,17 @@ nsFeedSniffer::GetMIMETypeFromContent(nsIRequest* request,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Don't sniff arbitrary types. Limit sniffing to situations that
|
||||
// we think can reasonably arise.
|
||||
if (!contentType.EqualsLiteral(TEXT_HTML) &&
|
||||
!contentType.EqualsLiteral(APPLICATION_OCTET_STREAM) &&
|
||||
// Same criterion as XMLHttpRequest. Should we be checking for "+xml"
|
||||
// and check for text/xml and application/xml by hand instead?
|
||||
contentType.Find("xml") == -1) {
|
||||
sniffedType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now we need to potentially decompress data served with
|
||||
// Content-Encoding: gzip
|
||||
nsresult rv = ConvertEncodedData(request, data, length);
|
||||
|
@ -64,7 +64,7 @@ const nsIWebNavigationInfo = Components.interfaces.nsIWebNavigationInfo;
|
||||
const nsIBrowserSearchService = Components.interfaces.nsIBrowserSearchService;
|
||||
const nsICommandLineValidator = Components.interfaces.nsICommandLineValidator;
|
||||
|
||||
const NS_BINDING_ABORTED = 0x804b0002;
|
||||
const NS_BINDING_ABORTED = Components.results.NS_BINDING_ABORTED;
|
||||
const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
|
||||
const NS_ERROR_ABORT = Components.results.NS_ERROR_ABORT;
|
||||
|
||||
|
@ -1087,7 +1087,7 @@ var BookmarkPropertiesPanel = {
|
||||
},
|
||||
|
||||
onMenuListFolderSelect: function BPP_onMenuListFolderSelect(aEvent) {
|
||||
if (this._folderTree.hidden)
|
||||
if (this._folderTree.collapsed)
|
||||
return;
|
||||
|
||||
this._folderTree.selectItems([this._getFolderIdFromMenuList()]);
|
||||
|
@ -306,7 +306,7 @@ var PlacesOrganizer = {
|
||||
// The command execution function will take care of seeing the
|
||||
// selection is a folder/container and loading its contents in
|
||||
// tabs for us.
|
||||
PlacesUIUtils.openContainerNodeInTabs(selectedNode);
|
||||
PlacesUIUtils.openContainerNodeInTabs(selectedNode, aEvent);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -47,9 +47,6 @@ MODULE = test_browser_places
|
||||
|
||||
XPCSHELL_TESTS = unit
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
DIRS += browser
|
||||
DIRS += perf
|
||||
endif
|
||||
DIRS = browser perf
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -48,5 +48,17 @@ _CHROME_FILES = \
|
||||
perf_large_delete.xul \
|
||||
$(NULL)
|
||||
|
||||
_BROWSER_TEST_FILES = \
|
||||
browser_ui_000_data.js\
|
||||
browser_ui_bookmarks_sidebar.js\
|
||||
browser_ui_history_sidebar.js\
|
||||
$(NULL)
|
||||
# XXX disabled tests, not working properly yet
|
||||
# browser_ui_history_menu.js\
|
||||
# browser_ui_locationbar.js\
|
||||
|
||||
libs:: $(_CHROME_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
|
||||
|
||||
libs:: $(_BROWSER_TEST_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
|
||||
|
163
browser/components/places/tests/perf/browser_ui_000_data.js
Normal file
163
browser/components/places/tests/perf/browser_ui_000_data.js
Normal file
@ -0,0 +1,163 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
|
||||
Sets up the database for subsequent performance
|
||||
tests, and test the speed of adding to history
|
||||
and bookmarks.
|
||||
|
||||
- add XXX visits distributed over XXX days
|
||||
- add XXX bookmarks distributed over XXX days
|
||||
|
||||
*/
|
||||
|
||||
/*********************** begin header **********************/
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_IDENTIFIER = "ui-perf-test";
|
||||
const TEST_SUITE = "places";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
|
||||
function add_visit(aURI, aDate) {
|
||||
var placeID = hs.addVisit(aURI,
|
||||
aDate,
|
||||
null, // no referrer
|
||||
hs.TRANSITION_TYPED, // user typed in URL bar
|
||||
false, // not redirect
|
||||
0);
|
||||
return placeID;
|
||||
}
|
||||
|
||||
function add_bookmark(aURI) {
|
||||
var bId = bs.insertBookmark(bs.unfiledBookmarksFolder, aURI,
|
||||
bs.DEFAULT_INDEX, "bookmark/" + aURI.spec);
|
||||
return bId;
|
||||
}
|
||||
|
||||
function make_test_report(testName, result, units) {
|
||||
return [TEST_IDENTIFIER, TEST_SUITE, testName, result, units||"ms"].join(":");
|
||||
}
|
||||
|
||||
// Each test is an obj w/ a name property and run method
|
||||
var ptests = [];
|
||||
|
||||
/*********************** end header **********************/
|
||||
|
||||
// add visits and bookmarks
|
||||
ptests.push({
|
||||
run: function() {
|
||||
bs.runInBatchMode({
|
||||
runBatched: function(aUserData) {
|
||||
// timespan - same as default history pref for now
|
||||
var days = 90;
|
||||
|
||||
// add visits, distributed across the timespan
|
||||
var total_visits = 300;
|
||||
var visits_per_day = total_visits/days;
|
||||
|
||||
var visit_date_microsec = Date.now() * 1000;
|
||||
var day_counter = 0;
|
||||
|
||||
var start = Date.now();
|
||||
for (var i = 0; i < days; i++) {
|
||||
visit_date_microsec -= 86400 * 1000 * 1000; // remove a day
|
||||
var spec = "http://example.com/" + visit_date_microsec;
|
||||
for (var j = 0; j < visits_per_day; j++) {
|
||||
var uri = ios.newURI(spec + j, null, null);
|
||||
add_visit(uri, visit_date_microsec);
|
||||
}
|
||||
}
|
||||
var duration = Date.now() - start;
|
||||
var report = make_test_report("add_visits", duration);
|
||||
ok(true, report);
|
||||
|
||||
// add bookmarks
|
||||
var bookmarks_total = total_visits/10; // bookmark a tenth of the URLs in history
|
||||
var bookmarks_per_day = bookmarks_total/days;
|
||||
|
||||
// reset visit date counter
|
||||
visit_date_microsec = Date.now() * 1000;
|
||||
var bookmark_counter = 0;
|
||||
start = Date.now();
|
||||
for (var i = 0; i < days; i++) {
|
||||
visit_date_microsec -= 86400 * 1000 * 1000; // remove a day
|
||||
var spec = "http://example.com/" + visit_date_microsec;
|
||||
for (var j = 0; j < visits_per_day; j++) {
|
||||
var uri = ios.newURI(spec + j, null, null);
|
||||
if (bookmark_counter < bookmarks_per_day) {
|
||||
add_bookmark(uri);
|
||||
bookmark_counter++;
|
||||
}
|
||||
else
|
||||
bookmark_counter = 0;
|
||||
}
|
||||
}
|
||||
duration = Date.now() - start;
|
||||
report = make_test_report("add_bookmarks", duration);
|
||||
ok(true, report);
|
||||
runNextTest();
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
});
|
||||
|
||||
function test() {
|
||||
// kick off tests
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (ptests.length > 0)
|
||||
ptests.shift().run();
|
||||
else
|
||||
finish();
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
Tests the performance of opening the bookmarks sidebar
|
||||
|
||||
*/
|
||||
|
||||
/*********************** begin header **********************/
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_IDENTIFIER = "ui-perf-test";
|
||||
const TEST_SUITE = "places";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
|
||||
function add_visit(aURI, aDate) {
|
||||
var placeID = hs.addVisit(aURI,
|
||||
aDate,
|
||||
null, // no referrer
|
||||
hs.TRANSITION_TYPED, // user typed in URL bar
|
||||
false, // not redirect
|
||||
0);
|
||||
return placeID;
|
||||
}
|
||||
|
||||
function add_bookmark(aURI) {
|
||||
var bId = bs.insertBookmark(bs.unfiledBookmarksFolder, aURI,
|
||||
bs.DEFAULT_INDEX, "bookmark/" + aURI.spec);
|
||||
return bId;
|
||||
}
|
||||
|
||||
function make_test_report(testName, result, units) {
|
||||
return [TEST_IDENTIFIER, TEST_SUITE, testName, result, units||"ms"].join(":");
|
||||
}
|
||||
|
||||
// Each test is an obj w/ a name property and run method
|
||||
var ptests = [];
|
||||
|
||||
/*********************** end header **********************/
|
||||
|
||||
const TEST_REPEAT_COUNT = 10;
|
||||
|
||||
// test duration of bookmarks sidebar opening
|
||||
ptests.push({
|
||||
name: "open_bookmarks_sidebar",
|
||||
times: [],
|
||||
run: function() {
|
||||
var self = this;
|
||||
var start = Date.now();
|
||||
var sb = document.getElementById("sidebar");
|
||||
sb.addEventListener("load", function() {
|
||||
var duration = Date.now() - start;
|
||||
sb.removeEventListener("load", arguments.callee, true);
|
||||
toggleSidebar("viewBookmarksSidebar", false);
|
||||
self.times.push(duration);
|
||||
if (self.times.length == TEST_REPEAT_COUNT)
|
||||
self.finish();
|
||||
else
|
||||
self.run();
|
||||
}, true);
|
||||
toggleSidebar("viewBookmarksSidebar", true);
|
||||
},
|
||||
finish: function() {
|
||||
this.times.sort(); // sort the scores
|
||||
this.times.pop(); // remove worst
|
||||
this.times.shift(); // remove best
|
||||
var totalDuration = this.times.reduce(function(time, total){ return time + total; });
|
||||
var avgDuration = totalDuration/this.times.length;
|
||||
var report = make_test_report("open_bookmarks_sidebar", avgDuration);
|
||||
ok(true, report);
|
||||
runNextTest();
|
||||
}
|
||||
});
|
||||
|
||||
function test() {
|
||||
// kick off tests
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (ptests.length > 0)
|
||||
ptests.shift().run();
|
||||
else
|
||||
finish();
|
||||
}
|
127
browser/components/places/tests/perf/browser_ui_history_menu.js
Normal file
127
browser/components/places/tests/perf/browser_ui_history_menu.js
Normal file
@ -0,0 +1,127 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
Tests the performance of opening the history menu.
|
||||
*/
|
||||
|
||||
/*********************** begin header **********************/
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_IDENTIFIER = "ui-perf-test";
|
||||
const TEST_SUITE = "places";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
|
||||
function add_visit(aURI, aDate) {
|
||||
var placeID = hs.addVisit(aURI,
|
||||
aDate,
|
||||
null, // no referrer
|
||||
hs.TRANSITION_TYPED, // user typed in URL bar
|
||||
false, // not redirect
|
||||
0);
|
||||
return placeID;
|
||||
}
|
||||
|
||||
function add_bookmark(aURI) {
|
||||
var bId = bs.insertBookmark(bs.unfiledBookmarksFolder, aURI,
|
||||
bs.DEFAULT_INDEX, "bookmark/" + aURI.spec);
|
||||
return bId;
|
||||
}
|
||||
|
||||
function make_test_report(testName, result, units) {
|
||||
return [TEST_IDENTIFIER, TEST_SUITE, testName, result, units||"ms"].join(":");
|
||||
}
|
||||
|
||||
// Each test is an obj w/ a name property and run method
|
||||
var ptests = [];
|
||||
|
||||
/*********************** end header **********************/
|
||||
|
||||
// test duration of history menu opening
|
||||
ptests.push({
|
||||
name: "open_history_menu",
|
||||
run: function() {
|
||||
var menu = document.getElementById("history-menu");
|
||||
ok(menu, "history menu should exist!");
|
||||
var start = Date.now();
|
||||
|
||||
var popup = document.getElementById("goPopup");
|
||||
popup.addEventListener("popupshown", function() {
|
||||
var duration = Date.now() - start;
|
||||
var report = make_test_report("open_history_menu", duration);
|
||||
ok(true, report);
|
||||
|
||||
// clean up
|
||||
popup.removeEventListener("popupshown", arguments.callee, false);
|
||||
menu.open = false;
|
||||
|
||||
runNextTest();
|
||||
}, false);
|
||||
|
||||
// XXX does not work, is still open=false immediately after setting it to true
|
||||
//menu.open = true;
|
||||
|
||||
// XXX does nada
|
||||
//EventUtils.sendMouseEvent({type:"click"}, "history-menu");
|
||||
}
|
||||
});
|
||||
|
||||
function test() {
|
||||
// kick off tests
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (ptests.length > 0)
|
||||
ptests.shift().run();
|
||||
else
|
||||
finish();
|
||||
}
|
@ -0,0 +1,246 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
Tests the performance of opening the History
|
||||
sidebar in all the available views.
|
||||
*/
|
||||
|
||||
/*********************** begin header **********************/
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_IDENTIFIER = "ui-perf-test";
|
||||
const TEST_SUITE = "places";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
|
||||
function add_visit(aURI, aDate) {
|
||||
var placeID = hs.addVisit(aURI,
|
||||
aDate,
|
||||
null, // no referrer
|
||||
hs.TRANSITION_TYPED, // user typed in URL bar
|
||||
false, // not redirect
|
||||
0);
|
||||
return placeID;
|
||||
}
|
||||
|
||||
function add_bookmark(aURI) {
|
||||
var bId = bs.insertBookmark(bs.unfiledBookmarksFolder, aURI,
|
||||
bs.DEFAULT_INDEX, "bookmark/" + aURI.spec);
|
||||
return bId;
|
||||
}
|
||||
|
||||
function make_test_report(testName, result, units) {
|
||||
return [TEST_IDENTIFIER, TEST_SUITE, testName, result, units||"ms"].join(":");
|
||||
}
|
||||
|
||||
// Each test is an obj w/ a name property and run method
|
||||
var ptests = [];
|
||||
|
||||
/*********************** end header **********************/
|
||||
|
||||
const TEST_REPEAT_COUNT = 10;
|
||||
|
||||
// test duration of history sidebar opening
|
||||
// default: bydayandsite
|
||||
ptests.push({
|
||||
name: "open_history_sidebar_bydayandsite",
|
||||
times: [],
|
||||
run: function() {
|
||||
var self = this;
|
||||
var start = Date.now();
|
||||
var sb = document.getElementById("sidebar");
|
||||
sb.addEventListener("load", function(aEvent) {
|
||||
sb.removeEventListener("load", arguments.callee, true);
|
||||
var duration = Date.now() - start;
|
||||
toggleSidebar("viewHistorySidebar", false);
|
||||
self.times.push(duration);
|
||||
if (self.times.length == TEST_REPEAT_COUNT)
|
||||
self.finish();
|
||||
else
|
||||
self.run();
|
||||
}, true);
|
||||
toggleSidebar("viewHistorySidebar", true);
|
||||
},
|
||||
finish: function() {
|
||||
processTestResult(this);
|
||||
runNextTest();
|
||||
}
|
||||
});
|
||||
|
||||
// bysite
|
||||
ptests.push({
|
||||
name: "history_sidebar_bysite",
|
||||
times: [],
|
||||
run: function() {
|
||||
var self = this;
|
||||
var start = Date.now();
|
||||
var sb = document.getElementById("sidebar");
|
||||
sb.addEventListener("load", function() {
|
||||
var duration = Date.now() - start;
|
||||
sb.removeEventListener("load", arguments.callee, true);
|
||||
sb.contentDocument.getElementById("bysite").doCommand();
|
||||
toggleSidebar("viewHistorySidebar", false);
|
||||
self.times.push(duration);
|
||||
if (self.times.length == TEST_REPEAT_COUNT)
|
||||
self.finish();
|
||||
else
|
||||
self.run();
|
||||
}, true);
|
||||
toggleSidebar("viewHistorySidebar", true);
|
||||
},
|
||||
finish: function() {
|
||||
processTestResult(this);
|
||||
runNextTest();
|
||||
}
|
||||
});
|
||||
|
||||
// byday
|
||||
ptests.push({
|
||||
name: "history_sidebar_byday",
|
||||
times: [],
|
||||
run: function() {
|
||||
var self = this;
|
||||
var start = Date.now();
|
||||
var sb = document.getElementById("sidebar");
|
||||
sb.addEventListener("load", function() {
|
||||
var duration = Date.now() - start;
|
||||
sb.removeEventListener("load", arguments.callee, true);
|
||||
sb.contentDocument.getElementById("byday").doCommand();
|
||||
toggleSidebar("viewHistorySidebar", false);
|
||||
self.times.push(duration);
|
||||
if (self.times.length == TEST_REPEAT_COUNT)
|
||||
self.finish();
|
||||
else
|
||||
self.run();
|
||||
}, true);
|
||||
toggleSidebar("viewHistorySidebar", true);
|
||||
},
|
||||
finish: function() {
|
||||
processTestResult(this);
|
||||
runNextTest();
|
||||
}
|
||||
});
|
||||
|
||||
// byvisited
|
||||
ptests.push({
|
||||
name: "history_sidebar_byvisited",
|
||||
times: [],
|
||||
run: function() {
|
||||
var self = this;
|
||||
var start = Date.now();
|
||||
var sb = document.getElementById("sidebar");
|
||||
sb.addEventListener("load", function() {
|
||||
var duration = Date.now() - start;
|
||||
sb.removeEventListener("load", arguments.callee, true);
|
||||
sb.contentDocument.getElementById("byvisited").doCommand();
|
||||
toggleSidebar("viewHistorySidebar", false);
|
||||
self.times.push(duration);
|
||||
if (self.times.length == TEST_REPEAT_COUNT)
|
||||
self.finish();
|
||||
else
|
||||
self.run();
|
||||
}, true);
|
||||
toggleSidebar("viewHistorySidebar", true);
|
||||
},
|
||||
finish: function() {
|
||||
processTestResult(this);
|
||||
runNextTest();
|
||||
}
|
||||
});
|
||||
|
||||
// bylastvisited
|
||||
ptests.push({
|
||||
name: "history_sidebar_bylastvisited",
|
||||
times: [],
|
||||
run: function() {
|
||||
var self = this;
|
||||
var start = Date.now();
|
||||
var sb = document.getElementById("sidebar");
|
||||
sb.addEventListener("load", function() {
|
||||
var duration = Date.now() - start;
|
||||
sb.removeEventListener("load", arguments.callee, true);
|
||||
sb.contentDocument.getElementById("bylastvisited").doCommand();
|
||||
toggleSidebar("viewHistorySidebar", false);
|
||||
self.times.push(duration);
|
||||
if (self.times.length == TEST_REPEAT_COUNT)
|
||||
self.finish();
|
||||
else
|
||||
self.run();
|
||||
}, true);
|
||||
toggleSidebar("viewHistorySidebar", true);
|
||||
},
|
||||
finish: function() {
|
||||
processTestResult(this);
|
||||
runNextTest();
|
||||
}
|
||||
});
|
||||
|
||||
function processTestResult(aTest) {
|
||||
aTest.times.sort(); // sort the scores
|
||||
aTest.times.pop(); // remove worst
|
||||
aTest.times.shift(); // remove best
|
||||
var totalDuration = aTest.times.reduce(function(time, total){ return time + total; });
|
||||
var avgDuration = totalDuration/aTest.times.length;
|
||||
var report = make_test_report(aTest.name, avgDuration);
|
||||
ok(true, report);
|
||||
}
|
||||
|
||||
function test() {
|
||||
// kick off tests
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (ptests.length > 0)
|
||||
ptests.shift().run();
|
||||
else
|
||||
finish();
|
||||
}
|
114
browser/components/places/tests/perf/browser_ui_locationbar.js
Normal file
114
browser/components/places/tests/perf/browser_ui_locationbar.js
Normal file
@ -0,0 +1,114 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
Tests the performance of opening the location bar dropdown.
|
||||
*/
|
||||
|
||||
/*********************** begin header **********************/
|
||||
waitForExplicitFinish();
|
||||
|
||||
const TEST_IDENTIFIER = "ui-perf-test";
|
||||
const TEST_SUITE = "places";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
|
||||
function add_visit(aURI, aDate) {
|
||||
var placeID = hs.addVisit(aURI,
|
||||
aDate,
|
||||
null, // no referrer
|
||||
hs.TRANSITION_TYPED, // user typed in URL bar
|
||||
false, // not redirect
|
||||
0);
|
||||
return placeID;
|
||||
}
|
||||
|
||||
function add_bookmark(aURI) {
|
||||
var bId = bs.insertBookmark(bs.unfiledBookmarksFolder, aURI,
|
||||
bs.DEFAULT_INDEX, "bookmark/" + aURI.spec);
|
||||
return bId;
|
||||
}
|
||||
|
||||
function make_test_report(testName, result, units) {
|
||||
return [TEST_IDENTIFIER, TEST_SUITE, testName, result, units||"ms"].join(":");
|
||||
}
|
||||
|
||||
// Each test is an obj w/ a name property and run method
|
||||
var ptests = [];
|
||||
|
||||
/*********************** end header **********************/
|
||||
|
||||
// test duration of history menu opening
|
||||
ptests.push({
|
||||
name: "open_locationbar_default",
|
||||
run: function() {
|
||||
var urlbar = document.getElementById("urlbar");
|
||||
urlbar.addEventListener("onsearchcomplete", function() {
|
||||
urlbar.removeEventListener("onsearchcomplete", arguments.callee, false);
|
||||
runNextTest();
|
||||
}, false);
|
||||
|
||||
urlbar.value = "example";
|
||||
urlbar.select();
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
});
|
||||
|
||||
function test() {
|
||||
// kick off tests
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (ptests.length > 0)
|
||||
ptests.shift().run();
|
||||
else
|
||||
finish();
|
||||
}
|
@ -43,7 +43,7 @@ VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += tests
|
||||
endif
|
||||
|
||||
|
@ -67,8 +67,11 @@ var gCookiesWindow = {
|
||||
|
||||
if ("arguments" in window && window.arguments[0] &&
|
||||
window.arguments[0].filterString)
|
||||
this.setFilter(window.arguments[0].filterString);
|
||||
|
||||
{
|
||||
document.getElementById("filter").value = window.arguments[0].filterString;
|
||||
this.filter();
|
||||
}
|
||||
|
||||
this._saveState();
|
||||
|
||||
document.getElementById("filter").focus();
|
||||
@ -790,8 +793,7 @@ var gCookiesWindow = {
|
||||
// Revert to single-select in the tree
|
||||
this._tree.setAttribute("seltype", "single");
|
||||
|
||||
// Clear the Filter and the Tree Display
|
||||
document.getElementById("filter").value = "";
|
||||
// Clear the Tree Display
|
||||
this._view._filtered = false;
|
||||
this._view._rowCount = 0;
|
||||
this._tree.treeBoxObject.rowCountChanged(0, -this._view._filterSet.length);
|
||||
@ -826,8 +828,6 @@ var gCookiesWindow = {
|
||||
this._lastSelectedRanges = [];
|
||||
|
||||
document.getElementById("cookiesIntro").value = this._bundle.getString("cookiesAll");
|
||||
document.getElementById("clearFilter").disabled = true;
|
||||
document.getElementById("filter").focus();
|
||||
},
|
||||
|
||||
_cookieMatchesFilter: function (aCookie)
|
||||
@ -875,68 +875,44 @@ var gCookiesWindow = {
|
||||
this._openIndices.push(i);
|
||||
}
|
||||
},
|
||||
|
||||
_filterTimeout: -1,
|
||||
onFilterInput: function ()
|
||||
{
|
||||
if (this._filterTimeout != -1)
|
||||
clearTimeout(this._filterTimeout);
|
||||
|
||||
function filterCookies()
|
||||
{
|
||||
var filter = document.getElementById("filter").value;
|
||||
if (filter == "") {
|
||||
gCookiesWindow.clearFilter();
|
||||
return;
|
||||
}
|
||||
var view = gCookiesWindow._view;
|
||||
view._filterSet = gCookiesWindow._filterCookies(filter);
|
||||
if (!view._filtered) {
|
||||
// Save Display Info for the Non-Filtered mode when we first
|
||||
// enter Filtered mode.
|
||||
gCookiesWindow._saveState();
|
||||
view._filtered = true;
|
||||
}
|
||||
// Move to multi-select in the tree
|
||||
gCookiesWindow._tree.setAttribute("seltype", "multiple");
|
||||
|
||||
// Clear the display
|
||||
var oldCount = view._rowCount;
|
||||
view._rowCount = 0;
|
||||
gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, -oldCount);
|
||||
// Set up the filtered display
|
||||
view._rowCount = view._filterSet.length;
|
||||
gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, view.rowCount);
|
||||
|
||||
// if the view is not empty then select the first item
|
||||
if (view.rowCount > 0)
|
||||
view.selection.select(0);
|
||||
|
||||
document.getElementById("cookiesIntro").value = gCookiesWindow._bundle.getString("cookiesFiltered");
|
||||
document.getElementById("clearFilter").disabled = false;
|
||||
}
|
||||
window.filterCookies = filterCookies;
|
||||
this._filterTimeout = setTimeout("filterCookies();", 500);
|
||||
},
|
||||
|
||||
onFilterKeyPress: function (aEvent)
|
||||
filter: function ()
|
||||
{
|
||||
var filter = document.getElementById("filter").value;
|
||||
if (aEvent.keyCode == 27 && filter != "") // ESC key
|
||||
this.clearFilter();
|
||||
if (filter == "") {
|
||||
gCookiesWindow.clearFilter();
|
||||
return;
|
||||
}
|
||||
var view = gCookiesWindow._view;
|
||||
view._filterSet = gCookiesWindow._filterCookies(filter);
|
||||
if (!view._filtered) {
|
||||
// Save Display Info for the Non-Filtered mode when we first
|
||||
// enter Filtered mode.
|
||||
gCookiesWindow._saveState();
|
||||
view._filtered = true;
|
||||
}
|
||||
// Move to multi-select in the tree
|
||||
gCookiesWindow._tree.setAttribute("seltype", "multiple");
|
||||
|
||||
// Clear the display
|
||||
var oldCount = view._rowCount;
|
||||
view._rowCount = 0;
|
||||
gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, -oldCount);
|
||||
// Set up the filtered display
|
||||
view._rowCount = view._filterSet.length;
|
||||
gCookiesWindow._tree.treeBoxObject.rowCountChanged(0, view.rowCount);
|
||||
|
||||
// if the view is not empty then select the first item
|
||||
if (view.rowCount > 0)
|
||||
view.selection.select(0);
|
||||
|
||||
document.getElementById("cookiesIntro").value = gCookiesWindow._bundle.getString("cookiesFiltered");
|
||||
},
|
||||
|
||||
|
||||
focusFilterBox: function ()
|
||||
{
|
||||
{
|
||||
var filter = document.getElementById("filter");
|
||||
filter.focus();
|
||||
filter.select();
|
||||
},
|
||||
|
||||
setFilter: function (aFilterString)
|
||||
{
|
||||
document.getElementById("filter").value = aFilterString;
|
||||
this.onFilterInput();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -62,15 +62,11 @@
|
||||
<key key="&focusSearch1.key;" modifiers="accel" oncommand="gCookiesWindow.focusFilterBox();"/>
|
||||
<key key="&focusSearch2.key;" modifiers="accel" oncommand="gCookiesWindow.focusFilterBox();"/>
|
||||
</keyset>
|
||||
|
||||
|
||||
<vbox flex="1" class="contentPane">
|
||||
<hbox align="center">
|
||||
<label accesskey="&filter.accesskey;" control="filter">&filter.label;</label>
|
||||
<textbox id="filter" flex="1" oninput="gCookiesWindow.onFilterInput();"
|
||||
onkeypress="gCookiesWindow.onFilterKeyPress(event);"/>
|
||||
<button id="clearFilter" icon="clear" label="&clear.label;"
|
||||
accesskey="&clear.accesskey;"
|
||||
oncommand="gCookiesWindow.clearFilter();" disabled="true"/>
|
||||
<textbox type="search" id="filter" flex="1" oncommand="gCookiesWindow.filter();"/>
|
||||
</hbox>
|
||||
<separator class="thin"/>
|
||||
<label control="cookiesList" id="cookiesIntro" value="&cookiesonsystem.label;"/>
|
||||
|
@ -45,7 +45,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = src
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += content/test
|
||||
endif
|
||||
|
||||
|
@ -43,7 +43,7 @@ VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS = test
|
||||
endif
|
||||
|
||||
|
@ -1553,13 +1553,6 @@ Engine.prototype = {
|
||||
* the engine object.
|
||||
*/
|
||||
_parseAsSherlock: function SRCH_ENG_parseAsSherlock() {
|
||||
/**
|
||||
* Trims leading and trailing whitespace from aStr.
|
||||
*/
|
||||
function sTrim(aStr) {
|
||||
return aStr.replace(/^\s+/g, "").replace(/\s+$/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts one Sherlock "section" from aSource. A section is essentially
|
||||
* an HTML element with attributes, but each attribute must be on a new
|
||||
@ -1616,11 +1609,11 @@ Engine.prototype = {
|
||||
|
||||
var section = {};
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = sTrim(lines[i]);
|
||||
var line = lines[i].trim();
|
||||
|
||||
var els = line.split("=");
|
||||
var name = sTrim(els.shift().toLowerCase());
|
||||
var value = sTrim(els.join("="));
|
||||
var name = els.shift().trim().toLowerCase();
|
||||
var value = els.join("=").trim();
|
||||
|
||||
if (!name || !value)
|
||||
continue;
|
||||
@ -1629,7 +1622,7 @@ Engine.prototype = {
|
||||
// value, and remove any trailing slashes or ">" characters
|
||||
value = value.replace(/^["']/, "")
|
||||
.replace(/["']\s*[\\\/]?>?\s*$/, "") || "";
|
||||
value = sTrim(value);
|
||||
value = value.trim();
|
||||
|
||||
// Don't clobber existing attributes
|
||||
if (!(name in section))
|
||||
@ -1747,7 +1740,7 @@ Engine.prototype = {
|
||||
lines.forEach(function (line) {
|
||||
// Strip leading/trailing whitespace and remove the surrounding markup
|
||||
// ("<input" and ">")
|
||||
line = sTrim(line).replace(/^<input/i, "").replace(/>$/, "");
|
||||
line = line.trim().replace(/^<input/i, "").replace(/>$/, "");
|
||||
|
||||
// If this is one of the "directional" inputs (<inputnext>/<inputprev>)
|
||||
const directionalInput = /^(prev|next)/i;
|
||||
|
@ -50,7 +50,7 @@ XPIDLSRCS = \
|
||||
|
||||
DIRS = src
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
|
@ -101,44 +101,41 @@ SessionStartup.prototype = {
|
||||
// get file references
|
||||
var dirService = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
this._sessionFile = dirService.get("ProfD", Ci.nsILocalFile);
|
||||
this._sessionFile.append("sessionstore.js");
|
||||
let sessionFile = dirService.get("ProfD", Ci.nsILocalFile);
|
||||
sessionFile.append("sessionstore.js");
|
||||
|
||||
let doResumeSession = this._prefBranch.getBoolPref("sessionstore.resume_session_once") ||
|
||||
this._prefBranch.getIntPref("startup.page") == 3;
|
||||
|
||||
// only read the session file if config allows possibility of restoring
|
||||
var resumeFromCrash = this._prefBranch.getBoolPref("sessionstore.resume_from_crash");
|
||||
if ((resumeFromCrash || this._doResumeSession()) && this._sessionFile.exists()) {
|
||||
// get string containing session state
|
||||
this._iniString = this._readStateFile(this._sessionFile);
|
||||
if (this._iniString) {
|
||||
try {
|
||||
// parse the session state into JS objects
|
||||
var s = new Components.utils.Sandbox("about:blank");
|
||||
var initialState = Components.utils.evalInSandbox(this._iniString, s);
|
||||
|
||||
// set bool detecting crash
|
||||
this._lastSessionCrashed =
|
||||
initialState.session && initialState.session.state &&
|
||||
initialState.session.state == STATE_RUNNING_STR;
|
||||
// invalid .INI file - nothing can be restored
|
||||
}
|
||||
catch (ex) { debug("The session file is invalid: " + ex); }
|
||||
}
|
||||
}
|
||||
|
||||
// prompt and check prefs
|
||||
if (this._iniString) {
|
||||
if (this._lastSessionCrashed && this._doRecoverSession())
|
||||
this._sessionType = Ci.nsISessionStartup.RECOVER_SESSION;
|
||||
else if (!this._lastSessionCrashed && this._doResumeSession())
|
||||
this._sessionType = Ci.nsISessionStartup.RESUME_SESSION;
|
||||
else
|
||||
this._iniString = null; // reset the state string
|
||||
}
|
||||
|
||||
if (this._prefBranch.getBoolPref("sessionstore.resume_session_once")) {
|
||||
this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
|
||||
}
|
||||
if (!resumeFromCrash && !doResumeSession || !sessionFile.exists())
|
||||
return;
|
||||
|
||||
// get string containing session state
|
||||
this._iniString = this._readStateFile(sessionFile);
|
||||
if (!this._iniString)
|
||||
return;
|
||||
|
||||
try {
|
||||
// parse the session state into JS objects
|
||||
var s = new Components.utils.Sandbox("about:blank");
|
||||
var initialState = Components.utils.evalInSandbox(this._iniString, s);
|
||||
}
|
||||
catch (ex) { debug("The session file is invalid: " + ex); }
|
||||
|
||||
let lastSessionCrashed =
|
||||
initialState && initialState.session && initialState.session.state &&
|
||||
initialState.session.state == STATE_RUNNING_STR;
|
||||
|
||||
// set the startup type
|
||||
if (lastSessionCrashed && resumeFromCrash && this._doRecoverSession())
|
||||
this._sessionType = Ci.nsISessionStartup.RECOVER_SESSION;
|
||||
else if (!lastSessionCrashed && doResumeSession)
|
||||
this._sessionType = Ci.nsISessionStartup.RESUME_SESSION;
|
||||
else
|
||||
this._iniString = null; // reset the state string
|
||||
|
||||
if (this._sessionType != Ci.nsISessionStartup.NO_SESSION) {
|
||||
// wait for the first browser window to open
|
||||
var observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
@ -165,8 +162,7 @@ SessionStartup.prototype = {
|
||||
this.init();
|
||||
break;
|
||||
case "quit-application":
|
||||
// make sure that we don't init at this point, as that might
|
||||
// unwantedly discard the session (cf. bug 409115)
|
||||
// no reason for initializing at this point (cf. bug 409115)
|
||||
observerService.removeObserver(this, "final-ui-startup");
|
||||
observerService.removeObserver(this, "quit-application");
|
||||
break;
|
||||
@ -241,25 +237,12 @@ SessionStartup.prototype = {
|
||||
|
||||
/* ........ Auxiliary Functions .............. */
|
||||
|
||||
/**
|
||||
* Whether or not to resume session, if not recovering from a crash.
|
||||
* @returns bool
|
||||
*/
|
||||
_doResumeSession: function sss_doResumeSession() {
|
||||
return this._prefBranch.getIntPref("startup.page") == 3 ||
|
||||
this._prefBranch.getBoolPref("sessionstore.resume_session_once");
|
||||
},
|
||||
|
||||
/**
|
||||
* prompt user whether or not to restore the previous session,
|
||||
* if the browser crashed
|
||||
* @returns bool
|
||||
*/
|
||||
_doRecoverSession: function sss_doRecoverSession() {
|
||||
// do not prompt or resume, post-crash
|
||||
if (!this._prefBranch.getBoolPref("sessionstore.resume_from_crash"))
|
||||
return false;
|
||||
|
||||
// if the prompt fails, recover anyway
|
||||
var recover = true;
|
||||
|
||||
@ -365,7 +348,7 @@ SessionStartup.prototype = {
|
||||
|
||||
return content.replace(/\r\n?/g, "\n");
|
||||
}
|
||||
catch (ex) { } // inexisting file?
|
||||
catch (ex) { Components.utils.reportError(ex); }
|
||||
|
||||
return null;
|
||||
},
|
||||
@ -386,8 +369,5 @@ SessionStartup.prototype = {
|
||||
|
||||
};
|
||||
|
||||
//module initialization
|
||||
function NSGetModule(aCompMgr, aFileSpec) {
|
||||
return XPCOMUtils.generateModule([SessionStartup]);
|
||||
}
|
||||
|
||||
function NSGetModule(aCompMgr, aFileSpec)
|
||||
XPCOMUtils.generateModule([SessionStartup]);
|
||||
|
@ -144,14 +144,12 @@ SessionStoreService.prototype = {
|
||||
_windows: {},
|
||||
|
||||
// in case the last closed window ain't a navigator:browser one
|
||||
_lastWindowClosed: null,
|
||||
// (also contains browser popup windows closed after the last non-popup one)
|
||||
_lastClosedWindows: null,
|
||||
|
||||
// not-"dirty" windows usually don't need to have their data updated
|
||||
_dirtyWindows: {},
|
||||
|
||||
// flag all windows as dirty
|
||||
_dirty: false,
|
||||
|
||||
/* ........ Global Event Handlers .............. */
|
||||
|
||||
/**
|
||||
@ -195,7 +193,7 @@ SessionStoreService.prototype = {
|
||||
this._sessionFileBackup = this._sessionFile.clone();
|
||||
this._sessionFile.append("sessionstore.js");
|
||||
this._sessionFileBackup.append("sessionstore.bak");
|
||||
|
||||
|
||||
// get string containing session state
|
||||
var iniString;
|
||||
try {
|
||||
@ -210,29 +208,34 @@ SessionStoreService.prototype = {
|
||||
try {
|
||||
// parse the session state into JS objects
|
||||
this._initialState = this._safeEval(iniString);
|
||||
// set bool detecting crash
|
||||
this._lastSessionCrashed =
|
||||
|
||||
// if last session crashed, backup the session
|
||||
let lastSessionCrashed =
|
||||
this._initialState.session && this._initialState.session.state &&
|
||||
this._initialState.session.state == STATE_RUNNING_STR;
|
||||
if (lastSessionCrashed) {
|
||||
try {
|
||||
this._writeFile(this._sessionFileBackup, iniString);
|
||||
}
|
||||
catch (ex) { } // nothing else we can do here
|
||||
}
|
||||
|
||||
// make sure that at least the first window doesn't have anything hidden
|
||||
delete this._initialState.windows[0].hidden;
|
||||
}
|
||||
catch (ex) { debug("The session file is invalid: " + ex); }
|
||||
}
|
||||
|
||||
// if last session crashed, backup the session
|
||||
if (this._lastSessionCrashed) {
|
||||
try {
|
||||
this._writeFile(this._sessionFileBackup, iniString);
|
||||
}
|
||||
catch (ex) { } // nothing else we can do here
|
||||
}
|
||||
|
||||
// remove the session data files if crash recovery is disabled
|
||||
if (!this._resume_from_crash)
|
||||
this._clearDisk();
|
||||
|
||||
// at this point, we've as good as resumed the session, so we can
|
||||
// clear the resume_session_once flag, if it's set
|
||||
if (this._loadState != STATE_QUITTING &&
|
||||
this._prefBranch.getBoolPref("sessionstore.resume_session_once"))
|
||||
this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
|
||||
|
||||
// As this is called at delayedStartup, restoration must be initiated here
|
||||
this.onLoad(aWindow);
|
||||
},
|
||||
@ -278,7 +281,6 @@ SessionStoreService.prototype = {
|
||||
this._collectWindowData(aWindow);
|
||||
});
|
||||
this._dirtyWindows = [];
|
||||
this._dirty = false;
|
||||
break;
|
||||
case "quit-application-granted":
|
||||
// freeze the data at what we've got (ignoring closing windows)
|
||||
@ -291,22 +293,27 @@ SessionStoreService.prototype = {
|
||||
this._uninit();
|
||||
break;
|
||||
case "browser:purge-session-history": // catch sanitization
|
||||
let openWindows = {};
|
||||
this._forEachBrowserWindow(function(aWindow) {
|
||||
Array.forEach(aWindow.getBrowser().browsers, function(aBrowser) {
|
||||
delete aBrowser.parentNode.__SS_data;
|
||||
});
|
||||
openWindows[aWindow.__SSi] = true;
|
||||
});
|
||||
this._lastWindowClosed = null;
|
||||
this._clearDisk();
|
||||
// also clear all data about closed tabs
|
||||
// also clear all data about closed tabs and windows
|
||||
for (ix in this._windows) {
|
||||
this._windows[ix]._closedTabs = [];
|
||||
if (ix in openWindows)
|
||||
this._windows[ix]._closedTabs = [];
|
||||
else
|
||||
delete this._windows[ix];
|
||||
}
|
||||
this._lastClosedWindows = null;
|
||||
this._clearDisk();
|
||||
// give the tabbrowsers a chance to clear their histories first
|
||||
var win = this._getMostRecentBrowserWindow();
|
||||
if (win)
|
||||
win.setTimeout(function() { _this.saveState(true); }, 0);
|
||||
else
|
||||
else if (this._loadState == STATE_RUNNING)
|
||||
this.saveState(true);
|
||||
break;
|
||||
case "nsPref:changed": // catch pref changes
|
||||
@ -357,9 +364,13 @@ SessionStoreService.prototype = {
|
||||
case "pageshow":
|
||||
this.onTabLoad(aEvent.currentTarget.ownerDocument.defaultView, aEvent.currentTarget, aEvent);
|
||||
break;
|
||||
case "change":
|
||||
case "input":
|
||||
case "DOMAutoComplete":
|
||||
this.onTabInput(aEvent.currentTarget.ownerDocument.defaultView, aEvent.currentTarget, aEvent);
|
||||
this.onTabInput(aEvent.currentTarget.ownerDocument.defaultView, aEvent.currentTarget);
|
||||
break;
|
||||
case "scroll":
|
||||
this.onTabScroll(aEvent.currentTarget.ownerDocument.defaultView);
|
||||
break;
|
||||
case "TabOpen":
|
||||
case "TabClose":
|
||||
@ -404,6 +415,8 @@ SessionStoreService.prototype = {
|
||||
|
||||
// and create its data object
|
||||
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [] };
|
||||
if (!aWindow.toolbar.visible)
|
||||
this._windows[aWindow.__SSi].isPopup = true;
|
||||
|
||||
// perform additional initialization when the first window is loading
|
||||
if (this._loadState == STATE_STOPPED) {
|
||||
@ -472,9 +485,16 @@ SessionStoreService.prototype = {
|
||||
this._collectWindowData(aWindow);
|
||||
|
||||
// preserve this window's data (in case it was the last navigator:browser)
|
||||
this._lastWindowClosed = this._windows[aWindow.__SSi];
|
||||
this._lastWindowClosed.title = aWindow.content.document.title;
|
||||
this._updateCookies([this._lastWindowClosed]);
|
||||
var winData = this._windows[aWindow.__SSi];
|
||||
winData.title = aWindow.content.document.title;
|
||||
|
||||
// if this is a popup window, append it to what we've already got (cf. bug 368677)
|
||||
if (!this._lastClosedWindows || !winData.isPopup)
|
||||
this._lastClosedWindows = [winData];
|
||||
else
|
||||
this._lastClosedWindows.push(winData);
|
||||
|
||||
this._updateCookies(this._lastClosedWindows);
|
||||
|
||||
// clear this window from the list
|
||||
delete this._windows[aWindow.__SSi];
|
||||
@ -488,7 +508,7 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
|
||||
// cache the window state until the window is completely gone
|
||||
aWindow.__SS_dyingCache = this._windows[aWindow.__SSi] || this._lastWindowClosed;
|
||||
aWindow.__SS_dyingCache = this._windows[aWindow.__SSi] || winData;
|
||||
|
||||
// reset the _tab property to avoid keeping the tab's XUL element alive
|
||||
// longer than we need it
|
||||
@ -512,8 +532,10 @@ SessionStoreService.prototype = {
|
||||
onTabAdd: function sss_onTabAdd(aWindow, aPanel, aNoNotification) {
|
||||
aPanel.addEventListener("load", this, true);
|
||||
aPanel.addEventListener("pageshow", this, true);
|
||||
aPanel.addEventListener("change", this, true);
|
||||
aPanel.addEventListener("input", this, true);
|
||||
aPanel.addEventListener("DOMAutoComplete", this, true);
|
||||
aPanel.addEventListener("scroll", this, true);
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
@ -532,11 +554,12 @@ SessionStoreService.prototype = {
|
||||
onTabRemove: function sss_onTabRemove(aWindow, aPanel, aNoNotification) {
|
||||
aPanel.removeEventListener("load", this, true);
|
||||
aPanel.removeEventListener("pageshow", this, true);
|
||||
aPanel.removeEventListener("change", this, true);
|
||||
aPanel.removeEventListener("input", this, true);
|
||||
aPanel.removeEventListener("DOMAutoComplete", this, true);
|
||||
aPanel.removeEventListener("scroll", this, true);
|
||||
|
||||
delete aPanel.__SS_data;
|
||||
delete aPanel.__SS_text;
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
@ -572,10 +595,18 @@ SessionStoreService.prototype = {
|
||||
delete tabState._tab;
|
||||
|
||||
// store closed-tab data for undo
|
||||
if (tabState.entries.length > 1 || tabState.entries[0].url != "about:blank") {
|
||||
if (tabState.entries.length > 0) {
|
||||
let tabTitle = aTab.label;
|
||||
let tabbrowser = aWindow.gBrowser;
|
||||
// replace "Loading..." with the document title (with minimal side-effects)
|
||||
if (tabTitle == tabbrowser.mStringBundle.getString("tabs.loading")) {
|
||||
tabbrowser.setTabTitle(aTab);
|
||||
[tabTitle, aTab.label] = [aTab.label, tabTitle];
|
||||
}
|
||||
|
||||
this._windows[aWindow.__SSi]._closedTabs.unshift({
|
||||
state: tabState,
|
||||
title: aTab.getAttribute("label"),
|
||||
title: tabTitle,
|
||||
image: aTab.getAttribute("image"),
|
||||
pos: aTab._tPos
|
||||
});
|
||||
@ -602,7 +633,6 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
|
||||
delete aPanel.__SS_data;
|
||||
delete aPanel.__SS_text;
|
||||
this.saveStateDelayed(aWindow);
|
||||
|
||||
// attempt to update the current URL we send in a crash report
|
||||
@ -611,18 +641,25 @@ SessionStoreService.prototype = {
|
||||
|
||||
/**
|
||||
* Called when a tabpanel sends the "input" notification
|
||||
* stores textarea data
|
||||
* @param aWindow
|
||||
* Window reference
|
||||
* @param aPanel
|
||||
* TabPanel reference
|
||||
* @param aEvent
|
||||
* Event obj
|
||||
*/
|
||||
onTabInput: function sss_onTabInput(aWindow, aPanel, aEvent) {
|
||||
if (this._saveTextData(aPanel, aEvent.originalTarget)) {
|
||||
this.saveStateDelayed(aWindow, 3000);
|
||||
}
|
||||
onTabInput: function sss_onTabInput(aWindow, aPanel) {
|
||||
if (aPanel.__SS_data)
|
||||
delete aPanel.__SS_data._formDataSaved;
|
||||
|
||||
this.saveStateDelayed(aWindow, 3000);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a tabpanel sends a "scroll" notification
|
||||
* @param aWindow
|
||||
* Window reference
|
||||
*/
|
||||
onTabScroll: function sss_onTabScroll(aWindow) {
|
||||
this.saveStateDelayed(aWindow, 3000);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -688,7 +725,7 @@ SessionStoreService.prototype = {
|
||||
|
||||
setTabState: function sss_setTabState(aTab, aState) {
|
||||
var tabState = this._safeEval("(" + aState + ")");
|
||||
if (!tabState.entries || !tabState.entries.length) {
|
||||
if (!tabState.entries) {
|
||||
Components.returnCode = Cr.NS_ERROR_INVALID_ARG;
|
||||
return;
|
||||
}
|
||||
@ -857,7 +894,7 @@ SessionStoreService.prototype = {
|
||||
* @returns object
|
||||
*/
|
||||
_collectTabData: function sss_collectTabData(aTab, aFullData) {
|
||||
var tabData = { entries: [], index: 0 };
|
||||
var tabData = { entries: [] };
|
||||
var browser = aTab.linkedBrowser;
|
||||
|
||||
if (!browser || !browser.currentURI)
|
||||
@ -888,7 +925,8 @@ SessionStoreService.prototype = {
|
||||
if (!aFullData)
|
||||
browser.parentNode.__SS_data = tabData;
|
||||
}
|
||||
else {
|
||||
else if (browser.currentURI.spec != "about:blank" ||
|
||||
browser.contentDocument.body.hasChildNodes()) {
|
||||
tabData.entries[0] = { url: browser.currentURI.spec };
|
||||
tabData.index = 1;
|
||||
}
|
||||
@ -1031,56 +1069,6 @@ SessionStoreService.prototype = {
|
||||
return entry;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the current document's cache of user entered text data
|
||||
* @param aPanel
|
||||
* TabPanel reference
|
||||
* @param aTextarea
|
||||
* HTML content element
|
||||
* @returns bool
|
||||
*/
|
||||
_saveTextData: function sss_saveTextData(aPanel, aTextarea) {
|
||||
var id = aTextarea.id ? "#" + aTextarea.id :
|
||||
aTextarea.name;
|
||||
if (!id
|
||||
|| !(aTextarea instanceof Ci.nsIDOMHTMLTextAreaElement
|
||||
|| aTextarea instanceof Ci.nsIDOMHTMLInputElement)) {
|
||||
return false; // nothing to save
|
||||
}
|
||||
|
||||
if (!aPanel.__SS_text) {
|
||||
aPanel.__SS_text = [];
|
||||
aPanel.__SS_text._refs = [];
|
||||
}
|
||||
|
||||
// get the index of the reference to the text element
|
||||
var ix = aPanel.__SS_text._refs.indexOf(aTextarea);
|
||||
if (ix == -1) {
|
||||
// we haven't registered this text element yet - do so now
|
||||
aPanel.__SS_text._refs.push(aTextarea);
|
||||
ix = aPanel.__SS_text.length;
|
||||
}
|
||||
else if (!aPanel.__SS_text[ix].cache) {
|
||||
// we've already marked this text element for saving (the cache is
|
||||
// added during save operations and would have to be updated here)
|
||||
return false;
|
||||
}
|
||||
|
||||
// determine the frame we're in and encode it into the textarea's ID
|
||||
var content = aTextarea.ownerDocument.defaultView;
|
||||
while (content != content.top) {
|
||||
var frames = content.parent.frames;
|
||||
for (var i = 0; i < frames.length && frames[i] != content; i++);
|
||||
id = i + "|" + id;
|
||||
content = content.parent;
|
||||
}
|
||||
|
||||
// mark this element for saving
|
||||
aPanel.__SS_text[ix] = { id: id, element: aTextarea };
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* go through all tabs and store the current scroll positions
|
||||
* and innerHTML content of WYSIWYG editors
|
||||
@ -1092,8 +1080,7 @@ SessionStoreService.prototype = {
|
||||
for (var i = 0; i < browsers.length; i++) {
|
||||
try {
|
||||
var tabData = this._windows[aWindow.__SSi].tabs[i];
|
||||
if (tabData.entries.length == 0 ||
|
||||
browsers[i].parentNode.__SS_data && browsers[i].parentNode.__SS_data._tab)
|
||||
if (browsers[i].parentNode.__SS_data && browsers[i].parentNode.__SS_data._tab)
|
||||
continue; // ignore incompletely initialized tabs
|
||||
this._updateTextAndScrollDataForTab(aWindow, browsers[i], tabData);
|
||||
}
|
||||
@ -1115,66 +1102,102 @@ SessionStoreService.prototype = {
|
||||
*/
|
||||
_updateTextAndScrollDataForTab:
|
||||
function sss_updateTextAndScrollDataForTab(aWindow, aBrowser, aTabData, aFullData) {
|
||||
var text = [];
|
||||
if (aBrowser.parentNode.__SS_text &&
|
||||
(aFullData || this._checkPrivacyLevel(aBrowser.currentURI.schemeIs("https")))) {
|
||||
for (var ix = aBrowser.parentNode.__SS_text.length - 1; ix >= 0; ix--) {
|
||||
var data = aBrowser.parentNode.__SS_text[ix];
|
||||
if (!data.cache)
|
||||
// update the text element's value before adding it to the data structure
|
||||
data.cache = encodeURI(data.element.value);
|
||||
text.push(data.id + "=" + data.cache);
|
||||
}
|
||||
}
|
||||
if (aBrowser.currentURI.spec == "about:config")
|
||||
text = ["#textbox=" + encodeURI(aBrowser.contentDocument.getElementById("textbox").
|
||||
wrappedJSObject.value)];
|
||||
if (text.length > 0)
|
||||
aTabData.text = text.join(" ");
|
||||
else if (aTabData.text)
|
||||
delete aTabData.text;
|
||||
|
||||
var tabIndex = (aTabData.index || aTabData.entries.length) - 1;
|
||||
// entry data needn't exist for tabs just initialized with an incomplete session state
|
||||
if (aTabData.entries[tabIndex])
|
||||
this._updateTextAndScrollDataForFrame(aWindow, aBrowser.contentWindow,
|
||||
aTabData.entries[tabIndex], aFullData);
|
||||
if (!aTabData.entries[tabIndex])
|
||||
return;
|
||||
|
||||
this._updateTextAndScrollDataForFrame(aWindow, aBrowser.contentWindow,
|
||||
aTabData.entries[tabIndex],
|
||||
!aTabData._formDataSaved, aFullData);
|
||||
aTabData._formDataSaved = true;
|
||||
if (aBrowser.currentURI.spec == "about:config")
|
||||
aTabData.entries[tabIndex].formdata = {
|
||||
"#textbox": aBrowser.contentDocument.getElementById("textbox").wrappedJSObject.value
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* go through all subframes and store the current scroll positions
|
||||
* and innerHTML content of WYSIWYG editors
|
||||
* go through all subframes and store all form data, the current
|
||||
* scroll positions and innerHTML content of WYSIWYG editors
|
||||
* @param aWindow
|
||||
* Window reference
|
||||
* @param aContent
|
||||
* frame reference
|
||||
* @param aData
|
||||
* part of a tabData object to add the information to
|
||||
* @param aUpdateFormData
|
||||
* update all form data for this tab
|
||||
* @param aFullData
|
||||
* always return privacy sensitive data (use with care)
|
||||
*/
|
||||
_updateTextAndScrollDataForFrame:
|
||||
function sss_updateTextAndScrollDataForFrame(aWindow, aContent, aData, aFullData) {
|
||||
function sss_updateTextAndScrollDataForFrame(aWindow, aContent, aData,
|
||||
aUpdateFormData, aFullData) {
|
||||
for (var i = 0; i < aContent.frames.length; i++) {
|
||||
if (aData.children && aData.children[i])
|
||||
this._updateTextAndScrollDataForFrame(aWindow, aContent.frames[i], aData.children[i], aFullData);
|
||||
this._updateTextAndScrollDataForFrame(aWindow, aContent.frames[i],
|
||||
aData.children[i], aUpdateFormData, aFullData);
|
||||
}
|
||||
// designMode is undefined e.g. for XUL documents (as about:config)
|
||||
var isHTTPS = this._getURIFromString((aContent.parent || aContent).
|
||||
document.location.href).schemeIs("https");
|
||||
if ((aContent.document.designMode || "") == "on" &&
|
||||
(aFullData || this._checkPrivacyLevel(isHTTPS))) {
|
||||
if (aData.innerHTML === undefined && !aFullData) {
|
||||
// we get no "input" events from iframes - listen for keypress here
|
||||
var _this = this;
|
||||
aContent.addEventListener("keypress", function(aEvent) {
|
||||
_this.saveStateDelayed(aWindow, 3000); }, true);
|
||||
if (aFullData || this._checkPrivacyLevel(isHTTPS)) {
|
||||
if (aFullData || aUpdateFormData) {
|
||||
let formData = this._collectFormDataForFrame(aContent.document);
|
||||
if (formData)
|
||||
aData.formdata = formData;
|
||||
else if (aData.formdata)
|
||||
delete aData.formdata;
|
||||
}
|
||||
|
||||
// designMode is undefined e.g. for XUL documents (as about:config)
|
||||
if ((aContent.document.designMode || "") == "on") {
|
||||
if (aData.innerHTML === undefined && !aFullData) {
|
||||
// we get no "input" events from iframes - listen for keypress here
|
||||
let _this = this;
|
||||
aContent.addEventListener("keypress", function(aEvent) {
|
||||
_this.saveStateDelayed(aWindow, 3000);
|
||||
}, true);
|
||||
}
|
||||
aData.innerHTML = aContent.document.body.innerHTML;
|
||||
}
|
||||
aData.innerHTML = aContent.document.body.innerHTML;
|
||||
}
|
||||
aData.scroll = aContent.scrollX + "," + aContent.scrollY;
|
||||
},
|
||||
|
||||
/**
|
||||
* collect the state of all form elements
|
||||
* @param aDocument
|
||||
* document reference
|
||||
*/
|
||||
_collectFormDataForFrame: function sss_collectFormDataForFrame(aDocument) {
|
||||
let formNodesXPath = "//textarea|//select|//xhtml:textarea|//xhtml:select|" +
|
||||
"//input[not(@type) or @type='text' or @type='checkbox' or @type='radio' or @type='file']|" +
|
||||
"//xhtml:input[not(@type) or @type='text' or @type='checkbox' or @type='radio' or @type='file']";
|
||||
let formNodes = aDocument.evaluate(formNodesXPath, aDocument, XPathHelper.resolveNS,
|
||||
Ci.nsIDOMXPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
|
||||
let node = formNodes.iterateNext();
|
||||
if (!node)
|
||||
return null;
|
||||
|
||||
let data = {};
|
||||
do {
|
||||
let id = node.id ? "#" + node.id : XPathHelper.generate(node);
|
||||
if (node instanceof Ci.nsIDOMHTMLInputElement)
|
||||
data[id] = node.type == "checkbox" || node.type == "radio" ? node.checked : node.value;
|
||||
else if (node instanceof Ci.nsIDOMHTMLTextAreaElement)
|
||||
data[id] = node.value;
|
||||
else if (!node.multiple)
|
||||
data[id] = node.selectedIndex;
|
||||
else {
|
||||
let options = Array.map(node.options, function(aOpt, aIx) aOpt.selected ? aIx : -1);
|
||||
data[id] = options.filter(function(aIx) aIx >= 0);
|
||||
}
|
||||
} while ((node = formNodes.iterateNext()));
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* store all hosts for a URL
|
||||
* @param aWindow
|
||||
@ -1277,15 +1300,17 @@ SessionStoreService.prototype = {
|
||||
|
||||
/**
|
||||
* serialize session data as Ini-formatted string
|
||||
* @param aUpdateAll
|
||||
* Bool update all windows
|
||||
* @returns string
|
||||
*/
|
||||
_getCurrentState: function sss_getCurrentState() {
|
||||
_getCurrentState: function sss_getCurrentState(aUpdateAll) {
|
||||
var activeWindow = this._getMostRecentBrowserWindow();
|
||||
|
||||
if (this._loadState == STATE_RUNNING) {
|
||||
// update the data for all windows with activities since the last save operation
|
||||
this._forEachBrowserWindow(function(aWindow) {
|
||||
if (this._dirty || this._dirtyWindows[aWindow.__SSi] || aWindow == activeWindow) {
|
||||
if (aUpdateAll || this._dirtyWindows[aWindow.__SSi] || aWindow == activeWindow) {
|
||||
this._collectWindowData(aWindow);
|
||||
}
|
||||
else { // always update the window features (whose change alone never triggers a save operation)
|
||||
@ -1293,21 +1318,25 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
}, this);
|
||||
this._dirtyWindows = [];
|
||||
this._dirty = false;
|
||||
}
|
||||
|
||||
// collect the data for all windows
|
||||
var total = [], windows = [];
|
||||
var nonPopupCount = 0;
|
||||
var ix;
|
||||
for (ix in this._windows) {
|
||||
total.push(this._windows[ix]);
|
||||
windows.push(ix);
|
||||
if (!this._windows[ix].isPopup)
|
||||
nonPopupCount++;
|
||||
}
|
||||
this._updateCookies(total);
|
||||
|
||||
// if no browser window remains open, return the state of the last closed window
|
||||
if (total.length == 0 && this._lastWindowClosed) {
|
||||
total.push(this._lastWindowClosed);
|
||||
// if no non-popup browser window remains open, return the state of the last closed window(s)
|
||||
if (nonPopupCount == 0 && this._lastClosedWindows) {
|
||||
// prepend the last non-popup browser window, so that if the user loads more tabs
|
||||
// at startup we don't accidentally add them to a popup window
|
||||
total = this._lastClosedWindows.concat(total);
|
||||
}
|
||||
if (activeWindow) {
|
||||
this.activeWindowSSiCache = activeWindow.__SSi || "";
|
||||
@ -1407,11 +1436,9 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
// don't restore a single blank tab when we've had an external
|
||||
// URL passed in for loading at startup (cf. bug 357419)
|
||||
else if (root._firstTabs && !aOverwriteTabs && winData.tabs.length == 1) {
|
||||
let tabEntries = winData.tabs[0].entries || [];
|
||||
if (tabEntries.length == 0 ||
|
||||
tabEntries.length == 1 && tabEntries[0].url == "about:blank")
|
||||
winData.tabs = [];
|
||||
else if (root._firstTabs && !aOverwriteTabs && winData.tabs.length == 1 &&
|
||||
(!winData.tabs[0].entries || winData.tabs[0].entries.length == 0)) {
|
||||
winData.tabs = [];
|
||||
}
|
||||
|
||||
var tabbrowser = aWindow.getBrowser();
|
||||
@ -1490,17 +1517,28 @@ SessionStoreService.prototype = {
|
||||
|
||||
// mark the tabs as loading
|
||||
for (t = 0; t < aTabs.length; t++) {
|
||||
if (!aTabs[t].entries || !aTabs[t].entries[0])
|
||||
continue; // there won't be anything to load
|
||||
|
||||
var tab = aTabs[t]._tab;
|
||||
var browser = tabbrowser.getBrowserForTab(tab);
|
||||
|
||||
if (!aTabs[t].entries || aTabs[t].entries.length == 0) {
|
||||
// make sure to blank out this tab's content
|
||||
// (just purging the tab's history won't be enough)
|
||||
browser.contentDocument.location = "about:blank";
|
||||
continue;
|
||||
}
|
||||
|
||||
browser.stop(); // in case about:blank isn't done yet
|
||||
|
||||
tab.setAttribute("busy", "true");
|
||||
tabbrowser.updateIcon(tab);
|
||||
tabbrowser.setTabTitleLoading(tab);
|
||||
|
||||
// wall-paper fix for bug 439675: make sure that the URL to be loaded
|
||||
// is always visible in the address bar
|
||||
let activeIndex = (aTabs[t].index || aTabs[t].entries.length) - 1;
|
||||
let activePageData = aTabs[t].entries[activeIndex] || null;
|
||||
browser.userTypedValue = activePageData ? activePageData.url || null : null;
|
||||
|
||||
// keep the data around to prevent dataloss in case
|
||||
// a tab gets closed before it's been properly restored
|
||||
browser.parentNode.__SS_data = aTabs[t];
|
||||
@ -1581,20 +1619,28 @@ SessionStoreService.prototype = {
|
||||
event.initEvent("SSTabRestoring", true, false);
|
||||
tab.dispatchEvent(event);
|
||||
|
||||
var activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
if (activeIndex >= tabData.entries.length)
|
||||
activeIndex = tabData.entries.length - 1;
|
||||
try {
|
||||
browser.webNavigation.gotoIndex(activeIndex);
|
||||
if (activeIndex >= 0)
|
||||
browser.webNavigation.gotoIndex(activeIndex);
|
||||
}
|
||||
catch (ex) {
|
||||
// ignore page load errors
|
||||
tab.removeAttribute("busy");
|
||||
}
|
||||
catch (ex) { } // ignore an invalid tabData.index
|
||||
|
||||
// restore those aspects of the currently active documents
|
||||
// which are not preserved in the plain history entries
|
||||
// (mainly scroll state and text data)
|
||||
browser.__SS_restore_data = tabData.entries[activeIndex] || {};
|
||||
browser.__SS_restore_text = tabData.text || "";
|
||||
browser.__SS_restore_tab = tab;
|
||||
browser.__SS_restore = this.restoreDocument_proxy;
|
||||
browser.addEventListener("load", browser.__SS_restore, true);
|
||||
if (tabData.entries.length > 0) {
|
||||
// restore those aspects of the currently active documents
|
||||
// which are not preserved in the plain history entries
|
||||
// (mainly scroll state and text data)
|
||||
browser.__SS_restore_data = tabData.entries[activeIndex] || {};
|
||||
browser.__SS_restore_text = tabData.text || "";
|
||||
browser.__SS_restore_tab = tab;
|
||||
browser.__SS_restore = this.restoreDocument_proxy;
|
||||
browser.addEventListener("load", browser.__SS_restore, true);
|
||||
}
|
||||
|
||||
aWindow.setTimeout(function(){ _this.restoreHistory(aWindow, aTabs, aIdMap); }, 0);
|
||||
},
|
||||
@ -1696,6 +1742,7 @@ SessionStoreService.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// restore text data saved by Firefox 2.0/3.0
|
||||
var textArray = this.__SS_restore_text ? this.__SS_restore_text.split(" ") : [];
|
||||
function restoreTextData(aContent, aPrefix) {
|
||||
textArray.forEach(function(aEntry) {
|
||||
@ -1713,8 +1760,41 @@ SessionStoreService.prototype = {
|
||||
});
|
||||
}
|
||||
|
||||
function restoreFormData(aDocument, aData) {
|
||||
for (let key in aData) {
|
||||
let node = key.charAt(0) == "#" ? aDocument.getElementById(key.slice(1)) :
|
||||
XPathHelper.resolve(aDocument, key);
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
let value = aData[key];
|
||||
if (typeof value == "string") {
|
||||
node.value = value;
|
||||
|
||||
let event = aDocument.createEvent("UIEvents");
|
||||
event.initUIEvent("input", true, true, aDocument.defaultView, 0);
|
||||
node.dispatchEvent(event);
|
||||
}
|
||||
else if (typeof value == "boolean")
|
||||
node.checked = value;
|
||||
else if (typeof value == "number")
|
||||
try {
|
||||
node.selectedIndex = value;
|
||||
} catch (ex) { /* throws for invalid indices */ }
|
||||
else if (value && typeof value.indexOf == "function" && node.options) {
|
||||
Array.forEach(node.options, function(aOpt, aIx) {
|
||||
aOpt.selected = value.indexOf(aIx) > -1;
|
||||
});
|
||||
}
|
||||
// NB: dispatching "change" events might have unintended side-effects
|
||||
}
|
||||
}
|
||||
|
||||
function restoreTextDataAndScrolling(aContent, aData, aPrefix) {
|
||||
restoreTextData(aContent, aPrefix);
|
||||
if (aData.formdata)
|
||||
restoreFormData(aContent.document, aData.formdata);
|
||||
else
|
||||
restoreTextData(aContent, aPrefix);
|
||||
if (aData.innerHTML) {
|
||||
aContent.setTimeout(function(aHTML) { if (this.document.designMode == "on") { this.document.body.innerHTML = aHTML; } }, 0, aData.innerHTML);
|
||||
}
|
||||
@ -1728,18 +1808,23 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
var content = aEvent.originalTarget.defaultView;
|
||||
if (this.currentURI.spec == "about:config") {
|
||||
// unwrap the document for about:config because otherwise the properties
|
||||
// of the XBL bindings - as the textbox - aren't accessible (see bug 350718)
|
||||
content = content.wrappedJSObject;
|
||||
// don't restore text data and scrolling state if the user has navigated
|
||||
// away before the loading completed (except for in-page navigation)
|
||||
if (!this.__SS_restore_data.url || this.currentURI.spec.replace(/#.*/, "") ==
|
||||
this.__SS_restore_data.url.replace(/#.*/, "")) {
|
||||
var content = aEvent.originalTarget.defaultView;
|
||||
if (this.currentURI.spec == "about:config") {
|
||||
// unwrap the document for about:config because otherwise the properties
|
||||
// of the XBL bindings - as the textbox - aren't accessible (see bug 350718)
|
||||
content = content.wrappedJSObject;
|
||||
}
|
||||
restoreTextDataAndScrolling(content, this.__SS_restore_data, "");
|
||||
|
||||
// notify the tabbrowser that this document has been completely restored
|
||||
var event = this.ownerDocument.createEvent("Events");
|
||||
event.initEvent("SSTabRestored", true, false);
|
||||
this.__SS_restore_tab.dispatchEvent(event);
|
||||
}
|
||||
restoreTextDataAndScrolling(content, this.__SS_restore_data, "");
|
||||
|
||||
// notify the tabbrowser that this document has been completely restored
|
||||
var event = this.ownerDocument.createEvent("Events");
|
||||
event.initEvent("SSTabRestored", true, false);
|
||||
this.__SS_restore_tab.dispatchEvent(event);
|
||||
|
||||
this.removeEventListener("load", this.__SS_restore, true);
|
||||
delete this.__SS_restore_data;
|
||||
@ -1761,6 +1846,11 @@ SessionStoreService.prototype = {
|
||||
aWindow[aItem].visible = hidden.indexOf(aItem) == -1;
|
||||
});
|
||||
|
||||
if (aWinData.isPopup)
|
||||
this._windows[aWindow.__SSi].isPopup = true;
|
||||
else
|
||||
delete this._windows[aWindow.__SSi].isPopup;
|
||||
|
||||
var _this = this;
|
||||
aWindow.setTimeout(function() {
|
||||
_this.restoreDimensions.apply(_this, [aWindow, aWinData.width || 0,
|
||||
@ -1810,7 +1900,7 @@ SessionStoreService.prototype = {
|
||||
// since resizing/moving a window brings it to the foreground,
|
||||
// we might want to re-focus the last focused window
|
||||
if (this.windowToFocus) {
|
||||
this.windowToFocus.focus();
|
||||
this.windowToFocus.content.focus();
|
||||
}
|
||||
},
|
||||
|
||||
@ -1889,8 +1979,7 @@ SessionStoreService.prototype = {
|
||||
if (!this._resume_from_crash && this._loadState == STATE_RUNNING)
|
||||
return;
|
||||
|
||||
this._dirty = aUpdateAll;
|
||||
var oState = this._getCurrentState();
|
||||
var oState = this._getCurrentState(aUpdateAll);
|
||||
oState.session = { state: ((this._loadState == STATE_RUNNING) ? STATE_RUNNING_STR : STATE_STOPPED_STR) };
|
||||
|
||||
var stateString = Cc["@mozilla.org/supports-string;1"].
|
||||
@ -2119,7 +2208,7 @@ SessionStoreService.prototype = {
|
||||
* @return the object's JSON representation
|
||||
*/
|
||||
_toJSONString: function sss_toJSONString(aJSObject) {
|
||||
var str = JSON.toString(aJSObject, ["_tab", "_hosts"] /* keys to drop */);
|
||||
let str = JSON.toString(aJSObject, ["_tab", "_hosts", "_formDataSaved"] /* keys to drop */);
|
||||
|
||||
// sanity check - so that API consumers can just eval this string
|
||||
if (!JSON.isMostlyHarmless(str))
|
||||
@ -2160,5 +2249,65 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
let XPathHelper = {
|
||||
// these two hashes should be kept in sync
|
||||
namespaceURIs: { "xhtml": "http://www.w3.org/1999/xhtml" },
|
||||
namespacePrefixes: { "http://www.w3.org/1999/xhtml": "xhtml" },
|
||||
|
||||
/**
|
||||
* Generates an approximate XPath query to an (X)HTML node
|
||||
*/
|
||||
generate: function sss_xph_generate(aNode) {
|
||||
// have we reached the document node already?
|
||||
if (!aNode.parentNode)
|
||||
return "";
|
||||
|
||||
let prefix = this.namespacePrefixes[aNode.namespaceURI] || null;
|
||||
let tag = (prefix ? prefix + ":" : "") + aNode.localName;
|
||||
|
||||
// stop once we've found a tag with an ID
|
||||
if (aNode.id)
|
||||
return "//" + tag + "[@id=" + this.quoteArgument(aNode.id) + "]";
|
||||
|
||||
// count the number of previous sibling nodes of the same tag
|
||||
// (and possible also the same name)
|
||||
let count = 0;
|
||||
let nName = aNode.name || null;
|
||||
for (let n = aNode; (n = n.previousSibling); )
|
||||
if (n.localName == aNode.localName && n.namespaceURI == aNode.namespaceURI &&
|
||||
(!nName || n.name == nName))
|
||||
count++;
|
||||
|
||||
// recurse until hitting either the document node or an ID'd node
|
||||
return this.generate(aNode.parentNode) + "/" + tag +
|
||||
(nName ? "[@name=" + this.quoteArgument(nName) + "]" : "") +
|
||||
(count ? "[" + (count + 1) + "]" : "");
|
||||
},
|
||||
|
||||
/**
|
||||
* Resolves an XPath query generated by XPathHelper.generate
|
||||
*/
|
||||
resolve: function sss_xph_resolve(aDocument, aQuery) {
|
||||
let xptype = Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE;
|
||||
return aDocument.evaluate(aQuery, aDocument, this.resolveNS, xptype, null).singleNodeValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Namespace resolver for the above XPath resolver
|
||||
*/
|
||||
resolveNS: function sss_xph_resolveNS(aPrefix) {
|
||||
return XPathHelper.namespaceURIs[aPrefix] || null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns a properly quoted string to insert into an XPath query
|
||||
*/
|
||||
quoteArgument: function sss_xph_quoteArgument(aArg) {
|
||||
return !/'/.test(aArg) ? "'" + aArg + "'" :
|
||||
!/"/.test(aArg) ? '"' + aArg + '"' :
|
||||
"concat('" + aArg.replace(/'+/g, "',\"$&\",'") + "')";
|
||||
}
|
||||
};
|
||||
|
||||
function NSGetModule(aComMgr, aFileSpec)
|
||||
XPCOMUtils.generateModule([SessionStoreService]);
|
||||
|
@ -45,7 +45,9 @@ include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_TEST_FILES = \
|
||||
browser_346337.js \
|
||||
browser_350525.js \
|
||||
browser_367052.js \
|
||||
browser_393716.js \
|
||||
browser_448741.js \
|
||||
$(NULL)
|
||||
|
125
browser/components/sessionstore/test/browser/browser_346337.js
Normal file
125
browser/components/sessionstore/test/browser/browser_346337.js
Normal file
@ -0,0 +1,125 @@
|
||||
/* ***** 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
|
||||
* Simon Bünzli <zeniko@gmail.com>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* 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 test() {
|
||||
/** Test for Bug 346337 **/
|
||||
|
||||
let fieldList = {
|
||||
"//input[@name='testinput']": Date.now().toString(),
|
||||
"//input[@name='bad name']": Math.random().toString(),
|
||||
"//input[@type='checkbox']": true,
|
||||
"//input[@type='radio'][1]": false,
|
||||
"//input[@type='radio'][2]": true,
|
||||
"//select": 2,
|
||||
"//select[@multiple]": [1, 3],
|
||||
"//textarea[1]": "",
|
||||
"//textarea[3]": "Some more test\n" + new Date()
|
||||
};
|
||||
|
||||
function getElementByXPath(aTab, aQuery) {
|
||||
let doc = aTab.linkedBrowser.contentDocument;
|
||||
let xptype = Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE;
|
||||
return doc.evaluate(aQuery, doc, null, xptype, null).singleNodeValue;
|
||||
}
|
||||
|
||||
function setFormValue(aTab, aQuery, aValue) {
|
||||
let node = getElementByXPath(aTab, aQuery);
|
||||
if (typeof aValue == "string")
|
||||
node.value = aValue;
|
||||
else if (typeof aValue == "boolean")
|
||||
node.checked = aValue;
|
||||
else if (typeof aValue == "number")
|
||||
node.selectedIndex = aValue;
|
||||
else
|
||||
Array.forEach(node.options, function(aOpt, aIx)
|
||||
(aOpt.selected = aValue.indexOf(aIx) > -1));
|
||||
}
|
||||
|
||||
function compareFormValue(aTab, aQuery, aValue) {
|
||||
let node = getElementByXPath(aTab, aQuery);
|
||||
if (!node)
|
||||
return false;
|
||||
if (node instanceof Ci.nsIDOMHTMLInputElement)
|
||||
return aValue == (node.type == "checkbox" || node.type == "radio" ?
|
||||
node.checked : node.value);
|
||||
if (node instanceof Ci.nsIDOMHTMLTextAreaElement)
|
||||
return aValue == node.value;
|
||||
if (!node.multiple)
|
||||
return aValue == node.selectedIndex;
|
||||
return Array.every(node.options, function(aOpt, aIx)
|
||||
(aValue.indexOf(aIx) > -1) == aOpt.selected);
|
||||
}
|
||||
|
||||
// test setup
|
||||
let tabbrowser = getBrowser();
|
||||
waitForExplicitFinish();
|
||||
|
||||
// make sure we don't save form data at all (except for tab duplication)
|
||||
let privacy_level = gPrefService.getIntPref("browser.sessionstore.privacy_level");
|
||||
gPrefService.setIntPref("browser.sessionstore.privacy_level", 2);
|
||||
|
||||
todo(false, "test doesn't run from the harness's http server");
|
||||
let tab = tabbrowser.addTab("https://bugzilla.mozilla.org/attachment.cgi?id=328502");
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
for (let xpath in fieldList)
|
||||
setFormValue(tab, xpath, fieldList[xpath]);
|
||||
|
||||
let tab2 = tabbrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
for (let xpath in fieldList)
|
||||
ok(compareFormValue(tab2, xpath, fieldList[xpath]),
|
||||
"The value for \"" + xpath + "\" was correctly restored");
|
||||
|
||||
// clean up
|
||||
tabbrowser.removeTab(tab2);
|
||||
tabbrowser.removeTab(tab);
|
||||
|
||||
undoCloseTab();
|
||||
|
||||
tab = tabbrowser.selectedTab;
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
for (let xpath in fieldList)
|
||||
if (fieldList[xpath])
|
||||
ok(!compareFormValue(tab, xpath, fieldList[xpath]),
|
||||
"The value for \"" + xpath + "\" was correctly discarded");
|
||||
|
||||
gPrefService.setIntPref("browser.sessionstore.privacy_level", privacy_level);
|
||||
tabbrowser.removeTab(tab);
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
}, true);
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
/* ***** 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
|
||||
@ -13,15 +11,14 @@
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
* The Original Code is sessionstore test code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* Simon Bünzli <zeniko@gmail.com>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Stuart Parmenter <pavlov@netscape.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
|
||||
@ -37,46 +34,39 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "imgICache.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
#include "prtypes.h"
|
||||
|
||||
class imgRequest;
|
||||
class nsIURI;
|
||||
class nsICacheEntryDescriptor;
|
||||
|
||||
#define NS_IMGCACHE_CID \
|
||||
{ /* fb4fd28a-1dd1-11b2-8391-e14242c59a41 */ \
|
||||
0xfb4fd28a, \
|
||||
0x1dd1, \
|
||||
0x11b2, \
|
||||
{0x83, 0x91, 0xe1, 0x42, 0x42, 0xc5, 0x9a, 0x41} \
|
||||
function test() {
|
||||
/** Test for Bug 367052 **/
|
||||
|
||||
// test setup
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
let tabbrowser = gBrowser;
|
||||
waitForExplicitFinish();
|
||||
|
||||
// make sure that the next closed tab will increase getClosedTabCount
|
||||
let max_tabs_undo = gPrefService.getIntPref("browser.sessionstore.max_tabs_undo");
|
||||
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
|
||||
let closedTabCount = ss.getClosedTabCount(window);
|
||||
|
||||
// restore a blank tab
|
||||
let tab = tabbrowser.addTab("about:");
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
let browser = tabbrowser.getBrowserForTab(tab);
|
||||
let history = browser.webNavigation.sessionHistory;
|
||||
ok(history.count >= 1, "the new tab does have at least one history entry");
|
||||
|
||||
ss.setTabState(tab, "{ entries: [] }");
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
ok(history.count == 0, "the tab was restored without any history whatsoever");
|
||||
|
||||
tabbrowser.removeTab(tab);
|
||||
ok(ss.getClosedTabCount(window) == closedTabCount,
|
||||
"The closed blank tab wasn't added to Recently Closed Tabs");
|
||||
|
||||
// clean up
|
||||
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo);
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
class imgCache : public imgICache,
|
||||
public nsIObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IMGICACHE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
imgCache();
|
||||
virtual ~imgCache();
|
||||
|
||||
static nsresult Init();
|
||||
|
||||
static void Shutdown(); // for use by the factory
|
||||
|
||||
/* additional members */
|
||||
static PRBool Put(nsIURI *aKey, imgRequest *request, nsICacheEntryDescriptor **aEntry);
|
||||
static PRBool Get(nsIURI *aKey, PRBool *aHasExpired, imgRequest **aRequest, nsICacheEntryDescriptor **aEntry);
|
||||
static PRBool Remove(nsIURI *aKey);
|
||||
|
||||
static nsresult ClearChromeImageCache();
|
||||
static nsresult ClearImageCache();
|
||||
};
|
||||
|
@ -44,7 +44,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = public src
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
|
@ -63,6 +63,8 @@
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <gtk/gtkversion.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
@ -446,58 +448,8 @@ nsGNOMEShellService::SetDesktopBackground(nsIDOMElement* aElement,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// In: pointer to two characters CC
|
||||
// Out: parsed color number
|
||||
static PRUint8
|
||||
HexToNum(char ch)
|
||||
{
|
||||
if ('0' <= ch && '9' >= ch)
|
||||
return ch - '0';
|
||||
|
||||
if ('A' <= ch && 'F' >= ch)
|
||||
return ch - 'A';
|
||||
|
||||
if ('a' <= ch && 'f' >= ch)
|
||||
return ch - 'a';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// In: 3 or 6-character RRGGBB hex string
|
||||
// Out: component colors
|
||||
static PRBool
|
||||
HexToRGB(const nsCString& aColorSpec,
|
||||
PRUint8 &aRed,
|
||||
PRUint8 &aGreen,
|
||||
PRUint8 &aBlue)
|
||||
{
|
||||
const char *buf = aColorSpec.get();
|
||||
|
||||
if (aColorSpec.Length() == 6) {
|
||||
aRed = HexToNum(buf[0]) >> 4 |
|
||||
HexToNum(buf[1]);
|
||||
aGreen = HexToNum(buf[2]) >> 4 |
|
||||
HexToNum(buf[3]);
|
||||
aBlue = HexToNum(buf[4]) >> 4 |
|
||||
HexToNum(buf[5]);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (aColorSpec.Length() == 3) {
|
||||
aRed = HexToNum(buf[0]);
|
||||
aGreen = HexToNum(buf[1]);
|
||||
aBlue = HexToNum(buf[2]);
|
||||
|
||||
aRed |= aRed >> 4;
|
||||
aGreen |= aGreen >> 4;
|
||||
aBlue |= aBlue >> 4;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
#define COLOR_16_TO_8_BIT(_c) ((_c) >> 8)
|
||||
#define COLOR_8_TO_16_BIT(_c) ((_c) << 8)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGNOMEShellService::GetDesktopBackgroundColor(PRUint32 *aColor)
|
||||
@ -512,22 +464,34 @@ nsGNOMEShellService::GetDesktopBackgroundColor(PRUint32 *aColor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Chop off the leading '#' character
|
||||
background.Cut(0, 1);
|
||||
GdkColor color;
|
||||
gboolean success = gdk_color_parse(background.get(), &color);
|
||||
|
||||
PRUint8 red, green, blue;
|
||||
if (!HexToRGB(background, red, green, blue))
|
||||
return NS_ERROR_FAILURE;
|
||||
NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
|
||||
|
||||
// The result must be in RGB order with the high 8 bits zero.
|
||||
*aColor = (red << 16 | green << 8 | blue);
|
||||
*aColor = COLOR_16_TO_8_BIT(color.red) << 16 |
|
||||
COLOR_16_TO_8_BIT(color.green) << 8 |
|
||||
COLOR_16_TO_8_BIT(color.blue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
ColorToHex(PRUint32 aColor, nsCString& aResult)
|
||||
ColorToCString(PRUint32 aColor, nsCString& aResult)
|
||||
{
|
||||
char *buf = aResult.BeginWriting(7);
|
||||
#if GTK_CHECK_VERSION(2,12,0)
|
||||
GdkColor color;
|
||||
color.red = COLOR_8_TO_16_BIT(aColor >> 16);
|
||||
color.green = COLOR_8_TO_16_BIT((aColor >> 8) & 0xff);
|
||||
color.blue = COLOR_8_TO_16_BIT(aColor & 0xff);
|
||||
|
||||
gchar *colorString = gdk_color_to_string(&color);
|
||||
aResult.Assign(colorString);
|
||||
g_free(colorString);
|
||||
|
||||
#else // GTK 2.12.0
|
||||
|
||||
// The #rrrrggggbbbb format is used to match gdk_color_to_string()
|
||||
char *buf = aResult.BeginWriting(13);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
@ -535,7 +499,8 @@ ColorToHex(PRUint32 aColor, nsCString& aResult)
|
||||
PRUint8 green = (aColor >> 8) & 0xff;
|
||||
PRUint8 blue = aColor & 0xff;
|
||||
|
||||
PR_snprintf(buf, 8, "#%02x%02x%02x", red, green, blue);
|
||||
PR_snprintf(buf, 14, "#%02x00%02x00%02x00", red, green, blue);
|
||||
#endif // GTK 2.12.0
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -544,7 +509,7 @@ nsGNOMEShellService::SetDesktopBackgroundColor(PRUint32 aColor)
|
||||
nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID);
|
||||
|
||||
nsCString colorString;
|
||||
ColorToHex(aColor, colorString);
|
||||
ColorToCString(aColor, colorString);
|
||||
|
||||
gconf->SetString(NS_LITERAL_CSTRING(kDesktopColorKey), colorString);
|
||||
|
||||
|
@ -42,6 +42,9 @@ relativesrcdir = browser/components/shell/test
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = test_browser_shell
|
||||
XPCSHELL_TESTS = unit
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_TEST_FILES = browser_420786.js \
|
||||
|
114
browser/components/shell/test/unit/test_421977.js
Normal file
114
browser/components/shell/test/unit/test_421977.js
Normal file
@ -0,0 +1,114 @@
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
const GCONF_BG_COLOR_KEY = "/desktop/gnome/background/primary_color";
|
||||
|
||||
var gShell;
|
||||
var gGConf;
|
||||
|
||||
/**
|
||||
* Converts from a rgb numerical color valule (r << 16 | g << 8 | b)
|
||||
* into a hex string in #RRGGBB format.
|
||||
*/
|
||||
function colorToHex(aColor) {
|
||||
const rMask = 4294901760;
|
||||
const gMask = 65280;
|
||||
const bMask = 255;
|
||||
|
||||
var r = (aColor & rMask) >> 16;
|
||||
var g = (aColor & gMask) >> 8;
|
||||
var b = (aColor & bMask);
|
||||
|
||||
return "#" + [r, g, b].map(function(aInt)
|
||||
aInt.toString(16).replace(/^(.)$/, "0$1"))
|
||||
.join("").toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a color string in #RRGGBB format to a rgb numerical color value
|
||||
* (r << 16 | g << 8 | b).
|
||||
*/
|
||||
function hexToColor(aString) {
|
||||
return parseInt(aString.substring(1,3), 16) << 16 |
|
||||
parseInt(aString.substring(3,5), 16) << 8 |
|
||||
parseInt(aString.substring(5,7), 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that setting the GConf background key to aGConfColor will
|
||||
* result in the Shell component returning a background color equals
|
||||
* to aExpectedShellColor in #RRGGBB format.
|
||||
*/
|
||||
function checkGConfToShellColor(aGConfColor, aExpectedShellColor) {
|
||||
|
||||
gGConf.setString(GCONF_BG_COLOR_KEY, aGConfColor);
|
||||
var shellColor = colorToHex(gShell.desktopBackgroundColor);
|
||||
|
||||
do_check_eq(shellColor, aExpectedShellColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that setting the background color (in #RRGGBB format) using the Shell
|
||||
* component will result in having a GConf key for the background color set to
|
||||
* aExpectedGConfColor.
|
||||
*/
|
||||
function checkShellToGConfColor(aShellColor, aExpectedGConfColor) {
|
||||
|
||||
gShell.desktopBackgroundColor = hexToColor(aShellColor);
|
||||
var gconfColor = gGConf.getString(GCONF_BG_COLOR_KEY);
|
||||
|
||||
do_check_eq(gconfColor, aExpectedGConfColor);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
||||
// This test is Linux specific for now
|
||||
if (!("@mozilla.org/gnome-gconf-service;1" in Cc))
|
||||
return;
|
||||
|
||||
gGConf = Cc["@mozilla.org/gnome-gconf-service;1"].
|
||||
getService(Ci.nsIGConfService);
|
||||
|
||||
gShell = Cc["@mozilla.org/browser/shell-service;1"].
|
||||
getService(Ci.nsIShellService);
|
||||
|
||||
// Save the original background color so that we can restore it
|
||||
// after the test.
|
||||
var origGConfColor = gGConf.getString(GCONF_BG_COLOR_KEY);
|
||||
|
||||
try {
|
||||
|
||||
checkGConfToShellColor("#000", "#000000");
|
||||
checkGConfToShellColor("#00f", "#0000FF");
|
||||
checkGConfToShellColor("#b2f", "#BB22FF");
|
||||
checkGConfToShellColor("#fff", "#FFFFFF");
|
||||
|
||||
checkGConfToShellColor("#000000", "#000000");
|
||||
checkGConfToShellColor("#0000ff", "#0000FF");
|
||||
checkGConfToShellColor("#b002f0", "#B002F0");
|
||||
checkGConfToShellColor("#ffffff", "#FFFFFF");
|
||||
|
||||
checkGConfToShellColor("#000000000", "#000000");
|
||||
checkGConfToShellColor("#00f00f00f", "#000000");
|
||||
checkGConfToShellColor("#aaabbbccc", "#AABBCC");
|
||||
checkGConfToShellColor("#fffffffff", "#FFFFFF");
|
||||
|
||||
checkGConfToShellColor("#000000000000", "#000000");
|
||||
checkGConfToShellColor("#000f000f000f", "#000000");
|
||||
checkGConfToShellColor("#00ff00ff00ff", "#000000");
|
||||
checkGConfToShellColor("#aaaabbbbcccc", "#AABBCC");
|
||||
checkGConfToShellColor("#111122223333", "#112233");
|
||||
checkGConfToShellColor("#ffffffffffff", "#FFFFFF");
|
||||
|
||||
checkShellToGConfColor("#000000", "#000000000000");
|
||||
checkShellToGConfColor("#0000FF", "#00000000ff00");
|
||||
checkShellToGConfColor("#FFFFFF", "#ff00ff00ff00");
|
||||
checkShellToGConfColor("#0A0B0C", "#0a000b000c00");
|
||||
checkShellToGConfColor("#A0B0C0", "#a000b000c000");
|
||||
checkShellToGConfColor("#AABBCC", "#aa00bb00cc00");
|
||||
|
||||
} finally {
|
||||
gGConf.setString(GCONF_BG_COLOR_KEY, origGConfColor);
|
||||
}
|
||||
}
|
@ -98,11 +98,11 @@ function (aTitle, aContentURL, aCustomizeURL)
|
||||
{
|
||||
debug("addPanel(" + aTitle + ", " + aContentURL + ", " +
|
||||
aCustomizeURL + ")");
|
||||
|
||||
|
||||
return this.addPanelInternal(aTitle, aContentURL, aCustomizeURL, false);
|
||||
}
|
||||
|
||||
nsSidebar.prototype.addPersistentPanel =
|
||||
nsSidebar.prototype.addPersistentPanel =
|
||||
function(aTitle, aContentURL, aCustomizeURL)
|
||||
{
|
||||
debug("addPersistentPanel(" + aTitle + ", " + aContentURL + ", " +
|
||||
@ -272,12 +272,13 @@ nsSidebar.prototype.getHelperForLanguage = function(count) {return null;}
|
||||
|
||||
nsSidebar.prototype.QueryInterface =
|
||||
function (iid) {
|
||||
if (!iid.equals(nsISidebar) &&
|
||||
!iid.equals(nsISidebarExternal) &&
|
||||
!iid.equals(nsIClassInfo) &&
|
||||
!iid.equals(nsISupports))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
if (iid.equals(nsISidebar) ||
|
||||
iid.equals(nsISidebarExternal) ||
|
||||
iid.equals(nsIClassInfo) ||
|
||||
iid.equals(nsISupports))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
var sidebarModule = new Object();
|
||||
@ -288,24 +289,25 @@ function (compMgr, fileSpec, location, type)
|
||||
debug("registering (all right -- a JavaScript module!)");
|
||||
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
||||
|
||||
compMgr.registerFactoryLocation(SIDEBAR_CID,
|
||||
compMgr.registerFactoryLocation(SIDEBAR_CID,
|
||||
"Sidebar JS Component",
|
||||
SIDEBAR_CONTRACTID,
|
||||
fileSpec,
|
||||
SIDEBAR_CONTRACTID,
|
||||
fileSpec,
|
||||
location,
|
||||
type);
|
||||
|
||||
const CATMAN_CONTRACTID = "@mozilla.org/categorymanager;1";
|
||||
const nsICategoryManager = Components.interfaces.nsICategoryManager;
|
||||
var catman = Components.classes[CATMAN_CONTRACTID].
|
||||
getService(nsICategoryManager);
|
||||
|
||||
|
||||
const JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY = "JavaScript global property";
|
||||
catman.addCategoryEntry(JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY,
|
||||
"sidebar",
|
||||
SIDEBAR_CONTRACTID,
|
||||
true,
|
||||
true);
|
||||
|
||||
|
||||
catman.addCategoryEntry(JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY,
|
||||
"external",
|
||||
SIDEBAR_CONTRACTID,
|
||||
@ -317,10 +319,10 @@ sidebarModule.getClassObject =
|
||||
function (compMgr, cid, iid) {
|
||||
if (!cid.equals(SIDEBAR_CID))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
|
||||
|
||||
if (!iid.equals(Components.interfaces.nsIFactory))
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
|
||||
return sidebarFactory;
|
||||
}
|
||||
|
||||
@ -330,7 +332,7 @@ function(compMgr)
|
||||
debug("Unloading component.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* factory object */
|
||||
var sidebarFactory = new Object();
|
||||
|
||||
@ -354,24 +356,15 @@ if (DEBUG)
|
||||
else
|
||||
debug = function (s) {}
|
||||
|
||||
var strBundleService = null;
|
||||
// String bundle service
|
||||
var gStrBundleService = null;
|
||||
|
||||
function srGetStrBundle(path)
|
||||
{
|
||||
var strBundle = null;
|
||||
if (!strBundleService) {
|
||||
try {
|
||||
strBundleService =
|
||||
Components.classes["@mozilla.org/intl/stringbundle;1"].getService();
|
||||
strBundleService =
|
||||
strBundleService.QueryInterface(Components.interfaces.nsIStringBundleService);
|
||||
} catch (ex) {
|
||||
dump("\n--** strBundleService failed: " + ex + "\n");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
strBundle = strBundleService.createBundle(path);
|
||||
if (!strBundle) {
|
||||
dump("\n--** strBundle createInstance failed **--\n");
|
||||
}
|
||||
return strBundle;
|
||||
if (!gStrBundleService)
|
||||
gStrBundleService =
|
||||
Components.classes["@mozilla.org/intl/stringbundle;1"]
|
||||
.getService(Components.interfaces.nsIStringBundleService);
|
||||
|
||||
return gStrBundleService.createBundle(path);
|
||||
}
|
||||
|
@ -2,5 +2,4 @@
|
||||
# . $topsrcdir/browser/config/mozconfig
|
||||
# to the top of your mozconfig file.
|
||||
|
||||
mk_add_options MOZ_CO_PROJECT=browser
|
||||
ac_add_options --enable-application=browser
|
||||
|
@ -41,6 +41,7 @@ MOZ_UPDATER=1
|
||||
MOZ_PHOENIX=1
|
||||
|
||||
MOZ_ENABLE_LIBXUL=1
|
||||
MOZ_STATIC_BUILD_UNSUPPORTED=1
|
||||
MOZ_PLACES=1
|
||||
# always enabled for form history
|
||||
MOZ_MORKREADER=1
|
||||
|
@ -44,7 +44,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = public src
|
||||
|
||||
ifdef MOZ_MOCHITEST
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += test
|
||||
endif
|
||||
|
||||
|
@ -47,6 +47,7 @@ include $(topsrcdir)/config/rules.mk
|
||||
_BROWSER_FILES =browser_Application.js \
|
||||
browser_ApplicationPrefs.js \
|
||||
browser_ApplicationStorage.js \
|
||||
browser_ApplicationQuitting.js \
|
||||
browser_Browser.js \
|
||||
browser_Bookmarks.js \
|
||||
ContentA.html \
|
||||
|
21
browser/fuel/test/browser_ApplicationQuitting.js
Normal file
21
browser/fuel/test/browser_ApplicationQuitting.js
Normal file
@ -0,0 +1,21 @@
|
||||
function test() {
|
||||
let quitRequestObserver = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
ok(aTopic == "quit-application-requested" &&
|
||||
aSubject instanceof Components.interfaces.nsISupportsPRBool,
|
||||
"Received a quit request we're going to deny");
|
||||
aSubject.data = true;
|
||||
}
|
||||
};
|
||||
|
||||
// ensure that we don't accidentally quit
|
||||
let os = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
os.addObserver(quitRequestObserver, "quit-application-requested", false);
|
||||
|
||||
ok(!Application.quit(), "Tried to quit - and didn't succeed");
|
||||
ok(!Application.restart(), "Tried to restart - and didn't succeed");
|
||||
|
||||
// clean up
|
||||
os.removeObserver(quitRequestObserver, "quit-application-requested", false);
|
||||
}
|
@ -672,7 +672,66 @@ Function leaveStartMenu
|
||||
FunctionEnd
|
||||
|
||||
Function preSummary
|
||||
!insertmacro createSummaryINI
|
||||
; Setup the summary.ini file for the Custom Summary Page
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "3"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Text "$(SUMMARY_INSTALLED_TO)"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Top "5"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Bottom "15"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Type "text"
|
||||
; The contents of this control must be set as follows in the pre function
|
||||
; ${MUI_INSTALLOPTIONS_READ} $1 "summary.ini" "Field 2" "HWND"
|
||||
; SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" state ""
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Top "17"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Bottom "30"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" flags "READONLY"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Text "$(SUMMARY_CLICK)"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Top "130"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Bottom "150"
|
||||
|
||||
${If} "$TmpVal" == "true"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Text "$(SUMMARY_REBOOT_REQUIRED_INSTALL)"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Top "35"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Bottom "45"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "4"
|
||||
${EndIf}
|
||||
|
||||
ReadINIStr $0 "$PLUGINSDIR\options.ini" "Field 6" "State"
|
||||
${If} "$0" == "1"
|
||||
${If} "$TmpVal" == "true"
|
||||
; To insert this control reset Top / Bottom for controls below this one
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Top "50"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field 4" Bottom "60"
|
||||
StrCpy $0 "5"
|
||||
${Else}
|
||||
StrCpy $0 "4"
|
||||
${EndIf}
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Text "$(SUMMARY_MAKE_DEFAULT)"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Top "35"
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Bottom "45"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "$0"
|
||||
${EndIf}
|
||||
|
||||
!insertmacro MUI_HEADER_TEXT "$(SUMMARY_PAGE_TITLE)" "$(SUMMARY_PAGE_SUBTITLE)"
|
||||
|
||||
; The Summary custom page has a textbox that will automatically receive
|
||||
@ -717,8 +776,90 @@ Function .onInit
|
||||
!insertmacro MUI_INSTALLOPTIONS_EXTRACT "options.ini"
|
||||
!insertmacro MUI_INSTALLOPTIONS_EXTRACT "shortcuts.ini"
|
||||
!insertmacro MUI_INSTALLOPTIONS_EXTRACT "summary.ini"
|
||||
!insertmacro createBasicCustomSetAsDefaultOptionsINI
|
||||
!insertmacro createShortcutsINI
|
||||
|
||||
; Setup the options.ini file for the Custom Options Page
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Settings" NumFields "6"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Text "$(OPTIONS_SUMMARY)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Top "0"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Bottom "10"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Type "RadioButton"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Text "$(OPTION_STANDARD_RADIO)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Top "25"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Bottom "35"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" State "1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Flags "GROUP"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Type "RadioButton"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Text "$(OPTION_CUSTOM_RADIO)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Top "55"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Bottom "65"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" State "0"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Text "$(OPTION_STANDARD_DESC)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Left "30"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Top "37"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Bottom "57"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Text "$(OPTION_CUSTOM_DESC)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Left "30"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Top "67"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Bottom "87"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 6" Type "checkbox"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 6" Text "$(OPTIONS_MAKE_DEFAULT)"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 6" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 6" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 6" Top "124"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 6" Bottom "145"
|
||||
WriteINIStr "$PLUGINSDIR\options.ini" "Field 6" State "1"
|
||||
|
||||
; Setup the shortcuts.ini file for the Custom Shortcuts Page
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Settings" NumFields "4"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Text "$(CREATE_ICONS_DESC)"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Top "5"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Bottom "15"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Type "checkbox"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Text "$(ICONS_DESKTOP)"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Top "20"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Bottom "30"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" State "1"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Flags "GROUP"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Type "checkbox"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Text "$(ICONS_STARTMENU)"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Top "40"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Bottom "50"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" State "1"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Type "checkbox"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Text "$(ICONS_QUICKLAUNCH)"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Left "15"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Top "60"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Bottom "70"
|
||||
WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" State "1"
|
||||
|
||||
; There must always be nonlocalized and localized directories.
|
||||
${GetSize} "$EXEDIR\nonlocalized\" "/S=0K" $R5 $R7 $R8
|
||||
|
@ -157,7 +157,7 @@ ShowUnInstDetails nevershow
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.leaveWelcome
|
||||
!insertmacro MUI_UNPAGE_WELCOME
|
||||
|
||||
; Uninstall Confirm Page
|
||||
; Custom Uninstall Confirm Page
|
||||
UninstPage custom un.preConfirm un.leaveConfirm
|
||||
|
||||
; Remove Files Page
|
||||
@ -409,7 +409,67 @@ Function un.preConfirm
|
||||
${un.ChangeMUIHeaderImage} "$PLUGINSDIR\modern-header.bmp"
|
||||
${EndIf}
|
||||
|
||||
!insertmacro un.createUnConfirmINI
|
||||
; Setup the unconfirm.ini file for the Custom Uninstall Confirm Page
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "5"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Text "$(UN_CONFIRM_UNINSTALLED_FROM)"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Top "5"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Bottom "15"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Type "text"
|
||||
; The contents of this control must be set as follows in the pre function
|
||||
; ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 2" "HWND"
|
||||
; SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" State ""
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Top "17"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Bottom "30"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" flags "READONLY"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Type "checkbox"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Text "$(UN_REMOVE_PROFILES)"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Top "40"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Bottom "50"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" State "0"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" flags "NOTIFY"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Type "text"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" State "$(UN_REMOVE_PROFILES_DESC)"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Top "52"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Bottom "120"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" flags "MULTILINE|READONLY"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Text "$(UN_CONFIRM_CLICK)"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Top "130"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Bottom "150"
|
||||
|
||||
${If} "$TmpVal" == "true"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Type "label"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Text "$(SUMMARY_REBOOT_REQUIRED_UNINSTALL)"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Left "0"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Right "-1"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Top "35"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Bottom "45"
|
||||
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "6"
|
||||
|
||||
; To insert this control reset Top / Bottom for controls below this one
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Top "55"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Bottom "65"
|
||||
WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Top "67"
|
||||
${EndIf}
|
||||
|
||||
!insertmacro MUI_HEADER_TEXT "$(UN_CONFIRM_PAGE_TITLE)" "$(UN_CONFIRM_PAGE_SUBTITLE)"
|
||||
; The Summary custom page has a textbox that will automatically receive
|
||||
; focus. This sets the focus to the Install button instead.
|
||||
|
@ -1,9 +1,12 @@
|
||||
<!ENTITY aboutDialog.title "About &brandFullName;">
|
||||
<!ENTITY copyright "Credits">
|
||||
<!ENTITY copyright.accesskey "C">
|
||||
<!ENTITY aboutLink "< About &brandFullName;">
|
||||
<!ENTITY aboutLink.accesskey "A">
|
||||
<!ENTITY aboutVersion "version">
|
||||
<!ENTITY copyrightInfo "©1998-2008 Contributors. All Rights Reserved. Firefox and the
|
||||
Firefox logos are trademarks of the Mozilla Foundation. All rights
|
||||
reserved.">
|
||||
<!ENTITY aboutDialog.title "About &brandFullName;">
|
||||
<!ENTITY copyright "Credits">
|
||||
<!ENTITY copyright.accesskey "C">
|
||||
<!ENTITY copyrightGNOME.accesskey "r">
|
||||
<!ENTITY aboutLink "< About &brandFullName;">
|
||||
<!ENTITY aboutLink.accesskey "A">
|
||||
<!ENTITY aboutVersion "version">
|
||||
<!ENTITY closeCmdGNOME.label "Close">
|
||||
<!ENTITY closeCmdGNOME.accesskey "C">
|
||||
<!ENTITY copyrightInfo "©1998-2008 Contributors. All Rights Reserved. Firefox and the
|
||||
Firefox logos are trademarks of the Mozilla Foundation. All rights
|
||||
reserved.">
|
||||
|
@ -22,9 +22,6 @@
|
||||
|
||||
<!ENTITY filter.label "Search:">
|
||||
<!ENTITY filter.accesskey "S">
|
||||
<!ENTITY clear.label "Clear">
|
||||
<!ENTITY clear.accesskey "l">
|
||||
|
||||
<!ENTITY button.close.label "Close">
|
||||
<!ENTITY button.close.accesskey "C">
|
||||
|
||||
|
@ -68,7 +68,6 @@ SUMMARY_MAKE_DEFAULT=$BrandShortName will be set as your default web browser.
|
||||
SUMMARY_CLICK=Click Install to continue.
|
||||
SURVEY_TEXT=&Tell us what you thought of $BrandShortName
|
||||
LAUNCH_TEXT=&Launch $BrandShortName now
|
||||
WARN_APP_RUNNING_INSTALL=$BrandShortName must be closed to proceed with the installation.\n\nClick "OK" to exit $BrandShortName automatically and continue.
|
||||
CREATE_ICONS_DESC=Create icons for $BrandShortName:
|
||||
ICONS_DESKTOP=On my &Desktop
|
||||
ICONS_STARTMENU=In my &Start Menu Programs folder
|
||||
@ -95,7 +94,6 @@ BANNER_CHECK_EXISTING=Checking existing installation…
|
||||
|
||||
STATUS_INSTALL_APP=Installing $BrandShortName…
|
||||
STATUS_INSTALL_LANG=Installing Language Files (${AB_CD})…
|
||||
STATUS_INSTALL_OPTIONAL=Installing Optional Components…
|
||||
STATUS_UNINSTALL_MAIN=Uninstalling $BrandShortName…
|
||||
STATUS_CLEANUP=A Little Housekeeping…
|
||||
|
||||
@ -105,9 +103,6 @@ OPTIONS_SUMMARY=Choose the type of setup you prefer, then click Next.
|
||||
# One line
|
||||
OPTION_STANDARD_DESC=$BrandShortName will be installed with the most common options.
|
||||
OPTION_STANDARD_RADIO=&Standard
|
||||
# One line
|
||||
OPTION_COMPLETE_DESC=$BrandShortName will be installed with all available options.
|
||||
OPTION_COMPLETE_RADIO=C&omplete
|
||||
# Two lines
|
||||
OPTION_CUSTOM_DESC=You may choose individual options to be installed. Recommended for experienced users.
|
||||
OPTION_CUSTOM_RADIO=&Custom
|
||||
|
@ -1132,21 +1132,17 @@ statusbarpanel#statusbar-display {
|
||||
}
|
||||
|
||||
#security-button {
|
||||
list-style-image: none;
|
||||
min-width: 20px;
|
||||
-moz-box-direction: reverse;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#security-button[level="high"],
|
||||
#security-button[level="low"] {
|
||||
list-style-image: url("chrome://browser/skin/Secure.png");
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#security-button[level="broken"] {
|
||||
list-style-image: url("chrome://browser/skin/Security-broken.png");
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
/* XXXsw prevent margins of a value-less label from shifting the image */
|
||||
|
@ -1493,23 +1493,16 @@ sidebarheader > .tabs-closebutton > .toolbarbutton-text {
|
||||
/* ----- SECURITY DISPLAY ----- */
|
||||
|
||||
#security-button {
|
||||
display: none;
|
||||
-moz-box-direction: reverse;
|
||||
}
|
||||
|
||||
#security-button[level="high"] {
|
||||
list-style-image: url("chrome://browser/skin/Secure-statusbar.png");
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#security-button[level="high"] ,
|
||||
#security-button[level="low"] {
|
||||
list-style-image: url("chrome://browser/skin/Secure-statusbar.png");
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#security-button[level="broken"] {
|
||||
list-style-image: url("chrome://browser/skin/Secure-statusbar-broken.png");
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
/* ----- PAGE REPORT DISPLAY ----- */
|
||||
|
@ -1301,21 +1301,17 @@ statusbarpanel#statusbar-display {
|
||||
}
|
||||
|
||||
#security-button {
|
||||
list-style-image: none;
|
||||
min-width: 20px;
|
||||
-moz-box-direction: reverse;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#security-button[level="high"],
|
||||
#security-button[level="low"] {
|
||||
list-style-image: url("chrome://browser/skin/Secure.png");
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#security-button[level="broken"] {
|
||||
list-style-image: url("chrome://browser/skin/Security-broken.png");
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
/* XXXsw prevent margins of a value-less label from shifting the image */
|
||||
|
@ -79,9 +79,13 @@ browser_path = \"$(DIST)/bin/$(PROGRAM)\"
|
||||
endif
|
||||
endif
|
||||
|
||||
_CERTS_DIR = _profile/pgo/certs
|
||||
|
||||
AUTOMATION_PPARGS = \
|
||||
-DBROWSER_PATH=$(browser_path) \
|
||||
-DXPC_BIN_PATH=\"$(DIST)/bin\" \
|
||||
-DBIN_SUFFIX=\"$(BIN_SUFFIX)\" \
|
||||
-DCERTS_DIR=\"../$(_CERTS_DIR)\" \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH),Darwin)
|
||||
|
@ -43,20 +43,27 @@ VPATH = @srcdir@
|
||||
relativesrcdir = build/pgo
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = \
|
||||
certs \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# Stuff to make a build with a profile
|
||||
_PROFILE_DIR = $(DEPTH)/_profile/pgo
|
||||
_CERTS_DIR = $(_PROFILE_DIR)/certs
|
||||
_CERTS_SRC_DIR = $(srcdir)/certs
|
||||
|
||||
_PGO_FILES = \
|
||||
automation.py \
|
||||
profileserver.py \
|
||||
genpgocert.py \
|
||||
index.html \
|
||||
quit.js \
|
||||
server-locations.txt \
|
||||
$(NULL)
|
||||
|
||||
|
||||
ifeq ($(USE_SHORT_LIBNAME), 1)
|
||||
PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX)
|
||||
else
|
||||
@ -80,6 +87,9 @@ endif
|
||||
AUTOMATION_PPARGS = \
|
||||
-DBROWSER_PATH=$(browser_path) \
|
||||
-DXPC_BIN_PATH=\"$(DIST)/bin\" \
|
||||
-DBIN_SUFFIX=\"$(BIN_SUFFIX)\" \
|
||||
-DCERTS_DIR=\"$(_CERTS_DIR)\" \
|
||||
-DCERTS_SRC_DIR=\"$(_CERTS_SRC_DIR)\" \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH),Darwin)
|
||||
@ -102,11 +112,15 @@ automation.py: automation.py.in
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
|
||||
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@
|
||||
|
||||
genpgocert.py: genpgocert.py.in
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
|
||||
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $^ > $@
|
||||
|
||||
profileserver.py: profileserver.py.in
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $^ > $@
|
||||
chmod +x $@
|
||||
|
||||
GARBAGE += automation.py profileserver.py
|
||||
GARBAGE += automation.py profileserver.py genpgocert.py
|
||||
|
||||
libs:: $(_PGO_FILES)
|
||||
$(INSTALL) $^ $(_PROFILE_DIR)
|
||||
|
@ -53,6 +53,8 @@ Runs the browser from a script, and provides useful utilities
|
||||
for setting up the browser environment.
|
||||
"""
|
||||
|
||||
SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
|
||||
|
||||
__all__ = [
|
||||
"UNIXISH",
|
||||
"IS_WIN32",
|
||||
@ -62,6 +64,7 @@ __all__ = [
|
||||
"initializeProfile",
|
||||
"DIST_BIN",
|
||||
"DEFAULT_APP",
|
||||
"environment",
|
||||
]
|
||||
|
||||
# These are generated in mozilla/build/Makefile.in
|
||||
@ -74,10 +77,12 @@ __all__ = [
|
||||
IS_CYGWIN = False
|
||||
#endif
|
||||
#expand IS_CAMINO = __IS_CAMINO__ != 0
|
||||
#expand BIN_SUFFIX = __BIN_SUFFIX__
|
||||
|
||||
UNIXISH = not IS_WIN32 and not IS_MAC
|
||||
|
||||
#expand DEFAULT_APP = "./" + __BROWSER_PATH__
|
||||
#expand CERTS_DIR = __CERTS_DIR__
|
||||
|
||||
###########
|
||||
# LOGGING #
|
||||
@ -103,7 +108,7 @@ class Process:
|
||||
non-Windows platforms. :-(
|
||||
"""
|
||||
|
||||
def __init__(self, command, args, env):
|
||||
def __init__(self, command, args, env, inputdata = None):
|
||||
"""
|
||||
Creates a process representing the execution of the given command, which
|
||||
must be an absolute path, with the given arguments in the given environment.
|
||||
@ -111,24 +116,40 @@ class Process:
|
||||
"""
|
||||
command = os.path.abspath(command)
|
||||
if IS_WIN32:
|
||||
import tempfile
|
||||
import subprocess
|
||||
|
||||
if inputdata:
|
||||
inputfile = tempfile.TemporaryFile()
|
||||
inputfile.write(inputdata)
|
||||
inputfile.seek(0)
|
||||
else:
|
||||
inputfile = None
|
||||
|
||||
cmd = [command]
|
||||
cmd.extend(args)
|
||||
p = subprocess.Popen(cmd, env = env,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.STDOUT)
|
||||
stderr = subprocess.STDOUT,
|
||||
stdin = inputfile)
|
||||
self._out = p.stdout
|
||||
else:
|
||||
import popen2
|
||||
cmd = []
|
||||
for (k, v) in env.iteritems():
|
||||
cmd.append(k + "='" + v + "' ")
|
||||
if env:
|
||||
for (k, v) in env.iteritems():
|
||||
cmd.append(k + "='" + v + "' ")
|
||||
|
||||
cmd.append("'" + command + "'")
|
||||
cmd.extend(map(lambda x: "'" + x + "'", args))
|
||||
cmd = " ".join(cmd)
|
||||
p = popen2.Popen4(cmd)
|
||||
self._out = p.fromchild
|
||||
|
||||
if inputdata:
|
||||
p.tochild.write(inputdata)
|
||||
p.tochild.close()
|
||||
|
||||
self._process = p
|
||||
self.pid = p.pid
|
||||
|
||||
@ -165,8 +186,13 @@ class Process:
|
||||
def kill(self):
|
||||
"Kills this process."
|
||||
try:
|
||||
if not IS_WIN32: # XXX
|
||||
if not IS_WIN32:
|
||||
os.kill(self._process.pid, signal.SIGKILL)
|
||||
else:
|
||||
import subprocess
|
||||
pid = "%i" % self.pid
|
||||
process = subprocess.Popen(["taskkill", "/F", "/PID", pid])
|
||||
process.wait()
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -201,13 +227,13 @@ class Location:
|
||||
self.options = options
|
||||
|
||||
|
||||
def readLocations():
|
||||
def readLocations(locationsPath = "server-locations.txt"):
|
||||
"""
|
||||
Reads the locations at which the Mochitest HTTP server is available from
|
||||
server-locations.txt.
|
||||
"""
|
||||
|
||||
locationFile = codecs.open("server-locations.txt", "r", "UTF-8")
|
||||
locationFile = codecs.open(locationsPath, "r", "UTF-8")
|
||||
|
||||
# Perhaps more detail than necessary, but it's the easiest way to make sure
|
||||
# we get exactly the format we want. See server-locations.txt for the exact
|
||||
@ -224,7 +250,7 @@ def readLocations():
|
||||
r"(?P<port>\d+)"
|
||||
r"(?:"
|
||||
r"\s+"
|
||||
r"(?P<options>\w+(?:,\w+)*)"
|
||||
r"(?P<options>\S+(?:,\S+)*)"
|
||||
r")?$")
|
||||
locations = []
|
||||
lineno = 0
|
||||
@ -274,12 +300,14 @@ user_pref("dom.max_script_run_time", 0); // no slow script dialogs
|
||||
user_pref("signed.applets.codebase_principal_support", true);
|
||||
user_pref("security.warn_submit_insecure", false);
|
||||
user_pref("browser.shell.checkDefaultBrowser", false);
|
||||
user_pref("shell.checkDefaultClient", false);
|
||||
user_pref("browser.warnOnQuit", false);
|
||||
user_pref("accessibility.typeaheadfind.autostart", false);
|
||||
user_pref("javascript.options.showInConsole", true);
|
||||
user_pref("layout.debug.enable_data_xbl", true);
|
||||
user_pref("browser.EULA.override", true);
|
||||
user_pref("javascript.options.jit.content", false);
|
||||
user_pref("gfx.color_management.force_srgb", true);
|
||||
|
||||
user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others
|
||||
"""
|
||||
@ -319,13 +347,20 @@ function FindProxyForURL(url, host)
|
||||
if (!matches)
|
||||
return 'DIRECT';
|
||||
var isHttp = matches[1] == 'http';
|
||||
var isHttps = matches[1] == 'https';
|
||||
if (!matches[3])
|
||||
matches[3] = isHttp ? '80' : '443';
|
||||
{
|
||||
if (isHttp) matches[3] = '80';
|
||||
if (isHttps) matches[3] = '443';
|
||||
}
|
||||
|
||||
var origin = matches[1] + '://' + matches[2] + ':' + matches[3];
|
||||
if (origins.indexOf(origin) < 0)
|
||||
return 'DIRECT';
|
||||
if (isHttp)
|
||||
return 'PROXY localhost:8888';
|
||||
return 'PROXY 127.0.0.1:8888';
|
||||
if (isHttps)
|
||||
return 'PROXY 127.0.0.1:4443';
|
||||
return 'DIRECT';
|
||||
}""" % { "origins": origins }
|
||||
pacURL = "".join(pacURL.splitlines())
|
||||
@ -343,12 +378,81 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
||||
prefsFile.write("".join(prefs))
|
||||
prefsFile.close()
|
||||
|
||||
def fillCertificateDB(profileDir):
|
||||
|
||||
pwfilePath = os.path.join(profileDir, ".crtdbpw")
|
||||
|
||||
pwfile = open(pwfilePath, "w")
|
||||
pwfile.write("\n")
|
||||
pwfile.close()
|
||||
|
||||
# Create head of the ssltunnel configuration file
|
||||
sslTunnelConfigPath = os.path.join(CERTS_DIR, "ssltunnel.cfg")
|
||||
sslTunnelConfig = open(sslTunnelConfigPath, "w")
|
||||
|
||||
sslTunnelConfig.write("httpproxy:1\n")
|
||||
sslTunnelConfig.write("certdbdir:%s\n" % CERTS_DIR)
|
||||
sslTunnelConfig.write("forward:127.0.0.1:8888\n")
|
||||
sslTunnelConfig.write("listen:*:4443:pgo server certificate\n")
|
||||
|
||||
# Generate automatic certificate and bond custom certificates
|
||||
locations = readLocations()
|
||||
locations.pop(0)
|
||||
for loc in locations:
|
||||
if loc.scheme == "https" and "nocert" not in loc.options:
|
||||
customCertRE = re.compile("^cert=(?P<nickname>[0-9a-zA-Z_ ]+)")
|
||||
for option in loc.options:
|
||||
match = customCertRE.match(option)
|
||||
if match:
|
||||
customcert = match.group("nickname");
|
||||
sslTunnelConfig.write("listen:%s:%s:4443:%s\n" % (loc.host, loc.port, customcert))
|
||||
break
|
||||
|
||||
sslTunnelConfig.close()
|
||||
|
||||
# Pre-create the certification database for the profile
|
||||
certutil = DIST_BIN + "/certutil" + BIN_SUFFIX
|
||||
status = Process(certutil, ["-N", "-d", profileDir, "-f", pwfilePath], environment()).wait()
|
||||
if status != 0:
|
||||
return status
|
||||
|
||||
# Walk the cert directory and add custom CAs as trusted
|
||||
files = os.listdir(CERTS_DIR)
|
||||
for item in files:
|
||||
root, ext = os.path.splitext(item)
|
||||
if ext == ".ca":
|
||||
Process(certutil, ["-A", "-i", os.path.join(CERTS_DIR, item), "-d", profileDir, "-f", pwfilePath, "-n", root, "-t", "CT,,"], environment())
|
||||
|
||||
os.unlink(pwfilePath)
|
||||
return 0
|
||||
|
||||
def environment(env = None):
|
||||
if env == None:
|
||||
env = dict(os.environ)
|
||||
|
||||
if UNIXISH:
|
||||
ldLibraryPath = os.path.join(SCRIPT_DIR, DIST_BIN)
|
||||
if "LD_LIBRARY_PATH" in env:
|
||||
ldLibraryPath = ldLibraryPath + ":" + env["LD_LIBRARY_PATH"]
|
||||
env["LD_LIBRARY_PATH"] = ldLibraryPath
|
||||
|
||||
return env
|
||||
|
||||
###############
|
||||
# RUN THE APP #
|
||||
###############
|
||||
|
||||
def runApp(testURL, env, app, profileDir, extraArgs):
|
||||
# create certificate database for the profile
|
||||
certificateStatus = fillCertificateDB(profileDir)
|
||||
if certificateStatus != 0:
|
||||
log.info("ERROR FAIL Certificate integration")
|
||||
return certificateStatus
|
||||
|
||||
ssltunnel = DIST_BIN + "/ssltunnel" + BIN_SUFFIX
|
||||
ssltunnelProcess = Process(ssltunnel, [os.path.join(CERTS_DIR, "ssltunnel.cfg")], environment())
|
||||
log.info("SSL tunnel pid: %d", ssltunnelProcess.pid)
|
||||
|
||||
"Run the app, returning the time at which it was started."
|
||||
# mark the start
|
||||
start = datetime.now()
|
||||
@ -374,10 +478,12 @@ def runApp(testURL, env, app, profileDir, extraArgs):
|
||||
else:
|
||||
args.append((testURL))
|
||||
args.extend(extraArgs)
|
||||
proc = Process(cmd, args, env = env)
|
||||
proc = Process(cmd, args, env = environment(env))
|
||||
log.info("Application pid: %d", proc.pid)
|
||||
status = proc.wait()
|
||||
if status != 0:
|
||||
log.info("ERROR FAIL Exited with code %d during test run", status)
|
||||
|
||||
ssltunnelProcess.kill()
|
||||
|
||||
return start
|
||||
|
@ -1,3 +1,4 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
@ -11,15 +12,15 @@
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code
|
||||
# The Original Code is Mozilla test code
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Rusty Lynch
|
||||
# Portions created by the Initial Developer are Copyright (C) 2004
|
||||
# Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Rusty Lynch <rusty.lynch@intel.com>
|
||||
# Honza Bambas <honzab@firemni.cz>
|
||||
#
|
||||
# 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
|
||||
@ -35,47 +36,30 @@
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
######################################
|
||||
# Makefile.in (Generic SANE Plugin Tree)
|
||||
######################################
|
||||
|
||||
DEPTH = ../../../..
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = SanePlugin
|
||||
LIBRARY_NAME = Sane
|
||||
EXPORT_LIBRARY = 1
|
||||
IS_COMPONENT = 1
|
||||
_PROFILE_DIR = $(DEPTH)/_profile/pgo
|
||||
_CERTS_DIR = $(_PROFILE_DIR)/certs
|
||||
|
||||
# Extension of files must be '.server'
|
||||
_SERVER_CERTS = \
|
||||
$(NULL)
|
||||
|
||||
# Extension of files must be '.ca'
|
||||
_CERT_AUTHORITIES = \
|
||||
pgoca.ca \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsSanePluginFactory.cpp \
|
||||
nsSanePlugin.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../public \
|
||||
-I/usr/lib/glib/include
|
||||
|
||||
EXTRA_DSO_LDOPTS += -L$(DIST)/lib -lgtksuperwin \
|
||||
$(TK_LIBS) -lsane -ljpeg
|
||||
|
||||
XPIDLSRCS = nsSanePluginControl.idl
|
||||
_SERV_FILES = \
|
||||
pgoca.p12 \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
libs:: $(TARGETS)
|
||||
$(INSTALL) $(srcdir)/test/camera.html $(DIST)/bin/res/samples
|
||||
$(INSTALL) $(srcdir)/test/scanner.html $(DIST)/bin/res/samples
|
||||
$(INSTALL) $(srcdir)/test/camera.html /home/httpd/html/test
|
||||
$(INSTALL) $(srcdir)/test/scanner.html /home/httpd/html/test
|
||||
|
||||
superclean: clean
|
||||
rm -f *~ test/*~
|
||||
|
||||
|
||||
|
||||
|
||||
libs:: $(_SERV_FILES) $(_SERVER_CERTS) $(_CERT_AUTHORITIES)
|
||||
$(INSTALL) $^ $(_CERTS_DIR)
|
15
build/pgo/certs/pgoca.ca
Normal file
15
build/pgo/certs/pgoca.ca
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICXTCCAcagAwIBAgIBATANBgkqhkiG9w0BAQUFADBqMSQwIgYDVQQLExtQcm9m
|
||||
aWxlIEd1aWRlZCBPcHRpbWl6YXRpb24xGDAWBgNVBAoTD01vemlsbGEgVGVzdGlu
|
||||
ZzEoMCYGA1UEAxMfVGVtcG9yYXJ5IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0w
|
||||
ODA1MjIwMDM4MDVaFw0xODA1MjIwMDM4MDVaMGoxJDAiBgNVBAsTG1Byb2ZpbGUg
|
||||
R3VpZGVkIE9wdGltaXphdGlvbjEYMBYGA1UEChMPTW96aWxsYSBUZXN0aW5nMSgw
|
||||
JgYDVQQDEx9UZW1wb3JhcnkgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqG
|
||||
SIb3DQEBAQUAA4GNADCBiQKBgQDg6iipAXGZYmgTcHfx8M2hcLqmqDalcj7sZ1A7
|
||||
a3LiCBb+1uHKKy9hUxRUe61aJF4NgMAF5oc+HpXN0hpvkiNHxqqD7R6hrkP3gAJ3
|
||||
eczEFKsFUI6AqaCL0+xpyhaaZmmarcHxU+PL2h5zq6VssxfBAsO0DkzWzk6E8vM+
|
||||
jrku7QIDAQABoxMwETAPBgNVHRMECDAGAQH/AgEAMA0GCSqGSIb3DQEBBQUAA4GB
|
||||
ALPbn3Ztg0m8qDt8Vkf5You6HEqIxZe+ffDTrfq/L7ofHk/OXEpL7OWKRHU33pNG
|
||||
QS8khBG+sO461C51s6u9giW+eq2PaQv2HGASBpDbvPqc/Hf+zupZsdsXzHv6rt0V
|
||||
lu5B6nOpMse1nhA494i1ARSuBNzLv5mas38YWG8Rr6jR
|
||||
-----END CERTIFICATE-----
|
BIN
build/pgo/certs/pgoca.p12
Normal file
BIN
build/pgo/certs/pgoca.p12
Normal file
Binary file not shown.
214
build/pgo/genpgocert.py.in
Normal file
214
build/pgo/genpgocert.py.in
Normal file
@ -0,0 +1,214 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Foundation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2008
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Honza Bambas <honzab@firemni.cz>
|
||||
#
|
||||
# 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 *****
|
||||
|
||||
import automation
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
#expand DIST_BIN = "./" + __XPC_BIN_PATH__
|
||||
#expand BIN_SUFFIX = __BIN_SUFFIX__
|
||||
#expand CERTS_DIR = __CERTS_DIR__
|
||||
#expand CERTS_SRC_DIR = __CERTS_SRC_DIR__
|
||||
|
||||
dbFiles = [
|
||||
re.compile("^cert[0-9]+\.db$"),
|
||||
re.compile("^key[0-9]+\.db$"),
|
||||
re.compile("^secmod\.db$")
|
||||
]
|
||||
|
||||
def unlinkDbFiles(path):
|
||||
for root, dirs, files in os.walk(path):
|
||||
for name in files:
|
||||
for dbFile in dbFiles:
|
||||
if dbFile.match(name) and os.path.exists(os.path.join(root, name)):
|
||||
os.unlink(os.path.join(root, name))
|
||||
|
||||
|
||||
def runUtil(util, args, inputdata = None):
|
||||
proc = automation.Process(util, args, automation.environment(), inputdata)
|
||||
return proc.wait()
|
||||
|
||||
|
||||
def createRandomFile(randomFile):
|
||||
import random
|
||||
file = open(randomFile, "wb");
|
||||
for count in xrange(0, 2048):
|
||||
file.write(chr(random.randint(0, 255)))
|
||||
file.close()
|
||||
|
||||
|
||||
def createCertificateAuthority(dbDir, srcDir):
|
||||
certutil = DIST_BIN + "/certutil" + BIN_SUFFIX
|
||||
pk12util = DIST_BIN + "/pk12util" + BIN_SUFFIX
|
||||
|
||||
tempDbDir = os.path.join(dbDir, ".temp")
|
||||
if not os.path.exists(tempDbDir):
|
||||
os.mkdir(tempDbDir)
|
||||
|
||||
pwfilePath = os.path.join(tempDbDir, ".crtdbpw")
|
||||
rndfilePath = os.path.join(tempDbDir, ".rndfile")
|
||||
pgoCAModulePathSrc = os.path.join(srcDir, "pgoca.p12")
|
||||
pgoCAPathSrc = os.path.join(srcDir, "pgoca.ca")
|
||||
pgoCAModulePath = os.path.join(srcDir, "pgoca.p12")
|
||||
pgoCAPath = os.path.join(srcDir, "pgoca.ca")
|
||||
|
||||
pwfile = open(pwfilePath, "w")
|
||||
pwfile.write("\n")
|
||||
pwfile.close()
|
||||
|
||||
unlinkDbFiles(tempDbDir)
|
||||
|
||||
# Create temporary certification database for CA generation
|
||||
status = runUtil(certutil, ["-N", "-d", tempDbDir, "-f", pwfilePath])
|
||||
if status != 0:
|
||||
return status
|
||||
|
||||
createRandomFile(rndfilePath);
|
||||
status = runUtil(certutil, ["-S", "-d", tempDbDir, "-s", "CN=Temporary Certificate Authority, O=Mozilla Testing, OU=Profile Guided Optimization", "-t", "C,,", "-x", "-m", "1", "-v", "120", "-n", "pgo temporary ca", "-2", "-f", pwfilePath, "-z", rndfilePath], "Y\n0\nN\n")
|
||||
if status != 0:
|
||||
return status
|
||||
|
||||
status = runUtil(certutil, ["-L", "-d", tempDbDir, "-n", "pgo temporary ca", "-a", "-o", pgoCAPathSrc, "-f", pwfilePath])
|
||||
if status != 0:
|
||||
return status
|
||||
|
||||
status = runUtil(pk12util, ["-o", pgoCAModulePathSrc, "-n", "pgo temporary ca", "-d", tempDbDir, "-w", pwfilePath, "-k", pwfilePath])
|
||||
if status != 0:
|
||||
return status
|
||||
|
||||
unlinkDbFiles(tempDbDir)
|
||||
os.unlink(pwfilePath)
|
||||
os.unlink(rndfilePath)
|
||||
os.rmdir(tempDbDir)
|
||||
return 0
|
||||
|
||||
|
||||
def createSSLServerCertificate(dbDir):
|
||||
certutil = DIST_BIN + "/certutil" + BIN_SUFFIX
|
||||
pk12util = DIST_BIN + "/pk12util" + BIN_SUFFIX
|
||||
|
||||
pwfilePath = os.path.join(dbDir, ".crtdbpw")
|
||||
rndfilePath = os.path.join(dbDir, ".rndfile")
|
||||
pgoCAPath = os.path.join(dbDir, "pgoca.p12")
|
||||
|
||||
pwfile = open(pwfilePath, "w")
|
||||
pwfile.write("\n")
|
||||
pwfile.close()
|
||||
|
||||
unlinkDbFiles(dbDir)
|
||||
|
||||
# Create certification database for ssltunnel
|
||||
status = runUtil(certutil, ["-N", "-d", dbDir, "-f", pwfilePath])
|
||||
if status != 0:
|
||||
return status
|
||||
|
||||
status = runUtil(pk12util, ["-i", pgoCAPath, "-w", pwfilePath, "-d", dbDir, "-k", pwfilePath])
|
||||
if status != 0:
|
||||
return status
|
||||
|
||||
# Generate automatic certificate
|
||||
locations = automation.readLocations(os.path.join(dbDir, "../server-locations.txt"))
|
||||
locations.pop(0)
|
||||
locationsParam = ""
|
||||
firstLocation = ""
|
||||
for loc in locations:
|
||||
if loc.scheme == "https" and "nocert" not in loc.options:
|
||||
customCertOption = False
|
||||
customCertRE = re.compile("^cert=(?:\w+)")
|
||||
for option in loc.options:
|
||||
match = customCertRE.match(option)
|
||||
if match:
|
||||
customCertOption = True
|
||||
break
|
||||
|
||||
if not customCertOption:
|
||||
if len(locationsParam) > 0:
|
||||
locationsParam += ","
|
||||
locationsParam += loc.host
|
||||
|
||||
if firstLocation == "":
|
||||
firstLocation = loc.host
|
||||
|
||||
if firstLocation == "":
|
||||
print "Nothing to generate, no automatic secure hosts specified"
|
||||
else:
|
||||
createRandomFile(rndfilePath);
|
||||
status = runUtil(certutil, ["-S", "-s", "CN=%s" % firstLocation, "-t", "Pu,,", "-c", "pgo temporary ca", "-m", "2", "-8", locationsParam, "-v", "12", "-n", "pgo server certificate", "-d", dbDir, "-z", rndfilePath, "-f", pwfilePath])
|
||||
if status != 0:
|
||||
return status
|
||||
|
||||
# Walk the cert directory and add what necessary
|
||||
files = os.listdir(CERTS_DIR)
|
||||
for item in files:
|
||||
root, ext = os.path.splitext(item)
|
||||
if ext == ".server":
|
||||
runUtil(pk12util, ["-i", os.path.join(CERTS_DIR, item), "-d", dbDir, "-k", pwfilePath, "-w", pwfilePath])
|
||||
|
||||
os.unlink(pwfilePath)
|
||||
os.unlink(rndfilePath)
|
||||
return 0
|
||||
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
print "Specify --gen-server or --gen-ca"
|
||||
sys.exit(1)
|
||||
|
||||
if sys.argv[1] == "--gen-server":
|
||||
certificateStatus = createSSLServerCertificate(CERTS_DIR)
|
||||
if certificateStatus != 0:
|
||||
print "ERROR FAIL: SSL Server Certificate generation"
|
||||
|
||||
sys.exit(certificateStatus)
|
||||
|
||||
if sys.argv[1] == "--gen-ca":
|
||||
certificateStatus = createCertificateAuthority(CERTS_DIR, CERTS_SRC_DIR)
|
||||
if certificateStatus != 0:
|
||||
print "ERROR FAIL: Certificate Authority generation"
|
||||
else:
|
||||
print "\n\n"
|
||||
print "==================================================="
|
||||
print " IMPORTANT:"
|
||||
print " To use this new certificate authority in tests"
|
||||
print " run 'make' at testing/mochitest"
|
||||
print "==================================================="
|
||||
|
||||
sys.exit(certificateStatus)
|
||||
|
||||
print "Invalid option specified"
|
||||
sys.exit(1)
|
@ -52,11 +52,24 @@
|
||||
# number is the default for the protocol.
|
||||
#
|
||||
# Unrecognized options are ignored. Recognized options are "primary" and
|
||||
# "privileged". "primary" denotes a location which is the canonical location of
|
||||
# "privileged", "nocert", "cert=some_cert_nickname".
|
||||
#
|
||||
# "primary" denotes a location which is the canonical location of
|
||||
# the server; this location is the one assumed for requests which don't
|
||||
# otherwise identify a particular origin (e.g. HTTP/1.0 requests). "privileged"
|
||||
# denotes a location which should have the ability to request elevated
|
||||
# privileges; the default is no privileges.
|
||||
# otherwise identify a particular origin (e.g. HTTP/1.0 requests).
|
||||
#
|
||||
# "privileged" denotes a location which should have the ability to request
|
||||
# elevated privileges; the default is no privileges.
|
||||
#
|
||||
# "nocert" makes sense only for https:// hosts and means there is not
|
||||
# any certificate automatically generated for this host.
|
||||
#
|
||||
# "cert=nickname" tells the pgo server to use a particular certificate
|
||||
# for this host. The certificate is referenced by its nickname that must
|
||||
# not contain any spaces. The certificate key files (PKCS12 modules)
|
||||
# for custom certification are loaded from build/pgo/ssltunnel/certs
|
||||
# directory. When new certificate is added to this dir pgo/ssltunnel
|
||||
# must be builded then.
|
||||
#
|
||||
|
||||
#
|
||||
@ -90,6 +103,15 @@ http://sub1.test2.example.com:80 privileged
|
||||
http://sub2.test1.example.com:80 privileged
|
||||
http://sub2.test2.example.com:80 privileged
|
||||
|
||||
https://example.com:443 privileged
|
||||
https://test1.example.com:443 privileged
|
||||
https://test2.example.com:443 privileged
|
||||
https://sub1.test1.example.com:443 privileged
|
||||
https://sub1.test2.example.com:443 privileged
|
||||
https://sub2.test1.example.com:443 privileged
|
||||
https://sub2.test2.example.com:443 privileged
|
||||
https://nocert.example.com:443 privileged,nocert
|
||||
|
||||
#
|
||||
# These are subdomains of <ält.example.org>.
|
||||
#
|
||||
@ -98,6 +120,9 @@ http://sub2.xn--lt-uia.example.org:80 privileged
|
||||
http://xn--exmple-cua.test:80 privileged
|
||||
http://sub1.xn--exmple-cua.test:80 privileged
|
||||
|
||||
https://xn--hxajbheg2az3al.xn--jxalpdlp:443 privileged
|
||||
https://sub1.xn--hxajbheg2az3al.xn--jxalpdlp:443 privileged
|
||||
|
||||
#
|
||||
# These are subdomains of <παράδειγμα.δοκιμή>, the Greek IDN for example.test.
|
||||
#
|
||||
@ -114,3 +139,8 @@ http://sectest1.example.org:80 privileged
|
||||
http://sub.sectest2.example.org:80 privileged
|
||||
http://sectest2.example.org:80
|
||||
http://sub.sectest1.example.org:80
|
||||
|
||||
https://sectest1.example.org:443 privileged
|
||||
https://sub.sectest2.example.org:443 privileged
|
||||
https://sectest2.example.org:443
|
||||
https://sub.sectest1.example.org:443
|
||||
|
@ -423,7 +423,7 @@ private:
|
||||
nsScriptSecurityManager();
|
||||
virtual ~nsScriptSecurityManager();
|
||||
|
||||
static JSBool JS_DLL_CALLBACK
|
||||
static JSBool
|
||||
CheckObjectAccess(JSContext *cx, JSObject *obj,
|
||||
jsval id, JSAccessMode mode,
|
||||
jsval *vp);
|
||||
|
@ -49,19 +49,19 @@
|
||||
#include "nsMemory.h"
|
||||
#include "nsStringBuffer.h"
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(void *)
|
||||
static void *
|
||||
nsGetPrincipalArray(JSContext *cx, JSPrincipals *prin)
|
||||
{
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSBool)
|
||||
static JSBool
|
||||
nsGlobalPrivilegesEnabled(JSContext *cx, JSPrincipals *jsprin)
|
||||
{
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSBool)
|
||||
static JSBool
|
||||
nsJSPrincipalsSubsume(JSPrincipals *jsprin, JSPrincipals *other)
|
||||
{
|
||||
nsJSPrincipals *nsjsprin = static_cast<nsJSPrincipals *>(jsprin);
|
||||
@ -73,7 +73,7 @@ nsJSPrincipalsSubsume(JSPrincipals *jsprin, JSPrincipals *other)
|
||||
return NS_SUCCEEDED(rv) && result;
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(void)
|
||||
static void
|
||||
nsDestroyJSPrincipals(JSContext *cx, struct JSPrincipals *jsprin)
|
||||
{
|
||||
nsJSPrincipals *nsjsprin = static_cast<nsJSPrincipals *>(jsprin);
|
||||
@ -99,7 +99,7 @@ nsDestroyJSPrincipals(JSContext *cx, struct JSPrincipals *jsprin)
|
||||
// so we don't need to worry about "codebase"
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSBool)
|
||||
static JSBool
|
||||
nsTranscodeJSPrincipals(JSXDRState *xdr, JSPrincipals **jsprinp)
|
||||
{
|
||||
nsresult rv;
|
||||
@ -179,10 +179,13 @@ nsJSPrincipals::Startup()
|
||||
rtsvc->GetRuntime(&rt);
|
||||
NS_ASSERTION(rt != nsnull, "no JSRuntime?!");
|
||||
|
||||
JSPrincipalsTranscoder oldpx;
|
||||
oldpx = ::JS_SetPrincipalsTranscoder(rt, nsTranscodeJSPrincipals);
|
||||
NS_ASSERTION(oldpx == nsnull, "oops, JS_SetPrincipalsTranscoder wars!");
|
||||
JSSecurityCallbacks *callbacks = JS_GetRuntimeSecurityCallbacks(rt);
|
||||
NS_ASSERTION(callbacks, "Need a callbacks struct by now!");
|
||||
|
||||
NS_ASSERTION(!callbacks->principalsTranscoder,
|
||||
"oops, JS_SetPrincipalsTranscoder wars!");
|
||||
|
||||
callbacks->principalsTranscoder = nsTranscodeJSPrincipals;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,7 @@ NS_IMPL_ISUPPORTS5(nsScriptSecurityManager,
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
///////////////// Security Checks /////////////////
|
||||
JSBool JS_DLL_CALLBACK
|
||||
JSBool
|
||||
nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj,
|
||||
jsval id, JSAccessMode mode,
|
||||
jsval *vp)
|
||||
@ -2050,7 +2050,7 @@ nsScriptSecurityManager::GetScriptPrincipal(JSContext *cx,
|
||||
JSPrincipals *jsp = JS_GetScriptPrincipals(cx, script);
|
||||
if (!jsp) {
|
||||
*rv = NS_ERROR_FAILURE;
|
||||
// Script didn't have principals -- shouldn't happen.
|
||||
NS_ERROR("Script compiled without principals!");
|
||||
return nsnull;
|
||||
}
|
||||
nsJSPrincipals *nsJSPrin = static_cast<nsJSPrincipals *>(jsp);
|
||||
@ -3225,17 +3225,21 @@ nsresult nsScriptSecurityManager::Init()
|
||||
rv = runtimeService->GetRuntime(&sRuntime);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
static JSSecurityCallbacks securityCallbacks = {
|
||||
CheckObjectAccess,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
JSCheckAccessOp oldCallback =
|
||||
JSSecurityCallbacks *oldcallbacks =
|
||||
#endif
|
||||
JS_SetCheckObjectAccessCallback(sRuntime, CheckObjectAccess);
|
||||
JS_SetRuntimeSecurityCallbacks(sRuntime, &securityCallbacks);
|
||||
NS_ASSERTION(!oldcallbacks, "Someone else set security callbacks!");
|
||||
|
||||
sXPConnect->GetXPCWrappedNativeJSClassInfo(&sXPCWrappedNativeJSClass,
|
||||
&sXPCWrappedNativeGetObjOps1,
|
||||
&sXPCWrappedNativeGetObjOps2);
|
||||
|
||||
// For now, assert that no callback was set previously
|
||||
NS_ASSERTION(!oldCallback, "Someone already set a JS CheckObjectAccess callback");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -3256,11 +3260,7 @@ void
|
||||
nsScriptSecurityManager::Shutdown()
|
||||
{
|
||||
if (sRuntime) {
|
||||
#ifdef DEBUG
|
||||
JSCheckAccessOp oldCallback =
|
||||
#endif
|
||||
JS_SetCheckObjectAccessCallback(sRuntime, nsnull);
|
||||
NS_ASSERTION(oldCallback == CheckObjectAccess, "Oops, we just clobbered someone else, oh well.");
|
||||
JS_SetRuntimeSecurityCallbacks(sRuntime, NULL);
|
||||
sRuntime = nsnull;
|
||||
}
|
||||
sEnabledID = JSVAL_VOID;
|
||||
|
@ -69,11 +69,7 @@ LIBXUL_SDK = @LIBXUL_SDK@
|
||||
|
||||
L10NBASEDIR = @L10NBASEDIR@
|
||||
|
||||
ifdef LIBXUL_SDK
|
||||
LIBXUL_DIST = $(LIBXUL_SDK)
|
||||
else
|
||||
LIBXUL_DIST = $(DIST)
|
||||
endif
|
||||
LIBXUL_DIST = @LIBXUL_DIST@
|
||||
|
||||
XULRUNNER_STUB_NAME = @XULRUNNER_STUB_NAME@
|
||||
|
||||
@ -165,7 +161,6 @@ MOZ_OGG = @MOZ_OGG@
|
||||
MOZ_MEDIA = @MOZ_MEDIA@
|
||||
NS_PRINTING = @NS_PRINTING@
|
||||
MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@
|
||||
MOZ_MOCHITEST = @MOZ_MOCHITEST@
|
||||
MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@
|
||||
MOC= @MOC@
|
||||
|
||||
|
@ -511,6 +511,7 @@ DEHYDRA_MODULES = \
|
||||
TREEHYDRA_MODULES = \
|
||||
$(topsrcdir)/xpcom/analysis/outparams.js \
|
||||
$(topsrcdir)/xpcom/analysis/stack.js \
|
||||
$(topsrcdir)/xpcom/analysis/flow.js \
|
||||
$(NULL)
|
||||
|
||||
DEHYDRA_ARGS = \
|
||||
|
51
configure.in
51
configure.in
@ -2955,6 +2955,11 @@ EOF
|
||||
fi # have visibility(hidden) attribute
|
||||
fi # GNU_CC
|
||||
|
||||
# visibility hidden flag for Sun Studio on Solaris
|
||||
if test -z "$GNU_CC" && test -z "$GNU_CXX" && test "$OS_ARCH" = "SunOS"; then
|
||||
VISIBILITY_FLAGS='-xldscope=hidden'
|
||||
fi # Sun Studio on Solaris
|
||||
|
||||
AC_SUBST(WRAP_SYSTEM_INCLUDES)
|
||||
AC_SUBST(VISIBILITY_FLAGS)
|
||||
|
||||
@ -4031,6 +4036,13 @@ elif test -n "$LIBXUL_SDK_DIR" -a "$LIBXUL_SDK_DIR" != "no"; then
|
||||
fi
|
||||
AC_SUBST(LIBXUL_SDK)
|
||||
|
||||
if test -n "$LIBXUL_SDK"; then
|
||||
LIBXUL_DIST="$LIBXUL_SDK"
|
||||
else
|
||||
LIBXUL_DIST="$MOZ_BUILD_ROOT/dist"
|
||||
fi
|
||||
AC_SUBST(LIBXUL_DIST)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = If NSPR was not detected in the system,
|
||||
dnl = use the one in the source tree (mozilla/nsprpub)
|
||||
@ -4054,22 +4066,22 @@ if test -n "$MOZ_NATIVE_NSPR"; then
|
||||
AC_MSG_ERROR([system NSPR does not support PR_STATIC_ASSERT]))
|
||||
CFLAGS=$_SAVE_CFLAGS
|
||||
else
|
||||
NSPR_CFLAGS='`$(DEPTH)/nsprpub/config/nspr-config --prefix=$(LIBXUL_DIST) --includedir=$(LIBXUL_DIST)/include/nspr --cflags`'
|
||||
NSPR_CFLAGS='`$(DEPTH)/nsprpub/config/nspr-config --prefix='${LIBXUL_DIST}' --includedir='${LIBXUL_DIST}'/include/nspr --cflags`'
|
||||
# explicitly set libs for Visual Age C++ for OS/2
|
||||
if test "$OS_ARCH" = "OS2" -a "$VACPP" = "yes"; then
|
||||
NSPR_LIBS='$(LIBXUL_DIST)/lib/nspr'$NSPR_VERSION'.lib $(LIBXUL_DIST)/lib/plc'$NSPR_VERSION'.lib $(LIBXUL_DIST)/lib/plds'$NSPR_VERSION'.lib '$_PTHREAD_LDFLAGS''
|
||||
NSPR_LIBS="${LIBXUL_DIST}/lib/nspr${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plc${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plds${NSPR_VERSION}.lib ${_PTHREAD_LDFLAGS}"
|
||||
elif test "$OS_ARCH" = "WINCE"; then
|
||||
NSPR_CFLAGS='-I$(LIBXUL_DIST)/include/nspr'
|
||||
NSPR_LIBS='$(LIBXUL_DIST)/lib/nspr'$NSPR_VERSION'.lib $(LIBXUL_DIST)/lib/plc'$NSPR_VERSION'.lib $(LIBXUL_DIST)/lib/plds'$NSPR_VERSION'.lib '
|
||||
NSPR_CFLAGS="-I${LIBXUL_DIST}/include/nspr"
|
||||
NSPR_LIBS="${LIBXUL_DIST}/lib/nspr${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plc${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plds${NSPR_VERSION}.lib "
|
||||
elif test "$OS_ARCH" = "WINNT"; then
|
||||
NSPR_CFLAGS='-I$(LIBXUL_DIST)/include/nspr'
|
||||
NSPR_CFLAGS="-I${LIBXUL_DIST}/include/nspr"
|
||||
if test -n "$GNU_CC"; then
|
||||
NSPR_LIBS="-L\$(LIBXUL_DIST)/lib -lnspr$NSPR_VERSION -lplc$NSPR_VERSION -lplds$NSPR_VERSION"
|
||||
NSPR_LIBS="-L${LIBXUL_DIST}/lib -lnspr${NSPR_VERSION} -lplc${NSPR_VERSION} -lplds${NSPR_VERSION}"
|
||||
else
|
||||
NSPR_LIBS='$(LIBXUL_DIST)/lib/nspr'$NSPR_VERSION'.lib $(LIBXUL_DIST)/lib/plc'$NSPR_VERSION'.lib $(LIBXUL_DIST)/lib/plds'$NSPR_VERSION'.lib '
|
||||
NSPR_LIBS="${LIBXUL_DIST}/lib/nspr${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plc${NSPR_VERSION}.lib ${LIBXUL_DIST}/lib/plds${NSPR_VERSION}.lib "
|
||||
fi
|
||||
else
|
||||
NSPR_LIBS='`$(DEPTH)/nsprpub/config/nspr-config --prefix=$(LIBXUL_DIST) --libdir=$(LIBXUL_DIST)/lib --libs`'
|
||||
NSPR_LIBS='`$(DEPTH)/nsprpub/config/nspr-config --prefix='${LIBXUL_DIST}' --libdir='${LIBXUL_DIST}'/lib --libs`'
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -4345,7 +4357,6 @@ MOZ_JSLOADER=1
|
||||
MOZ_LIBART_CFLAGS=
|
||||
MOZ_LIBART_LIBS=
|
||||
MOZ_MATHML=1
|
||||
MOZ_MOCHITEST=1
|
||||
MOZ_MORK=1
|
||||
MOZ_MORKREADER=
|
||||
MOZ_AUTH_EXTENSION=1
|
||||
@ -5517,15 +5528,6 @@ if test -z "$MOZ_CRASHREPORTER_ENABLE_PERCENT"; then
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(MOZ_CRASHREPORTER_ENABLE_PERCENT, $MOZ_CRASHREPORTER_ENABLE_PERCENT)
|
||||
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Build mochitest JS/DOM tests (on by default)
|
||||
dnl ========================================================
|
||||
MOZ_ARG_DISABLE_BOOL(mochitest,
|
||||
[ --disable-mochitest Disable mochitest harness],
|
||||
MOZ_MOCHITEST=,
|
||||
MOZ_MOCHITEST=1 )
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable compilation of specific extension modules
|
||||
dnl ========================================================
|
||||
@ -7149,6 +7151,10 @@ MOZ_ARG_ENABLE_BOOL(libxul,
|
||||
MOZ_ENABLE_LIBXUL=1,
|
||||
MOZ_ENABLE_LIBXUL=)
|
||||
|
||||
if test -n "$MOZ_STATIC_BUILD_UNSUPPORTED" -a -n "$BUILD_STATIC_LIBS"; then
|
||||
AC_MSG_ERROR([--enable-static is not supported for building $MOZ_APP_NAME. You probably want --enable-libxul.])
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_ENABLE_LIBXUL" -a -n "$BUILD_STATIC_LIBS"; then
|
||||
AC_MSG_ERROR([--enable-libxul is not compatible with --enable-static])
|
||||
fi
|
||||
@ -7899,7 +7905,6 @@ AC_SUBST(MOZ_SPELLCHECK)
|
||||
AC_SUBST(MOZ_XPFE_COMPONENTS)
|
||||
AC_SUBST(MOZ_USER_DIR)
|
||||
AC_SUBST(MOZ_CRASHREPORTER)
|
||||
AC_SUBST(MOZ_MOCHITEST)
|
||||
|
||||
AC_SUBST(ENABLE_STRIP)
|
||||
AC_SUBST(PKG_SKIP_STRIP)
|
||||
@ -8356,12 +8361,12 @@ if test -z "$MOZ_NATIVE_NSPR"; then
|
||||
# Hack to deal with the fact that we use NSPR_CFLAGS everywhere
|
||||
AC_MSG_WARN([Recreating autoconf.mk with updated nspr-config output])
|
||||
if test ! "$VACPP" && test "$OS_ARCH" != "WINNT" && test "$OS_ARCH" != "WINCE"; then
|
||||
_libs=`./nsprpub/config/nspr-config --prefix=$\(LIBXUL_DIST\) --exec-prefix=$\(DIST\) --libdir=$\(LIBXUL_DIST\)/lib --libs`
|
||||
$PERL -pi.bak -e "s '^NSPR_LIBS\\s*=.*'NSPR_LIBS = $_libs'" config/autoconf.mk
|
||||
NSPR_LIBS=`./nsprpub/config/nspr-config --prefix=$LIBXUL_DIST --exec-prefix=$MOZ_BUILD_ROOT/dist --libdir=$LIBXUL_DIST/lib --libs`
|
||||
$PERL -pi.bak -e "s '^NSPR_LIBS\\s*=.*'NSPR_LIBS = $NSPR_LIBS'" config/autoconf.mk
|
||||
fi
|
||||
if test "$OS_ARCH" != "WINNT" && test "$OS_ARCH" != "WINCE" ; then
|
||||
_cflags=`./nsprpub/config/nspr-config --prefix=$\(LIBXUL_DIST\) --exec-prefix=$\(DIST\) --includedir=$\(LIBXUL_DIST\)/include/nspr --cflags`
|
||||
$PERL -pi.bak -e "s '^NSPR_CFLAGS\\s*=.*'NSPR_CFLAGS = $_cflags'" config/autoconf.mk
|
||||
NSPR_CFLAGS=`./nsprpub/config/nspr-config --prefix=$LIBXUL_DIST --exec-prefix=$MOZ_BUILD_ROOT/dist --includedir=$LIBXUL_DIST/include/nspr --cflags`
|
||||
$PERL -pi.bak -e "s '^NSPR_CFLAGS\\s*=.*'NSPR_CFLAGS = $NSPR_CFLAGS'" config/autoconf.mk
|
||||
fi
|
||||
rm -f config/autoconf.mk.bak
|
||||
fi
|
||||
|
@ -94,6 +94,7 @@ class nsIJSRuntimeService;
|
||||
class nsIEventListenerManager;
|
||||
class nsIScriptContext;
|
||||
class nsIRunnable;
|
||||
class nsIInterfaceRequestor;
|
||||
template<class E> class nsCOMArray;
|
||||
class nsIPref;
|
||||
class nsVoidArray;
|
||||
@ -664,9 +665,7 @@ public:
|
||||
* @param aContent The content node to test.
|
||||
* @return whether it's draggable
|
||||
*/
|
||||
static PRBool ContentIsDraggable(nsIContent* aContent) {
|
||||
return IsDraggableImage(aContent) || IsDraggableLink(aContent);
|
||||
}
|
||||
static PRBool ContentIsDraggable(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Method that decides whether a content node is a draggable image
|
||||
@ -1323,6 +1322,12 @@ public:
|
||||
|
||||
static nsresult GetContextForEventHandlers(nsINode* aNode,
|
||||
nsIScriptContext** aContext);
|
||||
|
||||
static JSContext *GetCurrentJSContext();
|
||||
|
||||
|
||||
static nsIInterfaceRequestor* GetSameOriginChecker();
|
||||
|
||||
private:
|
||||
|
||||
static PRBool InitializeEventTable();
|
||||
@ -1400,6 +1405,8 @@ private:
|
||||
static PRUint32 sRemovableScriptBlockerCount;
|
||||
static nsCOMArray<nsIRunnable>* sBlockedScriptRunners;
|
||||
static PRUint32 sRunnersCountAtFirstBlocker;
|
||||
|
||||
static nsIInterfaceRequestor* sSameOriginChecker;
|
||||
};
|
||||
|
||||
#define NS_HOLD_JS_OBJECTS(obj, clazz) \
|
||||
@ -1505,6 +1512,78 @@ private:
|
||||
PRUint32 mNestingLevel;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class used to detect unexpected mutations. To use the class create an
|
||||
* nsMutationGuard on the stack before unexpected mutations could occur.
|
||||
* You can then at any time call Mutated to check if any unexpected mutations
|
||||
* have occured.
|
||||
*
|
||||
* When a guard is instantiated sMutationCount is set to 300. It is then
|
||||
* decremented by every mutation (capped at 0). This means that we can only
|
||||
* detect 300 mutations during the lifetime of a single guard, however that
|
||||
* should be more then we ever care about as we usually only care if more then
|
||||
* one mutation has occured.
|
||||
*
|
||||
* When the guard goes out of scope it will adjust sMutationCount so that over
|
||||
* the lifetime of the guard the guard itself has not affected sMutationCount,
|
||||
* while mutations that happened while the guard was alive still will. This
|
||||
* allows a guard to be instantiated even if there is another guard higher up
|
||||
* on the callstack watching for mutations.
|
||||
*
|
||||
* The only thing that has to be avoided is for an outer guard to be used
|
||||
* while an inner guard is alive. This can be avoided by only ever
|
||||
* instantiating a single guard per scope and only using the guard in the
|
||||
* current scope.
|
||||
*/
|
||||
class nsMutationGuard {
|
||||
public:
|
||||
nsMutationGuard()
|
||||
{
|
||||
mDelta = eMaxMutations - sMutationCount;
|
||||
sMutationCount = eMaxMutations;
|
||||
}
|
||||
~nsMutationGuard()
|
||||
{
|
||||
sMutationCount =
|
||||
mDelta > sMutationCount ? 0 : sMutationCount - mDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any unexpected mutations have occured. You can pass in
|
||||
* an 8-bit ignore count to ignore a number of expected mutations.
|
||||
*/
|
||||
PRBool Mutated(PRUint8 aIgnoreCount)
|
||||
{
|
||||
return sMutationCount < static_cast<PRUint32>(eMaxMutations - aIgnoreCount);
|
||||
}
|
||||
|
||||
// This function should be called whenever a mutation that we want to keep
|
||||
// track of happen. For now this is only done when children are added or
|
||||
// removed, but we might do it for attribute changes too in the future.
|
||||
static void DidMutate()
|
||||
{
|
||||
if (sMutationCount) {
|
||||
--sMutationCount;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// mDelta is the amount sMutationCount was adjusted when the guard was
|
||||
// initialized. It is needed so that we can undo that adjustment once
|
||||
// the guard dies.
|
||||
PRUint32 mDelta;
|
||||
|
||||
// The value 300 is not important, as long as it is bigger then anything
|
||||
// ever passed to Mutated().
|
||||
enum { eMaxMutations = 300 };
|
||||
|
||||
|
||||
// sMutationCount is a global mutation counter which is decreased by one at
|
||||
// every mutation. It is capped at 0 to avoid wrapping.
|
||||
// It's value is always between 0 and 300, inclusive.
|
||||
static PRUint32 sMutationCount;
|
||||
};
|
||||
|
||||
#define NS_AUTO_GCROOT_PASTE2(tok,line) tok##line
|
||||
#define NS_AUTO_GCROOT_PASTE(tok,line) \
|
||||
NS_AUTO_GCROOT_PASTE2(tok,line)
|
||||
|
@ -128,14 +128,15 @@ interface nsIDOMParser : nsISupports
|
||||
* The nsIDOMParserJS interface provides a scriptable way of calling init().
|
||||
* Do NOT use this interface from languages other than JavaScript.
|
||||
*/
|
||||
[scriptable, uuid(dca92fe9-ae7a-44b7-80aa-d151216698ac)]
|
||||
[scriptable, uuid(ba6bcd6c-63d8-49b3-bc8a-1e5e895645bc)]
|
||||
interface nsIDOMParserJS : nsISupports
|
||||
{
|
||||
/**
|
||||
* Just like nsIDOMParser.init, but callable from JS. It'll pick up the args
|
||||
* from XPConnect.
|
||||
* Just like nsIDOMParser.init, but callable from JS.
|
||||
*/
|
||||
void init();
|
||||
void init(in nsIPrincipal principal,
|
||||
in nsIURI documentURI,
|
||||
in nsIURI baseURI);
|
||||
};
|
||||
|
||||
%{ C++
|
||||
|
@ -894,7 +894,10 @@ nsTransferableFactory::Produce(nsDOMDataTransfer* aDataTransfer,
|
||||
nsIContent* findFormParent = findFormNode->GetParent();
|
||||
while (findFormParent) {
|
||||
nsCOMPtr<nsIFormControl> form(do_QueryInterface(findFormParent));
|
||||
if (form && form->GetType() != NS_FORM_OBJECT)
|
||||
if (form && form->GetType() != NS_FORM_OBJECT &&
|
||||
form->GetType() != NS_FORM_FIELDSET &&
|
||||
form->GetType() != NS_FORM_LEGEND &&
|
||||
form->GetType() != NS_FORM_LABEL)
|
||||
return NS_OK;
|
||||
findFormParent = findFormParent->GetParent();
|
||||
}
|
||||
|
@ -89,6 +89,7 @@
|
||||
#include "nsIDOMHTMLDocument.h"
|
||||
#include "nsIDOMHTMLCollection.h"
|
||||
#include "nsIDOMHTMLFormElement.h"
|
||||
#include "nsIDOMNSHTMLElement.h"
|
||||
#include "nsIForm.h"
|
||||
#include "nsIFormControl.h"
|
||||
#include "nsGkAtoms.h"
|
||||
@ -155,6 +156,8 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
|
||||
#include "nsReferencedElement.h"
|
||||
#include "nsIUGenCategory.h"
|
||||
#include "nsIDragService.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
|
||||
#ifdef IBMBIDI
|
||||
#include "nsIBidiKeyboard.h"
|
||||
@ -208,10 +211,13 @@ PRUint32 nsContentUtils::sScriptBlockerCount = 0;
|
||||
PRUint32 nsContentUtils::sRemovableScriptBlockerCount = 0;
|
||||
nsCOMArray<nsIRunnable>* nsContentUtils::sBlockedScriptRunners = nsnull;
|
||||
PRUint32 nsContentUtils::sRunnersCountAtFirstBlocker = 0;
|
||||
nsIInterfaceRequestor* nsContentUtils::sSameOriginChecker = nsnull;
|
||||
|
||||
nsIJSRuntimeService *nsAutoGCRoot::sJSRuntimeService;
|
||||
JSRuntime *nsAutoGCRoot::sJSScriptRuntime;
|
||||
|
||||
PRUint32 nsMutationGuard::sMutationCount = 0;
|
||||
|
||||
PRBool nsContentUtils::sInitialized = PR_FALSE;
|
||||
|
||||
static PLDHashTable sEventListenerManagersHash;
|
||||
@ -255,6 +261,14 @@ EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
|
||||
lm->~EventListenerManagerMapEntry();
|
||||
}
|
||||
|
||||
class nsSameOriginChecker : public nsIChannelEventSink,
|
||||
public nsIInterfaceRequestor
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
};
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsContentUtils::Init()
|
||||
@ -897,6 +911,8 @@ nsContentUtils::Shutdown()
|
||||
delete sBlockedScriptRunners;
|
||||
sBlockedScriptRunners = nsnull;
|
||||
|
||||
NS_IF_RELEASE(sSameOriginChecker);
|
||||
|
||||
nsAutoGCRoot::Shutdown();
|
||||
}
|
||||
|
||||
@ -2438,6 +2454,26 @@ nsContentUtils::GetImageFromContent(nsIImageLoadingContent* aContent,
|
||||
return image;
|
||||
}
|
||||
|
||||
// static
|
||||
PRBool
|
||||
nsContentUtils::ContentIsDraggable(nsIContent* aContent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNSHTMLElement> htmlElement = do_QueryInterface(aContent);
|
||||
if (htmlElement) {
|
||||
PRBool draggable = PR_FALSE;
|
||||
htmlElement->GetDraggable(&draggable);
|
||||
if (draggable)
|
||||
return PR_TRUE;
|
||||
|
||||
if (aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
|
||||
nsGkAtoms::_false, eIgnoreCase))
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// special handling for content area image and link dragging
|
||||
return IsDraggableImage(aContent) || IsDraggableLink(aContent);
|
||||
}
|
||||
|
||||
// static
|
||||
PRBool
|
||||
nsContentUtils::IsDraggableImage(nsIContent* aContent)
|
||||
@ -4314,6 +4350,17 @@ nsContentUtils::GetContextForEventHandlers(nsINode* aNode,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
JSContext *
|
||||
nsContentUtils::GetCurrentJSContext()
|
||||
{
|
||||
JSContext *cx = nsnull;
|
||||
|
||||
sThreadJSContextStack->Peek(&cx);
|
||||
|
||||
return cx;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsAutoGCRoot::Shutdown()
|
||||
@ -4349,3 +4396,45 @@ nsContentUtils::IsNamedItem(nsIContent* aContent)
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsIInterfaceRequestor*
|
||||
nsContentUtils::GetSameOriginChecker()
|
||||
{
|
||||
if (!sSameOriginChecker) {
|
||||
sSameOriginChecker = new nsSameOriginChecker();
|
||||
NS_IF_ADDREF(sSameOriginChecker);
|
||||
}
|
||||
return sSameOriginChecker;
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsSameOriginChecker,
|
||||
nsIChannelEventSink,
|
||||
nsIInterfaceRequestor)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSameOriginChecker::OnChannelRedirect(nsIChannel *aOldChannel,
|
||||
nsIChannel *aNewChannel,
|
||||
PRUint32 aFlags)
|
||||
{
|
||||
NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
|
||||
|
||||
nsCOMPtr<nsIURI> oldURI;
|
||||
nsresult rv = aOldChannel->GetURI(getter_AddRefs(oldURI)); // The original URI
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
rv = aNewChannel->GetURI(getter_AddRefs(newURI)); // The new URI
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return nsContentUtils::GetSecurityManager()->
|
||||
CheckSameOriginURI(oldURI, newURI, PR_TRUE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSameOriginChecker::GetInterface(const nsIID & aIID, void **aResult)
|
||||
{
|
||||
return QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
|
@ -506,39 +506,14 @@ nsDOMParser::Initialize(nsISupports* aOwner, JSContext* cx, JSObject* obj,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMParser::Init()
|
||||
nsDOMParser::Init(nsIPrincipal *principal, nsIURI *documentURI, nsIURI *baseURI)
|
||||
{
|
||||
AttemptedInitMarker marker(&mAttemptedInit);
|
||||
|
||||
nsAXPCNativeCallContext *ncc = nsnull;
|
||||
|
||||
nsresult rv = nsContentUtils::XPConnect()->
|
||||
GetCurrentNativeCallContext(&ncc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(ncc, NS_ERROR_UNEXPECTED);
|
||||
|
||||
JSContext *cx = nsnull;
|
||||
rv = ncc->GetJSContext(&cx);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
JSContext *cx = nsContentUtils::GetCurrentJSContext();
|
||||
NS_ENSURE_TRUE(cx, NS_ERROR_UNEXPECTED);
|
||||
|
||||
PRUint32 argc;
|
||||
jsval *argv = nsnull;
|
||||
ncc->GetArgc(&argc);
|
||||
ncc->GetArgvPtr(&argv);
|
||||
|
||||
if (argc != 3) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> prin;
|
||||
nsCOMPtr<nsIURI> documentURI;
|
||||
nsCOMPtr<nsIURI> baseURI;
|
||||
rv = GetInitArgs(cx, argc, argv, getter_AddRefs(prin),
|
||||
getter_AddRefs(documentURI), getter_AddRefs(baseURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
|
||||
return Init(prin, documentURI, baseURI,
|
||||
return Init(principal, documentURI, baseURI,
|
||||
scriptContext ? scriptContext->GetGlobalObject() : nsnull);
|
||||
}
|
||||
|
@ -301,9 +301,13 @@ nsIdentifierMapEntry::~nsIdentifierMapEntry()
|
||||
void
|
||||
nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback* aCallback)
|
||||
{
|
||||
if (mNameContentList != NAME_NOT_VALID)
|
||||
if (mNameContentList != NAME_NOT_VALID) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
|
||||
"mIdentifierMap mNameContentList");
|
||||
aCallback->NoteXPCOMChild(mNameContentList);
|
||||
}
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, "mIdentifierMap mDocAllList");
|
||||
aCallback->NoteXPCOMChild(static_cast<nsIDOMNodeList*>(mDocAllList));
|
||||
}
|
||||
|
||||
@ -1227,6 +1231,7 @@ public:
|
||||
nsCycleCollectionTraversalCallback *mCb;
|
||||
virtual void Visit(nsIContent* aContent)
|
||||
{
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*mCb, "mLinkMap entry");
|
||||
mCb->NoteXPCOMChild(aContent);
|
||||
}
|
||||
};
|
||||
@ -1236,7 +1241,6 @@ LinkMapTraverser(nsUint32ToContentHashEntry* aEntry, void* userArg)
|
||||
{
|
||||
LinkMapTraversalVisitor visitor;
|
||||
visitor.mCb = static_cast<nsCycleCollectionTraversalCallback*>(userArg);
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*visitor.mCb, "mLinkMap entry");
|
||||
aEntry->VisitContent(&visitor);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
@ -611,7 +611,7 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
NS_ASSERTION(IsRootOfNativeAnonymousSubtree() ||
|
||||
!HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
|
||||
aBindingParent->IsInNativeAnonymousSubtree(),
|
||||
"Trying to re-bind content from native anonymous subtree to"
|
||||
"Trying to re-bind content from native anonymous subtree to "
|
||||
"non-native anonymous parent!");
|
||||
slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
|
||||
if (IsRootOfNativeAnonymousSubtree() ||
|
||||
|
@ -149,6 +149,8 @@
|
||||
|
||||
#include "mozAutoDocUpdate.h"
|
||||
|
||||
#include "nsICSSParser.h"
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
PRBool NS_SVG_HaveFeature(const nsAString &aFeature);
|
||||
#endif /* MOZ_SVG */
|
||||
@ -789,10 +791,12 @@ nsNSElementTearoff::GetFirstElementChild(nsIDOMElement** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsXULElement* xul = nsXULElement::FromContent(mContent);
|
||||
if (xul) {
|
||||
xul->EnsureContentsGenerated();
|
||||
}
|
||||
#endif
|
||||
|
||||
nsAttrAndChildArray& children = mContent->mAttrsAndChildren;
|
||||
PRUint32 i, count = children.ChildCount();
|
||||
@ -811,10 +815,12 @@ nsNSElementTearoff::GetLastElementChild(nsIDOMElement** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsXULElement* xul = nsXULElement::FromContent(mContent);
|
||||
if (xul) {
|
||||
xul->EnsureContentsGenerated();
|
||||
}
|
||||
#endif
|
||||
|
||||
nsAttrAndChildArray& children = mContent->mAttrsAndChildren;
|
||||
PRUint32 i = children.ChildCount();
|
||||
@ -838,10 +844,12 @@ nsNSElementTearoff::GetPreviousElementSibling(nsIDOMElement** aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsXULElement* xul = nsXULElement::FromContent(parent);
|
||||
if (xul) {
|
||||
xul->EnsureContentsGenerated();
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(parent->IsNodeOfType(nsINode::eELEMENT) ||
|
||||
parent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT),
|
||||
@ -875,10 +883,12 @@ nsNSElementTearoff::GetNextElementSibling(nsIDOMElement** aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
nsXULElement* xul = nsXULElement::FromContent(parent);
|
||||
if (xul) {
|
||||
xul->EnsureContentsGenerated();
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(parent->IsNodeOfType(nsINode::eELEMENT) ||
|
||||
parent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT),
|
||||
@ -1692,9 +1702,6 @@ nsStaticContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
PRUint32 nsMutationGuard::sMutationCount = 0;
|
||||
|
||||
nsGenericElement::nsDOMSlots::nsDOMSlots(PtrBits aFlags)
|
||||
: nsINode::nsSlots(aFlags),
|
||||
mBindingParent(nsnull)
|
||||
@ -5153,6 +5160,10 @@ TryMatchingElementsInSubtree(nsINode* aRoot,
|
||||
nsIContent * const * kidSlot = aRoot->GetChildArray();
|
||||
nsIContent * const * end = kidSlot + count;
|
||||
|
||||
#ifdef DEBUG
|
||||
nsMutationGuard debugMutationGuard;
|
||||
#endif
|
||||
|
||||
PRBool continueIteration = PR_TRUE;
|
||||
for (; kidSlot != end; ++kidSlot) {
|
||||
nsIContent* kid = *kidSlot;
|
||||
@ -5214,6 +5225,11 @@ TryMatchingElementsInSubtree(nsINode* aRoot,
|
||||
/* Make sure to clean this up */
|
||||
prevSibling->~RuleProcessorData();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(!debugMutationGuard.Mutated(0), "Unexpected mutations happened");
|
||||
#endif
|
||||
|
||||
return continueIteration;
|
||||
}
|
||||
|
||||
|
@ -317,78 +317,6 @@ private:
|
||||
nsCOMArray<nsIContent> mList;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class used to detect unexpected mutations. To use the class create an
|
||||
* nsMutationGuard on the stack before unexpected mutations could occur.
|
||||
* You can then at any time call Mutated to check if any unexpected mutations
|
||||
* have occured.
|
||||
*
|
||||
* When a guard is instantiated sMutationCount is set to 300. It is then
|
||||
* decremented by every mutation (capped at 0). This means that we can only
|
||||
* detect 300 mutations during the lifetime of a single guard, however that
|
||||
* should be more then we ever care about as we usually only care if more then
|
||||
* one mutation has occured.
|
||||
*
|
||||
* When the guard goes out of scope it will adjust sMutationCount so that over
|
||||
* the lifetime of the guard the guard itself has not affected sMutationCount,
|
||||
* while mutations that happened while the guard was alive still will. This
|
||||
* allows a guard to be instantiated even if there is another guard higher up
|
||||
* on the callstack watching for mutations.
|
||||
*
|
||||
* The only thing that has to be avoided is for an outer guard to be used
|
||||
* while an inner guard is alive. This can be avoided by only ever
|
||||
* instantiating a single guard per scope and only using the guard in the
|
||||
* current scope.
|
||||
*/
|
||||
class nsMutationGuard {
|
||||
public:
|
||||
nsMutationGuard()
|
||||
{
|
||||
mDelta = eMaxMutations - sMutationCount;
|
||||
sMutationCount = eMaxMutations;
|
||||
}
|
||||
~nsMutationGuard()
|
||||
{
|
||||
sMutationCount =
|
||||
mDelta > sMutationCount ? 0 : sMutationCount - mDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any unexpected mutations have occured. You can pass in
|
||||
* an 8-bit ignore count to ignore a number of expected mutations.
|
||||
*/
|
||||
PRBool Mutated(PRUint8 aIgnoreCount)
|
||||
{
|
||||
return sMutationCount < static_cast<PRUint32>(eMaxMutations - aIgnoreCount);
|
||||
}
|
||||
|
||||
// This function should be called whenever a mutation that we want to keep
|
||||
// track of happen. For now this is only done when children are added or
|
||||
// removed, but we might do it for attribute changes too in the future.
|
||||
static void DidMutate()
|
||||
{
|
||||
if (sMutationCount) {
|
||||
--sMutationCount;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// mDelta is the amount sMutationCount was adjusted when the guard was
|
||||
// initialized. It is needed so that we can undo that adjustment once
|
||||
// the guard dies.
|
||||
PRUint32 mDelta;
|
||||
|
||||
// The value 300 is not important, as long as it is bigger then anything
|
||||
// ever passed to Mutated().
|
||||
enum { eMaxMutations = 300 };
|
||||
|
||||
|
||||
// sMutationCount is a global mutation counter which is decreased by one at
|
||||
// every mutation. It is capped at 0 to avoid wrapping.
|
||||
// It's value is always between 0 and 300, inclusive.
|
||||
static PRUint32 sMutationCount;
|
||||
};
|
||||
|
||||
// Forward declare to allow being a friend
|
||||
class nsNSElementTearoff;
|
||||
|
||||
|
@ -53,6 +53,7 @@
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULElement.h"
|
||||
#endif
|
||||
#include "nsBindingManager.h"
|
||||
|
||||
// This macro expects the ownerDocument of content_ to be in scope as
|
||||
// |nsIDocument* doc|
|
||||
|
@ -163,11 +163,11 @@ nsAsyncInstantiateEvent::Run()
|
||||
class nsPluginErrorEvent : public nsRunnable {
|
||||
public:
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
PRBool mBlocklisted;
|
||||
PluginSupportState mState;
|
||||
|
||||
nsPluginErrorEvent(nsIContent* aContent, PRBool aBlocklisted)
|
||||
nsPluginErrorEvent(nsIContent* aContent, PluginSupportState aState)
|
||||
: mContent(aContent),
|
||||
mBlocklisted(aBlocklisted)
|
||||
mState(aState)
|
||||
{}
|
||||
|
||||
~nsPluginErrorEvent() {}
|
||||
@ -180,14 +180,22 @@ nsPluginErrorEvent::Run()
|
||||
{
|
||||
LOG(("OBJLC []: Firing plugin not found event for content %p\n",
|
||||
mContent.get()));
|
||||
if (mBlocklisted)
|
||||
nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
|
||||
NS_LITERAL_STRING("PluginBlocklisted"),
|
||||
PR_TRUE, PR_TRUE);
|
||||
else
|
||||
nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
|
||||
NS_LITERAL_STRING("PluginNotFound"),
|
||||
PR_TRUE, PR_TRUE);
|
||||
nsString type;
|
||||
switch (mState) {
|
||||
case ePluginUnsupported:
|
||||
type = NS_LITERAL_STRING("PluginNotFound");
|
||||
break;
|
||||
case ePluginDisabled:
|
||||
type = NS_LITERAL_STRING("PluginDisabled");
|
||||
break;
|
||||
case ePluginBlocklisted:
|
||||
type = NS_LITERAL_STRING("PluginBlocklisted");
|
||||
break;
|
||||
default:
|
||||
return NS_OK;
|
||||
}
|
||||
nsContentUtils::DispatchTrustedEvent(mContent->GetDocument(), mContent,
|
||||
type, PR_TRUE, PR_TRUE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -232,28 +240,29 @@ class AutoNotifier {
|
||||
class AutoFallback {
|
||||
public:
|
||||
AutoFallback(nsObjectLoadingContent* aContent, const nsresult* rv)
|
||||
: mContent(aContent), mResult(rv), mTypeUnsupported(PR_FALSE) {}
|
||||
: mContent(aContent), mResult(rv), mPluginState(ePluginOtherState) {}
|
||||
~AutoFallback() {
|
||||
if (NS_FAILED(*mResult)) {
|
||||
LOG(("OBJLC [%p]: rv=%08x, falling back\n", mContent, *mResult));
|
||||
mContent->Fallback(PR_FALSE);
|
||||
if (mTypeUnsupported) {
|
||||
mContent->mTypeUnsupported = PR_TRUE;
|
||||
if (mPluginState != ePluginOtherState) {
|
||||
mContent->mPluginState = mPluginState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function can be called to indicate that, after falling back,
|
||||
* mTypeUnsupported should be set to true.
|
||||
* This should be set to something other than ePluginOtherState to indicate
|
||||
* a specific failure that should be passed on.
|
||||
*/
|
||||
void TypeUnsupported() {
|
||||
mTypeUnsupported = PR_TRUE;
|
||||
}
|
||||
void SetPluginState(PluginSupportState aState) {
|
||||
NS_ASSERTION(aState != ePluginOtherState, "Should not be setting ePluginOtherState");
|
||||
mPluginState = aState;
|
||||
}
|
||||
private:
|
||||
nsObjectLoadingContent* mContent;
|
||||
const nsresult* mResult;
|
||||
PRBool mTypeUnsupported;
|
||||
PluginSupportState mPluginState;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -340,7 +349,7 @@ nsObjectLoadingContent::nsObjectLoadingContent()
|
||||
, mInstantiating(PR_FALSE)
|
||||
, mUserDisabled(PR_FALSE)
|
||||
, mSuppressed(PR_FALSE)
|
||||
, mTypeUnsupported(PR_FALSE)
|
||||
, mPluginState(ePluginOtherState)
|
||||
{
|
||||
}
|
||||
|
||||
@ -573,20 +582,16 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
|
||||
case eType_Null:
|
||||
LOG(("OBJLC [%p]: Unsupported type, falling back\n", this));
|
||||
// Need to fallback here (instead of using the case below), so that we can
|
||||
// set mTypeUnsupported without it being overwritten. This is also why we
|
||||
// set mPluginState without it being overwritten. This is also why we
|
||||
// return early.
|
||||
Fallback(PR_FALSE);
|
||||
|
||||
PluginSupportState pluginState = GetPluginSupportState(thisContent,
|
||||
mContentType);
|
||||
// Do nothing, but fire the plugin not found event if needed
|
||||
if (pluginState == ePluginUnsupported ||
|
||||
pluginState == ePluginBlocklisted) {
|
||||
FirePluginError(thisContent, pluginState == ePluginBlocklisted);
|
||||
}
|
||||
if (pluginState != ePluginDisabled &&
|
||||
pluginState != ePluginBlocklisted) {
|
||||
mTypeUnsupported = PR_TRUE;
|
||||
if (pluginState != ePluginOtherState) {
|
||||
FirePluginError(thisContent, pluginState);
|
||||
mPluginState = pluginState;
|
||||
}
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
@ -892,8 +897,16 @@ nsObjectLoadingContent::ObjectState() const
|
||||
|
||||
// Otherwise, broken
|
||||
PRInt32 state = NS_EVENT_STATE_BROKEN;
|
||||
if (mTypeUnsupported) {
|
||||
state |= NS_EVENT_STATE_TYPE_UNSUPPORTED;
|
||||
switch (mPluginState) {
|
||||
case ePluginDisabled:
|
||||
state |= NS_EVENT_STATE_HANDLER_DISABLED;
|
||||
break;
|
||||
case ePluginBlocklisted:
|
||||
state |= NS_EVENT_STATE_HANDLER_BLOCKED;
|
||||
break;
|
||||
case ePluginUnsupported:
|
||||
state |= NS_EVENT_STATE_TYPE_UNSUPPORTED;
|
||||
break;
|
||||
}
|
||||
return state;
|
||||
};
|
||||
@ -961,16 +974,11 @@ nsObjectLoadingContent::UpdateFallbackState(nsIContent* aContent,
|
||||
AutoFallback& fallback,
|
||||
const nsCString& aTypeHint)
|
||||
{
|
||||
PluginSupportState pluginState = GetPluginDisabledState(aTypeHint);
|
||||
if (pluginState == ePluginUnsupported) {
|
||||
// For unknown plugins notify the UI and allow the unknown plugin binding
|
||||
// to attach.
|
||||
FirePluginError(aContent, PR_FALSE);
|
||||
fallback.TypeUnsupported();
|
||||
}
|
||||
else if (pluginState == ePluginBlocklisted) {
|
||||
// For blocklisted plugins just send a notification to the UI.
|
||||
FirePluginError(aContent, PR_TRUE);
|
||||
// Notify the UI and update the fallback state
|
||||
PluginSupportState state = GetPluginSupportState(aContent, aTypeHint);
|
||||
if (state != ePluginOtherState) {
|
||||
fallback.SetPluginState(state);
|
||||
FirePluginError(aContent, state);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1448,7 +1456,8 @@ nsObjectLoadingContent::UnloadContent()
|
||||
mFrameLoader = nsnull;
|
||||
}
|
||||
mType = eType_Null;
|
||||
mUserDisabled = mSuppressed = mTypeUnsupported = PR_FALSE;
|
||||
mUserDisabled = mSuppressed = PR_FALSE;
|
||||
mPluginState = ePluginOtherState;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1498,12 +1507,12 @@ nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
|
||||
|
||||
/* static */ void
|
||||
nsObjectLoadingContent::FirePluginError(nsIContent* thisContent,
|
||||
PRBool blocklisted)
|
||||
PluginSupportState state)
|
||||
{
|
||||
LOG(("OBJLC []: Dispatching nsPluginErrorEvent for content %p\n",
|
||||
thisContent));
|
||||
|
||||
nsCOMPtr<nsIRunnable> ev = new nsPluginErrorEvent(thisContent, blocklisted);
|
||||
nsCOMPtr<nsIRunnable> ev = new nsPluginErrorEvent(thisContent, state);
|
||||
nsresult rv = NS_DispatchToCurrentThread(ev);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("failed to dispatch nsPluginErrorEvent");
|
||||
@ -1766,7 +1775,7 @@ nsObjectLoadingContent::ShouldShowDefaultPlugin(nsIContent* aContent,
|
||||
return GetPluginSupportState(aContent, aContentType) == ePluginUnsupported;
|
||||
}
|
||||
|
||||
/* static */ nsObjectLoadingContent::PluginSupportState
|
||||
/* static */ PluginSupportState
|
||||
nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent,
|
||||
const nsCString& aContentType)
|
||||
{
|
||||
@ -1803,7 +1812,7 @@ nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent,
|
||||
GetPluginDisabledState(aContentType);
|
||||
}
|
||||
|
||||
/* static */ nsObjectLoadingContent::PluginSupportState
|
||||
/* static */ PluginSupportState
|
||||
nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType)
|
||||
{
|
||||
nsCOMPtr<nsIPluginHost> host(do_GetService("@mozilla.org/plugin/host;1"));
|
||||
|
@ -59,6 +59,15 @@ class AutoNotifier;
|
||||
class AutoFallback;
|
||||
class AutoSetInstantiatingToFalse;
|
||||
|
||||
enum PluginSupportState {
|
||||
ePluginUnsupported, // The plugin is not supported (not installed, say)
|
||||
ePluginDisabled, // The plugin has been explicitly disabled by the
|
||||
// user.
|
||||
ePluginBlocklisted, // The plugin is blocklisted and disabled
|
||||
ePluginOtherState // Something else (e.g. not a plugin at all as far
|
||||
// as we can tell).
|
||||
};
|
||||
|
||||
/**
|
||||
* INVARIANTS OF THIS CLASS
|
||||
* - mChannel is non-null between asyncOpen and onStopRequest (NOTE: Only needs
|
||||
@ -252,7 +261,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
* Fires the "Plugin not found" event. This function doesn't do any checks
|
||||
* whether it should be fired, the caller should do that.
|
||||
*/
|
||||
static void FirePluginError(nsIContent* thisContent, PRBool blocklisted);
|
||||
static void FirePluginError(nsIContent* thisContent, PluginSupportState state);
|
||||
|
||||
ObjectType GetTypeOfContent(const nsCString& aMIMEType);
|
||||
|
||||
@ -332,15 +341,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
static PRBool ShouldShowDefaultPlugin(nsIContent* aContent,
|
||||
const nsCString& aContentType);
|
||||
|
||||
enum PluginSupportState {
|
||||
ePluginUnsupported, // The plugin is not supported (not installed, say)
|
||||
ePluginDisabled, // The plugin has been explicitly disabled by the
|
||||
// user.
|
||||
ePluginBlocklisted, // The plugin is blocklisted and disabled
|
||||
ePluginOtherState // Something else (e.g. not a plugin at all as far
|
||||
// as we can tell).
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the plugin support state for the given content node and MIME type.
|
||||
* This is used for purposes of determining whether to fire PluginNotFound
|
||||
@ -418,8 +418,8 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
// Blocking status from content policy
|
||||
PRBool mUserDisabled : 1;
|
||||
PRBool mSuppressed : 1;
|
||||
// Whether we fell back because of an unsupported type
|
||||
PRBool mTypeUnsupported:1;
|
||||
// A specific state that caused us to fallback
|
||||
PluginSupportState mPluginState;
|
||||
|
||||
friend class nsAsyncInstantiateEvent;
|
||||
};
|
||||
|
@ -1157,6 +1157,10 @@ static nsresult SplitDataNode(nsIDOMCharacterData* aStartNode,
|
||||
|
||||
nsresult nsRange::CutContents(nsIDOMDocumentFragment** aFragment)
|
||||
{
|
||||
if (aFragment) {
|
||||
*aFragment = nsnull;
|
||||
}
|
||||
|
||||
if (IsDetached())
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
|
||||
@ -1196,7 +1200,11 @@ nsresult nsRange::CutContents(nsIDOMDocumentFragment** aFragment)
|
||||
if (iter.IsDone())
|
||||
{
|
||||
// There's nothing for us to delete.
|
||||
return CollapseRangeAfterDelete(this);
|
||||
rv = CollapseRangeAfterDelete(this);
|
||||
if (NS_SUCCEEDED(rv) && aFragment) {
|
||||
NS_ADDREF(*aFragment = retval);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We delete backwards to avoid iterator problems!
|
||||
@ -1355,11 +1363,11 @@ nsresult nsRange::CutContents(nsIDOMDocumentFragment** aFragment)
|
||||
// XXX_kin: desired behavior. For now we don't merge anything!
|
||||
// XXX ajvincent Filed as https://bugzilla.mozilla.org/show_bug.cgi?id=401276
|
||||
|
||||
if (aFragment) {
|
||||
rv = CollapseRangeAfterDelete(this);
|
||||
if (NS_SUCCEEDED(rv) && aFragment) {
|
||||
NS_ADDREF(*aFragment = retval);
|
||||
}
|
||||
|
||||
return CollapseRangeAfterDelete(this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsRange::DeleteContents()
|
||||
|
@ -202,6 +202,10 @@ _TEST_FILES = test_bug5141.html \
|
||||
test_bug28293.html \
|
||||
file_bug28293.sjs \
|
||||
test_title.html \
|
||||
test_bug453521.html \
|
||||
test_bug391728.html \
|
||||
file_bug391728.html \
|
||||
file_bug391728_2.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user