Merge mozilla-central into e10s.

This commit is contained in:
Benjamin Smedberg 2009-10-28 11:32:00 -04:00
commit 34440c4bbc
294 changed files with 5256 additions and 3530 deletions

View file

@ -54,9 +54,9 @@
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
#include "nsIURI.h" #include "nsIURI.h"
//------------- ////////////////////////////////////////////////////////////////////////////////
// nsLeafAccessible // nsLeafAccessible
//------------- ////////////////////////////////////////////////////////////////////////////////
nsLeafAccessible::nsLeafAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell): nsLeafAccessible::nsLeafAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
nsAccessibleWrap(aNode, aShell) nsAccessibleWrap(aNode, aShell)
@ -65,34 +65,6 @@ nsAccessibleWrap(aNode, aShell)
NS_IMPL_ISUPPORTS_INHERITED0(nsLeafAccessible, nsAccessible) NS_IMPL_ISUPPORTS_INHERITED0(nsLeafAccessible, nsAccessible)
/* nsIAccessible getFirstChild (); */
NS_IMETHODIMP nsLeafAccessible::GetFirstChild(nsIAccessible **_retval)
{
*_retval = nsnull;
return NS_OK;
}
/* nsIAccessible getLastChild (); */
NS_IMETHODIMP nsLeafAccessible::GetLastChild(nsIAccessible **_retval)
{
*_retval = nsnull;
return NS_OK;
}
/* long getAccChildCount (); */
NS_IMETHODIMP nsLeafAccessible::GetChildCount(PRInt32 *_retval)
{
*_retval = 0;
return NS_OK;
}
// nsAccessible::GetAllowsAnonChildAccessibles()
PRBool
nsLeafAccessible::GetAllowsAnonChildAccessibles()
{
return PR_FALSE;
}
// nsAccessible::GetChildAtPoint() // nsAccessible::GetChildAtPoint()
nsresult nsresult
nsLeafAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, nsLeafAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
@ -104,19 +76,29 @@ nsLeafAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
return NS_OK; return NS_OK;
} }
// nsAccessible::CacheChildren()
void
nsLeafAccessible::CacheChildren()
{
// No children for leaf accessible.
mAccChildCount = IsDefunct() ? eChildCountUninitialized : 0;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// nsLinkableAccessible // nsLinkableAccessible
////////////////////////////////////////////////////////////////////////////////
nsLinkableAccessible:: nsLinkableAccessible::
nsLinkableAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) : nsLinkableAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
nsHyperTextAccessibleWrap(aNode, aShell), nsAccessibleWrap(aNode, aShell),
mActionContent(nsnull), mActionContent(nsnull),
mIsLink(PR_FALSE), mIsLink(PR_FALSE),
mIsOnclick(PR_FALSE) mIsOnclick(PR_FALSE)
{ {
} }
NS_IMPL_ISUPPORTS_INHERITED0(nsLinkableAccessible, nsHyperTextAccessibleWrap) NS_IMPL_ISUPPORTS_INHERITED0(nsLinkableAccessible, nsAccessibleWrap)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// nsLinkableAccessible. nsIAccessible // nsLinkableAccessible. nsIAccessible
@ -128,14 +110,13 @@ nsLinkableAccessible::TakeFocus()
if (actionAcc) if (actionAcc)
return actionAcc->TakeFocus(); return actionAcc->TakeFocus();
return nsHyperTextAccessibleWrap::TakeFocus(); return nsAccessibleWrap::TakeFocus();
} }
nsresult nsresult
nsLinkableAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState) nsLinkableAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
{ {
nsresult rv = nsHyperTextAccessibleWrap::GetStateInternal(aState, nsresult rv = nsAccessibleWrap::GetStateInternal(aState, aExtraState);
aExtraState);
NS_ENSURE_A11Y_SUCCESS(rv, rv); NS_ENSURE_A11Y_SUCCESS(rv, rv);
if (mIsLink) { if (mIsLink) {
@ -153,7 +134,7 @@ nsLinkableAccessible::GetValue(nsAString& aValue)
{ {
aValue.Truncate(); aValue.Truncate();
nsHyperTextAccessible::GetValue(aValue); nsAccessible::GetValue(aValue);
if (!aValue.IsEmpty()) if (!aValue.IsEmpty())
return NS_OK; return NS_OK;
@ -206,7 +187,7 @@ nsLinkableAccessible::DoAction(PRUint8 aIndex)
if (actionAcc) if (actionAcc)
return actionAcc->DoAction(aIndex); return actionAcc->DoAction(aIndex);
return nsHyperTextAccessibleWrap::DoAction(aIndex); return nsAccessibleWrap::DoAction(aIndex);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -250,14 +231,14 @@ nsresult
nsLinkableAccessible::Init() nsLinkableAccessible::Init()
{ {
CacheActionContent(); CacheActionContent();
return nsHyperTextAccessibleWrap::Init(); return nsAccessibleWrap::Init();
} }
nsresult nsresult
nsLinkableAccessible::Shutdown() nsLinkableAccessible::Shutdown()
{ {
mActionContent = nsnull; mActionContent = nsnull;
return nsHyperTextAccessibleWrap::Shutdown(); return nsAccessibleWrap::Shutdown();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -62,24 +62,24 @@ public:
// nsISupports // nsISupports
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
// nsIAccessible
NS_IMETHOD GetFirstChild(nsIAccessible **_retval);
NS_IMETHOD GetLastChild(nsIAccessible **_retval);
NS_IMETHOD GetChildCount(PRInt32 *_retval);
// nsAccessible // nsAccessible
virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY, virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild, PRBool aDeepestChild,
nsIAccessible **aChild); nsIAccessible **aChild);
virtual PRBool GetAllowsAnonChildAccessibles();
protected:
// nsAccessible
virtual void CacheChildren();
}; };
/** /**
* A type of accessible for DOM nodes containing an href="" attribute. * Used for text or image accessible nodes contained by link accessibles or
* It knows how to report the state of the link ( traveled or not ) * accessibles for nodes with registered click event handler. It knows how to
* and can activate ( click ) the link programmatically. * report the state of the host link (traveled or not) and can activate (click)
*/ * the host accessible programmatically.
class nsLinkableAccessible : public nsHyperTextAccessibleWrap */
class nsLinkableAccessible : public nsAccessibleWrap
{ {
public: public:
enum { eAction_Jump = 0 }; enum { eAction_Jump = 0 };
@ -96,7 +96,7 @@ public:
NS_IMETHOD TakeFocus(); NS_IMETHOD TakeFocus();
NS_IMETHOD GetKeyboardShortcut(nsAString& _retval); NS_IMETHOD GetKeyboardShortcut(nsAString& _retval);
// nsIHyperLinkAccessible // nsIAccessibleHyperLink
NS_IMETHOD GetURI(PRInt32 i, nsIURI **aURI); NS_IMETHOD GetURI(PRInt32 i, nsIURI **aURI);
// nsAccessNode // nsAccessNode

View file

@ -38,27 +38,18 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
// NOTE: alphabetically ordered
#include "nsTextAccessible.h" #include "nsTextAccessible.h"
// ------------ ////////////////////////////////////////////////////////////////////////////////
// Text Accessibles // nsTextAccessible
// ------------ ////////////////////////////////////////////////////////////////////////////////
nsTextAccessible::nsTextAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell): nsTextAccessible::
nsLinkableAccessible(aDOMNode, aShell) nsTextAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell) :
{ nsLinkableAccessible(aDOMNode, aShell)
{
} }
// Make sure we don't support text or other irrelevant interfaces.
// We have nsLinkableAccessible in our inheritance chain as a convenience in order to
// get link actions and states on the text accessibles. Windows screen readers expect that.
NS_IMPL_ISUPPORTS_INHERITED2(nsTextAccessible, nsAccessNode,
nsAccessible, nsIAccessible)
/**
* We are text
*/
nsresult nsresult
nsTextAccessible::GetRoleInternal(PRUint32 *aRole) nsTextAccessible::GetRoleInternal(PRUint32 *aRole)
{ {
@ -66,33 +57,6 @@ nsTextAccessible::GetRoleInternal(PRUint32 *aRole)
return NS_OK; return NS_OK;
} }
/**
* No Children
*/
NS_IMETHODIMP nsTextAccessible::GetFirstChild(nsIAccessible **_retval)
{
*_retval = nsnull;
return NS_OK;
}
/**
* No Children
*/
NS_IMETHODIMP nsTextAccessible::GetLastChild(nsIAccessible **_retval)
{
*_retval = nsnull;
return NS_OK;
}
/**
* No Children
*/
NS_IMETHODIMP nsTextAccessible::GetChildCount(PRInt32 *_retval)
{
*_retval = 0;
return NS_OK;
}
nsresult nsresult
nsTextAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32 aLength) nsTextAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32 aLength)
{ {
@ -102,3 +66,9 @@ nsTextAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, PRUint32
return frame->GetRenderedText(&aText, nsnull, nsnull, aStartOffset, aLength); return frame->GetRenderedText(&aText, nsnull, nsnull, aStartOffset, aLength);
} }
void
nsTextAccessible::CacheChildren()
{
// No children for text accessible.
mAccChildCount = IsDefunct() ? eChildCountUninitialized : 0;
}

View file

@ -41,27 +41,23 @@
#include "nsBaseWidgetAccessible.h" #include "nsBaseWidgetAccessible.h"
/** /**
* Text nodes have no children, but since double inheritance * Generic class used for text nodes.
* no-worky we have to re-impl the LeafAccessiblity blocks */
* this way.
*/
class nsTextAccessible : public nsLinkableAccessible class nsTextAccessible : public nsLinkableAccessible
{ {
public: public:
NS_DECL_ISUPPORTS_INHERITED
nsTextAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell); nsTextAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
// nsIAccessible
NS_IMETHOD GetFirstChild(nsIAccessible **_retval);
NS_IMETHOD GetLastChild(nsIAccessible **_retval);
NS_IMETHOD GetChildCount(PRInt32 *_retval);
// nsAccessible // nsAccessible
virtual nsresult GetRoleInternal(PRUint32 *aRole); virtual nsresult GetRoleInternal(PRUint32 *aRole);
virtual nsresult AppendTextTo(nsAString& aText, PRUint32 aStartOffset, virtual nsresult AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
PRUint32 aLength); PRUint32 aLength);
protected:
// nsAccessible
virtual void CacheChildren();
}; };

View file

@ -47,12 +47,13 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// nsHTMLAreaAccessible // nsHTMLAreaAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLAreaAccessible:: nsHTMLAreaAccessible::
nsHTMLAreaAccessible(nsIDOMNode *aDomNode, nsIAccessible *aParent, nsHTMLAreaAccessible(nsIDOMNode *aDomNode, nsIAccessible *aParent,
nsIWeakReference* aShell): nsIWeakReference* aShell):
nsHTMLLinkAccessible(aDomNode, aShell) nsHTMLLinkAccessible(aDomNode, aShell)
{ {
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -89,33 +90,6 @@ nsHTMLAreaAccessible::GetDescription(nsAString& aDescription)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsHTMLAreaAccessible::GetFirstChild(nsIAccessible **aChild)
{
NS_ENSURE_ARG_POINTER(aChild);
*aChild = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLAreaAccessible::GetLastChild(nsIAccessible **aChild)
{
NS_ENSURE_ARG_POINTER(aChild);
*aChild = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLAreaAccessible::GetChildCount(PRInt32 *aCount)
{
NS_ENSURE_ARG_POINTER(aCount);
*aCount = 0;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLAreaAccessible::GetBounds(PRInt32 *x, PRInt32 *y, nsHTMLAreaAccessible::GetBounds(PRInt32 *x, PRInt32 *y,
PRInt32 *width, PRInt32 *height) PRInt32 *width, PRInt32 *height)
@ -161,7 +135,9 @@ nsHTMLAreaAccessible::GetBounds(PRInt32 *x, PRInt32 *y,
return NS_OK; return NS_OK;
} }
// nsAccessible::GetChildAtPoint() ////////////////////////////////////////////////////////////////////////////////
// nsAccessible public implementation
nsresult nsresult
nsHTMLAreaAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, nsHTMLAreaAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild, PRBool aDeepestChild,
@ -171,3 +147,13 @@ nsHTMLAreaAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
NS_ADDREF(*aChild = this); NS_ADDREF(*aChild = this);
return NS_OK; return NS_OK;
} }
////////////////////////////////////////////////////////////////////////////////
// nsAccessible protected implementation
void
nsHTMLAreaAccessible::CacheChildren()
{
// No children for aria accessible.
mAccChildCount = IsDefunct() ? eChildCountUninitialized : 0;
}

View file

@ -41,9 +41,9 @@
#include "nsHTMLLinkAccessible.h" #include "nsHTMLLinkAccessible.h"
/* Accessible for image map areas - must be child of image /**
* Accessible for image map areas - must be child of image.
*/ */
class nsHTMLAreaAccessible : public nsHTMLLinkAccessible class nsHTMLAreaAccessible : public nsHTMLLinkAccessible
{ {
@ -54,10 +54,6 @@ public:
// nsIAccessible // nsIAccessible
NS_IMETHOD GetDescription(nsAString& aDescription); NS_IMETHOD GetDescription(nsAString& aDescription);
NS_IMETHOD GetFirstChild(nsIAccessible **_retval);
NS_IMETHOD GetLastChild(nsIAccessible **_retval);
NS_IMETHOD GetChildCount(PRInt32 *_retval);
NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height); NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height);
// nsAccessible // nsAccessible
@ -65,6 +61,11 @@ public:
virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY, virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild, PRBool aDeepestChild,
nsIAccessible **aChild); nsIAccessible **aChild);
protected:
// nsAccessible
virtual void CacheChildren();
}; };
#endif #endif

View file

@ -57,6 +57,8 @@ nsTextAccessibleWrap(aDomNode, aShell)
{ {
} }
NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLTextAccessible, nsTextAccessible)
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLTextAccessible::GetName(nsAString& aName) nsHTMLTextAccessible::GetName(nsAString& aName)
{ {

View file

@ -50,7 +50,10 @@ class nsHTMLTextAccessible : public nsTextAccessibleWrap
{ {
public: public:
nsHTMLTextAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell); nsHTMLTextAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell);
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsIAccessible // nsIAccessible
NS_IMETHOD GetName(nsAString& aName); NS_IMETHOD GetName(nsAString& aName);

View file

@ -44,6 +44,6 @@ NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLImageAccessibleWrap,
nsHTMLImageAccessible) nsHTMLImageAccessible)
IMPL_IUNKNOWN_INHERITED1(nsHTMLImageAccessibleWrap, IMPL_IUNKNOWN_INHERITED1(nsHTMLImageAccessibleWrap,
nsHyperTextAccessibleWrap, nsAccessibleWrap,
CAccessibleImage); CAccessibleImage);

View file

@ -41,11 +41,8 @@
#define _nsXULTextAccessible_H_ #define _nsXULTextAccessible_H_
#include "nsBaseWidgetAccessible.h" #include "nsBaseWidgetAccessible.h"
#include "nsTextAccessibleWrap.h"
#include "nsHyperTextAccessibleWrap.h" #include "nsHyperTextAccessibleWrap.h"
class nsIWeakReference;
class nsXULTextAccessible : public nsHyperTextAccessibleWrap class nsXULTextAccessible : public nsHyperTextAccessibleWrap
{ {

View file

@ -69,7 +69,7 @@ GRE_BUILDID = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBX
DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID) DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID)
SOURCE_STAMP := $(shell cd $(topsrcdir) ; hg identify 2>/dev/null | cut -f1 -d' ') SOURCE_STAMP := $(shell cd $(topsrcdir) ; hg identify . 2>/dev/null | cut -f1 -d' ')
ifdef SOURCE_STAMP ifdef SOURCE_STAMP
DEFINES += -DMOZ_SOURCE_STAMP="$(SOURCE_STAMP)" DEFINES += -DMOZ_SOURCE_STAMP="$(SOURCE_STAMP)"
endif endif

View file

@ -134,6 +134,13 @@ td {
const Cc = Components.classes; const Cc = Components.classes;
const Ci = Components.interfaces; const Ci = Components.interfaces;
let gPrefService = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService)
.QueryInterface(Ci.nsIPrefBranch2);
const ELLIPSIS = gPrefService.getComplexValue("intl.ellipsis",
Ci.nsIPrefLocalizedString).data;
// We use a preferences whitelist to make sure we only show preferences that // We use a preferences whitelist to make sure we only show preferences that
// are useful for support and won't compromise the user's privacy. Note that // are useful for support and won't compromise the user's privacy. Note that
// entries are *prefixes*: for example, "accessibility." applies to all prefs // entries are *prefixes*: for example, "accessibility." applies to all prefs
@ -238,7 +245,7 @@ function formatPrefValue(prefValue) {
let maxPrefValueLen = 120; let maxPrefValueLen = 120;
let text = "" + prefValue; let text = "" + prefValue;
if (text.length > maxPrefValueLen) if (text.length > maxPrefValueLen)
text = text.substring(0, maxPrefValueLen) + "…"; text = text.substring(0, maxPrefValueLen) + ELLIPSIS;
return text; return text;
} }
@ -247,21 +254,18 @@ function getModifiedPrefs() {
// modified, rather that Application.prefs.all since the latter is // modified, rather that Application.prefs.all since the latter is
// much, much slower. Application.prefs.all also gets slower each // much, much slower. Application.prefs.all also gets slower each
// time it's called. See bug 517312. // time it's called. See bug 517312.
let prefService = Cc["@mozilla.org/preferences-service;1"] let prefNames = getWhitelistedPrefNames();
.getService(Ci.nsIPrefService);
let prefRootBranch = prefService.getBranch("");
let prefNames = getWhitelistedPrefNames(prefRootBranch);
let prefs = [Application.prefs.get(prefName) let prefs = [Application.prefs.get(prefName)
for each (prefName in prefNames) for each (prefName in prefNames)
if (prefRootBranch.prefHasUserValue(prefName) if (gPrefService.prefHasUserValue(prefName)
&& !isBlacklisted(prefName))]; && !isBlacklisted(prefName))];
return prefs; return prefs;
} }
function getWhitelistedPrefNames(prefRootBranch) { function getWhitelistedPrefNames() {
let results = []; let results = [];
PREFS_WHITELIST.forEach(function (prefStem) { PREFS_WHITELIST.forEach(function (prefStem) {
let prefNames = prefRootBranch.getChildList(prefStem, {}); let prefNames = gPrefService.getChildList(prefStem);
results = results.concat(prefNames); results = results.concat(prefNames);
}); });
return results; return results;
@ -333,7 +337,9 @@ function createTextForElement(elem) {
text = text.replace(/\n\n\n+/g, "\n\n"); text = text.replace(/\n\n\n+/g, "\n\n");
// Actual CR/LF pairs are needed for some Windows text editors. // Actual CR/LF pairs are needed for some Windows text editors.
#ifdef XP_WIN
text = text.replace(/\n/g, "\r\n"); text = text.replace(/\n/g, "\r\n");
#endif
return text; return text;
} }

View file

@ -32,7 +32,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > hbox[type="places"] {
-moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar); -moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar);
} }
#wrapper-urlbar-container #urlbar { #wrapper-urlbar-container > #urlbar-container > #urlbar {
-moz-user-input: disabled; -moz-user-input: disabled;
cursor: -moz-grab; cursor: -moz-grab;
} }
@ -55,26 +55,30 @@ toolbarpaletteitem[place="palette"] > toolbaritem > hbox[type="places"] {
display: none; display: none;
} }
#feed-menu:-moz-locale-dir(rtl) > menuitem { #feed-menu > .feed-menuitem:-moz-locale-dir(rtl) {
direction: rtl; direction: rtl;
} }
#urlbar[pageproxystate="invalid"] > #urlbar-icons > :not(#go-button) , #urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon:not(#go-button),
#urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button , #urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button ,
#urlbar[isempty="true"] > #urlbar-icons > #go-button { #urlbar[isempty="true"] > #urlbar-icons > #go-button {
visibility: collapse; visibility: collapse;
} }
#identity-box > hbox { #identity-box-inner {
max-width: 22em; max-width: 22em;
min-width: 1px; min-width: 1px;
} }
#wrapper-search-container > #search-container > #searchbar > .searchbar-textbox > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input {
visibility: hidden;
}
/* ::::: Unified Back-/Forward Button ::::: */ /* ::::: Unified Back-/Forward Button ::::: */
#back-button > dropmarker, #back-button > .toolbarbutton-menu-dropmarker,
#forward-button > dropmarker, #forward-button > .toolbarbutton-menu-dropmarker,
#back-forward-dropmarker > image , #back-forward-dropmarker > .toolbarbutton-icon,
#back-forward-dropmarker > label { #back-forward-dropmarker > .toolbarbutton-text {
display: none; display: none;
} }
.unified-nav-current { .unified-nav-current {

View file

@ -1540,8 +1540,7 @@ function initializeSanitizer()
*/ */
if (!gPrefService.getBoolPref("privacy.sanitize.migrateFx3Prefs")) { if (!gPrefService.getBoolPref("privacy.sanitize.migrateFx3Prefs")) {
let itemBranch = gPrefService.getBranch("privacy.item."); let itemBranch = gPrefService.getBranch("privacy.item.");
let itemCount = { value: 0 }; let itemArray = itemBranch.getChildList("");
let itemArray = itemBranch.getChildList("", itemCount);
// See if any privacy.item prefs are set // See if any privacy.item prefs are set
let doMigrate = itemArray.some(function (name) itemBranch.prefHasUserValue(name)); let doMigrate = itemArray.some(function (name) itemBranch.prefHasUserValue(name));
@ -6118,6 +6117,7 @@ var FeedHandler = {
var menuItem = document.createElement("menuitem"); var menuItem = document.createElement("menuitem");
var baseTitle = feedInfo.title || feedInfo.href; var baseTitle = feedInfo.title || feedInfo.href;
var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]); var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]);
menuItem.setAttribute("class", "feed-menuitem");
menuItem.setAttribute("label", labelStr); menuItem.setAttribute("label", labelStr);
menuItem.setAttribute("feed", feedInfo.href); menuItem.setAttribute("feed", feedInfo.href);
menuItem.setAttribute("tooltiptext", feedInfo.href); menuItem.setAttribute("tooltiptext", feedInfo.href);

View file

@ -133,14 +133,17 @@
<description id="editBookmarkPanelDescription"/> <description id="editBookmarkPanelDescription"/>
<hbox> <hbox>
<button id="editBookmarkPanelUndoRemoveButton" <button id="editBookmarkPanelUndoRemoveButton"
class="editBookmarkPanelHeaderButton"
hidden="true" hidden="true"
oncommand="StarUI.undoRemoveBookmarkCommand();" oncommand="StarUI.undoRemoveBookmarkCommand();"
label="&editBookmark.undo.label;" label="&editBookmark.undo.label;"
accesskey="&editBookmark.undo.accessKey;"/> accesskey="&editBookmark.undo.accessKey;"/>
<button id="editBookmarkPanelRemoveButton" <button id="editBookmarkPanelRemoveButton"
class="editBookmarkPanelHeaderButton"
oncommand="StarUI.removeBookmarkButtonCommand();" oncommand="StarUI.removeBookmarkButtonCommand();"
accesskey="&editBookmark.removeBookmark.accessKey;"/> accesskey="&editBookmark.removeBookmark.accessKey;"/>
<button id="editBookmarkPanelEditButton" <button id="editBookmarkPanelEditButton"
class="editBookmarkPanelHeaderButton"
oncommand="StarUI.editButtonCommand();" oncommand="StarUI.editButtonCommand();"
label="&editBookmark.edit.label;" label="&editBookmark.edit.label;"
accesskey="&editBookmark.edit.accessKey;"/> accesskey="&editBookmark.edit.accessKey;"/>
@ -151,17 +154,21 @@
<hbox id="editBookmarkPanelBottomButtons" pack="end"> <hbox id="editBookmarkPanelBottomButtons" pack="end">
#ifndef XP_UNIX #ifndef XP_UNIX
<button id="editBookmarkPanelDoneButton" <button id="editBookmarkPanelDoneButton"
class="editBookmarkPanelBottomButton"
label="&editBookmark.done.label;" label="&editBookmark.done.label;"
default="true" default="true"
oncommand="StarUI.panel.hidePopup();"/> oncommand="StarUI.panel.hidePopup();"/>
<button id="editBookmarkPanelDeleteButton" <button id="editBookmarkPanelDeleteButton"
class="editBookmarkPanelBottomButton"
label="&editBookmark.cancel.label;" label="&editBookmark.cancel.label;"
oncommand="StarUI.cancelButtonOnCommand();"/> oncommand="StarUI.cancelButtonOnCommand();"/>
#else #else
<button id="editBookmarkPanelDeleteButton" <button id="editBookmarkPanelDeleteButton"
class="editBookmarkPanelBottomButton"
label="&editBookmark.cancel.label;" label="&editBookmark.cancel.label;"
oncommand="StarUI.cancelButtonOnCommand();"/> oncommand="StarUI.cancelButtonOnCommand();"/>
<button id="editBookmarkPanelDoneButton" <button id="editBookmarkPanelDoneButton"
class="editBookmarkPanelBottomButton"
label="&editBookmark.done.label;" label="&editBookmark.done.label;"
default="true" default="true"
oncommand="StarUI.panel.hidePopup();"/> oncommand="StarUI.panel.hidePopup();"/>
@ -211,25 +218,32 @@
<hbox id="identity-popup-container" align="top"> <hbox id="identity-popup-container" align="top">
<image id="identity-popup-icon"/> <image id="identity-popup-icon"/>
<vbox id="identity-popup-content-box"> <vbox id="identity-popup-content-box">
<label id="identity-popup-connectedToLabel" value="&identity.connectedTo;"/> <label id="identity-popup-connectedToLabel"
class="identity-popup-label"
value="&identity.connectedTo;"/>
<label id="identity-popup-connectedToLabel2" <label id="identity-popup-connectedToLabel2"
class="identity-popup-label"
value="&identity.unverifiedsite2;"/> value="&identity.unverifiedsite2;"/>
<description id="identity-popup-content-host"/> <description id="identity-popup-content-host"
<label id="identity-popup-runByLabel" value="&identity.runBy;"/> class="identity-popup-description"/>
<description id="identity-popup-content-owner"/> <label id="identity-popup-runByLabel"
<description id="identity-popup-content-supplemental"/> class="identity-popup-label"
<description id="identity-popup-content-verifier"/> value="&identity.runBy;"/>
<description id="identity-popup-content-owner"
class="identity-popup-description"/>
<description id="identity-popup-content-supplemental"
class="identity-popup-description"/>
<description id="identity-popup-content-verifier"
class="identity-popup-description"/>
<hbox id="identity-popup-encryption" flex="1"> <hbox id="identity-popup-encryption" flex="1">
<vbox> <vbox>
<image id="identity-popup-encryption-icon"/> <image id="identity-popup-encryption-icon"/>
<spacer flex="1"/>
</vbox> </vbox>
<description id="identity-popup-encryption-label" flex="1"/> <description id="identity-popup-encryption-label" flex="1"
class="identity-popup-description"/>
</hbox> </hbox>
<spacer flex="1"/>
<!-- Footer button to open security page info --> <!-- Footer button to open security page info -->
<hbox> <hbox pack="end">
<spacer flex="1"/>
<button id="identity-popup-more-info-button" <button id="identity-popup-more-info-button"
label="&identity.moreInfoLinkText;" label="&identity.moreInfoLinkText;"
onblur="gIdentityHandler.hideIdentityPopup();" onblur="gIdentityHandler.hideIdentityPopup();"
@ -392,7 +406,7 @@
<box id="identity-box" role="button" <box id="identity-box" role="button"
onclick="gIdentityHandler.handleIdentityButtonEvent(event);" onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"> onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);">
<hbox align="center"> <hbox id="identity-box-inner" align="center">
<stack id="page-proxy-stack" <stack id="page-proxy-stack"
onclick="PageProxyClickHandler(event);"> onclick="PageProxyClickHandler(event);">
<image id="urlbar-throbber" busy="false"/> <image id="urlbar-throbber" busy="false"/>

View file

@ -1,5 +1,5 @@
#viewGroup radio { #viewGroup > radio {
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#viewbutton"); -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#viewbutton");
} }

View file

@ -314,8 +314,9 @@
</hbox> </hbox>
<vbox id="permList" flex="1"> <vbox id="permList" flex="1">
<vbox> <vbox class="permission">
<label id="permImageLabel" value="&permImage;" control="imageRadioGroup"/> <label class="permissionLabel" id="permImageLabel"
value="&permImage;" control="imageRadioGroup"/>
<hbox role="group" aria-labelledby="permImageLabel"> <hbox role="group" aria-labelledby="permImageLabel">
<checkbox id="imageDef" command="cmd_imageDef" label="&permUseDefault;"/> <checkbox id="imageDef" command="cmd_imageDef" label="&permUseDefault;"/>
<spacer flex="1"/> <spacer flex="1"/>
@ -325,8 +326,9 @@
</radiogroup> </radiogroup>
</hbox> </hbox>
</vbox> </vbox>
<vbox> <vbox class="permission">
<label id="permPopupLabel" value="&permPopup;" control="popupRadioGroup"/> <label class="permissionLabel" id="permPopupLabel"
value="&permPopup;" control="popupRadioGroup"/>
<hbox role="group" aria-labelledby="permPopupLabel"> <hbox role="group" aria-labelledby="permPopupLabel">
<checkbox id="popupDef" command="cmd_popupDef" label="&permUseDefault;"/> <checkbox id="popupDef" command="cmd_popupDef" label="&permUseDefault;"/>
<spacer flex="1"/> <spacer flex="1"/>
@ -336,8 +338,9 @@
</radiogroup> </radiogroup>
</hbox> </hbox>
</vbox> </vbox>
<vbox> <vbox class="permission">
<label id="permCookieLabel" value="&permCookie;" control="cookieRadioGroup"/> <label class="permissionLabel" id="permCookieLabel"
value="&permCookie;" control="cookieRadioGroup"/>
<hbox role="group" aria-labelledby="permCookieLabel"> <hbox role="group" aria-labelledby="permCookieLabel">
<checkbox id="cookieDef" command="cmd_cookieDef" label="&permUseDefault;"/> <checkbox id="cookieDef" command="cmd_cookieDef" label="&permUseDefault;"/>
<spacer flex="1"/> <spacer flex="1"/>
@ -348,8 +351,9 @@
</radiogroup> </radiogroup>
</hbox> </hbox>
</vbox> </vbox>
<vbox> <vbox class="permission">
<label id="permInstallLabel" value="&permInstall;" control="installRadioGroup"/> <label class="permissionLabel" id="permInstallLabel"
value="&permInstall;" control="installRadioGroup"/>
<hbox role="group" aria-labelledby="permInstallLabel"> <hbox role="group" aria-labelledby="permInstallLabel">
<checkbox id="installDef" command="cmd_installDef" label="&permUseDefault;"/> <checkbox id="installDef" command="cmd_installDef" label="&permUseDefault;"/>
<spacer flex="1"/> <spacer flex="1"/>
@ -359,9 +363,9 @@
</radiogroup> </radiogroup>
</hbox> </hbox>
</vbox> </vbox>
<vbox class="permission">
<vbox> <label class="permissionLabel" id="permGeoLabel"
<label id="permGeoLabel" value="&permGeo;" control="geoRadioGroup"/> value="&permGeo;" control="geoRadioGroup"/>
<hbox role="group" aria-labelledby="permGeoLabel"> <hbox role="group" aria-labelledby="permGeoLabel">
<checkbox id="geoDef" command="cmd_geoDef" label="&permAskAlways;"/> <checkbox id="geoDef" command="cmd_geoDef" label="&permAskAlways;"/>
<spacer flex="1"/> <spacer flex="1"/>

View file

@ -806,7 +806,7 @@ WebContentConverterRegistrar.prototype = {
* branch and stop cycling once that's true. This doesn't fix the case * branch and stop cycling once that's true. This doesn't fix the case
* where a user manually removes a reader, but that's not supported yet! * where a user manually removes a reader, but that's not supported yet!
*/ */
var vals = branch.getChildList("", {}); var vals = branch.getChildList("");
if (vals.length == 0) if (vals.length == 0)
return; return;
@ -832,7 +832,7 @@ WebContentConverterRegistrar.prototype = {
getService(Ci.nsIPrefService); getService(Ci.nsIPrefService);
var kids = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH) var kids = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
.getChildList("", {}); .getChildList("");
// first get the numbers of the providers by getting all ###.uri prefs // first get the numbers of the providers by getting all ###.uri prefs
var nums = []; var nums = [];
@ -857,7 +857,7 @@ WebContentConverterRegistrar.prototype = {
// so that getWebContentHandlerByURI can return successfully. // so that getWebContentHandlerByURI can return successfully.
try { try {
var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO); var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
var childPrefs = autoBranch.getChildList("", { }); var childPrefs = autoBranch.getChildList("");
for (var i = 0; i < childPrefs.length; ++i) { for (var i = 0; i < childPrefs.length; ++i) {
var type = childPrefs[i]; var type = childPrefs[i];
var uri = autoBranch.getCharPref(type); var uri = autoBranch.getCharPref(type);

View file

@ -64,8 +64,9 @@
<!-- Bookmarks and history tooltip --> <!-- Bookmarks and history tooltip -->
<tooltip id="bhTooltip"/> <tooltip id="bhTooltip"/>
<hbox align="center"> <hbox id="sidebar-search-container" align="center">
<label value="&search.label;" accesskey="&search.accesskey;" control="search-box"/> <label id="sidebar-search-label"
value="&search.label;" accesskey="&search.accesskey;" control="search-box"/>
<textbox id="search-box" flex="1" type="search" class="compact" <textbox id="search-box" flex="1" type="search" class="compact"
aria-controls="bookmarks-view" aria-controls="bookmarks-view"
oncommand="searchBookmarks(this.value);"/> oncommand="searchBookmarks(this.value);"/>

View file

@ -61,6 +61,7 @@
<rows id="editBMPanel_rows"> <rows id="editBMPanel_rows">
<row align="center" id="editBMPanel_nameRow"> <row align="center" id="editBMPanel_nameRow">
<label value="&editBookmarkOverlay.name.label;" <label value="&editBookmarkOverlay.name.label;"
class="editBMPanel_rowLabel"
accesskey="&editBookmarkOverlay.name.accesskey;" accesskey="&editBookmarkOverlay.name.accesskey;"
control="editBMPanel_namePicker" control="editBMPanel_namePicker"
observes="paneElementsBroadcaster"/> observes="paneElementsBroadcaster"/>
@ -84,6 +85,7 @@
<row align="center" id="editBMPanel_locationRow"> <row align="center" id="editBMPanel_locationRow">
<label value="&editBookmarkOverlay.location.label;" <label value="&editBookmarkOverlay.location.label;"
class="editBMPanel_rowLabel"
accesskey="&editBookmarkOverlay.location.accesskey;" accesskey="&editBookmarkOverlay.location.accesskey;"
control="editBMPanel_locationField" control="editBMPanel_locationField"
observes="paneElementsBroadcaster"/> observes="paneElementsBroadcaster"/>
@ -95,6 +97,7 @@
<row align="center" id="editBMPanel_feedLocationRow"> <row align="center" id="editBMPanel_feedLocationRow">
<label value="&editBookmarkOverlay.feedLocation.label;" <label value="&editBookmarkOverlay.feedLocation.label;"
class="editBMPanel_rowLabel"
accesskey="&editBookmarkOverlay.feedLocation.accesskey;" accesskey="&editBookmarkOverlay.feedLocation.accesskey;"
control="editBMPanel_feedLocationField" control="editBMPanel_feedLocationField"
observes="paneElementsBroadcaster"/> observes="paneElementsBroadcaster"/>
@ -106,6 +109,7 @@
<row align="center" id="editBMPanel_siteLocationRow"> <row align="center" id="editBMPanel_siteLocationRow">
<label value="&editBookmarkOverlay.siteLocation.label;" <label value="&editBookmarkOverlay.siteLocation.label;"
class="editBMPanel_rowLabel"
accesskey="&editBookmarkOverlay.siteLocation.accesskey;" accesskey="&editBookmarkOverlay.siteLocation.accesskey;"
control="editBMPanel_siteLocationField" control="editBMPanel_siteLocationField"
observes="paneElementsBroadcaster"/> observes="paneElementsBroadcaster"/>
@ -117,6 +121,7 @@
<row align="center" id="editBMPanel_folderRow"> <row align="center" id="editBMPanel_folderRow">
<label value="&editBookmarkOverlay.folder.label;" <label value="&editBookmarkOverlay.folder.label;"
class="editBMPanel_rowLabel"
control="editBMPanel_folderMenuList" control="editBMPanel_folderMenuList"
observes="paneElementsBroadcaster"/> observes="paneElementsBroadcaster"/>
<hbox flex="1" align="center"> <hbox flex="1" align="center">
@ -178,6 +183,7 @@
<row align="center" id="editBMPanel_tagsRow"> <row align="center" id="editBMPanel_tagsRow">
<label value="&editBookmarkOverlay.tags.label;" <label value="&editBookmarkOverlay.tags.label;"
class="editBMPanel_rowLabel"
accesskey="&editBookmarkOverlay.tags.accesskey;" accesskey="&editBookmarkOverlay.tags.accesskey;"
control="editBMPanel_tagsField" control="editBMPanel_tagsField"
observes="paneElementsBroadcaster"/> observes="paneElementsBroadcaster"/>
@ -215,6 +221,7 @@
<row align="center" id="editBMPanel_keywordRow"> <row align="center" id="editBMPanel_keywordRow">
<observes element="additionalInfoBroadcaster" attribute="hidden"/> <observes element="additionalInfoBroadcaster" attribute="hidden"/>
<label value="&editBookmarkOverlay.keyword.label;" <label value="&editBookmarkOverlay.keyword.label;"
class="editBMPanel_rowLabel"
accesskey="&editBookmarkOverlay.keyword.accesskey;" accesskey="&editBookmarkOverlay.keyword.accesskey;"
control="editBMPanel_keywordField" control="editBMPanel_keywordField"
observes="paneElementsBroadcaster"/> observes="paneElementsBroadcaster"/>
@ -226,6 +233,7 @@
<row id="editBMPanel_descriptionRow"> <row id="editBMPanel_descriptionRow">
<observes element="additionalInfoBroadcaster" attribute="hidden"/> <observes element="additionalInfoBroadcaster" attribute="hidden"/>
<label value="&editBookmarkOverlay.description.label;" <label value="&editBookmarkOverlay.description.label;"
class="editBMPanel_rowLabel"
accesskey="&editBookmarkOverlay.description.accesskey;" accesskey="&editBookmarkOverlay.description.accesskey;"
control="editBMPanel_descriptionField" control="editBMPanel_descriptionField"
observes="paneElementsBroadcaster"/> observes="paneElementsBroadcaster"/>

View file

@ -80,8 +80,9 @@
<!-- Bookmarks and history tooltip --> <!-- Bookmarks and history tooltip -->
<tooltip id="bhTooltip"/> <tooltip id="bhTooltip"/>
<hbox align="center"> <hbox id="sidebar-search-container" align="center">
<label value="&find.label;" accesskey="&find.accesskey;" <label id="sidebar-search-label"
value="&find.label;" accesskey="&find.accesskey;"
control="search-box"/> control="search-box"/>
<textbox id="search-box" flex="1" type="search" class="compact" <textbox id="search-box" flex="1" type="search" class="compact"
aria-controls="historyTree" aria-controls="historyTree"

View file

@ -1555,7 +1555,7 @@ SessionStoreService.prototype = {
if (node.type != "file") if (node.type != "file")
data[id] = node.type == "checkbox" || node.type == "radio" ? node.checked : node.value; data[id] = node.type == "checkbox" || node.type == "radio" ? node.checked : node.value;
else else
data[id] = { type: "file", value: node.value }; data[id] = { type: "file", fileList: node.mozGetFileNameArray() };
} }
else if (node instanceof Ci.nsIDOMHTMLTextAreaElement) else if (node instanceof Ci.nsIDOMHTMLTextAreaElement)
data[id] = node.value; data[id] = node.value;
@ -2286,8 +2286,8 @@ SessionStoreService.prototype = {
try { try {
node.selectedIndex = value; node.selectedIndex = value;
} catch (ex) { /* throws for invalid indices */ } } catch (ex) { /* throws for invalid indices */ }
else if (value && value.type && value.type == node.type) else if (value && value.fileList && value.type == "file" && node.type == "file")
node.value = value.value; node.mozSetFileNameArray(value.fileList, value.fileList.length);
else if (value && typeof value.indexOf == "function" && node.options) { else if (value && typeof value.indexOf == "function" && node.options) {
Array.forEach(node.options, function(aOpt, aIx) { Array.forEach(node.options, function(aOpt, aIx) {
aOpt.selected = value.indexOf(aIx) > -1; aOpt.selected = value.indexOf(aIx) > -1;

View file

@ -51,7 +51,8 @@ function test() {
"//textarea[1]": "", "//textarea[1]": "",
"//textarea[2]": "Some text... " + Math.random(), "//textarea[2]": "Some text... " + Math.random(),
"//textarea[3]": "Some more text\n" + new Date(), "//textarea[3]": "Some more text\n" + new Date(),
"//input[@type='file']": "/dev/null" "//input[@type='file'][1]": ["/dev/null"],
"//input[@type='file'][2]": ["/dev/null", "/dev/stdin"]
}; };
function getElementByXPath(aTab, aQuery) { function getElementByXPath(aTab, aQuery) {
@ -68,6 +69,8 @@ function test() {
node.checked = aValue; node.checked = aValue;
else if (typeof aValue == "number") else if (typeof aValue == "number")
node.selectedIndex = aValue; node.selectedIndex = aValue;
else if (node instanceof Ci.nsIDOMHTMLInputElement && node.type == "file")
node.mozSetFileNameArray(aValue, aValue.length);
else else
Array.forEach(node.options, function(aOpt, aIx) Array.forEach(node.options, function(aOpt, aIx)
(aOpt.selected = aValue.indexOf(aIx) > -1)); (aOpt.selected = aValue.indexOf(aIx) > -1));
@ -77,9 +80,15 @@ function test() {
let node = getElementByXPath(aTab, aQuery); let node = getElementByXPath(aTab, aQuery);
if (!node) if (!node)
return false; return false;
if (node instanceof Ci.nsIDOMHTMLInputElement) if (node instanceof Ci.nsIDOMHTMLInputElement) {
if (node.type == "file") {
let fileNames = node.mozGetFileNameArray();
return fileNames.length == aValue.length &&
Array.every(fileNames, function(aFile) aValue.indexOf(aFile) >= 0);
}
return aValue == (node.type == "checkbox" || node.type == "radio" ? return aValue == (node.type == "checkbox" || node.type == "radio" ?
node.checked : node.value); node.checked : node.value);
}
if (node instanceof Ci.nsIDOMHTMLTextAreaElement) if (node instanceof Ci.nsIDOMHTMLTextAreaElement)
return aValue == node.value; return aValue == node.value;
if (!node.multiple) if (!node.multiple)

View file

@ -34,3 +34,4 @@
<h3>File Selector</h3> <h3>File Selector</h3>
<input type="file"> <input type="file">
<input type="file" multiple>

View file

@ -69,7 +69,7 @@
[browser] [browser]
; [Base Browser Files] ; [Base Browser Files]
#ifdef XP_WIN32 #ifndef XP_UNIX
@BINPATH@/@MOZ_APP_NAME@.exe @BINPATH@/@MOZ_APP_NAME@.exe
#else #else
@BINPATH@/@MOZ_APP_NAME@-bin @BINPATH@/@MOZ_APP_NAME@-bin
@ -87,6 +87,8 @@
#ifndef WINCE #ifndef WINCE
@BINPATH@/plugins/npnul32.dll @BINPATH@/plugins/npnul32.dll
#endif #endif
#elifdef XP_OS2
@BINPATH@/plugins/npnulos2.dll
#endif #endif
@BINPATH@/@DLL_PREFIX@sqlite3@DLL_SUFFIX@ @BINPATH@/@DLL_PREFIX@sqlite3@DLL_SUFFIX@
@BINPATH@/README.txt @BINPATH@/README.txt
@ -298,8 +300,13 @@
@BINPATH@/components/nsSessionStartup.js @BINPATH@/components/nsSessionStartup.js
@BINPATH@/components/nsSessionStore.js @BINPATH@/components/nsSessionStore.js
@BINPATH@/components/nsURLFormatter.js @BINPATH@/components/nsURLFormatter.js
#ifndef XP_OS2
@BINPATH@/components/@DLL_PREFIX@browserdirprovider@DLL_SUFFIX@ @BINPATH@/components/@DLL_PREFIX@browserdirprovider@DLL_SUFFIX@
@BINPATH@/components/@DLL_PREFIX@browsercomps@DLL_SUFFIX@ @BINPATH@/components/@DLL_PREFIX@browsercomps@DLL_SUFFIX@
#else
@BINPATH@/components/brwsrdir@DLL_SUFFIX@
@BINPATH@/components/brwsrcmp@DLL_SUFFIX@
#endif
@BINPATH@/components/txEXSLTRegExFunctions.js @BINPATH@/components/txEXSLTRegExFunctions.js
@BINPATH@/components/nsLivemarkService.js @BINPATH@/components/nsLivemarkService.js
@BINPATH@/components/nsTaggingService.js @BINPATH@/components/nsTaggingService.js
@ -352,7 +359,7 @@
; shell icons ; shell icons
#ifndef XP_WIN32 #ifdef XP_UNIX
@BINPATH@/icons/*.xpm @BINPATH@/icons/*.xpm
@BINPATH@/icons/*.png @BINPATH@/icons/*.png
#endif #endif

View file

@ -52,7 +52,7 @@
-moz-box-orient: vertical; /* for flex hack */ -moz-box-orient: vertical; /* for flex hack */
} }
#menubar-items > menubar { #main-menubar {
-moz-box-flex: 1; /* make menu items expand to fill toolbar height */ -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
} }
@ -60,10 +60,6 @@
min-height: 29px; min-height: 29px;
} }
#wrapper-search-container #searchbar html|*.textbox-input {
visibility: hidden;
}
#navigator-toolbox[inFullscreen="true"], #navigator-toolbox[inFullscreen="true"],
#navigator-toolbox[inFullscreen="true"] > #nav-bar { #navigator-toolbox[inFullscreen="true"] > #nav-bar {
border-top: none; border-top: none;
@ -71,7 +67,7 @@
} }
#urlbar:-moz-lwtheme:not([focused="true"]), #urlbar:-moz-lwtheme:not([focused="true"]),
#searchbar:-moz-lwtheme > textbox:not([focused="true"]), .searchbar-textbox:-moz-lwtheme:not([focused="true"]),
.tabbrowser-tab:-moz-lwtheme:not([selected="true"]) { .tabbrowser-tab:-moz-lwtheme:not([selected="true"]) {
opacity: .85; opacity: .85;
} }
@ -856,12 +852,12 @@ toolbar[iconsize="small"] #fullscreen-button {
outline: 1px dotted -moz-DialogText; outline: 1px dotted -moz-DialogText;
} }
#identity-box:hover > hbox { #identity-box:hover > #identity-box-inner {
background-color: rgba(255, 255, 255, .2); background-color: rgba(255, 255, 255, .2);
} }
#identity-box:hover:active > hbox, #identity-box:hover:active > #identity-box-inner,
#identity-box[open="true"] > hbox { #identity-box[open="true"] > #identity-box-inner {
background-color: rgba(0, 0, 0, .1); background-color: rgba(0, 0, 0, .1);
} }
@ -902,14 +898,13 @@ toolbar[iconsize="small"] #fullscreen-button {
} }
/* Identity popup body text */ /* Identity popup body text */
#identity-popup-content-box > description, .identity-popup-description {
#identity-popup-encryption-label {
white-space: pre-wrap; white-space: pre-wrap;
-moz-padding-start: 15px; -moz-padding-start: 15px;
margin: 2px 0 4px; margin: 2px 0 4px;
} }
#identity-popup-content-box > label { .identity-popup-label {
white-space: pre-wrap; white-space: pre-wrap;
-moz-padding-start: 15px; -moz-padding-start: 15px;
margin: 0; margin: 0;
@ -947,7 +942,6 @@ toolbar[iconsize="small"] #fullscreen-button {
/* Identity popup bounding box */ /* Identity popup bounding box */
#identity-popup-container { #identity-popup-container {
background-image: none;
min-width: 280px; min-width: 280px;
padding: 10px; padding: 10px;
} }

View file

@ -42,7 +42,7 @@
@import url("chrome://global/skin/"); @import url("chrome://global/skin/");
/* View buttons */ /* View buttons */
#viewGroup radio { #viewGroup > radio {
list-style-image: url("chrome://browser/skin/pageInfo.png"); list-style-image: url("chrome://browser/skin/pageInfo.png");
-moz-box-orient: vertical; -moz-box-orient: vertical;
-moz-box-align: center; -moz-box-align: center;
@ -53,7 +53,7 @@
color: -moz-FieldText; color: -moz-FieldText;
} }
#viewGroup radio[selected="true"] { #viewGroup > radio[selected="true"] {
background-color: Highlight; background-color: Highlight;
color: HighlightText; color: HighlightText;
} }
@ -255,7 +255,7 @@ treechildren::-moz-tree-cell-text(broken) {
color: -moz-FieldText; color: -moz-FieldText;
} }
#permList > vbox { .permission {
padding-top: 6px; padding-top: 6px;
padding-bottom: 6px; padding-bottom: 6px;
-moz-padding-start: 7px; -moz-padding-start: 7px;
@ -264,11 +264,11 @@ treechildren::-moz-tree-cell-text(broken) {
border-bottom: 1px dotted #C0C0C0; border-bottom: 1px dotted #C0C0C0;
} }
#permList > vbox > label { .permissionLabel {
font-weight: bold; font-weight: bold;
} }
#permList > vbox:hover { .permission:hover {
background-color: -moz-dialog; background-color: -moz-dialog;
color: -moz-DialogText; color: -moz-DialogText;
} }

View file

@ -47,11 +47,11 @@
@namespace html url("http://www.w3.org/1999/xhtml"); @namespace html url("http://www.w3.org/1999/xhtml");
#urlbar:-moz-lwtheme:not([focused="true"]), #urlbar:-moz-lwtheme:not([focused="true"]),
#searchbar:-moz-lwtheme > textbox:not([focused="true"]) { .searchbar-textbox:-moz-lwtheme:not([focused="true"]) {
opacity: .9; opacity: .9;
} }
#navigator-toolbox:-moz-lwtheme toolbarbutton { #navigator-toolbox toolbarbutton:-moz-lwtheme {
color: inherit !important; color: inherit !important;
text-shadow: inherit; text-shadow: inherit;
} }
@ -70,10 +70,10 @@
background: none !important; background: none !important;
} }
.tabbrowser-tab[selected="true"]:-moz-lwtheme { .tabbrowser-tab:-moz-lwtheme[selected="true"] {
background-color: transparent !important; background-color: transparent !important;
} }
.tabbrowser-tab:not([selected="true"]):-moz-lwtheme:not(:hover) > .tab-text { .tabbrowser-tab:-moz-lwtheme:not([selected="true"]):not(:hover) > .tab-text {
opacity: .8; opacity: .8;
} }
@ -91,7 +91,7 @@
-moz-border-right-colors: rgba(255,255,255,.1) rgba(255,255,255,.6) rgba(255,255,255,.2); -moz-border-right-colors: rgba(255,255,255,.1) rgba(255,255,255,.6) rgba(255,255,255,.2);
} }
.tabbrowser-tab[selected="true"]:-moz-lwtheme-brighttext { .tabbrowser-tab:-moz-lwtheme-brighttext[selected="true"] {
-moz-border-left-colors: rgba(255,255,255,.6) rgba(255,255,255,.2); -moz-border-left-colors: rgba(255,255,255,.6) rgba(255,255,255,.2);
-moz-border-bottom-colors: rgba(255,255,255,.6) rgba(255,255,255,.2); -moz-border-bottom-colors: rgba(255,255,255,.6) rgba(255,255,255,.2);
-moz-border-right-colors: rgba(255,255,255,.6) rgba(255,255,255,.2); -moz-border-right-colors: rgba(255,255,255,.6) rgba(255,255,255,.2);
@ -159,12 +159,6 @@
background-color: -moz-mac-chrome-inactive; background-color: -moz-mac-chrome-inactive;
} }
/* ----- SEARCH FIELD ----- */
#wrapper-search-container #searchbar html|*.textbox-input {
visibility: hidden;
}
/* ----- BOOKMARK TOOLBAR ----- */ /* ----- BOOKMARK TOOLBAR ----- */
#PersonalToolbar { #PersonalToolbar {
@ -817,7 +811,7 @@ toolbar[iconsize="small"] #unified-back-forward-button > #back-forward-dropmarke
-moz-margin-start: 0; -moz-margin-start: 0;
} }
#wrapper-urlbar-container #urlbar, #wrapper-urlbar-container > #urlbar-container > #urlbar,
#urlbar[readonly="true"] { #urlbar[readonly="true"] {
-moz-padding-end: 12px; -moz-padding-end: 12px;
} }
@ -826,16 +820,10 @@ toolbar[iconsize="small"] #unified-back-forward-button > #back-forward-dropmarke
max-width: 20em; max-width: 20em;
} }
#wrapper-urlbar-container > #urlbar-container > #urlbar > #identity-box > hbox > #identity-icon-label, #wrapper-urlbar-container > #urlbar-container > #urlbar > .autocomplete-history-dropmarker {
#wrapper-urlbar-container #urlbar > .autocomplete-history-dropmarker {
display: none; display: none;
} }
#wrapper-urlbar-container > #urlbar-container > #urlbar > #identity-box.verifiedIdentity > hbox > #identity-icon-label,
#wrapper-urlbar-container > #urlbar-container > #urlbar > #identity-box.verifiedDomain > hbox > #identity-icon-label {
display: -moz-box;
}
/* Keep the URL bar LTR */ /* Keep the URL bar LTR */
#PopupAutoCompleteRichResult { #PopupAutoCompleteRichResult {
@ -1019,15 +1007,15 @@ richlistitem[selected="true"][current="true"] > hbox > .ac-result-type-bookmark,
font-weight: bold; font-weight: bold;
} }
#editBookmarkPanel > hbox, #editBookmarkPanelContent,
#editBookmarkPanel > vbox { #editBookmarkPanelBottomButtons {
margin-right: -30px; margin-right: -30px;
} }
/**** HUD style buttons ****/ /**** HUD style buttons ****/
#editBookmarkPanelHeader > vbox > hbox > button, .editBookmarkPanelHeaderButton,
#editBookmarkPanelBottomButtons > button { .editBookmarkPanelBottomButton {
-moz-appearance: none; -moz-appearance: none;
background: url("chrome://browser/skin/hud-style-button-middle-background.png") repeat-x #464646 center center; background: url("chrome://browser/skin/hud-style-button-middle-background.png") repeat-x #464646 center center;
border-width: 3px; border-width: 3px;
@ -1044,19 +1032,19 @@ richlistitem[selected="true"][current="true"] > hbox > .ac-result-type-bookmark,
color: #ffffff; color: #ffffff;
} }
#editBookmarkPanelHeader > vbox > hbox > button:hover:active, .editBookmarkPanelHeaderButton:hover:active,
#editBookmarkPanelBottomButtons > button:hover:active { .editBookmarkPanelBottomButton:hover:active {
background-color: #86888B; background-color: #86888B;
} }
#editBookmarkPanelHeader > vbox > hbox > button:focus, .editBookmarkPanelHeaderButton:focus,
#editBookmarkPanelBottomButtons > button:focus { .editBookmarkPanelBottomButton:focus {
outline: 2px solid -moz-mac-focusring; outline: 2px solid -moz-mac-focusring;
outline-offset: -2px; outline-offset: -2px;
-moz-outline-radius: 100%; -moz-outline-radius: 100%;
} }
#editBookmarkPanelBottomButtons > button[default="true"] { .editBookmarkPanelBottomButton[default="true"] {
background-color: #666; background-color: #666;
} }
@ -1333,7 +1321,7 @@ richlistitem[selected="true"][current="true"] > hbox > .ac-result-type-bookmark,
color: #fff !important; color: #fff !important;
} }
#editBookmarkPanelGrid > rows > row > label { .editBMPanel_rowLabel {
text-align: end; text-align: end;
} }
@ -1571,7 +1559,7 @@ tabbrowser > tabbox {
} }
.tabbrowser-tab:-moz-lwtheme, .tabbrowser-tab:-moz-lwtheme,
#main-window:-moz-lwtheme:not([active="true"]) .tabbrowser-tab { #main-window:not([active="true"]) .tabbrowser-tab:-moz-lwtheme {
color: inherit; color: inherit;
text-shadow: inherit; text-shadow: inherit;
} }
@ -1842,7 +1830,7 @@ tabpanels.plain {
background-image: url("chrome://browser/skin/urlbar/startcap-focused-graphite.png"); background-image: url("chrome://browser/skin/urlbar/startcap-focused-graphite.png");
} }
#identity-box:focus > hbox > #page-proxy-deck { #identity-box:focus > #identity-box-inner > #page-proxy-deck {
outline: 2px solid #4F8EC9; outline: 2px solid #4F8EC9;
-moz-outline-radius: 2px; -moz-outline-radius: 2px;
} }
@ -1859,7 +1847,7 @@ tabpanels.plain {
-moz-padding-end: 14px; -moz-padding-end: 14px;
} }
#identity-box.unknownIdentity > hbox > #identity-icon-label { #identity-box.unknownIdentity > #identity-box-inner > #identity-icon-label {
display: none; display: none;
} }
@ -1871,13 +1859,13 @@ tabpanels.plain {
-moz-padding-start: 13px; -moz-padding-start: 13px;
} }
#identity-box.verifiedDomain > hbox { #identity-box.verifiedDomain > #identity-box-inner {
padding: 0; padding: 0;
background: url("chrome://browser/skin/urlbar/startcap-secure-mid.png") repeat-x center center; background: url("chrome://browser/skin/urlbar/startcap-secure-mid.png") repeat-x center center;
-moz-box-pack: center; -moz-box-pack: center;
} }
#identity-box.verifiedDomain > hbox > #identity-icon-label { #identity-box.verifiedDomain > #identity-box-inner > #identity-icon-label {
background: url("chrome://browser/skin/urlbar/startcap-secure-end.png") no-repeat center right; background: url("chrome://browser/skin/urlbar/startcap-secure-end.png") no-repeat center right;
} }
@ -1887,15 +1875,15 @@ tabpanels.plain {
background-image: url("chrome://browser/skin/urlbar/startcap-secure-start-active.png"); background-image: url("chrome://browser/skin/urlbar/startcap-secure-start-active.png");
} }
#identity-box.verifiedDomain[open="true"] > hbox, #identity-box.verifiedDomain[open="true"] > #identity-box-inner,
#identity-box.verifiedDomain:hover:active > hbox { #identity-box.verifiedDomain:hover:active > #identity-box-inner {
padding: 0; padding: 0;
background: url("chrome://browser/skin/urlbar/startcap-secure-mid-active.png") repeat-x center center; background: url("chrome://browser/skin/urlbar/startcap-secure-mid-active.png") repeat-x center center;
-moz-box-pack: center; -moz-box-pack: center;
} }
#identity-box.verifiedDomain[open="true"] > hbox > #identity-icon-label, #identity-box.verifiedDomain[open="true"] > #identity-box-inner > #identity-icon-label,
#identity-box.verifiedDomain:hover:active > hbox > #identity-icon-label { #identity-box.verifiedDomain:hover:active > #identity-box-inner > #identity-icon-label {
background: url("chrome://browser/skin/urlbar/startcap-secure-end-active.png") no-repeat center right; background: url("chrome://browser/skin/urlbar/startcap-secure-end-active.png") no-repeat center right;
} }
@ -1904,11 +1892,11 @@ tabpanels.plain {
background-image: url("chrome://browser/skin/urlbar/startcap-secure-start-focused.png"); background-image: url("chrome://browser/skin/urlbar/startcap-secure-start-focused.png");
} }
#urlbar[focused="true"] > #identity-box.verifiedDomain > hbox { #urlbar[focused="true"] > #identity-box.verifiedDomain > #identity-box-inner {
background-image: url("chrome://browser/skin/urlbar/startcap-secure-mid-focused.png"); background-image: url("chrome://browser/skin/urlbar/startcap-secure-mid-focused.png");
} }
#urlbar[focused="true"] > #identity-box.verifiedDomain > hbox > #identity-icon-label { #urlbar[focused="true"] > #identity-box.verifiedDomain > #identity-box-inner > #identity-icon-label {
background-image: url("chrome://browser/skin/urlbar/startcap-secure-end-focused.png"); background-image: url("chrome://browser/skin/urlbar/startcap-secure-end-focused.png");
} }
@ -1916,15 +1904,15 @@ tabpanels.plain {
background-image: url("chrome://browser/skin/urlbar/startcap-secure-start-focused-graphite.png"); background-image: url("chrome://browser/skin/urlbar/startcap-secure-start-focused-graphite.png");
} }
#urlbar[focused="true"] > #identity-box.verifiedDomain > hbox:-moz-system-metric(mac-graphite-theme) { #urlbar[focused="true"] > #identity-box.verifiedDomain > #identity-box-inner:-moz-system-metric(mac-graphite-theme) {
background-image: url("chrome://browser/skin/urlbar/startcap-secure-mid-focused-graphite.png"); background-image: url("chrome://browser/skin/urlbar/startcap-secure-mid-focused-graphite.png");
} }
#urlbar[focused="true"] > #identity-box.verifiedDomain > hbox > #identity-icon-label:-moz-system-metric(mac-graphite-theme) { #urlbar[focused="true"] > #identity-box.verifiedDomain > #identity-box-inner > #identity-icon-label:-moz-system-metric(mac-graphite-theme) {
background-image: url("chrome://browser/skin/urlbar/startcap-secure-end-focused-graphite.png"); background-image: url("chrome://browser/skin/urlbar/startcap-secure-end-focused-graphite.png");
} }
#identity-box.verifiedDomain > hbox > #identity-icon-label[value=""] { #identity-box.verifiedDomain > #identity-box-inner > #identity-icon-label[value=""] {
-moz-padding-start: 3px !important; -moz-padding-start: 3px !important;
-moz-padding-end: 8px !important; -moz-padding-end: 8px !important;
} }
@ -1937,13 +1925,13 @@ tabpanels.plain {
-moz-padding-start: 13px; -moz-padding-start: 13px;
} }
#identity-box.verifiedIdentity > hbox { #identity-box.verifiedIdentity > #identity-box-inner {
padding: 0; padding: 0;
background: url("chrome://browser/skin/urlbar/startcap-verified-mid.png") repeat-x center center; background: url("chrome://browser/skin/urlbar/startcap-verified-mid.png") repeat-x center center;
-moz-box-pack: center; -moz-box-pack: center;
} }
#identity-box.verifiedIdentity > hbox > #identity-icon-label { #identity-box.verifiedIdentity > #identity-box-inner > #identity-icon-label {
background: url("chrome://browser/skin/urlbar/startcap-verified-end.png") no-repeat center right; background: url("chrome://browser/skin/urlbar/startcap-verified-end.png") no-repeat center right;
} }
@ -1953,13 +1941,13 @@ tabpanels.plain {
background-image: url("chrome://browser/skin/urlbar/startcap-verified-start-active.png"); background-image: url("chrome://browser/skin/urlbar/startcap-verified-start-active.png");
} }
#identity-box.verifiedIdentity[open="true"] > hbox, #identity-box.verifiedIdentity[open="true"] > #identity-box-inner,
#identity-box.verifiedIdentity:hover:active > hbox { #identity-box.verifiedIdentity:hover:active > #identity-box-inner {
background: url("chrome://browser/skin/urlbar/startcap-verified-mid-active.png") repeat-x center center; background: url("chrome://browser/skin/urlbar/startcap-verified-mid-active.png") repeat-x center center;
} }
#identity-box.verifiedIdentity[open="true"] > hbox > #identity-icon-label, #identity-box.verifiedIdentity[open="true"] > #identity-box-inner > #identity-icon-label,
#identity-box.verifiedIdentity:hover:active > hbox > #identity-icon-label { #identity-box.verifiedIdentity:hover:active > #identity-box-inner > #identity-icon-label {
background: url("chrome://browser/skin/urlbar/startcap-verified-end-active.png") no-repeat center right; background: url("chrome://browser/skin/urlbar/startcap-verified-end-active.png") no-repeat center right;
} }
@ -1968,11 +1956,11 @@ tabpanels.plain {
background-image: url("chrome://browser/skin/urlbar/startcap-verified-start-focused.png"); background-image: url("chrome://browser/skin/urlbar/startcap-verified-start-focused.png");
} }
#urlbar[focused="true"] > #identity-box.verifiedIdentity > hbox { #urlbar[focused="true"] > #identity-box.verifiedIdentity > #identity-box-inner {
background-image: url("chrome://browser/skin/urlbar/startcap-verified-mid-focused.png"); background-image: url("chrome://browser/skin/urlbar/startcap-verified-mid-focused.png");
} }
#urlbar[focused="true"] > #identity-box.verifiedIdentity > hbox > #identity-icon-label { #urlbar[focused="true"] > #identity-box.verifiedIdentity > #identity-box-inner > #identity-icon-label {
background-image: url("chrome://browser/skin/urlbar/startcap-verified-end-focused.png"); background-image: url("chrome://browser/skin/urlbar/startcap-verified-end-focused.png");
} }
@ -1980,17 +1968,17 @@ tabpanels.plain {
background-image: url("chrome://browser/skin/urlbar/startcap-verified-start-focused-graphite.png"); background-image: url("chrome://browser/skin/urlbar/startcap-verified-start-focused-graphite.png");
} }
#urlbar[focused="true"] > #identity-box.verifiedIdentity > hbox:-moz-system-metric(mac-graphite-theme) { #urlbar[focused="true"] > #identity-box.verifiedIdentity > #identity-box-inner:-moz-system-metric(mac-graphite-theme) {
background-image: url("chrome://browser/skin/urlbar/startcap-verified-mid-focused-graphite.png"); background-image: url("chrome://browser/skin/urlbar/startcap-verified-mid-focused-graphite.png");
} }
#urlbar[focused="true"] > #identity-box.verifiedIdentity > hbox > #identity-icon-label:-moz-system-metric(mac-graphite-theme) { #urlbar[focused="true"] > #identity-box.verifiedIdentity > #identity-box-inner > #identity-icon-label:-moz-system-metric(mac-graphite-theme) {
background-image: url("chrome://browser/skin/urlbar/startcap-verified-end-focused-graphite.png"); background-image: url("chrome://browser/skin/urlbar/startcap-verified-end-focused-graphite.png");
} }
/* Favicon Glow */ /* Favicon Glow */
#identity-box.verifiedIdentity > hbox > #page-proxy-stack, #identity-box.verifiedIdentity > #identity-box-inner > #page-proxy-stack,
#identity-box.verifiedDomain > hbox > #page-proxy-stack { #identity-box.verifiedDomain > #identity-box-inner > #page-proxy-stack {
-moz-margin-start: -3px; -moz-margin-start: -3px;
width: 24px; width: 24px;
height: 20px; height: 20px;
@ -2017,15 +2005,14 @@ tabpanels.plain {
} }
/* Popup Body Text */ /* Popup Body Text */
#identity-popup-content-box > description, .identity-popup-description {
#identity-popup-encryption-label {
white-space: pre-wrap; white-space: pre-wrap;
color: #ffffff; color: #ffffff;
-moz-padding-start: 15px; -moz-padding-start: 15px;
margin: 2px 0 4px; margin: 2px 0 4px;
} }
#identity-popup-content-box > label { .identity-popup-label {
white-space: pre-wrap; white-space: pre-wrap;
-moz-padding-start: 15px; -moz-padding-start: 15px;
margin: 0; margin: 0;
@ -2074,9 +2061,8 @@ tabpanels.plain {
} }
#identity-popup-container { #identity-popup-container {
-moz-appearance: none;
margin: 4px 3px 2px -30px; margin: 4px 3px 2px -30px;
color: #ffffff; color: #fff;
} }
#identity-popup-content-box { #identity-popup-content-box {
@ -2096,7 +2082,7 @@ tabpanels.plain {
padding: 1px 9px; padding: 1px 9px;
margin: 10px 0 0; margin: 10px 0 0;
min-height: 0px; min-height: 0px;
color: #ffffff; color: #fff;
} }
#identity-popup-more-info-button > .button-box > .button-text { #identity-popup-more-info-button > .button-box > .button-text {

View file

@ -184,7 +184,7 @@ treechildren::-moz-tree-cell-text(broken) {
background-color: -moz-field; background-color: -moz-field;
} }
#permList > vbox { .permission {
padding-top: 6px; padding-top: 6px;
padding-bottom: 6px; padding-bottom: 6px;
-moz-padding-start: 7px; -moz-padding-start: 7px;
@ -193,11 +193,11 @@ treechildren::-moz-tree-cell-text(broken) {
border-bottom: 1px dotted #C0C0C0; border-bottom: 1px dotted #C0C0C0;
} }
#permList > vbox > label { .permissionLabel {
font-weight: bold; font-weight: bold;
} }
#permList > vbox:hover { .permission:hover {
background-color: -moz-dialog; background-color: -moz-dialog;
} }

View file

@ -394,10 +394,6 @@ window:not([active="true"]) #placesList > treechildren::-moz-tree-row(selected)
list-style-image: url("chrome://browser/skin/places/expander-open-active.png") !important; list-style-image: url("chrome://browser/skin/places/expander-open-active.png") !important;
} }
.no-margin-button {
min-width:0em;
}
/** /**
* info pane * info pane
*/ */
@ -425,6 +421,6 @@ window:not([active="true"]) #placesList > treechildren::-moz-tree-row(selected)
color: GrayText; color: GrayText;
} }
#editBookmarkPanelGrid > rows > row > label { .editBMPanel_rowLabel {
text-align: right !important; text-align: right !important;
} }

View file

@ -3,11 +3,6 @@
/* Sidebars */ /* Sidebars */
.sidebar-placesTree { .sidebar-placesTree {
border-top: none !important;
}
#sidebar tree,
#sidebar page {
background-color: transparent !important; background-color: transparent !important;
-moz-appearance: none !important; -moz-appearance: none !important;
border: none !important; border: none !important;
@ -15,15 +10,14 @@
#bookmarksPanel, #bookmarksPanel,
#history-panel, #history-panel,
#bookmarksPanel > hbox, #sidebar-search-container {
#history-panel > hbox {
-moz-appearance: none !important; -moz-appearance: none !important;
background-color: transparent !important; background-color: transparent !important;
border-top: none !important; border-top: none !important;
} }
tree.sidebar-placesTree, .sidebar-placesTree,
tree.sidebar-placesTree treechildren::-moz-tree-row { .sidebar-placesTreechildren::-moz-tree-row {
background-color: transparent; background-color: transparent;
border-color: transparent; border-color: transparent;
padding-bottom: 1px; padding-bottom: 1px;
@ -32,47 +26,41 @@ tree.sidebar-placesTree treechildren::-moz-tree-row {
border: none; border: none;
} }
tree.sidebar-placesTree treechildren::-moz-tree-separator { .sidebar-placesTreechildren::-moz-tree-separator {
border-top: 1px solid #505d6d; border-top: 1px solid #505d6d;
margin: 0 10px; margin: 0 10px;
} }
#historyTree, .sidebar-placesTree {
#bookmarks-view {
border-top: 1px solid #bebebe; border-top: 1px solid #bebebe;
} }
#bookmarks-view treechildren::-moz-tree-row(selected), .sidebar-placesTreechildren::-moz-tree-row(selected) {
#historyTree treechildren::-moz-tree-row(selected) {
background: @sidebarItemBackground@; background: @sidebarItemBackground@;
border-top: @sidebarItemBorderTop@; border-top: @sidebarItemBorderTop@;
} }
#bookmarks-view treechildren::-moz-tree-row(selected,focus), .sidebar-placesTreechildren::-moz-tree-row(selected,focus) {
#historyTree treechildren::-moz-tree-row(selected,focus) {
background: @sidebarItemFocusedBackground@; background: @sidebarItemFocusedBackground@;
border-top: @sidebarItemFocusedBorderTop@; border-top: @sidebarItemFocusedBorderTop@;
} }
#bookmarks-view:-moz-system-metric(mac-graphite-theme) treechildren::-moz-tree-row(selected), .sidebar-placesTreechildren::-moz-tree-row(selected):-moz-system-metric(mac-graphite-theme) {
#historyTree:-moz-system-metric(mac-graphite-theme) treechildren::-moz-tree-row(selected) {
background: @sidebarItemGraphiteBackground@; background: @sidebarItemGraphiteBackground@;
border-top: @sidebarItemGraphiteBorderTop@; border-top: @sidebarItemGraphiteBorderTop@;
} }
#bookmarks-view:-moz-system-metric(mac-graphite-theme) treechildren::-moz-tree-row(selected,focus), .sidebar-placesTreechildren::-moz-tree-row(selected,focus):-moz-system-metric(mac-graphite-theme) {
#historyTree:-moz-system-metric(mac-graphite-theme) treechildren::-moz-tree-row(selected,focus) {
background: @sidebarItemGraphiteFocusedBackground@; background: @sidebarItemGraphiteFocusedBackground@;
border-top: @sidebarItemGraphiteFocusedBorderTop@; border-top: @sidebarItemGraphiteFocusedBorderTop@;
} }
tree.sidebar-placesTree treechildren::-moz-tree-cell-text(selected) { .sidebar-placesTreechildren::-moz-tree-cell-text(selected) {
font-weight: bold !important; font-weight: bold !important;
color: #ffffff !important; color: #ffffff !important;
} }
#bookmarksPanel > hbox > label, #sidebar-search-label {
#history-panel > hbox > label {
display: none; display: none;
} }
@ -100,8 +88,8 @@ tree.sidebar-placesTree treechildren::-moz-tree-cell-text(selected) {
-moz-outline-radius: 10px; -moz-outline-radius: 10px;
} }
page > hbox { #sidebar-search-container {
margin: 0 4px 6px 4px; margin: 0 4px 6px;
} }
/* Trees */ /* Trees */

View file

@ -146,7 +146,7 @@ prefpane .groupbox-body {
margin: 0; margin: 0;
} }
#paneTabs > vbox { #tabPrefsBox {
margin: 12px 4px; margin: 12px 4px;
} }

View file

@ -47,11 +47,11 @@
@namespace html url("http://www.w3.org/1999/xhtml"); @namespace html url("http://www.w3.org/1999/xhtml");
#urlbar:-moz-lwtheme:not([focused="true"]), #urlbar:-moz-lwtheme:not([focused="true"]),
#searchbar:-moz-lwtheme > textbox:not([focused="true"]) { .searchbar-textbox:-moz-lwtheme:not([focused="true"]) {
opacity: .85; opacity: .85;
} }
.tabbrowser-tab[selected="true"]:-moz-lwtheme { .tabbrowser-tab:-moz-lwtheme[selected="true"] {
text-shadow: none; text-shadow: none;
} }
@ -69,7 +69,7 @@
-moz-box-orient: vertical; /* for flex hack */ -moz-box-orient: vertical; /* for flex hack */
} }
#menubar-items > menubar { #main-menubar {
-moz-box-flex: 1; /* make menu items expand to fill toolbar height */ -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
} }
@ -77,10 +77,6 @@
min-height: 24px; min-height: 24px;
} }
#wrapper-search-container #searchbar html|*.textbox-input {
visibility: hidden;
}
#navigator-toolbox:-moz-system-metric(windows-default-theme) { #navigator-toolbox:-moz-system-metric(windows-default-theme) {
padding-bottom: 1px; /* uxtheme border drawing fix/hack */ padding-bottom: 1px; /* uxtheme border drawing fix/hack */
} }
@ -1766,14 +1762,13 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
} }
/* Popup Body Text */ /* Popup Body Text */
#identity-popup-content-box > description, .identity-popup-description {
#identity-popup-encryption-label {
white-space: pre-wrap; white-space: pre-wrap;
-moz-padding-start: 15px; -moz-padding-start: 15px;
margin: 2px 0 4px; margin: 2px 0 4px;
} }
#identity-popup-content-box > label { .identity-popup-label {
white-space: pre-wrap; white-space: pre-wrap;
-moz-padding-start: 15px; -moz-padding-start: 15px;
margin: 0; margin: 0;
@ -1835,7 +1830,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
} }
#identity-popup-container { #identity-popup-container {
background-image: none;
min-width: 280px; min-width: 280px;
padding: 9px; padding: 9px;
} }

View file

@ -40,7 +40,7 @@
@import "chrome://global/skin/"; @import "chrome://global/skin/";
/* View buttons */ /* View buttons */
#viewGroup radio { #viewGroup > radio {
list-style-image: url("chrome://browser/skin/pageInfo.png"); list-style-image: url("chrome://browser/skin/pageInfo.png");
-moz-box-orient: vertical; -moz-box-orient: vertical;
-moz-box-align: center; -moz-box-align: center;
@ -234,7 +234,7 @@ treechildren::-moz-tree-cell-text(broken) {
background-color: -moz-field; background-color: -moz-field;
} }
#permList > vbox { .permission {
padding-top: 6px; padding-top: 6px;
padding-bottom: 6px; padding-bottom: 6px;
-moz-padding-start: 7px; -moz-padding-start: 7px;
@ -243,11 +243,11 @@ treechildren::-moz-tree-cell-text(broken) {
border-bottom: 1px dotted #C0C0C0; border-bottom: 1px dotted #C0C0C0;
} }
#permList > vbox > label { .permissionLabel {
font-weight: bold; font-weight: bold;
} }
#permList > vbox:hover { .permission:hover {
background-color: -moz-dialog; background-color: -moz-dialog;
} }

View file

@ -60,8 +60,8 @@
-moz-margin-end: 4px; -moz-margin-end: 4px;
} }
.expander-up > hbox, .expander-up > .button-box,
.expander-down > hbox { .expander-down > .button-box {
padding: 0; padding: 0;
} }

View file

@ -21,7 +21,7 @@
color: -moz-win-mediatext; color: -moz-win-mediatext;
} }
#placesMenu:-moz-system-metric(windows-default-theme) > menu > label { #placesMenu > menu > .menubar-text:-moz-system-metric(windows-default-theme) {
-moz-padding-end: 15px; -moz-padding-end: 15px;
background-image: url(chrome://browser/skin/places/dropDown.png); background-image: url(chrome://browser/skin/places/dropDown.png);
} }

View file

@ -13,8 +13,8 @@
border: none; border: none;
} }
#placesToolbar > toolbarbutton > image, #placesToolbar > toolbarbutton > .toolbarbutton-icon,
#placesToolbar > toolbarbutton > label { #placesToolbar > toolbarbutton > .toolbarbutton-text {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
@ -89,12 +89,12 @@
padding-bottom: 1px; padding-bottom: 1px;
} }
#placesMenu > menu > label { #placesMenu > menu > .menubar-text {
-moz-padding-end: 8px; -moz-padding-end: 8px;
background: url(chrome://global/skin/arrow/arrow-dn.gif) right center no-repeat; background: url(chrome://global/skin/arrow/arrow-dn.gif) right center no-repeat;
} }
#placesMenu:-moz-locale-dir(rtl) > menu > label { #placesMenu > menu > .menubar-text:-moz-locale-dir(rtl) {
background-position: left center; background-position: left center;
} }
@ -171,13 +171,12 @@
margin: 0 1px; margin: 0 1px;
} }
#organizerScopeBar > toolbarbutton > label, #organizerScopeBar > toolbarbutton > .toolbarbutton-icon {
#organizerScopeBar > toolbarbutton > image {
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
#organizerScopeBar .toolbarbutton-text { #organizerScopeBar > toolbarbutton > .toolbarbutton-text {
margin: 0; margin: 0;
padding: 2px 5px; padding: 2px 5px;
} }

View file

@ -133,7 +133,7 @@ treechildren::-moz-tree-cell-text(date, session-continue) {
margin-bottom: 2px; margin-bottom: 2px;
} }
#viewButton > hbox > dropmarker { #viewButton > .button-box > .button-menu-dropmarker {
height: auto; height: auto;
width: auto; width: auto;
-moz-margin-end: -3px; -moz-margin-end: -3px;

View file

@ -59,8 +59,8 @@
margin: 0; margin: 0;
} }
.expander-up > hbox, .expander-up > .button-box,
.expander-down > hbox { .expander-down > .button-box {
padding: 0; padding: 0;
} }

View file

@ -335,7 +335,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
for v in extraPrefs: for v in extraPrefs:
thispref = v.split("=") thispref = v.split("=")
if len(thispref) < 2: if len(thispref) < 2:
print "Error: syntax error in --extra-pref=" + v print "Error: syntax error in --setpref=" + v
sys.exit(1) sys.exit(1)
part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1]) part = 'user_pref("%s", %s);\n' % (thispref[0], thispref[1])
prefs.append(part) prefs.append(part)

View file

@ -1,2 +1,2 @@
repo: f5ab154deef2ffa97f1b2139589ae4a1962090a4 repo: f5ab154deef2ffa97f1b2139589ae4a1962090a4
node: 0aa14be496b38ea56b28158f375d01dc0cb91d1f node: 3476582628db128ad061c30cab1a74a0c5d14b9b

View file

@ -1008,7 +1008,7 @@ class Target(object):
makefile.context.defer(cb, error=self.error, didanything=self.didanything) makefile.context.defer(cb, error=self.error, didanything=self.didanything)
del self._callbacks del self._callbacks
def make(self, makefile, targetstack, cb, avoidremakeloop=False): def make(self, makefile, targetstack, cb, avoidremakeloop=False, printerror=True):
""" """
If we are out of date, asynchronously make ourself. This is a multi-stage process, mostly handled If we are out of date, asynchronously make ourself. This is a multi-stage process, mostly handled
by the helper objects RemakeTargetSerially, RemakeTargetParallel, by the helper objects RemakeTargetSerially, RemakeTargetParallel,
@ -1051,7 +1051,8 @@ class Target(object):
try: try:
self.resolvedeps(makefile, targetstack, [], False) self.resolvedeps(makefile, targetstack, [], False)
except util.MakeError, e: except util.MakeError, e:
print e if printerror:
print e
self.error = True self.error = True
self.notifydone(makefile) self.notifydone(makefile)
return return
@ -1312,7 +1313,7 @@ class _RemakeContext(object):
if len(self.toremake): if len(self.toremake):
target, self.required = self.toremake.pop(0) target, self.required = self.toremake.pop(0)
target.make(self.makefile, [], avoidremakeloop=True, cb=self.remakecb) target.make(self.makefile, [], avoidremakeloop=True, cb=self.remakecb, printerror=False)
else: else:
for t, required in self.included: for t, required in self.included:
if t.wasremade: if t.wasremade:

View file

@ -71,7 +71,7 @@ class Data(object):
""" """
m = _skipws.search(self.s, offset, self.lend) m = _skipws.search(self.s, offset, self.lend)
if m is None: if m is None:
return None return self.lend
return m.start(0) return m.start(0)

View file

@ -2,7 +2,7 @@ import os
class MakeError(Exception): class MakeError(Exception):
def __init__(self, message, loc=None): def __init__(self, message, loc=None):
self.message = message self.msg = message
self.loc = loc self.loc = loc
def __str__(self): def __str__(self):
@ -10,7 +10,7 @@ class MakeError(Exception):
if self.loc is not None: if self.loc is not None:
locstr = "%s:" % (self.loc,) locstr = "%s:" % (self.loc,)
return "%s%s" % (locstr, self.message) return "%s%s" % (locstr, self.msg)
def joiniter(fd, it): def joiniter(fd, it):
""" """
@ -32,6 +32,8 @@ def checkmsyscompat():
letting Python use the system shell.""" letting Python use the system shell."""
if 'SHELL' in os.environ: if 'SHELL' in os.environ:
shell = os.environ['SHELL'] shell = os.environ['SHELL']
elif 'MOZILLABUILD' in os.environ:
shell = os.environ['MOZILLABUILD'] + '/msys/bin/sh.exe'
elif 'COMSPEC' in os.environ: elif 'COMSPEC' in os.environ:
shell = os.environ['COMSPEC'] shell = os.environ['COMSPEC']
else: else:

View file

@ -0,0 +1,5 @@
all:
@echo TEST-PASS
foo: ;

View file

@ -0,0 +1,4 @@
-include TEST-FAIL.mk
all:
@echo TEST-PASS

View file

@ -73,7 +73,7 @@ while (<>) {
my @deps = split /\s+/, $rest; my @deps = split /\s+/, $rest;
push @{$alldeps{$obj}}, @deps; push @{$alldeps{$obj}}, @deps;
if (DEBUG >= 2) { if (DEBUG >= 2) {
foreach my $dep (@deps) { print "add $obj $dep\n"; } foreach my $dep (@deps) { print STDERR "add $obj $dep\n"; }
} }
} }
@ -88,21 +88,21 @@ OBJ_LOOP: foreach my $obj (keys %alldeps) {
foreach my $dep_file (@{$deps}) { foreach my $dep_file (@{$deps}) {
my $dep_mtime = $modtimes{$dep_file}; my $dep_mtime = $modtimes{$dep_file};
if (not defined $dep_mtime) { if (not defined $dep_mtime) {
print "Skipping $dep_file for $obj, will stat() later\n" if DEBUG >= 2; print STDERR "Skipping $dep_file for $obj, will stat() later\n" if DEBUG >= 2;
$not_in_cache{$dep_file} = 1; $not_in_cache{$dep_file} = 1;
next; next;
} }
print "Found $dep_file in cache\n" if DEBUG >= 2; print STDERR "Found $dep_file in cache\n" if DEBUG >= 2;
if ($dep_mtime > $mtime) { if ($dep_mtime > $mtime) {
print "$dep_file($dep_mtime) newer than $obj($mtime)\n" if DEBUG; print STDERR "$dep_file($dep_mtime) newer than $obj($mtime)\n" if DEBUG;
} }
elsif ($dep_mtime == -1) { elsif ($dep_mtime == -1) {
print "Couldn't stat $dep_file for $obj\n" if DEBUG; print STDERR "Couldn't stat $dep_file for $obj\n" if DEBUG;
} }
else { else {
print "$dep_file($dep_mtime) older than $obj($mtime)\n" if DEBUG >= 2; print STDERR "$dep_file($dep_mtime) older than $obj($mtime)\n" if DEBUG >= 2;
next; next;
} }
@ -111,17 +111,17 @@ OBJ_LOOP: foreach my $obj (keys %alldeps) {
} }
foreach my $dep_file (keys %not_in_cache) { foreach my $dep_file (keys %not_in_cache) {
print "STAT $dep_file for $obj\n" if DEBUG >= 2; print STDERR "STAT $dep_file for $obj\n" if DEBUG >= 2;
my $dep_mtime = $modtimes{$dep_file} = (stat $dep_file)[9] || -1; my $dep_mtime = $modtimes{$dep_file} = (stat $dep_file)[9] || -1;
if ($dep_mtime > $mtime) { if ($dep_mtime > $mtime) {
print "$dep_file($dep_mtime) newer than $obj($mtime)\n" if DEBUG; print STDERR "$dep_file($dep_mtime) newer than $obj($mtime)\n" if DEBUG;
} }
elsif ($dep_mtime == -1) { elsif ($dep_mtime == -1) {
print "Couldn't stat $dep_file for $obj\n" if DEBUG; print STDERR "Couldn't stat $dep_file for $obj\n" if DEBUG;
} }
else { else {
print "$dep_file($dep_mtime) older than $obj($mtime)\n" if DEBUG >= 2; print STDERR "$dep_file($dep_mtime) older than $obj($mtime)\n" if DEBUG >= 2;
next; next;
} }
@ -133,7 +133,11 @@ OBJ_LOOP: foreach my $obj (keys %alldeps) {
} }
# Output objects to rebuild (if needed). # Output objects to rebuild (if needed).
if (@objs) { if ($outfile eq '-') {
if (@objs) {
print "@objs: FORCE\n";
}
} elsif (@objs) {
my $old_output; my $old_output;
my $new_output = "@objs: FORCE\n"; my $new_output = "@objs: FORCE\n";

View file

@ -39,7 +39,6 @@ cmdname=`basename "$0"`
MOZ_DIST_BIN=`dirname "$0"` MOZ_DIST_BIN=`dirname "$0"`
MOZ_DEFAULT_NAME="./${cmdname}-bin" MOZ_DEFAULT_NAME="./${cmdname}-bin"
MOZ_APPRUNNER_NAME="./mozilla-bin" MOZ_APPRUNNER_NAME="./mozilla-bin"
MOZ_VIEWER_NAME="./viewer"
MOZ_PROGRAM="" MOZ_PROGRAM=""
exitcode=1 exitcode=1
@ -62,18 +61,10 @@ echo " --debugger debugger"
echo "" echo ""
echo " Examples:" echo " Examples:"
echo "" echo ""
echo " Run the viewer"
echo ""
echo " ${cmdname} viewer"
echo ""
echo " Run the mozilla-bin binary" echo " Run the mozilla-bin binary"
echo "" echo ""
echo " ${cmdname} mozilla-bin" echo " ${cmdname} mozilla-bin"
echo "" echo ""
echo " Debug the viewer in a debugger"
echo ""
echo " ${cmdname} -g viewer"
echo ""
echo " Debug the mozilla-bin binary in gdb" echo " Debug the mozilla-bin binary in gdb"
echo "" echo ""
echo " ${cmdname} -g mozilla-bin -d gdb" echo " ${cmdname} -g mozilla-bin -d gdb"
@ -239,11 +230,6 @@ then
if [ -x "$MOZ_DEFAULT_NAME" ] if [ -x "$MOZ_DEFAULT_NAME" ]
then then
MOZ_PROGRAM=$MOZ_DEFAULT_NAME MOZ_PROGRAM=$MOZ_DEFAULT_NAME
## Try viewer (this should be deprecated)
##
elif [ -x "$MOZ_VIEWER_NAME" ]
then
MOZ_PROGRAM=$MOZ_VIEWER_NAME
## ##
## Try mozilla-bin ## Try mozilla-bin
## ##

View file

@ -250,6 +250,7 @@ class JarMaker(object):
that against the l10nbases. l10nbases can either be path strings, or that against the l10nbases. l10nbases can either be path strings, or
callables. In the latter case, that will be called with the callables. In the latter case, that will be called with the
relativesrcdir as argument, and is expected to return a path string. relativesrcdir as argument, and is expected to return a path string.
This logic is disabled if the jar.mn path is not inside the topsrcdir.
''' '''
topsourcedir = os.path.normpath(os.path.abspath(topsourcedir)) topsourcedir = os.path.normpath(os.path.abspath(topsourcedir))
def resolveL10nBase(relpath): def resolveL10nBase(relpath):
@ -265,13 +266,18 @@ class JarMaker(object):
l10ndir = srcdir l10ndir = srcdir
if os.path.basename(srcdir) == 'locales': if os.path.basename(srcdir) == 'locales':
l10ndir = os.path.dirname(l10ndir) l10ndir = os.path.dirname(l10ndir)
assert srcdir.startswith(topsourcedir), "src dir %s not in topsourcedir %s" % (srcdir, topsourcedir)
rell10ndir = l10ndir[len(topsourcedir):].lstrip(os.sep) l10ndirs = None
# srcdir may not be a child of topsourcedir, in which case
l10ndirs = map(resolveL10nBase(rell10ndir), l10nbases) # we assume that the caller passed in suitable sourcedirs,
if localedirs is not None: # and just skip passing in localedirs
l10ndirs += [os.path.normpath(os.path.abspath(s)) if srcdir.startswith(topsourcedir):
for s in localedirs] rell10ndir = l10ndir[len(topsourcedir):].lstrip(os.sep)
l10ndirs = map(resolveL10nBase(rell10ndir), l10nbases)
if localedirs is not None:
l10ndirs += [os.path.normpath(os.path.abspath(s))
for s in localedirs]
srcdirs = [os.path.normpath(os.path.abspath(s)) srcdirs = [os.path.normpath(os.path.abspath(s))
for s in sourcedirs] + [srcdir] for s in sourcedirs] + [srcdir]
self.makeJar(infile=infile, self.makeJar(infile=infile,
@ -375,7 +381,7 @@ class JarMaker(object):
if realsrc is None: if realsrc is None:
if jf is not None: if jf is not None:
jf.close() jf.close()
raise RuntimeError("file not found: " + src) raise RuntimeError('File "%s" not found in %s' % (src, ', '.join(src_base)))
if m.group('optPreprocess'): if m.group('optPreprocess'):
outf = outHelper.getOutput(out) outf = outHelper.getOutput(out)
inf = open(realsrc) inf = open(realsrc)

View file

@ -157,8 +157,13 @@ clean clobber realclean clobber_all::
cd $(MKDEPEND_DIR); $(MAKE) $@ cd $(MKDEPEND_DIR); $(MAKE) $@
endif endif
PYUNITS := unit-Expression.py unit-Preprocessor.py unit-nsinstall.py \ PYUNITS := \
unit-printprereleasesuffix.py unit-Expression.py \
unit-Preprocessor.py \
unit-nsinstall.py \
unit-printprereleasesuffix.py \
unit-JarMaker.py \
$(NULL)
check:: check-python-modules check-jar-mn check:: check-python-modules check-jar-mn

View file

@ -51,6 +51,7 @@ MOZ_BUILD_APP = @MOZ_BUILD_APP@
MOZ_APP_NAME = @MOZ_APP_NAME@ MOZ_APP_NAME = @MOZ_APP_NAME@
MOZ_APP_DISPLAYNAME = @MOZ_APP_DISPLAYNAME@ MOZ_APP_DISPLAYNAME = @MOZ_APP_DISPLAYNAME@
MOZ_APP_VERSION = @MOZ_APP_VERSION@ MOZ_APP_VERSION = @MOZ_APP_VERSION@
MOZ_APP_UA_EXTRA = @MOZ_APP_UA_EXTRA@
MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@ MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@
@ -168,6 +169,7 @@ MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@
MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@ MOZ_HELP_VIEWER = @MOZ_HELP_VIEWER@
MOC= @MOC@ MOC= @MOC@
MOZ_NSS_PATCH = @MOZ_NSS_PATCH@ MOZ_NSS_PATCH = @MOZ_NSS_PATCH@
MOZ_WEBGL = @MOZ_WEBGL@
MOZ_JAVAXPCOM = @MOZ_JAVAXPCOM@ MOZ_JAVAXPCOM = @MOZ_JAVAXPCOM@
JAVA_INCLUDE_PATH="@JAVA_INCLUDE_PATH@" JAVA_INCLUDE_PATH="@JAVA_INCLUDE_PATH@"

66
config/mozunit.py Normal file
View file

@ -0,0 +1,66 @@
from unittest import TextTestRunner as _TestRunner, TestResult as _TestResult
import inspect
'''Helper to make python unit tests report the way that the Mozilla
unit test infrastructure expects tests to report.
Usage:
import unittest
from mozunit import MozTestRunner
if __name__ == '__main__':
unittest.main(testRunner=MozTestRunner())
'''
class _MozTestResult(_TestResult):
def __init__(self, stream, descriptions):
_TestResult.__init__(self)
self.stream = stream
self.descriptions = descriptions
def getDescription(self, test):
if self.descriptions:
return test.shortDescription() or str(test)
else:
return str(test)
def addSuccess(self, test):
_TestResult.addSuccess(self, test)
filename = inspect.getfile(test.__class__)
testname = test._testMethodName
self.stream.writeln("TEST-PASS | %s | %s" % (filename, testname))
def addError(self, test, err):
_TestResult.addError(self, test, err)
self.printFail(test, err)
def addFailure(self, test, err):
_TestResult.addFailure(self, test, err)
self.printFail(test,err)
def printFail(self, test, err):
exctype, value, tb = err
# Skip test runner traceback levels
while tb and self._is_relevant_tb_level(tb):
tb = tb.tb_next
if not tb:
self.stream.writeln("TEST-UNEXPECTED-FAIL | NO TRACEBACK |")
_f, _ln, _t = inspect.getframeinfo(tb)[:3]
self.stream.writeln("TEST-UNEXPECTED-FAIL | %s | line %d, %s: %s" %
(_f, _ln, _t, value.message))
def printErrorList(self):
for test, err in self.errors:
self.stream.writeln("ERROR: %s" % self.getDescription(test))
self.stream.writeln("%s" % err)
class MozTestRunner(_TestRunner):
def _makeResult(self):
return _MozTestResult(self.stream, self.descriptions)
def run(self, test):
result = self._makeResult()
test(result)
result.printErrorList()
return result

View file

@ -360,6 +360,10 @@ endif # GNU_CC
endif # ENABLE_CXX_EXCEPTIONS endif # ENABLE_CXX_EXCEPTIONS
endif # WINNT endif # WINNT
ifeq ($(SOLARIS_SUNPRO_CXX),1)
CXXFLAGS += -features=extensions -D__FUNCTION__=__func__
endif # Solaris Sun Studio C++
ifeq (,$(filter-out WINNT WINCE,$(HOST_OS_ARCH))) ifeq (,$(filter-out WINNT WINCE,$(HOST_OS_ARCH)))
HOST_PDBFILE=$(basename $(@F)).pdb HOST_PDBFILE=$(basename $(@F)).pdb
endif endif
@ -2064,21 +2068,14 @@ ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
MDDEPEND_FILES := $(strip $(wildcard $(MDDEPDIR)/*.pp)) MDDEPEND_FILES := $(strip $(wildcard $(MDDEPDIR)/*.pp))
ifneq (,$(MDDEPEND_FILES)) ifneq (,$(MDDEPEND_FILES))
ifdef PERL
# The script mddepend.pl checks the dependencies and writes to stdout # The script mddepend.pl checks the dependencies and writes to stdout
# one rule to force out-of-date objects. For example, # one rule to force out-of-date objects. For example,
# foo.o boo.o: FORCE # foo.o boo.o: FORCE
# The script has an advantage over including the *.pp files directly # The script has an advantage over including the *.pp files directly
# because it handles the case when header files are removed from the build. # because it handles the case when header files are removed from the build.
# 'make' would complain that there is no way to build missing headers. # 'make' would complain that there is no way to build missing headers.
ifeq (,$(MAKE_RESTARTS)) ALL_PP_RESULTS = $(shell $(PERL) $(BUILD_TOOLS)/mddepend.pl - $(MDDEPEND_FILES))
$(MDDEPDIR)/.all.pp: FORCE $(eval $(ALL_PP_RESULTS))
@$(PERL) $(BUILD_TOOLS)/mddepend.pl $@ $(MDDEPEND_FILES)
endif
-include $(MDDEPDIR)/.all.pp
else
include $(MDDEPEND_FILES)
endif
endif endif
endif endif

View file

@ -0,0 +1,161 @@
import unittest
import os, sys, os.path, time, inspect
from filecmp import dircmp
from tempfile import mkdtemp
from shutil import rmtree, copy2
from zipfile import ZipFile
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from mozunit import MozTestRunner
from JarMaker import JarMaker
class _TreeDiff(dircmp):
"""Helper to report rich results on difference between two directories.
"""
def _fillDiff(self, dc, rv, basepath="%s"):
rv['right_only'] += map(lambda l: basepath % l, dc.right_only)
rv['left_only'] += map(lambda l: basepath % l, dc.left_only)
rv['diff_files'] += map(lambda l: basepath % l, dc.diff_files)
rv['funny'] += map(lambda l: basepath % l, dc.common_funny)
rv['funny'] += map(lambda l: basepath % l, dc.funny_files)
for subdir, _dc in dc.subdirs.iteritems():
self._fillDiff(_dc, rv, basepath % (subdir + "/%s"))
def allResults(self, left, right):
rv = {'right_only':[], 'left_only':[],
'diff_files':[], 'funny': []}
self._fillDiff(self, rv)
chunks = []
if rv['right_only']:
chunks.append('%s only in %s' % (', '.join(rv['right_only']),
right))
if rv['left_only']:
chunks.append('%s only in %s' % (', '.join(rv['left_only']),
left))
if rv['diff_files']:
chunks.append('%s differ' % ', '.join(rv['diff_files']))
if rv['funny']:
chunks.append("%s don't compare" % ', '.join(rv['funny']))
return '; '.join(chunks)
class TestJarMaker(unittest.TestCase):
"""
Unit tests for JarMaker.py
"""
debug = False # set to True to debug failing tests on disk
def setUp(self):
self.tmpdir = mkdtemp()
self.srcdir = os.path.join(self.tmpdir, 'src')
os.mkdir(self.srcdir)
self.builddir = os.path.join(self.tmpdir, 'build')
os.mkdir(self.builddir)
self.refdir = os.path.join(self.tmpdir, 'ref')
os.mkdir(self.refdir)
self.stagedir = os.path.join(self.tmpdir, 'stage')
os.mkdir(self.stagedir)
def tearDown(self):
if self.debug:
print self.tmpdir
else:
rmtree(self.tmpdir)
def _jar_and_compare(self, *args, **kwargs):
jm = JarMaker(outputFormat='jar')
kwargs['jardir'] = os.path.join(self.builddir, 'chrome')
if 'topsourcedir' not in kwargs:
kwargs['topsourcedir'] = self.srcdir
jm.makeJars(*args, **kwargs)
cwd = os.getcwd()
os.chdir(self.builddir)
try:
# expand build to stage
for path, dirs, files in os.walk('.'):
stagedir = os.path.join(self.stagedir, path)
if not os.path.isdir(stagedir):
os.mkdir(stagedir)
for file in files:
if file.endswith('.jar'):
# expand jar
stagepath = os.path.join(stagedir, file)
os.mkdir(stagepath)
zf = ZipFile(os.path.join(path, file))
# extractall is only in 2.6, do this manually :-(
for entry_name in zf.namelist():
segs = entry_name.split('/')
fname = segs.pop()
dname = os.path.join(stagepath, *segs)
if not os.path.isdir(dname):
os.makedirs(dname)
if not fname:
# directory, we're done
continue
_c = zf.read(entry_name)
open(os.path.join(dname, fname), 'wb').write(_c)
zf.close()
else:
copy2(os.path.join(path, file), stagedir)
# compare both dirs
os.chdir('..')
td = _TreeDiff('ref', 'stage')
return td.allResults('reference', 'build')
finally:
os.chdir(cwd)
def test_a_simple_jar(self):
'''Test a simple jar.mn'''
# create src content
jarf = open(os.path.join(self.srcdir, 'jar.mn'), 'w')
jarf.write('''test.jar:
dir/foo (bar)
''')
jarf.close()
open(os.path.join(self.srcdir,'bar'),'w').write('content\n')
# create reference
refpath = os.path.join(self.refdir, 'chrome', 'test.jar', 'dir')
os.makedirs(refpath)
open(os.path.join(refpath, 'foo'), 'w').write('content\n')
# call JarMaker
rv = self._jar_and_compare((os.path.join(self.srcdir,'jar.mn'),),
tuple(),
sourcedirs = [self.srcdir])
self.assertTrue(not rv, rv)
def test_k_multi_relative_jar(self):
'''Test the API for multiple l10n jars, with different relative paths'''
# create app src content
def _mangle(relpath):
'method we use to map relpath to srcpaths'
return os.path.join(self.srcdir, 'other-' + relpath)
jars = []
for relpath in ('foo', 'bar'):
ldir = os.path.join(self.srcdir, relpath, 'locales')
os.makedirs(ldir)
jp = os.path.join(ldir, 'jar.mn')
jars.append(jp)
open(jp, 'w').write('''ab-CD.jar:
% locale app ab-CD %app
app/''' + relpath + ' (%' + relpath + ''')
''')
ldir = _mangle(relpath)
os.mkdir(ldir)
open(os.path.join(ldir, relpath), 'w').write(relpath+" content\n")
# create reference
chrome_ref = os.path.join(self.refdir, 'chrome')
os.mkdir(chrome_ref)
mf = open(os.path.join(chrome_ref, 'ab-CD.manifest'), 'wb')
mf.write('locale app ab-CD jar:ab-CD.jar!/app\n')
mf.close()
ldir = os.path.join(chrome_ref, 'ab-CD.jar', 'app')
os.makedirs(ldir)
for relpath in ('foo', 'bar'):
open(os.path.join(ldir, relpath), 'w').write(relpath+" content\n")
# call JarMaker
difference = self._jar_and_compare(jars,
(_mangle,),
sourcedirs = [])
self.assertTrue(not difference, difference)
if __name__ == '__main__':
unittest.main(testRunner=MozTestRunner())

View file

@ -288,18 +288,18 @@ case "$target" in
ac_exeext=.exe ac_exeext=.exe
_pwdw=`pwd -W` _pwd=`pwd -W`
_pwd=`pwd` _topsrcdirwin=`cd \`dirname $0\`; pwd -W`
make OGLES_SDK_DIR="$OGLES_SDK_DIR" WINCE_SDK_DIR="$WINCE_SDK_DIR" TOPSRCDIR="$_topsrcdir" OBJDIR="$_pwdw" -C $srcdir/build/wince/tools make OGLES_SDK_DIR="$OGLES_SDK_DIR" WINCE_SDK_DIR="$WINCE_SDK_DIR" TOPSRCDIR="$_topsrcdirwin" OBJDIR="$_pwd" -C $srcdir/build/wince/tools
CC="$_pwd/dist/sdk/bin/arm-wince-gcc" CC="$_pwd/dist/sdk/bin/arm-wince-gcc.exe"
CXX="$_pwd/dist/sdk/bin/arm-wince-gcc" CXX="$_pwd/dist/sdk/bin/arm-wince-gcc.exe"
CPP="$_pwd/dist/sdk/bin/arm-wince-gcc -E -nologo" CPP="$_pwd/dist/sdk/bin/arm-wince-gcc.exe -E -nologo"
CXXCPP="$_pwd/dist/sdk/bin/arm-wince-gcc -TP -E -nologo" CXXCPP="$_pwd/dist/sdk/bin/arm-wince-gcc.exe -TP -E -nologo"
LD="$_pwd/dist/sdk/bin/arm-wince-link" LD="$_pwd/dist/sdk/bin/arm-wince-link.exe"
AR="$_pwd/dist/sdk/bin/arm-wince-lib" AR="$_pwd/dist/sdk/bin/arm-wince-lib.exe"
AS="$_pwd/dist/sdk/bin/arm-wince-as" AS="$_pwd/dist/sdk/bin/arm-wince-as.exe"
RC="$_pwd/dist/sdk/bin/arm-wince-res" RC="$_pwd/dist/sdk/bin/arm-wince-res.exe"
echo ----------------------------------------------------------------------------- echo -----------------------------------------------------------------------------
@ -508,7 +508,7 @@ MOZ_ARG_DISABLE_BOOL(vista-sdk-requirements,
[ --disable-vista-sdk-requirements [ --disable-vista-sdk-requirements
Do not build Vista SDK specific code], Do not build Vista SDK specific code],
MOZ_DISABLE_VISTA_SDK_REQUIREMENTS=1, MOZ_DISABLE_VISTA_SDK_REQUIREMENTS=1,
MOZ_DISABLE_VISTA_SDK_REQUIREMENTS=) MOZ_DISABLE_VISTA_SDK_REQUIREMENTS=$_PLATFORM_MOZ_DISABLE_VISTA_SDK_REQUIREMENTS)
if test -n "$COMPILE_ENVIRONMENT"; then if test -n "$COMPILE_ENVIRONMENT"; then
if test -n "$MOZ_DISABLE_VISTA_SDK_REQUIREMENTS"; then if test -n "$MOZ_DISABLE_VISTA_SDK_REQUIREMENTS"; then
AC_MSG_WARN([--disable-vista-sdk-requirements is deprecated, use --with-windows-version=502 instead]) AC_MSG_WARN([--disable-vista-sdk-requirements is deprecated, use --with-windows-version=502 instead])
@ -2004,7 +2004,10 @@ case "$target" in
*-wince*) *-wince*)
TARGET_COMPILER_ABI=msvc TARGET_COMPILER_ABI=msvc
MOZ_TOOLS_DIR=`echo $MOZ_TOOLS` _PLATFORM_DEFAULT_TOOLKIT=cairo-windows
_PLATFORM_MOZ_DISABLE_VISTA_SDK_REQUIREMENTS=1
MOZ_TOOLS_DIR=`cd $MOZ_TOOLS && pwd -W`
MOZ_BUILD_ROOT=`cd $MOZ_BUILD_ROOT && pwd -W`
AR_LIST="$AR -list" AR_LIST="$AR -list"
AR_EXTRACT="$AR -extract" AR_EXTRACT="$AR -extract"
AR_DELETE="$AR d" AR_DELETE="$AR d"
@ -3346,7 +3349,7 @@ AC_MSG_CHECKING(for ARM NEON support in compiler)
_SAVE_CFLAGS="$CFLAGS" _SAVE_CFLAGS="$CFLAGS"
if test "$GNU_CC"; then if test "$GNU_CC"; then
# gcc needs -mfpu=neon to recognize NEON instructions # gcc needs -mfpu=neon to recognize NEON instructions
CFLAGS="$CFLAGS -mfpu=neon" CFLAGS="$CFLAGS -mfpu=neon -mfloat-abi=softfp"
fi fi
AC_TRY_COMPILE([], AC_TRY_COMPILE([],
[asm("vadd.i8 d0, d0, d0");], [asm("vadd.i8 d0, d0, d0");],
@ -4743,12 +4746,16 @@ photon)
cairo-windows) cairo-windows)
MOZ_WIDGET_TOOLKIT=windows MOZ_WIDGET_TOOLKIT=windows
if test -z "$WINCE"; then
MOZ_WEBGL=1
fi
;; ;;
cairo-gtk2|cairo-gtk2-x11) cairo-gtk2|cairo-gtk2-x11)
MOZ_WIDGET_TOOLKIT=gtk2 MOZ_WIDGET_TOOLKIT=gtk2
MOZ_ENABLE_GTK2=1 MOZ_ENABLE_GTK2=1
MOZ_ENABLE_XREMOTE=1 MOZ_ENABLE_XREMOTE=1
MOZ_WEBGL=1
AC_DEFINE(MOZ_X11) AC_DEFINE(MOZ_X11)
MOZ_X11=1 MOZ_X11=1
@ -4761,6 +4768,7 @@ cairo-gtk2|cairo-gtk2-x11)
cairo-gtk2-dfb) cairo-gtk2-dfb)
MOZ_WIDGET_TOOLKIT=gtk2 MOZ_WIDGET_TOOLKIT=gtk2
MOZ_ENABLE_GTK2=1 MOZ_ENABLE_GTK2=1
MOZ_WEBGL=1
AC_DEFINE(MOZ_DFB) AC_DEFINE(MOZ_DFB)
MOZ_DFB=1 MOZ_DFB=1
@ -4813,6 +4821,7 @@ cairo-cocoa)
CXXFLAGS="$CXXFLAGS $TK_CFLAGS" CXXFLAGS="$CXXFLAGS $TK_CFLAGS"
LIBXUL_LIBS='$(XPCOM_FROZEN_LDOPTS) $(LIBXUL_DIST)/bin/XUL -lobjc' LIBXUL_LIBS='$(XPCOM_FROZEN_LDOPTS) $(LIBXUL_DIST)/bin/XUL -lobjc'
MOZ_FS_LAYOUT=bundle MOZ_FS_LAYOUT=bundle
MOZ_WEBGL=1
;; ;;
esac esac
@ -6235,6 +6244,7 @@ if test $NS_OSSO; then
fi fi
AC_DEFINE(NS_OSSO) AC_DEFINE(NS_OSSO)
MOZ_GFX_OPTIMIZE_MOBILE=1 MOZ_GFX_OPTIMIZE_MOBILE=1
MOZ_WEBGL=
fi fi
AC_SUBST(LIBOSSO_CFLAGS) AC_SUBST(LIBOSSO_CFLAGS)
AC_SUBST(LIBOSSO_LIBS) AC_SUBST(LIBOSSO_LIBS)
@ -7848,6 +7858,7 @@ AC_SUBST(MOZ_PLACES_BOOKMARKS)
AC_SUBST(MOZ_STORAGE) AC_SUBST(MOZ_STORAGE)
AC_SUBST(MOZ_FEEDS) AC_SUBST(MOZ_FEEDS)
AC_SUBST(NS_PRINTING) AC_SUBST(NS_PRINTING)
AC_SUBST(MOZ_WEBGL)
AC_SUBST(MOZ_JAVAXPCOM) AC_SUBST(MOZ_JAVAXPCOM)
AC_SUBST(JAVA_INCLUDE_PATH) AC_SUBST(JAVA_INCLUDE_PATH)
@ -7901,6 +7912,7 @@ AC_SUBST(OGLES_SDK_DIR)
AC_SUBST(MOZ_APP_NAME) AC_SUBST(MOZ_APP_NAME)
AC_SUBST(MOZ_APP_DISPLAYNAME) AC_SUBST(MOZ_APP_DISPLAYNAME)
AC_SUBST(MOZ_APP_VERSION) AC_SUBST(MOZ_APP_VERSION)
AC_SUBST(MOZ_APP_UA_EXTRA)
AC_SUBST(FIREFOX_VERSION) AC_SUBST(FIREFOX_VERSION)
AC_SUBST(MOZ_PKG_SPECIAL) AC_SUBST(MOZ_PKG_SPECIAL)
@ -8077,6 +8089,16 @@ if test "$MOZ_X11"; then
fi fi
fi # MOZ_X11 fi # MOZ_X11
dnl Check for headers, etc. needed by WebGL.
if test -n "$MOZ_WEBGL"; then
if test "$MOZ_WIDGET_TOOLKIT" = gtk2; then
AC_CHECK_HEADER(GL/glx.h)
if test "$ac_cv_header_GL_glx_h" != "yes"; then
AC_MSG_ERROR([Can't find header GL/glx.h for WebGL (install mesa-common-dev (Ubuntu), mesa-libGL-devel (Fedora), or Mesa (SuSE))])
fi
fi
fi # MOZ_WEBGL
fi # COMPILE_ENVIRONMENT fi # COMPILE_ENVIRONMENT
dnl Set various defines and substitutions dnl Set various defines and substitutions

View file

@ -45,57 +45,46 @@
#define NS_HTML_STYLE_PROPERTY_NOT_THERE \ #define NS_HTML_STYLE_PROPERTY_NOT_THERE \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 2) NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 2)
/** Error codes for MaybeTriggerAutoLink */
#define NS_XML_AUTOLINK_EMBED \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 3)
#define NS_XML_AUTOLINK_NEW \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 4)
#define NS_XML_AUTOLINK_REPLACE \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 5)
#define NS_XML_AUTOLINK_UNDEFINED \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 6)
/** Error codes for nsScriptLoader */ /** Error codes for nsScriptLoader */
#define NS_CONTENT_SCRIPT_IS_EVENTHANDLER \ #define NS_CONTENT_SCRIPT_IS_EVENTHANDLER \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 7) NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 3)
/** Error codes for image loading */ /** Error codes for image loading */
#define NS_ERROR_IMAGE_SRC_CHANGED \ #define NS_ERROR_IMAGE_SRC_CHANGED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 8) NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 4)
#define NS_ERROR_IMAGE_BLOCKED \ #define NS_ERROR_IMAGE_BLOCKED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 9) NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 5)
/** Error codes for content policy blocking */ /** Error codes for content policy blocking */
#define NS_ERROR_CONTENT_BLOCKED \ #define NS_ERROR_CONTENT_BLOCKED \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 10) NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 6)
#define NS_ERROR_CONTENT_BLOCKED_SHOW_ALT \ #define NS_ERROR_CONTENT_BLOCKED_SHOW_ALT \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 11) NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 7)
/** Success variations of content policy blocking */ /** Success variations of content policy blocking */
#define NS_CONTENT_BLOCKED \ #define NS_CONTENT_BLOCKED \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 12) NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 8)
#define NS_CONTENT_BLOCKED_SHOW_ALT \ #define NS_CONTENT_BLOCKED_SHOW_ALT \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 13) NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 9)
#define NS_PROPTABLE_PROP_NOT_THERE \ #define NS_PROPTABLE_PROP_NOT_THERE \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 14) NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 10)
#define NS_PROPTABLE_PROP_OVERWRITTEN \ #define NS_PROPTABLE_PROP_OVERWRITTEN \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 15) NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 11)
/* Error codes for FindBroadcaster in nsXULDocument.cpp */ /* Error codes for FindBroadcaster in nsXULDocument.cpp */
#define NS_FINDBROADCASTER_NOT_FOUND \ #define NS_FINDBROADCASTER_NOT_FOUND \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 16) NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 12)
#define NS_FINDBROADCASTER_FOUND \ #define NS_FINDBROADCASTER_FOUND \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 17) NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 13)
#define NS_FINDBROADCASTER_AWAIT_OVERLAYS \ #define NS_FINDBROADCASTER_AWAIT_OVERLAYS \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 18) NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 14)
#endif // nsContentErrors_h___ #endif // nsContentErrors_h___

View file

@ -1294,7 +1294,7 @@ public:
/** /**
* Hide any XUL popups associated with aDocument, including any documents * Hide any XUL popups associated with aDocument, including any documents
* displayed in child frames. * displayed in child frames. Does nothing if aDocument is null.
*/ */
static void HidePopupsInDocument(nsIDocument* aDocument); static void HidePopupsInDocument(nsIDocument* aDocument);
@ -1606,6 +1606,7 @@ public:
// Pop() will be a no-op if Push() or PushNull() fail // Pop() will be a no-op if Push() or PushNull() fail
void Pop(); void Pop();
nsIScriptContext* GetCurrentScriptContext() { return mScx; }
private: private:
// Combined code for PushNull() and Push(JSContext*) // Combined code for PushNull() and Push(JSContext*)
PRBool DoPush(JSContext* cx); PRBool DoPush(JSContext* cx);

View file

@ -70,10 +70,10 @@ enum nsLinkState {
}; };
// IID for the nsIContent interface // IID for the nsIContent interface
// d510382f-f5eb-48bb-9ad9-b3dc4806faaf // c726e716-a4be-4202-8a5e-32d0525903e8
#define NS_ICONTENT_IID \ #define NS_ICONTENT_IID \
{ 0xd510382f, 0xf5eb, 0x48bb, \ { 0xc726e716, 0xa4be, 0x4202, \
{ 0x9a, 0xd9, 0xb3, 0xdc, 0x48, 0x06, 0xfa, 0xaf } } { 0x8a, 0x5e, 0x32, 0xd0, 0x52, 0x59, 0x03, 0xe8 } }
/** /**
* A node of content in a document's content model. This interface * A node of content in a document's content model. This interface
@ -673,26 +673,6 @@ public:
return nsnull; return nsnull;
} }
/**
* Give this element a chance to fire links that should be fired
* automatically when loaded. If the element was an autoloading link
* and it was successfully handled, we will throw special nsresult values.
*
* @param aShell the current doc shell (to possibly load the link on)
* @throws NS_OK if nothing happened
* @throws NS_XML_AUTOLINK_EMBED if the caller is loading the link embedded
* @throws NS_XML_AUTOLINK_NEW if the caller is loading the link in a new
* window
* @throws NS_XML_AUTOLINK_REPLACE if it is loading a link that will replace
* the current window (and thus the caller must stop parsing)
* @throws NS_XML_AUTOLINK_UNDEFINED if it is loading in any other way--in
* which case, the caller should stop parsing as well.
*/
virtual nsresult MaybeTriggerAutoLink(nsIDocShell *aShell)
{
return NS_OK;
}
/** /**
* This method is called when the parser finishes creating the element. This * This method is called when the parser finishes creating the element. This
* particularly means that it has done everything you would expect it to have * particularly means that it has done everything you would expect it to have

View file

@ -129,6 +129,8 @@ public:
mCompatMode(eCompatibility_FullStandards), mCompatMode(eCompatibility_FullStandards),
mIsInitialDocumentInWindow(PR_FALSE), mIsInitialDocumentInWindow(PR_FALSE),
mMayStartLayout(PR_TRUE), mMayStartLayout(PR_TRUE),
mVisible(PR_TRUE),
mRemovedFromDocShell(PR_FALSE),
// mAllowDNSPrefetch starts true, so that we can always reliably && it // mAllowDNSPrefetch starts true, so that we can always reliably && it
// with various values that might disable it. Since we never prefetch // with various values that might disable it. Since we never prefetch
// unless we get a window, and in that case the docshell value will get // unless we get a window, and in that case the docshell value will get
@ -689,12 +691,10 @@ public:
nsIPrincipal* aPrincipal) = 0; nsIPrincipal* aPrincipal) = 0;
/** /**
* Set the container (docshell) for this document. * Set the container (docshell) for this document. Virtual so that
* docshell can call it.
*/ */
void SetContainer(nsISupports *aContainer) virtual void SetContainer(nsISupports *aContainer);
{
mDocumentContainer = do_GetWeakReference(aContainer);
}
/** /**
* Get the container (docshell) for this document. * Get the container (docshell) for this document.
@ -1120,6 +1120,16 @@ public:
* called yet. * called yet.
*/ */
PRBool IsShowing() { return mIsShowing; } PRBool IsShowing() { return mIsShowing; }
/**
* Return whether the document is currently visible (in the sense of
* OnPageHide having been called and OnPageShow not yet having been called)
*/
PRBool IsVisible() { return mVisible; }
/**
* Return true when this document is active, i.e., the active document
* in a content viewer.
*/
PRBool IsActive() { return mDocumentContainer && !mRemovedFromDocShell; }
void RegisterFreezableElement(nsIContent* aContent); void RegisterFreezableElement(nsIContent* aContent);
PRBool UnregisterFreezableElement(nsIContent* aContent); PRBool UnregisterFreezableElement(nsIContent* aContent);
@ -1281,6 +1291,15 @@ protected:
// True iff IsShowing() should be returning true // True iff IsShowing() should be returning true
PRPackedBool mIsShowing; PRPackedBool mIsShowing;
// True iff the document "page" is not hidden (i.e. currently in the
// bfcache)
PRPackedBool mVisible;
// True if our content viewer has been removed from the docshell
// (it may still be displayed, but in zombie state). Form control data
// has been saved.
PRPackedBool mRemovedFromDocShell;
// True iff DNS prefetch is allowed for this document. Note that if the // True iff DNS prefetch is allowed for this document. Note that if the
// document has no window, DNS prefetch won't be performed no matter what. // document has no window, DNS prefetch won't be performed no matter what.
PRPackedBool mAllowDNSPrefetch; PRPackedBool mAllowDNSPrefetch;

View file

@ -228,7 +228,10 @@ interface nsIXMLHttpRequest : nsISupports
* @param password (optional) A password for authentication if necessary. * @param password (optional) A password for authentication if necessary.
* The default value is the empty string * The default value is the empty string
*/ */
void open(in AUTF8String method, in AUTF8String url); [optional_argc] void open(in AUTF8String method, in AUTF8String url,
[optional] in boolean async,
[optional] in DOMString user,
[optional] in DOMString password);
/** /**
* Sends the request. If the request is asynchronous, returns * Sends the request. If the request is asynchronous, returns

View file

@ -4601,11 +4601,9 @@ nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,
void void
nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument) nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument)
{ {
NS_PRECONDITION(aDocument, "Null document");
#ifdef MOZ_XUL #ifdef MOZ_XUL
nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
if (pm) { if (pm && aDocument) {
nsCOMPtr<nsISupports> container = aDocument->GetContainer(); nsCOMPtr<nsISupports> container = aDocument->GetContainer();
nsCOMPtr<nsIDocShellTreeItem> docShellToHide = do_QueryInterface(container); nsCOMPtr<nsIDocShellTreeItem> docShellToHide = do_QueryInterface(container);
if (docShellToHide) if (docShellToHide)
@ -5071,13 +5069,10 @@ nsContentUtils::CanAccessNativeAnon()
fp = nsnull; fp = nsnull;
} }
void *annotation = fp ? JS_GetFrameAnnotation(cx, fp) : nsnull;
PRBool privileged; PRBool privileged;
if (NS_SUCCEEDED(principal->IsCapabilityEnabled("UniversalXPConnect", if (NS_SUCCEEDED(sSecurityManager->IsSystemPrincipal(principal, &privileged)) &&
annotation,
&privileged)) &&
privileged) { privileged) {
// UniversalXPConnect things are allowed to touch us. // Chrome things are allowed to touch us.
return PR_TRUE; return PR_TRUE;
} }
@ -5091,6 +5086,12 @@ nsContentUtils::CanAccessNativeAnon()
return PR_TRUE; return PR_TRUE;
} }
// Before we throw, check for UniversalXPConnect.
nsresult rv = sSecurityManager->IsCapabilityEnabled("UniversalXPConnect", &privileged);
if (NS_SUCCEEDED(rv) && privileged) {
return PR_TRUE;
}
return PR_FALSE; return PR_FALSE;
} }

View file

@ -169,6 +169,7 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
#include "nsIPropertyBag2.h" #include "nsIPropertyBag2.h"
#include "nsIDOMPageTransitionEvent.h" #include "nsIDOMPageTransitionEvent.h"
#include "nsFrameLoader.h" #include "nsFrameLoader.h"
#include "nsHTMLMediaElement.h"
#include "mozAutoDocUpdate.h" #include "mozAutoDocUpdate.h"
@ -1481,8 +1482,7 @@ nsDOMImplementation::Init(nsIURI* aDocumentURI, nsIURI* aBaseURI,
// bother initializing members to 0. // bother initializing members to 0.
nsDocument::nsDocument(const char* aContentType) nsDocument::nsDocument(const char* aContentType)
: nsIDocument(), : nsIDocument()
mVisible(PR_TRUE)
{ {
mContentType = aContentType; mContentType = aContentType;
@ -3575,6 +3575,25 @@ nsDocument::GetScopeObject()
return scope; return scope;
} }
static void
NotifyActivityChanged(nsIContent *aContent, void *aUnused)
{
#ifdef MOZ_MEDIA
nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aContent));
if (domMediaElem) {
nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aContent);
mediaElem->NotifyOwnerDocumentActivityChanged();
}
#endif
}
void
nsIDocument::SetContainer(nsISupports* aContainer)
{
mDocumentContainer = do_GetWeakReference(aContainer);
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
}
void void
nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject) nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
{ {
@ -6973,6 +6992,7 @@ nsDocument::RemovedFromDocShell()
return; return;
mRemovedFromDocShell = PR_TRUE; mRemovedFromDocShell = PR_TRUE;
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
PRUint32 i, count = mChildren.ChildCount(); PRUint32 i, count = mChildren.ChildCount();
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i) {
@ -7157,6 +7177,8 @@ void
nsDocument::OnPageShow(PRBool aPersisted, nsIDOMEventTarget* aDispatchStartTarget) nsDocument::OnPageShow(PRBool aPersisted, nsIDOMEventTarget* aDispatchStartTarget)
{ {
mVisible = PR_TRUE; mVisible = PR_TRUE;
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
UpdateLinkMap(); UpdateLinkMap();
nsIContent* root = GetRootContent(); nsIContent* root = GetRootContent();
@ -7237,6 +7259,7 @@ nsDocument::OnPageHide(PRBool aPersisted, nsIDOMEventTarget* aDispatchStartTarge
DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted); DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted);
mVisible = PR_FALSE; mVisible = PR_FALSE;
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
} }
void void

View file

@ -1171,14 +1171,8 @@ protected:
// True if the document has been detached from its content viewer. // True if the document has been detached from its content viewer.
PRPackedBool mIsGoingAway:1; PRPackedBool mIsGoingAway:1;
// True if our content viewer has been removed from the docshell
// (it may still be displayed, but in zombie state). Form control data
// has been saved.
PRPackedBool mRemovedFromDocShell:1;
// True if the document is being destroyed. // True if the document is being destroyed.
PRPackedBool mInDestructor:1; PRPackedBool mInDestructor:1;
// True if the document "page" is not hidden
PRPackedBool mVisible:1;
// True if document has ever had script handling object. // True if document has ever had script handling object.
PRPackedBool mHasHadScriptHandlingObject:1; PRPackedBool mHasHadScriptHandlingObject:1;

View file

@ -96,17 +96,17 @@ public:
nsIDocShell* GetExistingDocShell() { return mDocShell; } nsIDocShell* GetExistingDocShell() { return mDocShell; }
/** /**
* Called from the layout frame associated with this frame loader, * Called from the layout frame associated with this frame loader;
* set up and show the base window associated with our docshell. * this notifies us to hook up with the widget and view.
*/ */
bool Show(PRInt32 marginWidth, PRInt32 marginHeight, bool Show(PRInt32 marginWidth, PRInt32 marginHeight,
PRInt32 scrollbarPrefX, PRInt32 scrollbarPrefY, PRInt32 scrollbarPrefX, PRInt32 scrollbarPrefY,
nsIFrameFrame* frame); nsIFrameFrame* frame);
/** /**
* Called from the layout frame associated with this frame loader, * Called from the layout frame associated with this frame loader, when
* which is being torn down: remove our docshell from the widget/view * the frame is being torn down; this notifies us that out widget and view
* hierarchy. * are going away and we should unhook from them.
*/ */
void Hide(); void Hide();

View file

@ -56,6 +56,7 @@
#endif #endif
#include "nsBindingManager.h" #include "nsBindingManager.h"
#include "nsGenericHTMLElement.h" #include "nsGenericHTMLElement.h"
#include "nsHTMLMediaElement.h"
// This macro expects the ownerDocument of content_ to be in scope as // This macro expects the ownerDocument of content_ to be in scope as
// |nsIDocument* doc| // |nsIDocument* doc|
@ -604,6 +605,8 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
nsIDocument* newDoc = aNode->GetOwnerDoc(); nsIDocument* newDoc = aNode->GetOwnerDoc();
if (newDoc) { if (newDoc) {
// XXX what if oldDoc is null, we don't know if this should be
// registered or not! Can that really happen?
if (wasRegistered) { if (wasRegistered) {
newDoc->RegisterFreezableElement(static_cast<nsIContent*>(aNode)); newDoc->RegisterFreezableElement(static_cast<nsIContent*>(aNode));
} }
@ -620,6 +623,16 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
} }
} }
#ifdef MOZ_MEDIA
if (wasRegistered && oldDoc != newDoc) {
nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode));
if (domMediaElem) {
nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aNode);
mediaElem->NotifyOwnerDocumentActivityChanged();
}
}
#endif
if (elem) { if (elem) {
elem->RecompileScriptEventListeners(); elem->RecompileScriptEventListeners();
} }

View file

@ -261,6 +261,10 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType)
nsCOMPtr<nsIStreamLoader> loader; nsCOMPtr<nsIStreamLoader> loader;
nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mDocument->GetScriptGlobalObject())); nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(mDocument->GetScriptGlobalObject()));
if (!window) {
return NS_ERROR_NULL_POINTER;
}
nsIDocShell *docshell = window->GetDocShell(); nsIDocShell *docshell = window->GetDocShell();
nsCOMPtr<nsIInterfaceRequestor> prompter(do_QueryInterface(docshell)); nsCOMPtr<nsIInterfaceRequestor> prompter(do_QueryInterface(docshell));

View file

@ -1753,30 +1753,14 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
/* void open (in AUTF8String method, in AUTF8String url); */ /* void open (in AUTF8String method, in AUTF8String url); */
NS_IMETHODIMP NS_IMETHODIMP
nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url) nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url,
PRBool async, const nsAString& user,
const nsAString& password, PRUint8 optional_argc)
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
PRBool async = PR_TRUE;
nsAutoString user, password;
nsAXPCNativeCallContext *cc = nsnull; if (nsContentUtils::GetCurrentJSContext()) {
nsIXPConnect *xpc = nsContentUtils::XPConnect(); // We're (likely) called from JS
if (xpc) {
rv = xpc->GetCurrentNativeCallContext(&cc);
}
if (NS_SUCCEEDED(rv) && cc) {
PRUint32 argc;
rv = cc->GetArgc(&argc);
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
jsval* argv;
rv = cc->GetArgvPtr(&argv);
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
JSContext* cx;
rv = cc->GetJSContext(&cx);
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
// Find out if UniversalBrowserRead privileges are enabled // Find out if UniversalBrowserRead privileges are enabled
if (nsContentUtils::IsCallerTrustedForRead()) { if (nsContentUtils::IsCallerTrustedForRead()) {
@ -1784,33 +1768,11 @@ nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url)
} else { } else {
mState &= ~XML_HTTP_REQUEST_XSITEENABLED; mState &= ~XML_HTTP_REQUEST_XSITEENABLED;
} }
}
if (argc > 2) { if (!optional_argc) {
JSAutoRequest ar(cx); // No optional arguments were passed in. Default async to true.
JSBool asyncBool; async = PR_TRUE;
::JS_ValueToBoolean(cx, argv[2], &asyncBool);
async = (PRBool)asyncBool;
if (argc > 3 && !JSVAL_IS_NULL(argv[3]) && !JSVAL_IS_VOID(argv[3])) {
JSString* userStr = ::JS_ValueToString(cx, argv[3]);
if (userStr) {
user.Assign(reinterpret_cast<PRUnichar *>
(::JS_GetStringChars(userStr)),
::JS_GetStringLength(userStr));
}
if (argc > 4 && !JSVAL_IS_NULL(argv[4]) && !JSVAL_IS_VOID(argv[4])) {
JSString* passwdStr = JS_ValueToString(cx, argv[4]);
if (passwdStr) {
password.Assign(reinterpret_cast<PRUnichar *>
(::JS_GetStringChars(passwdStr)),
::JS_GetStringLength(passwdStr));
}
}
}
}
} }
return OpenRequest(method, url, async, user, password); return OpenRequest(method, url, async, user, password);

View file

@ -55,12 +55,7 @@ CPPSRCS = \
# Canvas 3D Pieces # Canvas 3D Pieces
# only allow on platforms/toolkits we know are good ifdef MOZ_WEBGL
ifneq (,$(NS_OSSO)$(WINCE)$(filter-out windows cocoa gtk2,$(MOZ_WIDGET_TOOLKIT)))
DISABLE_WEBGL=1
endif
ifndef DISABLE_WEBGL
CPPSRCS += \ CPPSRCS += \
WebGLContext.cpp \ WebGLContext.cpp \

View file

@ -488,14 +488,17 @@ protected:
* Gets the pres shell from either the canvas element or the doc shell * Gets the pres shell from either the canvas element or the doc shell
*/ */
nsIPresShell *GetPresShell() { nsIPresShell *GetPresShell() {
nsIPresShell *presShell = nsnull;
nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement); nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
if (content) { if (content) {
presShell = content->GetOwnerDoc()->GetPrimaryShell(); nsIDocument* ownerDoc = content->GetOwnerDoc();
} else if (mDocShell) { return ownerDoc ? ownerDoc->GetPrimaryShell() : nsnull;
mDocShell->GetPresShell(&presShell);
} }
return presShell; if (mDocShell) {
nsCOMPtr<nsIPresShell> shell;
mDocShell->GetPresShell(getter_AddRefs(shell));
return shell.get();
}
return nsnull;
} }
// text // text
@ -618,14 +621,6 @@ protected:
return mStyleStack[mSaveCount]; return mStyleStack[mSaveCount];
} }
// stolen from nsJSUtils
static PRBool ConvertJSValToUint32(PRUint32* aProp, JSContext* aContext,
jsval aValue);
static PRBool ConvertJSValToXPCObject(nsISupports** aSupports, REFNSIID aIID,
JSContext* aContext, jsval aValue);
static PRBool ConvertJSValToDouble(double* aProp, JSContext* aContext,
jsval aValue);
// other helpers // other helpers
void GetAppUnitsValues(PRUint32 *perDevPixel, PRUint32 *perCSSPixel) { void GetAppUnitsValues(PRUint32 *perDevPixel, PRUint32 *perCSSPixel) {
// If we don't have a canvas element, we just return something generic. // If we don't have a canvas element, we just return something generic.
@ -2925,45 +2920,19 @@ bitblt(gfxImageSurface *s, int src_x, int src_y, int width, int height,
// -- render the region defined by (sx,sy,sw,wh) in image-local space into the region (dx,dy,dw,dh) on the canvas // -- render the region defined by (sx,sy,sw,wh) in image-local space into the region (dx,dy,dw,dh) on the canvas
NS_IMETHODIMP NS_IMETHODIMP
nsCanvasRenderingContext2D::DrawImage() nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
float a2, float a3, float a4, float a5,
float a6, float a7, float a8,
PRUint8 optional_argc)
{ {
NS_ENSURE_ARG(imgElt);
nsresult rv; nsresult rv;
gfxRect dirty; gfxRect dirty;
nsAXPCNativeCallContext *ncc = nsnull;
rv = nsContentUtils::XPConnect()->
GetCurrentNativeCallContext(&ncc);
NS_ENSURE_SUCCESS(rv, rv);
if (!ncc)
return NS_ERROR_FAILURE;
JSContext *ctx = nsnull;
rv = ncc->GetJSContext(&ctx);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 argc;
jsval *argv = nsnull;
ncc->GetArgc(&argc);
ncc->GetArgvPtr(&argv);
// we always need at least an image and a dx,dy
if (argc < 3)
return NS_ERROR_INVALID_ARG;
JSAutoRequest ar(ctx);
double sx,sy,sw,sh; double sx,sy,sw,sh;
double dx,dy,dw,dh; double dx,dy,dw,dh;
nsCOMPtr<nsIDOMElement> imgElt;
if (!ConvertJSValToXPCObject(getter_AddRefs(imgElt),
NS_GET_IID(nsIDOMElement),
ctx, argv[0]))
return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
gfxMatrix matrix; gfxMatrix matrix;
nsRefPtr<gfxPattern> pattern; nsRefPtr<gfxPattern> pattern;
nsRefPtr<gfxPath> path; nsRefPtr<gfxPath> path;
@ -2997,40 +2966,36 @@ nsCanvasRenderingContext2D::DrawImage()
gfxContextPathAutoSaveRestore pathSR(mThebes, PR_FALSE); gfxContextPathAutoSaveRestore pathSR(mThebes, PR_FALSE);
#define GET_ARG(dest,whicharg) \
do { if (!ConvertJSValToDouble(dest, ctx, whicharg)) { rv = NS_ERROR_INVALID_ARG; goto FINISH; } } while (0)
rv = NS_OK; rv = NS_OK;
if (argc == 3) { if (optional_argc == 0) {
GET_ARG(&dx, argv[1]); dx = a1;
GET_ARG(&dy, argv[2]); dy = a2;
sx = sy = 0.0; sx = sy = 0.0;
dw = sw = (double) imgSize.width; dw = sw = (double) imgSize.width;
dh = sh = (double) imgSize.height; dh = sh = (double) imgSize.height;
} else if (argc == 5) { } else if (optional_argc == 2) {
GET_ARG(&dx, argv[1]); dx = a1;
GET_ARG(&dy, argv[2]); dy = a2;
GET_ARG(&dw, argv[3]); dw = a3;
GET_ARG(&dh, argv[4]); dh = a4;
sx = sy = 0.0; sx = sy = 0.0;
sw = (double) imgSize.width; sw = (double) imgSize.width;
sh = (double) imgSize.height; sh = (double) imgSize.height;
} else if (argc == 9) { } else if (optional_argc == 6) {
GET_ARG(&sx, argv[1]); sx = a1;
GET_ARG(&sy, argv[2]); sy = a2;
GET_ARG(&sw, argv[3]); sw = a3;
GET_ARG(&sh, argv[4]); sh = a4;
GET_ARG(&dx, argv[5]); dx = a5;
GET_ARG(&dy, argv[6]); dy = a6;
GET_ARG(&dw, argv[7]); dw = a7;
GET_ARG(&dh, argv[8]); dh = a8;
} else { } else {
// XXX ERRMSG we need to report an error to developers here! (bug 329026) // XXX ERRMSG we need to report an error to developers here! (bug 329026)
rv = NS_ERROR_INVALID_ARG; rv = NS_ERROR_INVALID_ARG;
goto FINISH; goto FINISH;
} }
#undef GET_ARG
if (dw == 0.0 || dh == 0.0) { if (dw == 0.0 || dh == 0.0) {
rv = NS_OK; rv = NS_OK;
@ -3039,7 +3004,7 @@ nsCanvasRenderingContext2D::DrawImage()
goto FINISH; goto FINISH;
} }
if (!FloatValidate(sx,sy,sw,sh) || !FloatValidate(dx,dy,dw,dh)) { if (!FloatValidate(sx, sy, sw, sh) || !FloatValidate(dx, dy, dw, dh)) {
rv = NS_ERROR_DOM_SYNTAX_ERR; rv = NS_ERROR_DOM_SYNTAX_ERR;
goto FINISH; goto FINISH;
} }
@ -3225,61 +3190,6 @@ nsCanvasRenderingContext2D::GetGlobalCompositeOperation(nsAString& op)
} }
//
// Utils
//
PRBool
nsCanvasRenderingContext2D::ConvertJSValToUint32(PRUint32* aProp, JSContext* aContext,
jsval aValue)
{
uint32 temp;
if (::JS_ValueToECMAUint32(aContext, aValue, &temp)) {
*aProp = (PRUint32)temp;
}
else {
::JS_ReportError(aContext, "Parameter must be an integer");
return JS_FALSE;
}
return JS_TRUE;
}
PRBool
nsCanvasRenderingContext2D::ConvertJSValToDouble(double* aProp, JSContext* aContext,
jsval aValue)
{
jsdouble temp;
if (::JS_ValueToNumber(aContext, aValue, &temp)) {
*aProp = (jsdouble)temp;
}
else {
::JS_ReportError(aContext, "Parameter must be a number");
return JS_FALSE;
}
return JS_TRUE;
}
PRBool
nsCanvasRenderingContext2D::ConvertJSValToXPCObject(nsISupports** aSupports, REFNSIID aIID,
JSContext* aContext, jsval aValue)
{
*aSupports = nsnull;
if (JSVAL_IS_NULL(aValue)) {
return JS_TRUE;
}
if (JSVAL_IS_OBJECT(aValue)) {
// WrapJS does all the work to recycle an existing wrapper and/or do a QI
nsresult rv = nsContentUtils::XPConnect()->
WrapJS(aContext, JSVAL_TO_OBJECT(aValue), aIID, (void**)aSupports);
return NS_SUCCEEDED(rv);
}
return JS_FALSE;
}
static void static void
FlushLayoutForTree(nsIDOMWindow* aWindow) FlushLayoutForTree(nsIDOMWindow* aWindow)
{ {
@ -3398,6 +3308,15 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
// //
// device pixel getting/setting // device pixel getting/setting
// //
extern "C" {
#include "jstypes.h"
JS_FRIEND_API(JSBool)
js_CoerceArrayToCanvasImageData(JSObject *obj, jsuint offset, jsuint count,
JSUint8 *dest);
JS_FRIEND_API(JSObject *)
js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector);
}
// ImageData getImageData (in float x, in float y, in float width, in float height); // ImageData getImageData (in float x, in float y, in float width, in float height);
NS_IMETHODIMP NS_IMETHODIMP
@ -3469,10 +3388,14 @@ nsCanvasRenderingContext2D::GetImageData()
if (len > (((PRUint32)0xfff00000)/sizeof(jsval))) if (len > (((PRUint32)0xfff00000)/sizeof(jsval)))
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
nsAutoArrayPtr<jsval> jsvector(new (std::nothrow) jsval[w * h * 4]); jsval *dest;
if (!jsvector) JSObject *dataArray = js_NewArrayObjectWithCapacity(ctx, len, &dest);
if (!dataArray)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
jsval *dest = jsvector.get();
nsAutoGCRoot arrayGCRoot(&dataArray, &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRUint8 *row; PRUint8 *row;
for (int j = 0; j < h; j++) { for (int j = 0; j < h; j++) {
row = surfaceData + surfaceDataOffset + (surfaceDataStride * j); row = surfaceData + surfaceDataOffset + (surfaceDataStride * j);
@ -3504,13 +3427,8 @@ nsCanvasRenderingContext2D::GetImageData()
} }
} }
JSObject *dataArray = JS_NewArrayObject(ctx, w*h*4, jsvector.get()); // Allocate result object after array, so if we have to trigger gc
if (!dataArray) // we do it now.
return NS_ERROR_OUT_OF_MEMORY;
nsAutoGCRoot arrayGCRoot(&dataArray, &rv);
NS_ENSURE_SUCCESS(rv, rv);
JSObject *result = JS_NewObject(ctx, NULL, NULL, NULL); JSObject *result = JS_NewObject(ctx, NULL, NULL, NULL);
if (!result) if (!result)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
@ -3531,13 +3449,6 @@ nsCanvasRenderingContext2D::GetImageData()
return NS_OK; return NS_OK;
} }
extern "C" {
#include "jstypes.h"
JS_FRIEND_API(JSBool)
js_CoerceArrayToCanvasImageData(JSObject *obj, jsuint offset, jsuint count,
JSUint8 *dest);
}
static inline PRUint8 ToUint8(jsint aInput) static inline PRUint8 ToUint8(jsint aInput)
{ {
if (PRUint32(aInput) > 255) if (PRUint32(aInput) > 255)
@ -3803,21 +3714,19 @@ nsCanvasRenderingContext2D::CreateImageData()
if (len / 4 != len0) if (len / 4 != len0)
return NS_ERROR_DOM_INDEX_SIZE_ERR; return NS_ERROR_DOM_INDEX_SIZE_ERR;
nsAutoArrayPtr<jsval> jsvector(new (std::nothrow) jsval[w * h * 4]); jsval *dest;
if (!jsvector) JSObject *dataArray = js_NewArrayObjectWithCapacity(ctx, len, &dest);
return NS_ERROR_OUT_OF_MEMORY;
jsval *dest = jsvector.get();
for (PRUint32 i = 0; i < len; i++)
*dest++ = JSVAL_ZERO;
JSObject *dataArray = JS_NewArrayObject(ctx, w*h*4, jsvector.get());
if (!dataArray) if (!dataArray)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
nsAutoGCRoot arrayGCRoot(&dataArray, &rv); nsAutoGCRoot arrayGCRoot(&dataArray, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
for (PRUint32 i = 0; i < len; i++)
*dest++ = JSVAL_ZERO;
// Allocate result object after array, so if we have to trigger gc
// we do it now.
JSObject *result = JS_NewObject(ctx, NULL, NULL, NULL); JSObject *result = JS_NewObject(ctx, NULL, NULL, NULL);
if (!result) if (!result)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;

View file

@ -3649,18 +3649,20 @@ isPixel(ctx, 50,25, 0,255,0,255, 2);
function test_2d_drawImage_wrongtype() { function test_2d_drawImage_wrongtype() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var canvas = document.getElementById('c127'); var canvas = document.getElementById('c127');
var ctx = canvas.getContext('2d'); var ctx = canvas.getContext('2d');
var _thrown = undefined; try { var _thrown = undefined; try {
ctx.drawImage(undefined, 0, 0); ctx.drawImage(undefined, 0, 0);
} catch (e) { _thrown = e }; ok(_thrown && _thrown.code == DOMException.TYPE_MISMATCH_ERR, "should throw TYPE_MISMATCH_ERR"); } catch (e) { _thrown = e }; ok(_thrown && _thrown.result == Components.results.NS_ERROR_INVALID_ARG, "should throw NS_ERROR_INVALID_ARG");
var _thrown = undefined; try { var _thrown = undefined; try {
ctx.drawImage(0, 0, 0); ctx.drawImage(0, 0, 0);
} catch (e) { _thrown = e }; ok(_thrown && _thrown.code == DOMException.TYPE_MISMATCH_ERR, "should throw TYPE_MISMATCH_ERR"); } catch (e) { _thrown = e }; ok(_thrown && _thrown.result == Components.results.NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL, "should throw NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL");
var _thrown = undefined; try { var _thrown = undefined; try {
ctx.drawImage("", 0, 0); ctx.drawImage("", 0, 0);
} catch (e) { _thrown = e }; ok(_thrown && _thrown.code == DOMException.TYPE_MISMATCH_ERR, "should throw TYPE_MISMATCH_ERR"); } catch (e) { _thrown = e }; ok(_thrown && _thrown.result == Components.results.NS_ERROR_XPC_BAD_CONVERT_JS, "should throw NS_ERROR_XPC_BAD_CONVERT_JS");
var _thrown = undefined; try { var _thrown = undefined; try {
ctx.drawImage(document.createElement('p'), 0, 0); ctx.drawImage(document.createElement('p'), 0, 0);
} catch (e) { _thrown = e }; todo(_thrown && _thrown.code == DOMException.TYPE_MISMATCH_ERR, "should throw TYPE_MISMATCH_ERR"); } catch (e) { _thrown = e }; todo(_thrown && _thrown.code == DOMException.TYPE_MISMATCH_ERR, "should throw TYPE_MISMATCH_ERR");
@ -7352,8 +7354,8 @@ var _thrown_outer = false;
var imgdata1 = ctx.createImageData(10.01, 10.99); var imgdata1 = ctx.createImageData(10.01, 10.99);
var imgdata2 = ctx.getImageData(0, 0, 10.01, 10.99); var imgdata2 = ctx.getImageData(0, 0, 10.01, 10.99);
ok(imgdata1.width == imgdata2.width, "imgdata1.width == imgdata2.width"); is(imgdata1.width, imgdata2.width, "imgdata1.width == imgdata2.width");
ok(imgdata1.height == imgdata2.height, "imgdata1.height == imgdata2.height"); is(imgdata1.height, imgdata2.height, "imgdata1.height == imgdata2.height");
} }

View file

@ -50,13 +50,14 @@ class nsIAtom;
class nsPIDOMEventTarget; class nsPIDOMEventTarget;
class nsIEventListenerInfo; class nsIEventListenerInfo;
template<class E> class nsCOMArray; template<class E> class nsCOMArray;
class nsCxPusher;
/* /*
* Event listener manager interface. * Event listener manager interface.
*/ */
#define NS_IEVENTLISTENERMANAGER_IID \ #define NS_IEVENTLISTENERMANAGER_IID \
{ 0xac49ce4e, 0xaecf, 0x45db, \ { 0x2412fcd0, 0xd168, 0x4a1c, \
{ 0xa1, 0xe0, 0xea, 0x1d, 0x38, 0x73, 0x39, 0xa3 } } { 0xaa, 0x28, 0x70, 0xed, 0x58, 0xf0, 0x4c, 0xec } }
class nsIEventListenerManager : public nsISupports { class nsIEventListenerManager : public nsISupports {
@ -65,6 +66,8 @@ public:
nsIEventListenerManager() : mMayHavePaintEventListener(PR_FALSE), nsIEventListenerManager() : mMayHavePaintEventListener(PR_FALSE),
mMayHaveMutationListeners(PR_FALSE), mMayHaveMutationListeners(PR_FALSE),
mMayHaveCapturingListeners(PR_FALSE),
mMayHaveSystemGroupListeners(PR_FALSE),
mNoListenerForEvent(0) mNoListenerForEvent(0)
{} {}
@ -147,7 +150,8 @@ public:
nsIDOMEvent** aDOMEvent, nsIDOMEvent** aDOMEvent,
nsPIDOMEventTarget* aCurrentTarget, nsPIDOMEventTarget* aCurrentTarget,
PRUint32 aFlags, PRUint32 aFlags,
nsEventStatus* aEventStatus) = 0; nsEventStatus* aEventStatus,
nsCxPusher* aPusher) = 0;
/** /**
* Tells the event listener manager that its target (which owns it) is * Tells the event listener manager that its target (which owns it) is
@ -217,10 +221,9 @@ public:
protected: protected:
PRUint32 mMayHavePaintEventListener : 1; PRUint32 mMayHavePaintEventListener : 1;
PRUint32 mMayHaveMutationListeners : 1; PRUint32 mMayHaveMutationListeners : 1;
// These two member variables are used to cache the information PRUint32 mMayHaveCapturingListeners : 1;
// about the last event which was handled but for which event listener manager PRUint32 mMayHaveSystemGroupListeners : 1;
// didn't have event listeners. PRUint32 mNoListenerForEvent : 28;
PRUint32 mNoListenerForEvent : 30;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsIEventListenerManager, NS_DEFINE_STATIC_IID_ACCESSOR(nsIEventListenerManager,

View file

@ -75,7 +75,7 @@ interface nsIEventListenerService : nsISupports
* If aEventTarget doesn't have any listeners, this returns null. * If aEventTarget doesn't have any listeners, this returns null.
*/ */
void getListenerInfoFor(in nsIDOMEventTarget aEventTarget, void getListenerInfoFor(in nsIDOMEventTarget aEventTarget,
out unsigned long aCount, [optional] out unsigned long aCount,
[retval, array, size_is(aCount)] out [retval, array, size_is(aCount)] out
nsIEventListenerInfo aOutArray); nsIEventListenerInfo aOutArray);
@ -88,7 +88,7 @@ interface nsIEventListenerService : nsISupports
* event target chain than what this methods returns. * event target chain than what this methods returns.
*/ */
void getEventTargetChainFor(in nsIDOMEventTarget aEventTarget, void getEventTargetChainFor(in nsIDOMEventTarget aEventTarget,
out unsigned long aCount, [optional] out unsigned long aCount,
[retval, array, size_is(aCount)] out [retval, array, size_is(aCount)] out
nsIDOMEventTarget aOutArray); nsIDOMEventTarget aOutArray);
}; };

View file

@ -235,15 +235,21 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
// nsIDOMEventInterface // nsIDOMEventInterface
NS_METHOD nsDOMEvent::GetType(nsAString& aType) NS_METHOD nsDOMEvent::GetType(nsAString& aType)
{ {
if (!mCachedType.IsEmpty()) {
aType = mCachedType;
return NS_OK;
}
const char* name = GetEventName(mEvent->message); const char* name = GetEventName(mEvent->message);
if (name) { if (name) {
CopyASCIItoUTF16(name, aType); CopyASCIItoUTF16(name, aType);
mCachedType = aType;
return NS_OK; return NS_OK;
} else if (mEvent->message == NS_USER_DEFINED_EVENT && mEvent->userType) { } else if (mEvent->message == NS_USER_DEFINED_EVENT && mEvent->userType) {
nsAutoString name; nsAutoString name;
mEvent->userType->ToString(name); mEvent->userType->ToString(name);
aType = Substring(name, 2, name.Length() - 2); // Remove "on" aType = Substring(name, 2, name.Length() - 2); // Remove "on"
mCachedType = aType;
return NS_OK; return NS_OK;
} }
@ -724,7 +730,7 @@ nsDOMEvent::InitEvent(const nsAString& aEventTypeArg, PRBool aCanBubbleArg, PRBo
// re-dispatching it. // re-dispatching it.
mEvent->target = nsnull; mEvent->target = nsnull;
mEvent->originalTarget = nsnull; mEvent->originalTarget = nsnull;
mCachedType = aEventTypeArg;
return NS_OK; return NS_OK;
} }

View file

@ -212,6 +212,7 @@ protected:
nsCOMPtr<nsPresContext> mPresContext; nsCOMPtr<nsPresContext> mPresContext;
nsCOMPtr<nsIDOMEventTarget> mTmpRealOriginalTarget; nsCOMPtr<nsIDOMEventTarget> mTmpRealOriginalTarget;
nsCOMPtr<nsIDOMEventTarget> mExplicitOriginalTarget; nsCOMPtr<nsIDOMEventTarget> mExplicitOriginalTarget;
nsString mCachedType;
PRPackedBool mEventIsInternal; PRPackedBool mEventIsInternal;
PRPackedBool mPrivateDataDuplicated; PRPackedBool mPrivateDataDuplicated;
}; };

View file

@ -145,7 +145,8 @@ public:
nsresult HandleEventTargetChain(nsEventChainPostVisitor& aVisitor, nsresult HandleEventTargetChain(nsEventChainPostVisitor& aVisitor,
PRUint32 aFlags, PRUint32 aFlags,
nsDispatchingCallback* aCallback, nsDispatchingCallback* aCallback,
PRBool aMayHaveNewListenerManagers); PRBool aMayHaveNewListenerManagers,
nsCxPusher* aPusher);
/** /**
* Resets aVisitor object and calls PreHandleEvent. * Resets aVisitor object and calls PreHandleEvent.
@ -159,7 +160,8 @@ public:
* and calls nsIEventListenerManager::HandleEvent(). * and calls nsIEventListenerManager::HandleEvent().
*/ */
nsresult HandleEvent(nsEventChainPostVisitor& aVisitor, PRUint32 aFlags, nsresult HandleEvent(nsEventChainPostVisitor& aVisitor, PRUint32 aFlags,
PRBool aMayHaveNewListenerManagers); PRBool aMayHaveNewListenerManagers,
nsCxPusher* aPusher);
/** /**
* Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent. * Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent.
@ -221,7 +223,8 @@ nsEventTargetChainItem::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
nsresult nsresult
nsEventTargetChainItem::HandleEvent(nsEventChainPostVisitor& aVisitor, nsEventTargetChainItem::HandleEvent(nsEventChainPostVisitor& aVisitor,
PRUint32 aFlags, PRUint32 aFlags,
PRBool aMayHaveNewListenerManagers) PRBool aMayHaveNewListenerManagers,
nsCxPusher* aPusher)
{ {
if (WantsWillHandleEvent()) { if (WantsWillHandleEvent()) {
mTarget->WillHandleEvent(aVisitor); mTarget->WillHandleEvent(aVisitor);
@ -241,7 +244,8 @@ nsEventTargetChainItem::HandleEvent(nsEventChainPostVisitor& aVisitor,
mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent, mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
&aVisitor.mDOMEvent, &aVisitor.mDOMEvent,
CurrentTarget(), aFlags, CurrentTarget(), aFlags,
&aVisitor.mEventStatus); &aVisitor.mEventStatus,
aPusher);
NS_ASSERTION(aVisitor.mEvent->currentTarget == nsnull, NS_ASSERTION(aVisitor.mEvent->currentTarget == nsnull,
"CurrentTarget should be null!"); "CurrentTarget should be null!");
} }
@ -260,7 +264,8 @@ nsEventTargetChainItem::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
nsresult nsresult
nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor, PRUint32 aFlags, nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor, PRUint32 aFlags,
nsDispatchingCallback* aCallback, nsDispatchingCallback* aCallback,
PRBool aMayHaveNewListenerManagers) PRBool aMayHaveNewListenerManagers,
nsCxPusher* aPusher)
{ {
PRUint32 createdELMs = nsEventListenerManager::sCreatedCount; PRUint32 createdELMs = nsEventListenerManager::sCreatedCount;
// Save the target so that it can be restored later. // Save the target so that it can be restored later.
@ -276,7 +281,8 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
!(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) { !(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) {
item->HandleEvent(aVisitor, aFlags & NS_EVENT_CAPTURE_MASK, item->HandleEvent(aVisitor, aFlags & NS_EVENT_CAPTURE_MASK,
aMayHaveNewListenerManagers || aMayHaveNewListenerManagers ||
createdELMs != nsEventListenerManager::sCreatedCount); createdELMs != nsEventListenerManager::sCreatedCount,
aPusher);
} }
if (item->GetNewTarget()) { if (item->GetNewTarget()) {
@ -305,7 +311,8 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
// <xul:dialog>'s buttons. Bug 235441. // <xul:dialog>'s buttons. Bug 235441.
item->HandleEvent(aVisitor, aFlags, item->HandleEvent(aVisitor, aFlags,
aMayHaveNewListenerManagers || aMayHaveNewListenerManagers ||
createdELMs != nsEventListenerManager::sCreatedCount); createdELMs != nsEventListenerManager::sCreatedCount,
aPusher);
} }
if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) { if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
item->PostHandleEvent(aVisitor); item->PostHandleEvent(aVisitor);
@ -327,7 +334,8 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
item->ForceContentDispatch()) && item->ForceContentDispatch()) &&
!(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) { !(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) {
item->HandleEvent(aVisitor, aFlags & NS_EVENT_BUBBLE_MASK, item->HandleEvent(aVisitor, aFlags & NS_EVENT_BUBBLE_MASK,
createdELMs != nsEventListenerManager::sCreatedCount); createdELMs != nsEventListenerManager::sCreatedCount,
aPusher);
} }
if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) { if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
item->PostHandleEvent(aVisitor); item->PostHandleEvent(aVisitor);
@ -357,7 +365,8 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
aVisitor.mEvent->target = firstTarget; aVisitor.mEvent->target = firstTarget;
HandleEventTargetChain(aVisitor, aFlags | NS_EVENT_FLAG_SYSTEM_EVENT, HandleEventTargetChain(aVisitor, aFlags | NS_EVENT_FLAG_SYSTEM_EVENT,
aCallback, aCallback,
createdELMs != nsEventListenerManager::sCreatedCount); createdELMs != nsEventListenerManager::sCreatedCount,
aPusher);
} }
return NS_OK; return NS_OK;
@ -542,11 +551,13 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
} else { } else {
// Event target chain is created. Handle the chain. // Event target chain is created. Handle the chain.
nsEventChainPostVisitor postVisitor(preVisitor); nsEventChainPostVisitor postVisitor(preVisitor);
nsCxPusher pusher;
rv = topEtci->HandleEventTargetChain(postVisitor, rv = topEtci->HandleEventTargetChain(postVisitor,
NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_BUBBLE |
NS_EVENT_FLAG_CAPTURE, NS_EVENT_FLAG_CAPTURE,
aCallback, aCallback,
PR_TRUE); PR_TRUE,
&pusher);
preVisitor.mEventStatus = postVisitor.mEventStatus; preVisitor.mEventStatus = postVisitor.mEventStatus;
// If the DOM event was created during event flow. // If the DOM event was created during event flow.

View file

@ -408,6 +408,7 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
sysGroup->IsSameEventGroup(aEvtGrp, &isSame); sysGroup->IsSameEventGroup(aEvtGrp, &isSame);
if (isSame) { if (isSame) {
group = NS_EVENT_FLAG_SYSTEM_EVENT; group = NS_EVENT_FLAG_SYSTEM_EVENT;
mMayHaveSystemGroupListeners = PR_TRUE;
} }
} }
@ -453,6 +454,9 @@ nsEventListenerManager::AddEventListener(nsIDOMEventListener *aListener,
ls->mGroupFlags = group; ls->mGroupFlags = group;
ls->mHandlerIsString = PR_FALSE; ls->mHandlerIsString = PR_FALSE;
ls->mTypeData = aTypeData; ls->mTypeData = aTypeData;
if (aFlags & NS_EVENT_FLAG_CAPTURE) {
mMayHaveCapturingListeners = PR_TRUE;
}
if (aType == NS_AFTERPAINT) { if (aType == NS_AFTERPAINT) {
mMayHavePaintEventListener = PR_TRUE; mMayHavePaintEventListener = PR_TRUE;
@ -617,7 +621,7 @@ nsEventListenerManager::SetJSEventListener(nsIScriptContext *aContext,
// If we didn't find a script listener or no listeners existed // If we didn't find a script listener or no listeners existed
// create and add a new one. // create and add a new one.
nsCOMPtr<nsIDOMEventListener> scriptListener; nsCOMPtr<nsIDOMEventListener> scriptListener;
rv = NS_NewJSEventListener(aContext, aScopeObject, aObject, rv = NS_NewJSEventListener(aContext, aScopeObject, aObject, aName,
getter_AddRefs(scriptListener)); getter_AddRefs(scriptListener));
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
AddEventListener(scriptListener, eventType, aName, nsnull, AddEventListener(scriptListener, eventType, aName, nsnull,
@ -880,7 +884,7 @@ nsEventListenerManager::CompileScriptEventListener(nsIScriptContext *aContext,
if (ls->mHandlerIsString) { if (ls->mHandlerIsString) {
rv = CompileEventHandlerInternal(aContext, aScope, aObject, aName, rv = CompileEventHandlerInternal(aContext, aScope, aObject, aName,
ls, /*XXX fixme*/nsnull); ls, /*XXX fixme*/nsnull, PR_TRUE);
} }
// Set *aDidCompile to true even if we didn't really compile // Set *aDidCompile to true even if we didn't really compile
@ -899,7 +903,8 @@ nsEventListenerManager::CompileEventHandlerInternal(nsIScriptContext *aContext,
nsISupports *aObject, nsISupports *aObject,
nsIAtom *aName, nsIAtom *aName,
nsListenerStruct *aListenerStruct, nsListenerStruct *aListenerStruct,
nsISupports* aCurrentTarget) nsISupports* aCurrentTarget,
PRBool aNeedsCxPush)
{ {
nsresult result = NS_OK; nsresult result = NS_OK;
@ -962,7 +967,8 @@ nsEventListenerManager::CompileEventHandlerInternal(nsIScriptContext *aContext,
} }
nsCxPusher pusher; nsCxPusher pusher;
if (!pusher.Push((JSContext*)aContext->GetNativeContext())) { if (aNeedsCxPush &&
!pusher.Push((JSContext*)aContext->GetNativeContext())) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -1009,7 +1015,8 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
nsIDOMEventListener* aListener, nsIDOMEventListener* aListener,
nsIDOMEvent* aDOMEvent, nsIDOMEvent* aDOMEvent,
nsPIDOMEventTarget* aCurrentTarget, nsPIDOMEventTarget* aCurrentTarget,
PRUint32 aPhaseFlags) PRUint32 aPhaseFlags,
nsCxPusher* aPusher)
{ {
nsresult result = NS_OK; nsresult result = NS_OK;
@ -1019,15 +1026,30 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
aListenerStruct->mHandlerIsString) { aListenerStruct->mHandlerIsString) {
nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(aListener); nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(aListener);
if (jslistener) { if (jslistener) {
nsAutoString eventString; // We probably have the atom already.
if (NS_SUCCEEDED(aDOMEvent->GetType(eventString))) { nsCOMPtr<nsIAtom> atom = aListenerStruct->mTypeAtom;
nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + eventString); if (!atom) {
nsAutoString eventString;
if (NS_SUCCEEDED(aDOMEvent->GetType(eventString))) {
atom = do_GetAtom(NS_LITERAL_STRING("on") + eventString);
}
}
if (atom) {
#ifdef DEBUG
nsAutoString type;
aDOMEvent->GetType(type);
nsCOMPtr<nsIAtom> eventAtom = do_GetAtom(NS_LITERAL_STRING("on") + type);
NS_ASSERTION(eventAtom == atom, "Something wrong with event atoms!");
#endif
result = CompileEventHandlerInternal(jslistener->GetEventContext(), result = CompileEventHandlerInternal(jslistener->GetEventContext(),
jslistener->GetEventScope(), jslistener->GetEventScope(),
jslistener->GetEventTarget(), jslistener->GetEventTarget(),
atom, aListenerStruct, atom, aListenerStruct,
aCurrentTarget); aCurrentTarget,
!jslistener->GetEventContext() ||
jslistener->GetEventContext() !=
aPusher->GetCurrentScriptContext());
} }
} }
} }
@ -1054,12 +1076,23 @@ nsEventListenerManager::HandleEvent(nsPresContext* aPresContext,
nsEvent* aEvent, nsIDOMEvent** aDOMEvent, nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
nsPIDOMEventTarget* aCurrentTarget, nsPIDOMEventTarget* aCurrentTarget,
PRUint32 aFlags, PRUint32 aFlags,
nsEventStatus* aEventStatus) nsEventStatus* aEventStatus,
nsCxPusher* aPusher)
{ {
if (mListeners.IsEmpty() || aEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) { if (mListeners.IsEmpty() || aEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) {
return NS_OK; return NS_OK;
} }
if (!mMayHaveCapturingListeners &&
!(aEvent->flags & NS_EVENT_FLAG_BUBBLE)) {
return NS_OK;
}
if (!mMayHaveSystemGroupListeners &&
aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
return NS_OK;
}
// Check if we already know that there is no event listener for the event. // Check if we already know that there is no event listener for the event.
if (mNoListenerForEvent == aEvent->message && if (mNoListenerForEvent == aEvent->message &&
(mNoListenerForEvent != NS_USER_DEFINED_EVENT || (mNoListenerForEvent != NS_USER_DEFINED_EVENT ||
@ -1104,7 +1137,6 @@ found:
nsAutoTObserverArray<nsListenerStruct, 2>::EndLimitedIterator iter(mListeners); nsAutoTObserverArray<nsListenerStruct, 2>::EndLimitedIterator iter(mListeners);
nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent)); nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
PRBool hasListener = PR_FALSE; PRBool hasListener = PR_FALSE;
nsCxPusher pusher;
while (iter.HasMore()) { while (iter.HasMore()) {
nsListenerStruct* ls = &iter.GetNext(); nsListenerStruct* ls = &iter.GetNext();
PRBool useTypeInterface = PRBool useTypeInterface =
@ -1134,13 +1166,13 @@ found:
} }
nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = ls->mListener; nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = ls->mListener;
if (useTypeInterface) { if (useTypeInterface) {
pusher.Pop(); aPusher->Pop();
DispatchToInterface(*aDOMEvent, ls->mListener, DispatchToInterface(*aDOMEvent, ls->mListener,
dispData->method, *typeData->iid); dispData->method, *typeData->iid);
} else if (useGenericInterface && } else if (useGenericInterface &&
pusher.RePush(aCurrentTarget)) { aPusher->RePush(aCurrentTarget)) {
HandleEventSubType(ls, ls->mListener, *aDOMEvent, HandleEventSubType(ls, ls->mListener, *aDOMEvent,
aCurrentTarget, aFlags); aCurrentTarget, aFlags, aPusher);
} }
} }
} }
@ -1408,7 +1440,8 @@ nsEventListenerManager::GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList)
jslistener->GetEventTarget(), jslistener->GetEventTarget(),
ls.mTypeAtom, ls.mTypeAtom,
const_cast<nsListenerStruct*>(&ls), const_cast<nsListenerStruct*>(&ls),
mTarget); mTarget,
PR_TRUE);
} }
} }
if (ls.mTypeData) { if (ls.mTypeData) {

View file

@ -116,7 +116,8 @@ public:
nsIDOMEvent** aDOMEvent, nsIDOMEvent** aDOMEvent,
nsPIDOMEventTarget* aCurrentTarget, nsPIDOMEventTarget* aCurrentTarget,
PRUint32 aFlags, PRUint32 aFlags,
nsEventStatus* aEventStatus); nsEventStatus* aEventStatus,
nsCxPusher* aPusher);
NS_IMETHOD Disconnect(); NS_IMETHOD Disconnect();
@ -154,13 +155,15 @@ protected:
nsIDOMEventListener* aListener, nsIDOMEventListener* aListener,
nsIDOMEvent* aDOMEvent, nsIDOMEvent* aDOMEvent,
nsPIDOMEventTarget* aCurrentTarget, nsPIDOMEventTarget* aCurrentTarget,
PRUint32 aPhaseFlags); PRUint32 aPhaseFlags,
nsCxPusher* aPusher);
nsresult CompileEventHandlerInternal(nsIScriptContext *aContext, nsresult CompileEventHandlerInternal(nsIScriptContext *aContext,
void *aScopeObject, void *aScopeObject,
nsISupports *aObject, nsISupports *aObject,
nsIAtom *aName, nsIAtom *aName,
nsListenerStruct *aListenerStruct, nsListenerStruct *aListenerStruct,
nsISupports* aCurrentTarget); nsISupports* aCurrentTarget,
PRBool aNeedsCxPush);
nsListenerStruct* FindJSEventListener(PRUint32 aEventType, nsIAtom* aTypeAtom); nsListenerStruct* FindJSEventListener(PRUint32 aEventType, nsIAtom* aTypeAtom);
nsresult SetJSEventListener(nsIScriptContext *aContext, nsresult SetJSEventListener(nsIScriptContext *aContext,
void *aScopeGlobal, void *aScopeGlobal,

View file

@ -80,6 +80,7 @@ _TEST_FILES = \
test_bug489671.html \ test_bug489671.html \
test_bug493251.html \ test_bug493251.html \
test_bug502818.html \ test_bug502818.html \
test_bug517851.html \
$(NULL) $(NULL)
_CHROME_FILES = \ _CHROME_FILES = \

View file

@ -0,0 +1,86 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=517851
-->
<head>
<title>Test for Bug 517851</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=517851">Mozilla Bug 517851</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 517851 **/
window.handledCount = 0;
window.testReturnValue = false;
var target = document.createElement("div");
target.setAttribute("onerror", "++window.handledCount; return window.testReturnValue;");
target.setAttribute("onmouseover", "++window.handledCount; return window.testReturnValue;");
target.setAttribute("onbeforeunload", "++window.handledCount; return window.testReturnValue;");
target.setAttribute("onmousemove", "++window.handledCount; return window.testReturnValue;");
var e = document.createEvent("Event");
e.initEvent("error", true, true);
window.testReturnValue = false;
is(target.dispatchEvent(e), !window.testReturnValue,
"error event should have reverse return value handling!");
is(handledCount, 1, "Wrong event count!");
window.testReturnValue = true;
is(target.dispatchEvent(e), !window.testReturnValue,
"error event should have reverse return value handling (2)!");
is(handledCount, 2, "Wrong event count!");
e = document.createEvent("MouseEvent");
e.initEvent("mouseover", true, true);
window.testReturnValue = false;
is(target.dispatchEvent(e), !window.testReturnValue,
"mouseover event should have reverse return value handling!");
is(handledCount, 3, "Wrong event count!");
window.testReturnValue = true;
is(target.dispatchEvent(e), !window.testReturnValue,
"mouseover event should have reverse return value handling (2)!");
is(handledCount, 4, "Wrong event count!");
e = document.createEvent("BeforeUnloadEvent");
e.initEvent("beforeunload", true, true);
window.testReturnValue = true;
is(target.dispatchEvent(e), false,
"beforeunload event should be prevented!");
is(handledCount, 5, "Wrong event count!");
window.testReturnValue = false;
is(target.dispatchEvent(e), false,
"beforeunload event should be prevented (2)!");
is(handledCount, 6, "Wrong event count!");
// Create normal event for beforeunload.
e = document.createEvent("Event");
e.initEvent("beforeunload", true, true);
window.testReturnValue = true;
is(target.dispatchEvent(e), true,
"beforeunload event shouldn't be prevented (3)!");
is(handledCount, 7, "Wrong event count!");
e = document.createEvent("MouseEvent");
e.initEvent("mousemove", true, true);
window.testReturnValue = true;
is(target.dispatchEvent(e), window.testReturnValue,
"mousemove event shouldn't have reverse return value handling!");
is(handledCount, 8, "Wrong event count!");
window.testReturnValue = false;
is(target.dispatchEvent(e), window.testReturnValue,
"mousemove event shouldn't have reverse return value handling (2)!");
is(handledCount, 9, "Wrong event count!");
</script>
</pre>
</body>
</html>

View file

@ -88,6 +88,8 @@ public:
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue, nsIAtom* aPrefix, const nsAString& aValue,
PRBool aNotify); PRBool aNotify);
virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
PRBool aNotify);
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent, nsIContent* aBindingParent,
@ -97,7 +99,12 @@ public:
virtual PRBool IsDoneAddingChildren(); virtual PRBool IsDoneAddingChildren();
virtual nsresult DoneAddingChildren(PRBool aHaveNotified); virtual nsresult DoneAddingChildren(PRBool aHaveNotified);
virtual void DestroyContent();
/**
* Call this to reevaluate whether we should start/stop due to our owner
* document being active or inactive.
*/
void NotifyOwnerDocumentActivityChanged();
// Called by the video decoder object, on the main thread, // Called by the video decoder object, on the main thread,
// when it has read the metadata containing video dimensions, // when it has read the metadata containing video dimensions,
@ -180,6 +187,9 @@ public:
// events can be fired. // events can be fired.
void ChangeReadyState(nsMediaReadyState aState); void ChangeReadyState(nsMediaReadyState aState);
// Return true if we can activate autoplay assuming enough data has arrived.
PRBool CanActivateAutoplay();
// Notify that enough data has arrived to start autoplaying. // Notify that enough data has arrived to start autoplaying.
// If the element is 'autoplay' and is ready to play back (not paused, // If the element is 'autoplay' and is ready to play back (not paused,
// autoplay pref enabled, etc), it should start playing back. // autoplay pref enabled, etc), it should start playing back.
@ -204,11 +214,6 @@ public:
// main thread when/if the size changes. // main thread when/if the size changes.
void UpdateMediaSize(nsIntSize size); void UpdateMediaSize(nsIntSize size);
// Handle moving into and out of the bfcache by pausing and playing
// as needed.
void Freeze();
void Thaw();
// Returns true if we can handle this MIME type. // Returns true if we can handle this MIME type.
// If it returns true, then it also returns a null-terminated list // If it returns true, then it also returns a null-terminated list
// of supported codecs in *aSupportedCodecs. This // of supported codecs in *aSupportedCodecs. This
@ -277,10 +282,10 @@ protected:
void SetPlayedOrSeeked(PRBool aValue); void SetPlayedOrSeeked(PRBool aValue);
/** /**
* Create a decoder for the given aMIMEType. Returns false if we * Create a decoder for the given aMIMEType. Returns null if we
* were unable to create the decoder. * were unable to create the decoder.
*/ */
PRBool CreateDecoder(const nsACString& aMIMEType); already_AddRefed<nsMediaDecoder> CreateDecoder(const nsACString& aMIMEType);
/** /**
* Initialize a decoder as a clone of an existing decoder in another * Initialize a decoder as a clone of an existing decoder in another
@ -298,7 +303,7 @@ protected:
/** /**
* Finish setting up the decoder after Load() has been called on it. * Finish setting up the decoder after Load() has been called on it.
*/ */
nsresult FinishDecoderSetup(); nsresult FinishDecoderSetup(nsMediaDecoder* aDecoder);
/** /**
* Execute the initial steps of the load algorithm that ensure existing * Execute the initial steps of the load algorithm that ensure existing
@ -371,6 +376,18 @@ protected:
nsIChannel *aNewChannel, nsIChannel *aNewChannel,
PRUint32 aFlags); PRUint32 aFlags);
/**
* Call this to reevaluate whether we should be holding a self-reference.
*/
void AddRemoveSelfReference();
/**
* Alias for Release(), but using stdcall calling convention so on
* platforms where Release has a strange calling convention (Windows)
* we can still get a method pointer to this method.
*/
void DoRelease() { Release(); }
nsRefPtr<nsMediaDecoder> mDecoder; nsRefPtr<nsMediaDecoder> mDecoder;
// Holds a reference to the first channel we open to the media resource. // Holds a reference to the first channel we open to the media resource.
@ -462,10 +479,8 @@ protected:
// to raise the 'waiting' event as per 4.7.1.8 in HTML 5 specification. // to raise the 'waiting' event as per 4.7.1.8 in HTML 5 specification.
PRPackedBool mPlayingBeforeSeek; PRPackedBool mPlayingBeforeSeek;
// PR_TRUE if the video was paused before Freeze was called. This is checked // PR_TRUE iff this element is paused because the document is inactive
// to ensure that the playstate doesn't change when the user goes Forward/Back PRPackedBool mPausedForInactiveDocument;
// from the bfcache.
PRPackedBool mPausedBeforeFreeze;
// PR_TRUE if we've reported a "waiting" event since the last // PR_TRUE if we've reported a "waiting" event since the last
// readyState change to HAVE_CURRENT_DATA. // readyState change to HAVE_CURRENT_DATA.
@ -499,4 +514,9 @@ protected:
// PR_TRUE if we've played or completed a seek. We use this to determine // PR_TRUE if we've played or completed a seek. We use this to determine
// when the poster frame should be shown. // when the poster frame should be shown.
PRPackedBool mHasPlayedOrSeeked; PRPackedBool mHasPlayedOrSeeked;
// PR_TRUE if we've added a reference to ourselves to keep the element
// alive while no-one is referencing it but the element may still fire
// events of its own accord.
PRPackedBool mHasSelfReference;
}; };

View file

@ -40,7 +40,11 @@
#define nsIFileControlElement_h___ #define nsIFileControlElement_h___
#include "nsISupports.h" #include "nsISupports.h"
class nsAString; #include "nsTArray.h"
#include "nsString.h"
#include "nsCOMArray.h"
class nsIFile;
// IID for the nsIFileControl interface // IID for the nsIFileControl interface
#define NS_IFILECONTROLELEMENT_IID \ #define NS_IFILECONTROLELEMENT_IID \
@ -57,14 +61,23 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFILECONTROLELEMENT_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFILECONTROLELEMENT_IID)
/** /**
* Gets filename to be uploaded when this control is submitted * Gets a readable string representing the list of files currently
* selected by this control. This value might not be a valid file name
* and should not be used for anything but displaying the filename to the
* user.
*/ */
virtual void GetFileName(nsAString& aFileName) = 0; virtual void GetDisplayFileName(nsAString& aFileName) = 0;
/** /**
* Sets filename to be uploaded when this control is submitted * Sets the list of filenames currently selected by this control.
*/ */
virtual void SetFileName(const nsAString& aFileName) = 0; virtual void SetFileNames(const nsTArray<nsString>& aFileNames) = 0;
/**
* Gets a list of nsIFile objects for the files currently selected by
* this control.
*/
virtual void GetFileArray(nsCOMArray<nsIFile>& aFiles) = 0;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileControlElement, NS_DEFINE_STATIC_IID_ACCESSOR(nsIFileControlElement,

View file

@ -721,7 +721,7 @@ nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
} }
nsresult nsresult
nsGenericHTMLElement::ScrollIntoView(PRBool aTop) nsGenericHTMLElement::ScrollIntoView(PRBool aTop, PRUint8 optional_argc)
{ {
nsIDocument *document = GetCurrentDoc(); nsIDocument *document = GetCurrentDoc();
@ -735,6 +735,10 @@ nsGenericHTMLElement::ScrollIntoView(PRBool aTop)
return NS_OK; return NS_OK;
} }
if (!optional_argc) {
aTop = PR_TRUE;
}
PRIntn vpercent = aTop ? NS_PRESSHELL_SCROLL_TOP : PRIntn vpercent = aTop ? NS_PRESSHELL_SCROLL_TOP :
NS_PRESSHELL_SCROLL_BOTTOM; NS_PRESSHELL_SCROLL_BOTTOM;

View file

@ -142,7 +142,7 @@ public:
nsresult GetOffsetParent(nsIDOMElement** aOffsetParent); nsresult GetOffsetParent(nsIDOMElement** aOffsetParent);
virtual nsresult GetInnerHTML(nsAString& aInnerHTML); virtual nsresult GetInnerHTML(nsAString& aInnerHTML);
virtual nsresult SetInnerHTML(const nsAString& aInnerHTML); virtual nsresult SetInnerHTML(const nsAString& aInnerHTML);
nsresult ScrollIntoView(PRBool aTop); nsresult ScrollIntoView(PRBool aTop, PRUint8 optional_argc);
// Declare Focus(), Blur(), GetTabIndex(), SetTabIndex(), GetSpellcheck(), // Declare Focus(), Blur(), GetTabIndex(), SetTabIndex(), GetSpellcheck(),
// SetSpellcheck(), and GetDraggable() such that classes that inherit interfaces // SetSpellcheck(), and GetDraggable() such that classes that inherit interfaces
// with those methods properly override them // with those methods properly override them

View file

@ -295,66 +295,23 @@ nsHTMLCanvasElement::ParseAttribute(PRInt32 aNamespaceID,
// nsHTMLCanvasElement::toDataURL // nsHTMLCanvasElement::toDataURL
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLCanvasElement::ToDataURL(nsAString& aDataURL) nsHTMLCanvasElement::ToDataURL(const nsAString& aType, const nsAString& aParams,
PRUint8 optional_argc, nsAString& aDataURL)
{ {
nsresult rv;
nsAXPCNativeCallContext *ncc = nsnull;
rv = nsContentUtils::XPConnect()->
GetCurrentNativeCallContext(&ncc);
NS_ENSURE_SUCCESS(rv, rv);
if (!ncc)
return NS_ERROR_FAILURE;
JSContext *ctx = nsnull;
rv = ncc->GetJSContext(&ctx);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 argc;
jsval *argv = nsnull;
ncc->GetArgc(&argc);
ncc->GetArgvPtr(&argv);
// do a trust check if this is a write-only canvas // do a trust check if this is a write-only canvas
// or if we're trying to use the 2-arg form // or if we're trying to use the 2-arg form
if ((mWriteOnly || argc >= 2) && !nsContentUtils::IsCallerTrustedForRead()) { if ((mWriteOnly || optional_argc >= 2) &&
!nsContentUtils::IsCallerTrustedForRead()) {
return NS_ERROR_DOM_SECURITY_ERR; return NS_ERROR_DOM_SECURITY_ERR;
} }
// 0-arg case; convert to png nsAutoString type(aType);
if (argc == 0) {
return ToDataURLImpl(NS_LITERAL_STRING("image/png"), EmptyString(), aDataURL); if (type.IsEmpty()) {
type.AssignLiteral("image/png");
} }
JSAutoRequest ar(ctx); return ToDataURLImpl(type, aParams, aDataURL);
// 1-arg case; convert to given mime type
if (argc == 1) {
if (!JSVAL_IS_STRING(argv[0]))
return NS_ERROR_DOM_SYNTAX_ERR;
JSString *type = JS_ValueToString(ctx, argv[0]);
return ToDataURLImpl (nsDependentString(reinterpret_cast<PRUnichar*>((JS_GetStringChars(type)))),
EmptyString(), aDataURL);
}
// 2-arg case; trusted only (checked above), convert to mime type with params
if (argc == 2) {
if (!JSVAL_IS_STRING(argv[0]) || !JSVAL_IS_STRING(argv[1]))
return NS_ERROR_DOM_SYNTAX_ERR;
JSString *type, *params;
type = JS_ValueToString(ctx, argv[0]);
params = JS_ValueToString(ctx, argv[1]);
return ToDataURLImpl (nsDependentString(reinterpret_cast<PRUnichar*>(JS_GetStringChars(type))),
nsDependentString(reinterpret_cast<PRUnichar*>(JS_GetStringChars(params))),
aDataURL);
}
return NS_ERROR_DOM_SYNTAX_ERR;
} }

View file

@ -192,24 +192,23 @@ class nsHTMLInputElementState : public nsISupports
mValue = aValue; mValue = aValue;
} }
const nsString& GetFilename() { const nsTArray<nsString>& GetFilenames() {
return mFilename; return mFilenames;
} }
void SetFilename(const nsAString &aFilename) { void SetFilenames(const nsTArray<nsString> &aFilenames) {
mFilename = aFilename; mFilenames = aFilenames;
} }
nsHTMLInputElementState() nsHTMLInputElementState()
: mValue() : mValue()
, mFilename()
, mChecked(PR_FALSE) , mChecked(PR_FALSE)
, mCheckedSet(PR_FALSE) , mCheckedSet(PR_FALSE)
{}; {};
protected: protected:
nsString mValue; nsString mValue;
nsString mFilename; nsTArray<nsString> mFilenames;
PRPackedBool mChecked; PRPackedBool mChecked;
PRPackedBool mCheckedSet; PRPackedBool mCheckedSet;
}; };
@ -298,8 +297,9 @@ public:
NS_IMETHOD SetValueChanged(PRBool aValueChanged); NS_IMETHOD SetValueChanged(PRBool aValueChanged);
// nsIFileControlElement // nsIFileControlElement
virtual void GetFileName(nsAString& aFileName); virtual void GetDisplayFileName(nsAString& aFileName);
virtual void SetFileName(const nsAString& aFileName); virtual void GetFileArray(nsCOMArray<nsIFile> &aFile);
virtual void SetFileNames(const nsTArray<nsString>& aFileNames);
// nsIRadioControlElement // nsIRadioControlElement
NS_IMETHOD RadioSetChecked(PRBool aNotify); NS_IMETHOD RadioSetChecked(PRBool aNotify);
@ -331,6 +331,17 @@ protected:
nsITextControlFrame* aFrame, nsITextControlFrame* aFrame,
PRBool aUserInput); PRBool aUserInput);
void ClearFileNames() {
nsTArray<nsString> fileNames;
SetFileNames(fileNames);
}
void SetSingleFileName(const nsAString& aFileName) {
nsAutoTArray<nsString, 1> fileNames;
fileNames.AppendElement(aFileName);
SetFileNames(fileNames);
}
nsresult SetIndeterminateInternal(PRBool aValue, nsresult SetIndeterminateInternal(PRBool aValue,
PRBool aShouldInvalidate); PRBool aShouldInvalidate);
@ -404,11 +415,6 @@ protected:
*/ */
nsresult MaybeSubmitForm(nsPresContext* aPresContext); nsresult MaybeSubmitForm(nsPresContext* aPresContext);
/**
* Get an nsIFile for the currently selected file in an file control.
*/
nsresult GetFile(nsIFile** aFile);
/** /**
* Update mFileList with the currently selected file. * Update mFileList with the currently selected file.
*/ */
@ -431,16 +437,16 @@ protected:
*/ */
char* mValue; char* mValue;
/** /**
* The value of the input if it is a file input. This is the filename used * The value of the input if it is a file input. This is the list of filenames
* when uploading a file. It is vital that this is kept separate from mValue * used when uploading a file. It is vital that this is kept separate from
* so that it won't be possible to 'leak' the value from a text-input to a * mValue so that it won't be possible to 'leak' the value from a text-input
* file-input. Additionally, the logic for this value is kept as simple as * to a file-input. Additionally, the logic for this value is kept as simple
* possible to avoid accidental errors where the wrong filename is used. * as possible to avoid accidental errors where the wrong filename is used.
* Therefor the filename is always owned by this member, never by the frame. * Therefor the list of filenames is always owned by this member, never by
* Whenever the frame wants to change the filename it has to call * the frame. Whenever the frame wants to change the filename it has to call
* SetFileName to update this member. * SetFileNames to update this member.
*/ */
nsAutoPtr<nsString> mFileName; nsTArray<nsString> mFileNames;
nsRefPtr<nsDOMFileList> mFileList; nsRefPtr<nsDOMFileList> mFileList;
}; };
@ -537,9 +543,7 @@ nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
} }
break; break;
case NS_FORM_INPUT_FILE: case NS_FORM_INPUT_FILE:
if (mFileName) { it->mFileNames = mFileNames;
it->mFileName = new nsString(*mFileName);
}
break; break;
case NS_FORM_INPUT_RADIO: case NS_FORM_INPUT_RADIO:
case NS_FORM_INPUT_CHECKBOX: case NS_FORM_INPUT_CHECKBOX:
@ -745,6 +749,7 @@ NS_IMPL_STRING_ATTR(nsHTMLInputElement, Align, align)
NS_IMPL_STRING_ATTR(nsHTMLInputElement, Alt, alt) NS_IMPL_STRING_ATTR(nsHTMLInputElement, Alt, alt)
//NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Checked, checked) //NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Checked, checked)
NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Disabled, disabled) NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Disabled, disabled)
NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Multiple, multiple)
NS_IMPL_INT_ATTR(nsHTMLInputElement, MaxLength, maxlength) NS_IMPL_INT_ATTR(nsHTMLInputElement, MaxLength, maxlength)
NS_IMPL_STRING_ATTR(nsHTMLInputElement, Name, name) NS_IMPL_STRING_ATTR(nsHTMLInputElement, Name, name)
NS_IMPL_BOOL_ATTR(nsHTMLInputElement, ReadOnly, readonly) NS_IMPL_BOOL_ATTR(nsHTMLInputElement, ReadOnly, readonly)
@ -868,17 +873,17 @@ nsHTMLInputElement::GetValue(nsAString& aValue)
if (mType == NS_FORM_INPUT_FILE) { if (mType == NS_FORM_INPUT_FILE) {
if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) { if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) {
if (mFileName) { if (!mFileNames.IsEmpty()) {
aValue = *mFileName; aValue = mFileNames[0];
} }
else { else {
aValue.Truncate(); aValue.Truncate();
} }
} else { } else {
// Just return the leaf name // Just return the leaf name
nsCOMPtr<nsIFile> file; nsCOMArray<nsIFile> files;
GetFile(getter_AddRefs(file)); GetFileArray(files);
if (!file || NS_FAILED(file->GetLeafName(aValue))) { if (files.Count() == 0 || NS_FAILED(files[0]->GetLeafName(aValue))) {
aValue.Truncate(); aValue.Truncate();
} }
} }
@ -912,8 +917,11 @@ nsHTMLInputElement::SetValue(const nsAString& aValue)
// UniversalFileRead privilege // UniversalFileRead privilege
return NS_ERROR_DOM_SECURITY_ERR; return NS_ERROR_DOM_SECURITY_ERR;
} }
SetSingleFileName(aValue);
}
else {
ClearFileNames();
} }
SetFileName(aValue);
} }
else { else {
SetValueInternal(aValue, nsnull, PR_FALSE); SetValueInternal(aValue, nsnull, PR_FALSE);
@ -922,6 +930,47 @@ nsHTMLInputElement::SetValue(const nsAString& aValue)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsHTMLInputElement::MozGetFileNameArray(PRUint32 *aLength, PRUnichar ***aFileNames)
{
if (!nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) {
// Since this function returns full paths it's important that normal pages
// can't call it.
return NS_ERROR_DOM_SECURITY_ERR;
}
*aLength = mFileNames.Length();
PRUnichar **ret =
static_cast<PRUnichar **>(NS_Alloc(mFileNames.Length() * sizeof(PRUnichar*)));
for (PRUint32 i = 0; i < mFileNames.Length(); i++) {
ret[i] = NS_strdup(mFileNames[i].get());
}
*aFileNames = ret;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLInputElement::MozSetFileNameArray(const PRUnichar **aFileNames, PRUint32 aLength)
{
if (!nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) {
// setting the value of a "FILE" input widget requires the
// UniversalFileRead privilege
return NS_ERROR_DOM_SECURITY_ERR;
}
nsTArray<nsString> fileNames(aLength);
for (PRUint32 i = 0; i < aLength; ++i) {
fileNames.AppendElement(aFileNames[i]);
}
SetFileNames(fileNames);
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLInputElement::SetUserInput(const nsAString& aValue) nsHTMLInputElement::SetUserInput(const nsAString& aValue)
{ {
@ -931,7 +980,7 @@ nsHTMLInputElement::SetUserInput(const nsAString& aValue)
if (mType == NS_FORM_INPUT_FILE) if (mType == NS_FORM_INPUT_FILE)
{ {
SetFileName(aValue); SetSingleFileName(aValue);
} else { } else {
SetValueInternal(aValue, nsnull, PR_TRUE); SetValueInternal(aValue, nsnull, PR_TRUE);
} }
@ -949,28 +998,36 @@ nsHTMLInputElement::TakeTextFrameValue(const nsAString& aValue)
} }
void void
nsHTMLInputElement::GetFileName(nsAString& aValue) nsHTMLInputElement::GetDisplayFileName(nsAString& aValue)
{ {
if (mFileName) { aValue.Truncate();
aValue = *mFileName; for (PRUint32 i = 0; i < mFileNames.Length(); ++i) {
} if (i == 0) {
else { aValue.Append(mFileNames[i]);
aValue.Truncate(); }
else {
aValue.Append(NS_LITERAL_STRING(", ") + mFileNames[i]);
}
} }
} }
void void
nsHTMLInputElement::SetFileName(const nsAString& aValue) nsHTMLInputElement::SetFileNames(const nsTArray<nsString>& aFileNames)
{ {
// No big deal if |new| fails, we simply won't submit the file mFileNames = aFileNames;
mFileName = aValue.IsEmpty() ? nsnull : new nsString(aValue); #if DEBUG
for (PRUint32 i = 0; i < (PRUint32)aFileNames.Length(); ++i) {
NS_ASSERTION(!aFileNames[i].IsEmpty(), "Empty file name");
}
#endif
// No need to flush here, if there's no frame at this point we // No need to flush here, if there's no frame at this point we
// don't need to force creation of one just to tell it about this // don't need to force creation of one just to tell it about this
// new value. We just want the display to update as needed. // new value. We just want the display to update as needed.
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE); nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
if (formControlFrame) { if (formControlFrame) {
formControlFrame->SetFormProperty(nsGkAtoms::value, aValue); nsAutoString readableValue;
GetDisplayFileName(readableValue);
formControlFrame->SetFormProperty(nsGkAtoms::value, readableValue);
} }
UpdateFileList(); UpdateFileList();
@ -978,32 +1035,37 @@ nsHTMLInputElement::SetFileName(const nsAString& aValue)
SetValueChanged(PR_TRUE); SetValueChanged(PR_TRUE);
} }
nsresult void
nsHTMLInputElement::GetFile(nsIFile** aFile) nsHTMLInputElement::GetFileArray(nsCOMArray<nsIFile> &aFiles)
{ {
*aFile = nsnull; aFiles.Clear();
if (!mFileName || mType != NS_FORM_INPUT_FILE) { if (mType != NS_FORM_INPUT_FILE) {
return NS_ERROR_NOT_AVAILABLE; return;
} }
nsresult rv = NS_ERROR_NOT_AVAILABLE; for (PRUint32 i = 0; i < mFileNames.Length(); ++i) {
nsCOMPtr<nsIFile> file;
if (StringBeginsWith(mFileNames[i], NS_LITERAL_STRING("file:"),
nsCaseInsensitiveStringComparator())) {
// Converts the URL string into the corresponding nsIFile if possible.
// A local file will be created if the URL string begins with file://.
NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(mFileNames[i]),
getter_AddRefs(file));
}
if (StringBeginsWith(*mFileName, NS_LITERAL_STRING("file:"), if (!file) {
nsCaseInsensitiveStringComparator())) { // this is no "file://", try as local file
// Converts the URL string into the corresponding nsIFile if possible. nsCOMPtr<nsILocalFile> localFile;
// A local file will be created if the URL string begins with file://. NS_NewLocalFile(mFileNames[i], PR_FALSE, getter_AddRefs(localFile));
rv = NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(*mFileName), aFile); // Wish there was a better way to downcast an already_AddRefed
file = dont_AddRef(static_cast<nsIFile*>(localFile.forget().get()));
}
if (file) {
aFiles.AppendObject(file);
}
} }
if (!(*aFile)) {
// this is no "file://", try as local file
nsCOMPtr<nsILocalFile> localFile;
rv = NS_NewLocalFile(*mFileName, PR_FALSE, getter_AddRefs(localFile));
NS_IF_ADDREF(*aFile = localFile);
}
return rv;
} }
nsresult nsresult
@ -1012,12 +1074,10 @@ nsHTMLInputElement::UpdateFileList()
if (mFileList) { if (mFileList) {
mFileList->Clear(); mFileList->Clear();
if (mType == NS_FORM_INPUT_FILE && mFileName) { nsCOMArray<nsIFile> files;
nsCOMPtr<nsIFile> file; GetFileArray(files);
nsresult rv = GetFile(getter_AddRefs(file)); for (PRUint32 i = 0; i < (PRUint32)files.Count(); ++i) {
NS_ENSURE_SUCCESS(rv, rv); nsRefPtr<nsDOMFile> domFile = new nsDOMFile(files[i]);
nsRefPtr<nsDOMFile> domFile = new nsDOMFile(file);
if (domFile) { if (domFile) {
if (!mFileList->Append(domFile)) { if (!mFileList->Append(domFile)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -2113,14 +2173,11 @@ nsHTMLInputElement::ParseAttribute(PRInt32 aNamespaceID,
// makes assumptions about our frame based on mType, but we won't have // makes assumptions about our frame based on mType, but we won't have
// had time to recreate frames yet -- that happens later in the // had time to recreate frames yet -- that happens later in the
// SetAttr() process). // SetAttr() process).
if (newType == NS_FORM_INPUT_FILE) { if (newType == NS_FORM_INPUT_FILE || mType == NS_FORM_INPUT_FILE) {
// These calls aren't strictly needed any more since we'll never // This call isn't strictly needed any more since we'll never
// confuse values and filenames. However they're there for backwards // confuse values and filenames. However it's there for backwards
// compat. // compat.
SetFileName(EmptyString()); ClearFileNames();
SetValueInternal(EmptyString(), nsnull, PR_FALSE);
} else if (mType == NS_FORM_INPUT_FILE) {
SetFileName(EmptyString());
} }
mType = newType; mType = newType;
@ -2471,7 +2528,7 @@ nsHTMLInputElement::Reset()
case NS_FORM_INPUT_FILE: case NS_FORM_INPUT_FILE:
{ {
// Resetting it to blank should not perform security check // Resetting it to blank should not perform security check
SetFileName(EmptyString()); ClearFileNames();
break; break;
} }
// Value is the same as defaultValue for hidden inputs // Value is the same as defaultValue for hidden inputs
@ -2593,87 +2650,65 @@ nsHTMLInputElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
// Submit file if its input type=file and this encoding method accepts files // Submit file if its input type=file and this encoding method accepts files
// //
if (mType == NS_FORM_INPUT_FILE) { if (mType == NS_FORM_INPUT_FILE) {
// // Submit files
// Open the file
//
nsCOMPtr<nsIFile> file;
rv = GetFile(getter_AddRefs(file));
if (file) { nsCOMPtr<nsIMIMEService> MIMEService =
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMArray<nsIFile> files;
GetFileArray(files);
for (PRUint32 i = 0; i < (PRUint32)files.Count(); ++i) {
nsIFile* file = files[i];
//
// Get the leaf path name (to be submitted as the value) // Get the leaf path name (to be submitted as the value)
// PRBool fileSent = PR_FALSE;
nsAutoString filename; nsAutoString filename;
rv = file->GetLeafName(filename); rv = file->GetLeafName(filename);
if (NS_FAILED(rv)) {
filename.Truncate();
}
if (NS_SUCCEEDED(rv) && !filename.IsEmpty()) { if (!filename.IsEmpty() && aFormSubmission->AcceptsFiles()) {
PRBool acceptsFiles = aFormSubmission->AcceptsFiles(); // Get content type
nsCAutoString contentType;
if (acceptsFiles) { rv = MIMEService->GetTypeFromFile(file, contentType);
// if (NS_FAILED(rv)) {
// Get content type contentType.AssignLiteral("application/octet-stream");
//
nsCOMPtr<nsIMIMEService> MIMEService =
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString contentType;
rv = MIMEService->GetTypeFromFile(file, contentType);
if (NS_FAILED(rv)) {
contentType.AssignLiteral("application/octet-stream");
}
//
// Get input stream
//
nsCOMPtr<nsIInputStream> fileStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream),
file, -1, -1,
nsIFileInputStream::CLOSE_ON_EOF |
nsIFileInputStream::REOPEN_ON_REWIND);
if (fileStream) {
//
// Create buffered stream (for efficiency)
//
nsCOMPtr<nsIInputStream> bufferedStream;
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
fileStream, 8192);
NS_ENSURE_SUCCESS(rv, rv);
if (bufferedStream) {
//
// Submit
//
aFormSubmission->AddNameFilePair(this, name, filename,
bufferedStream, contentType,
PR_FALSE);
return rv;
}
}
} }
// // Get input stream
nsCOMPtr<nsIInputStream> fileStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream),
file, -1, -1,
nsIFileInputStream::CLOSE_ON_EOF |
nsIFileInputStream::REOPEN_ON_REWIND);
if (fileStream) {
// Create buffered stream (for efficiency)
nsCOMPtr<nsIInputStream> bufferedStream;
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
fileStream, 8192);
NS_ENSURE_SUCCESS(rv, rv);
// Submit
aFormSubmission->AddNameFilePair(this, name, filename,
bufferedStream, contentType,
PR_FALSE);
fileSent = PR_TRUE;
}
}
if (!fileSent) {
// If we don't submit as a file, at least submit the truncated filename. // If we don't submit as a file, at least submit the truncated filename.
//
aFormSubmission->AddNameFilePair(this, name, filename, aFormSubmission->AddNameFilePair(this, name, filename,
nsnull, NS_LITERAL_CSTRING("application/octet-stream"), nsnull, NS_LITERAL_CSTRING("application/octet-stream"),
PR_FALSE); PR_FALSE);
return rv;
} else {
// Ignore error returns from GetLeafName. See bug 199053
rv = NS_OK;
} }
} }
// return NS_OK;
// If we can't even make a truncated filename, submit empty string
// rather than sending everything
//
aFormSubmission->AddNameFilePair(this, name, EmptyString(),
nsnull, NS_LITERAL_CSTRING("application/octet-stream"),
PR_FALSE);
return rv;
} }
// Submit // Submit
@ -2740,13 +2775,13 @@ nsHTMLInputElement::SaveState()
} }
case NS_FORM_INPUT_FILE: case NS_FORM_INPUT_FILE:
{ {
if (mFileName) { if (!mFileNames.IsEmpty()) {
inputState = new nsHTMLInputElementState(); inputState = new nsHTMLInputElementState();
if (!inputState) { if (!inputState) {
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
inputState->SetFilename(*mFileName); inputState->SetFilenames(mFileNames);
} }
break; break;
} }
@ -2859,7 +2894,7 @@ nsHTMLInputElement::RestoreState(nsPresState* aState)
} }
case NS_FORM_INPUT_FILE: case NS_FORM_INPUT_FILE:
{ {
SetFileName(inputState->GetFilename()); SetFileNames(inputState->GetFilenames());
break; break;
} }
} }

View file

@ -96,6 +96,48 @@ static PRLogModuleInfo* gMediaElementEventsLog;
#define LOG_EVENT(type, msg) #define LOG_EVENT(type, msg)
#endif #endif
// Under certain conditions there may be no-one holding references to
// a media element from script, DOM parent, etc, but the element may still
// fire meaningful events in the future so we can't destroy it yet:
// 1) If the element is delaying the load event (or would be, if it were
// in a document), then events up to loadeddata or error could be fired,
// so we need to stay alive.
// 2) If the element is not paused and playback has not ended, then
// we will (or might) play, sending timeupdate and ended events and possibly
// audio output, so we need to stay alive.
// 3) if the element is seeking then we will fire seeking events and possibly
// start playing afterward, so we need to stay alive.
// 4) If autoplay could start playback in this element (if we got enough data),
// then we need to stay alive.
// 5) if the element is currently loading and not suspended,
// script might be waiting for progress events or a 'suspend' event,
// so we need to stay alive. If we're already suspended then (all other
// conditions being met) it's OK to just disappear without firing any more
// events, since we have the freedom to remain suspended indefinitely. Note
// that we could use this 'suspended' loophole to garbage-collect a suspended
// element in case 4 even if it had 'autoplay' set, but we choose not to.
// If someone throws away all references to a loading 'autoplay' element
// sound should still eventually play.
//
// Media elements owned by inactive documents (i.e. documents not contained in any
// document viewer) should never hold a self-reference because none of the
// above conditions are allowed: the element will stop loading and playing
// and never resume loading or playing unless its owner document changes to
// an active document (which can only happen if there is an external reference
// to the element).
// Media elements with no owner doc should be able to hold a self-reference.
// Something native must have created the element and may expect it to
// stay alive to play.
// It's very important that any change in state which could change the value of
// needSelfReference in AddRemoveSelfReference be followed by a call to
// AddRemoveSelfReference before this element could die!
// It's especially important if needSelfReference would change to 'true',
// since if we neglect to add a self-reference, this element might be
// garbage collected while there are still event listeners that should
// receive events. If we neglect to remove the self-reference then the element
// just lives longer than it needs to.
class nsMediaEvent : public nsRunnable class nsMediaEvent : public nsRunnable
{ {
public: public:
@ -414,14 +456,21 @@ void nsHTMLMediaElement::AbortExistingLoads()
DispatchSimpleEvent(NS_LITERAL_STRING("emptied")); DispatchSimpleEvent(NS_LITERAL_STRING("emptied"));
} }
// We may have changed mPaused, mAutoplaying, mNetworkState and other
// things which can affect AddRemoveSelfReference
AddRemoveSelfReference();
mIsRunningSelectResource = PR_FALSE; mIsRunningSelectResource = PR_FALSE;
} }
void nsHTMLMediaElement::NoSupportedMediaSourceError() void nsHTMLMediaElement::NoSupportedMediaSourceError()
{ {
NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during source selection?");
mError = new nsHTMLMediaError(nsIDOMHTMLMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED); mError = new nsHTMLMediaError(nsIDOMHTMLMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("error")); DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
ChangeDelayLoadStatus(PR_FALSE); ChangeDelayLoadStatus(PR_FALSE);
} }
@ -465,16 +514,21 @@ static PRBool HasPotentialResource(nsIContent *aElement)
void nsHTMLMediaElement::SelectResource() void nsHTMLMediaElement::SelectResource()
{ {
NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during resource selection?");
if (!HasPotentialResource(this)) { if (!HasPotentialResource(this)) {
// While the media element has neither a src attribute nor any source // While the media element has neither a src attribute nor any source
// element children, wait. (This steps might wait forever.) // element children, wait. (This steps might wait forever.)
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
mLoadWaitStatus = WAITING_FOR_SRC_OR_SOURCE; mLoadWaitStatus = WAITING_FOR_SRC_OR_SOURCE;
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
ChangeDelayLoadStatus(PR_FALSE); ChangeDelayLoadStatus(PR_FALSE);
return; return;
} }
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
// Load event was delayed, and still is, so no need to call
// AddRemoveSelfReference, since it must still be held
DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart")); DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart"));
nsAutoString src; nsAutoString src;
@ -508,8 +562,8 @@ void nsHTMLMediaElement::NotifyLoadError()
void nsHTMLMediaElement::LoadFromSourceChildren() void nsHTMLMediaElement::LoadFromSourceChildren()
{ {
NS_ASSERTION(!IsInDoc() || mDelayingLoadEvent, NS_ASSERTION(mDelayingLoadEvent,
"Should delay load event while loading in document"); "Should delay load event (if in document) during load");
while (PR_TRUE) { while (PR_TRUE) {
nsresult rv; nsresult rv;
nsCOMPtr<nsIURI> uri = GetNextSource(); nsCOMPtr<nsIURI> uri = GetNextSource();
@ -534,8 +588,8 @@ void nsHTMLMediaElement::LoadFromSourceChildren()
nsresult nsHTMLMediaElement::LoadResource(nsIURI* aURI) nsresult nsHTMLMediaElement::LoadResource(nsIURI* aURI)
{ {
NS_ASSERTION(!IsInDoc() || mDelayingLoadEvent, NS_ASSERTION(mDelayingLoadEvent,
"Should delay load event while loading in document"); "Should delay load event (if in document) during load");
nsresult rv; nsresult rv;
if (mChannel) { if (mChannel) {
@ -721,6 +775,10 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(float aCurrentTime)
// event if it changes the playback position as a result of the seek. // event if it changes the playback position as a result of the seek.
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) starting seek", this, aCurrentTime)); LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) starting seek", this, aCurrentTime));
nsresult rv = mDecoder->Seek(clampedTime); nsresult rv = mDecoder->Seek(clampedTime);
// We changed whether we're seeking so we need to AddRemoveSelfReference
AddRemoveSelfReference();
return rv; return rv;
} }
@ -752,6 +810,8 @@ NS_IMETHODIMP nsHTMLMediaElement::Pause()
PRBool oldPaused = mPaused; PRBool oldPaused = mPaused;
mPaused = PR_TRUE; mPaused = PR_TRUE;
mAutoplaying = PR_FALSE; mAutoplaying = PR_FALSE;
// We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
AddRemoveSelfReference();
if (!oldPaused) { if (!oldPaused) {
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("timeupdate")); DispatchAsyncSimpleEvent(NS_LITERAL_STRING("timeupdate"));
@ -827,7 +887,7 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
mMuted(PR_FALSE), mMuted(PR_FALSE),
mIsDoneAddingChildren(!aFromParser), mIsDoneAddingChildren(!aFromParser),
mPlayingBeforeSeek(PR_FALSE), mPlayingBeforeSeek(PR_FALSE),
mPausedBeforeFreeze(PR_FALSE), mPausedForInactiveDocument(PR_FALSE),
mWaitingFired(PR_FALSE), mWaitingFired(PR_FALSE),
mIsBindingToTree(PR_FALSE), mIsBindingToTree(PR_FALSE),
mIsRunningLoadMethod(PR_FALSE), mIsRunningLoadMethod(PR_FALSE),
@ -836,7 +896,8 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
mIsRunningSelectResource(PR_FALSE), mIsRunningSelectResource(PR_FALSE),
mSuspendedAfterFirstFrame(PR_FALSE), mSuspendedAfterFirstFrame(PR_FALSE),
mAllowSuspendAfterFirstFrame(PR_TRUE), mAllowSuspendAfterFirstFrame(PR_TRUE),
mHasPlayedOrSeeked(PR_FALSE) mHasPlayedOrSeeked(PR_FALSE),
mHasSelfReference(PR_FALSE)
{ {
#ifdef PR_LOGGING #ifdef PR_LOGGING
if (!gMediaElementLog) { if (!gMediaElementLog) {
@ -848,10 +909,14 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
#endif #endif
RegisterFreezableElement(); RegisterFreezableElement();
NotifyOwnerDocumentActivityChanged();
} }
nsHTMLMediaElement::~nsHTMLMediaElement() nsHTMLMediaElement::~nsHTMLMediaElement()
{ {
NS_ASSERTION(!mHasSelfReference,
"How can we be destroyed if we're still holding a self reference?");
UnregisterFreezableElement(); UnregisterFreezableElement();
if (mDecoder) { if (mDecoder) {
mDecoder->Shutdown(); mDecoder->Shutdown();
@ -905,8 +970,10 @@ NS_IMETHODIMP nsHTMLMediaElement::Play()
if (mDecoder->IsEnded()) { if (mDecoder->IsEnded()) {
SetCurrentTime(0); SetCurrentTime(0);
} }
nsresult rv = mDecoder->Play(); if (!mPausedForInactiveDocument) {
NS_ENSURE_SUCCESS(rv, rv); nsresult rv = mDecoder->Play();
NS_ENSURE_SUCCESS(rv, rv);
}
} }
// TODO: If the playback has ended, then the user agent must set // TODO: If the playback has ended, then the user agent must set
@ -928,6 +995,8 @@ NS_IMETHODIMP nsHTMLMediaElement::Play()
mPaused = PR_FALSE; mPaused = PR_FALSE;
mAutoplaying = PR_FALSE; mAutoplaying = PR_FALSE;
// We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
AddRemoveSelfReference();
return NS_OK; return NS_OK;
} }
@ -979,6 +1048,8 @@ nsresult nsHTMLMediaElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) { if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
NotifyAutoplayDataReady(); NotifyAutoplayDataReady();
} }
// This attribute can affect AddRemoveSelfReference
AddRemoveSelfReference();
} else if (aName == nsGkAtoms::autobuffer) { } else if (aName == nsGkAtoms::autobuffer) {
StopSuspendingAfterFirstFrame(); StopSuspendingAfterFirstFrame();
} }
@ -987,6 +1058,22 @@ nsresult nsHTMLMediaElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
return rv; return rv;
} }
nsresult nsHTMLMediaElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
PRBool aNotify)
{
nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttr, aNotify);
if (aNotify && aNameSpaceID == kNameSpaceID_None) {
if (aAttr == nsGkAtoms::autoplay) {
// This attribute can affect AddRemoveSelfReference
AddRemoveSelfReference();
}
// We perhaps should stop loading if 'autobuffer' is being removed,
// and we're buffering only because of 'autobuffer', but why bother?
}
return rv;
}
static PRBool IsAutoplayEnabled() static PRBool IsAutoplayEnabled()
{ {
return nsContentUtils::GetBoolPref("media.autoplay.enabled"); return nsContentUtils::GetBoolPref("media.autoplay.enabled");
@ -1227,25 +1314,26 @@ void nsHTMLMediaElement::ShutdownMediaTypes()
} }
} }
PRBool nsHTMLMediaElement::CreateDecoder(const nsACString& aType) already_AddRefed<nsMediaDecoder>
nsHTMLMediaElement::CreateDecoder(const nsACString& aType)
{ {
#ifdef MOZ_OGG #ifdef MOZ_OGG
if (IsOggType(aType)) { if (IsOggType(aType)) {
mDecoder = new nsOggDecoder(); nsRefPtr<nsOggDecoder> decoder = new nsOggDecoder();
if (mDecoder && !mDecoder->Init(this)) { if (decoder && decoder->Init(this)) {
mDecoder = nsnull; return decoder.forget().get();
} }
} }
#endif #endif
#ifdef MOZ_WAVE #ifdef MOZ_WAVE
if (IsWaveType(aType)) { if (IsWaveType(aType)) {
mDecoder = new nsWaveDecoder(); nsRefPtr<nsWaveDecoder> decoder = new nsWaveDecoder();
if (mDecoder && !mDecoder->Init(this)) { if (decoder && decoder->Init(this)) {
mDecoder = nsnull; return decoder.forget().get();
} }
} }
#endif #endif
return mDecoder != nsnull; return nsnull;
} }
nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal) nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
@ -1253,38 +1341,35 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
nsMediaStream* originalStream = aOriginal->GetCurrentStream(); nsMediaStream* originalStream = aOriginal->GetCurrentStream();
if (!originalStream) if (!originalStream)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
mDecoder = aOriginal->Clone(); nsRefPtr<nsMediaDecoder> decoder = aOriginal->Clone();
if (!mDecoder) if (!decoder)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
LOG(PR_LOG_DEBUG, ("%p Cloned decoder %p from %p", this, mDecoder.get(), aOriginal)); LOG(PR_LOG_DEBUG, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
if (!mDecoder->Init(this)) { if (!decoder->Init(this)) {
mDecoder = nsnull;
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
float duration = aOriginal->GetDuration(); float duration = aOriginal->GetDuration();
if (duration >= 0) { if (duration >= 0) {
mDecoder->SetDuration(PRInt64(NS_round(duration * 1000))); decoder->SetDuration(PRInt64(NS_round(duration * 1000)));
mDecoder->SetSeekable(aOriginal->GetSeekable()); decoder->SetSeekable(aOriginal->GetSeekable());
} }
nsMediaStream* stream = originalStream->CloneData(mDecoder); nsMediaStream* stream = originalStream->CloneData(decoder);
if (!stream) { if (!stream) {
mDecoder = nsnull;
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
nsresult rv = mDecoder->Load(stream, nsnull); nsresult rv = decoder->Load(stream, nsnull);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mDecoder = nsnull;
return rv; return rv;
} }
return FinishDecoderSetup(); return FinishDecoderSetup(decoder);
} }
nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel, nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
@ -1293,20 +1378,21 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
nsCAutoString mimeType; nsCAutoString mimeType;
aChannel->GetContentType(mimeType); aChannel->GetContentType(mimeType);
if (!CreateDecoder(mimeType)) nsRefPtr<nsMediaDecoder> decoder = CreateDecoder(mimeType);
if (!decoder) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
}
LOG(PR_LOG_DEBUG, ("%p Created decoder %p for type %s", this, mDecoder.get(), mimeType.get())); LOG(PR_LOG_DEBUG, ("%p Created decoder %p for type %s", this, decoder.get(), mimeType.get()));
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
nsMediaStream* stream = nsMediaStream::Create(mDecoder, aChannel); nsMediaStream* stream = nsMediaStream::Create(decoder, aChannel);
if (!stream) if (!stream)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = mDecoder->Load(stream, aListener); nsresult rv = decoder->Load(stream, aListener);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mDecoder = nsnull;
return rv; return rv;
} }
@ -1314,18 +1400,28 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
// which owns the channel. // which owns the channel.
mChannel = nsnull; mChannel = nsnull;
return FinishDecoderSetup(); return FinishDecoderSetup(decoder);
} }
nsresult nsHTMLMediaElement::FinishDecoderSetup() nsresult nsHTMLMediaElement::FinishDecoderSetup(nsMediaDecoder* aDecoder)
{ {
mDecoder = aDecoder;
// The new stream has not been suspended by us.
mPausedForInactiveDocument = PR_FALSE;
// But we may want to suspend it now.
// This will also do an AddRemoveSelfReference.
NotifyOwnerDocumentActivityChanged();
nsresult rv = NS_OK; nsresult rv = NS_OK;
mDecoder->SetVolume(mMuted ? 0.0 : mVolume); mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
if (!mPaused) { if (!mPaused) {
SetPlayedOrSeeked(PR_TRUE); SetPlayedOrSeeked(PR_TRUE);
rv = mDecoder->Play(); if (!mPausedForInactiveDocument) {
rv = mDecoder->Play();
}
} }
mBegun = PR_TRUE; mBegun = PR_TRUE;
@ -1393,6 +1489,7 @@ void nsHTMLMediaElement::ResourceLoaded()
{ {
mBegun = PR_FALSE; mBegun = PR_FALSE;
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
AddRemoveSelfReference();
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA); ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
// The download has stopped // The download has stopped
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("suspend")); DispatchAsyncSimpleEvent(NS_LITERAL_STRING("suspend"));
@ -1404,6 +1501,7 @@ void nsHTMLMediaElement::NetworkError()
mBegun = PR_FALSE; mBegun = PR_FALSE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("error")); DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
AddRemoveSelfReference();
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied")); DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied"));
ChangeDelayLoadStatus(PR_FALSE); ChangeDelayLoadStatus(PR_FALSE);
} }
@ -1414,6 +1512,7 @@ void nsHTMLMediaElement::DecodeError()
mBegun = PR_FALSE; mBegun = PR_FALSE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("error")); DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
AddRemoveSelfReference();
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied")); DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied"));
ChangeDelayLoadStatus(PR_FALSE); ChangeDelayLoadStatus(PR_FALSE);
} }
@ -1421,6 +1520,9 @@ void nsHTMLMediaElement::DecodeError()
void nsHTMLMediaElement::PlaybackEnded() void nsHTMLMediaElement::PlaybackEnded()
{ {
NS_ASSERTION(mDecoder->IsEnded(), "Decoder fired ended, but not in ended state"); NS_ASSERTION(mDecoder->IsEnded(), "Decoder fired ended, but not in ended state");
// We changed the state of IsPlaybackEnded which can affect AddRemoveSelfReference
AddRemoveSelfReference();
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("ended")); DispatchAsyncSimpleEvent(NS_LITERAL_STRING("ended"));
} }
@ -1434,12 +1536,15 @@ void nsHTMLMediaElement::SeekCompleted()
mPlayingBeforeSeek = PR_FALSE; mPlayingBeforeSeek = PR_FALSE;
SetPlayedOrSeeked(PR_TRUE); SetPlayedOrSeeked(PR_TRUE);
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("seeked")); DispatchAsyncSimpleEvent(NS_LITERAL_STRING("seeked"));
// We changed whether we're seeking so we need to AddRemoveSelfReference
AddRemoveSelfReference();
} }
void nsHTMLMediaElement::DownloadSuspended() void nsHTMLMediaElement::DownloadSuspended()
{ {
if (mBegun) { if (mBegun) {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
AddRemoveSelfReference();
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("suspend")); DispatchAsyncSimpleEvent(NS_LITERAL_STRING("suspend"));
} }
} }
@ -1448,6 +1553,7 @@ void nsHTMLMediaElement::DownloadResumed()
{ {
if (mBegun) { if (mBegun) {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
AddRemoveSelfReference();
} }
} }
@ -1578,13 +1684,21 @@ void nsHTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
} }
} }
PRBool nsHTMLMediaElement::CanActivateAutoplay()
{
return mAutoplaying &&
mPaused &&
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
mAutoplayEnabled;
}
void nsHTMLMediaElement::NotifyAutoplayDataReady() void nsHTMLMediaElement::NotifyAutoplayDataReady()
{ {
if (mAutoplaying && if (CanActivateAutoplay()) {
mPaused &&
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
mAutoplayEnabled) {
mPaused = PR_FALSE; mPaused = PR_FALSE;
// We changed mPaused which can affect AddRemoveSelfReference
AddRemoveSelfReference();
if (mDecoder) { if (mDecoder) {
SetPlayedOrSeeked(PR_TRUE); SetPlayedOrSeeked(PR_TRUE);
mDecoder->Play(); mDecoder->Play();
@ -1685,7 +1799,7 @@ PRBool nsHTMLMediaElement::IsPotentiallyPlaying() const
// TODO: // TODO:
// playback has not stopped due to errors, // playback has not stopped due to errors,
// and the element has not paused for user interaction // and the element has not paused for user interaction
return return
!mPaused && !mPaused &&
(mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA || (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA ||
mReadyState == nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) && mReadyState == nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) &&
@ -1714,38 +1828,61 @@ void nsHTMLMediaElement::UpdateMediaSize(nsIntSize size)
mMediaSize = size; mMediaSize = size;
} }
void nsHTMLMediaElement::DestroyContent() void nsHTMLMediaElement::NotifyOwnerDocumentActivityChanged()
{ {
if (mDecoder) { nsIDocument* ownerDoc = GetOwnerDoc();
mDecoder->Shutdown(); // Don't pause if we have no ownerDoc. Something native must have created
mDecoder = nsnull; // us and be expecting us to work without a document.
PRBool pauseForInactiveDocument =
ownerDoc && (!ownerDoc->IsActive() || !ownerDoc->IsVisible());
if (pauseForInactiveDocument != mPausedForInactiveDocument) {
mPausedForInactiveDocument = pauseForInactiveDocument;
if (mDecoder) {
if (pauseForInactiveDocument) {
mDecoder->Pause();
mDecoder->Suspend();
} else {
mDecoder->Resume();
if (IsPotentiallyPlaying()) {
mDecoder->Play();
}
}
}
} }
if (mChannel) {
mChannel->Cancel(NS_BINDING_ABORTED); AddRemoveSelfReference();
mChannel = nsnull;
}
nsGenericHTMLElement::DestroyContent();
} }
void nsHTMLMediaElement::Freeze() void nsHTMLMediaElement::AddRemoveSelfReference()
{ {
mPausedBeforeFreeze = mPaused; // XXX we could release earlier here in many situations if we examined
if (!mPaused) { // which event listeners are attached. Right now we assume there is a
Pause(); // potential listener for every event. We would also have to keep the
} // element alive if it was playing and producing audio output --- right now
if (mDecoder) { // that's covered by the !mPaused check.
mDecoder->Suspend(); nsIDocument* ownerDoc = GetOwnerDoc();
}
}
void nsHTMLMediaElement::Thaw() // See the comment at the top of this file for the explanation of this
{ // boolean expression.
if (!mPausedBeforeFreeze) { PRBool needSelfReference = (!ownerDoc || ownerDoc->IsActive()) &&
Play(); (mDelayingLoadEvent ||
} (!mPaused && mDecoder && !mDecoder->IsEnded()) ||
(mDecoder && mDecoder->IsSeeking()) ||
CanActivateAutoplay() ||
mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
if (mDecoder) { if (needSelfReference != mHasSelfReference) {
mDecoder->Resume(); mHasSelfReference = needSelfReference;
if (needSelfReference) {
NS_ADDREF(this);
} else {
// Dispatch Release asynchronously so that we don't destroy this object
// inside a call stack of method calls on this object
nsCOMPtr<nsIRunnable> event =
NS_NEW_RUNNABLE_METHOD(nsHTMLMediaElement, this, DoRelease);
NS_DispatchToMainThread(event);
}
} }
} }
@ -1848,6 +1985,9 @@ void nsHTMLMediaElement::ChangeDelayLoadStatus(PRBool aDelay) {
mLoadBlockedDoc->UnblockOnload(PR_FALSE); mLoadBlockedDoc->UnblockOnload(PR_FALSE);
mLoadBlockedDoc = nsnull; mLoadBlockedDoc = nsnull;
} }
// We changed mDelayingLoadEvent which can affect AddRemoveSelfReference
AddRemoveSelfReference();
} }
already_AddRefed<nsILoadGroup> nsHTMLMediaElement::GetDocumentLoadGroup() already_AddRefed<nsILoadGroup> nsHTMLMediaElement::GetDocumentLoadGroup()

View file

@ -1945,3 +1945,36 @@ nsHTMLOptionCollection::GetSelect(nsIDOMHTMLSelectElement **aReturn)
NS_IF_ADDREF(*aReturn = mSelect); NS_IF_ADDREF(*aReturn = mSelect);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsHTMLOptionCollection::Add(nsIDOMHTMLOptionElement *aOption,
PRInt32 aIndex, PRUint8 optional_argc)
{
if (!aOption) {
return NS_ERROR_INVALID_ARG;
}
if (aIndex < -1) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
if (!mSelect) {
return NS_ERROR_NOT_INITIALIZED;
}
PRUint32 length;
GetLength(&length);
if (optional_argc == 0 || aIndex == -1 || aIndex > (PRInt32)length) {
// IE appends in these cases
aIndex = length;
}
nsCOMPtr<nsIDOMNode> beforeNode;
Item(aIndex, getter_AddRefs(beforeNode));
nsCOMPtr<nsIDOMHTMLOptionElement> beforeElement =
do_QueryInterface(beforeNode);
return mSelect->Add(aOption, beforeElement);
}

View file

@ -139,6 +139,8 @@ _TEST_FILES = test_bug589.html \
test_bug514856.html \ test_bug514856.html \
bug514856_iframe.html \ bug514856_iframe.html \
test_bug519987.html \ test_bug519987.html \
test_bug523771.html \
form_submit_server.sjs \
$(NULL) $(NULL)
libs:: $(_TEST_FILES) libs:: $(_TEST_FILES)

View file

@ -0,0 +1,47 @@
const CC = Components.Constructor;
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream");
function handleRequest(request, response)
{
var bodyStream = new BinaryInputStream(request.bodyInputStream);
var bodyBytes = [];
var result = [];
while ((bodyAvail = bodyStream.available()) > 0)
Array.prototype.push.apply(bodyBytes, bodyStream.readByteArray(bodyAvail));
if (request.method == "POST") {
// assume UTF8 for now
var requestBody = decodeURIComponent(
escape(String.fromCharCode.apply(null, bodyBytes)));
var contentTypeParams = {};
request.getHeader("Content-Type").split(/\s*\;\s*/).forEach(function(s) {
if (s.indexOf('=') >= 0) {
let [name, value] = s.split('=');
contentTypeParams[name] = value;
}
else {
contentTypeParams[''] = s;
}
});
if (contentTypeParams[''] == "multipart/form-data") {
requestBody.split("--" + contentTypeParams.boundary).slice(1, -1).forEach(function (s) {
let headers = {};
headerEnd = s.indexOf("\r\n\r\n");
s.substr(2, headerEnd-2).split("\r\n").forEach(function(s) {
let [name, value] = s.split(': ');
headers[name] = value;
});
result.push({ headers: headers, body: s.substring(headerEnd + 4, s.length - 2)});
});
}
}
// Send response body
response.setHeader("Content-Type", "text/plain", false);
response.write(JSON.stringify(result));
}

View file

@ -0,0 +1,129 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=523771
-->
<head>
<title>Test for Bug 523771</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=523771">Mozilla Bug 523771</a>
<p id="display"></p>
<iframe name="target_iframe" id="target_iframe"></iframe>
<form action="form_submit_server.sjs" target="target_iframe" id="form"
method="POST" enctype="multipart/form-data">
<input id=singleFile name=singleFile type=file>
<input id=multiFile name=multiFile type=file multiple>
</form>
<pre id="test">
<script class="testbody" type="text/javascript">
var filesToKill = [];
singleFileInput = document.getElementById('singleFile');
multiFileInput = document.getElementById('multiFile');
var input1File = { name: "523771_file1", type: null, body: "file1 contents"};
var input2Files =
[{ name: "523771_file2", type: null, body: "second file contents" },
{ name: "523771_file3.txt", type: "text/plain", body: "123456" },
{ name: "523771_file4.html", type: "text/html", body: "<html>content</html>" }
];
SimpleTest.waitForExplicitFinish();
function setFileInputs () {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
f = createFileWithData(input1File.name, input1File.body);
singleFileInput.mozSetFileNameArray([f.path], 1);
var input2FileNames = [];
for each (file in input2Files) {
f = createFileWithData(file.name, file.body);
input2FileNames.push(f.path);
}
multiFileInput.mozSetFileNameArray(input2FileNames, input2FileNames.length);
}
function createFileWithData(fileName, fileData) {
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
var testFile = dirSvc.get("ProfD", Components.interfaces.nsIFile);
testFile.append(fileName);
var outStream = Components.
classes["@mozilla.org/network/file-output-stream;1"].
createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
filesToKill.push(testFile);
return testFile;
}
function cleanupFiles() {
singleFileInput.value = "";
multiFileInput.value = "";
filesToKill.forEach(
function (testFile) {
try {
testFile.remove(false);
} catch (e) {}
}
);
}
is(singleFileInput.files.length, 0, "single-file .files.length"); // bug 524421
is(multiFileInput.files.length, 0, "multi-file .files.length"); // bug 524421
setFileInputs();
is(singleFileInput.multiple, false, "single-file input .multiple");
is(multiFileInput.multiple, true, "multi-file input .multiple");
is(singleFileInput.value, input1File.name, "single-file input .value");
is(multiFileInput.value, input2Files[0].name, "multi-file input .value");
is(singleFileInput.files[0].name, input1File.name, "single-file input .files[n].name");
is(singleFileInput.files[0].size, input1File.body.length, "single-file input .files[n].size");
is(singleFileInput.files[0].mediaType, input1File.type, "single-file input .files[n].mediaType");
for(i = 0; i < input2Files.length; ++i) {
is(multiFileInput.files[i].name, input2Files[i].name, "multi-file input .files[n].name");
is(multiFileInput.files[i].size, input2Files[i].body.length, "multi-file input .files[n].size");
is(multiFileInput.files[i].mediaType, input2Files[i].type, "multi-file input .files[n].mediaType");
}
document.getElementById('form').submit();
iframe = document.getElementById('target_iframe');
iframe.onload = function() {
response = JSON.parse(iframe.contentDocument.documentElement.textContent);
is(response[0].headers["Content-Disposition"],
"form-data; name=\"singleFile\"; filename=\"" + input1File.name +
"\"",
"singleFile Content-Disposition");
is(response[0].headers["Content-Type"], input1File.type || "application/octet-stream",
"singleFile Content-Type");
is(response[0].body, input1File.body, "singleFile body");
for(i = 0; i < input2Files.length; ++i) {
is(response[i + 1].headers["Content-Disposition"],
"form-data; name=\"multiFile\"; filename=\"" + input2Files[i].name +
"\"",
"multiFile Content-Disposition");
is(response[i + 1].headers["Content-Type"], input2Files[i].type || "application/octet-stream",
"multiFile Content-Type");
is(response[i + 1].body, input2Files[i].body, "multiFile body");
}
cleanupFiles();
is(singleFileInput.files.length, 0, "single-file .files.length"); // bug 524421
is(multiFileInput.files.length, 0, "multi-file .files.length"); // bug 524421
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View file

@ -465,6 +465,8 @@ nsMediaCacheStream::BlockList::NotifyBlockSwapped(PRInt32 aBlockIndex1,
e1Prev = e1->mPrevBlock; e1Prev = e1->mPrevBlock;
e1Next = e1->mNextBlock; e1Next = e1->mNextBlock;
mEntries.RemoveEntry(aBlockIndex1); mEntries.RemoveEntry(aBlockIndex1);
// Refresh pointer after hashtable mutation.
e2 = mEntries.GetEntry(aBlockIndex2);
} }
if (e2) { if (e2) {
e2Prev = e2->mPrevBlock; e2Prev = e2->mPrevBlock;
@ -973,263 +975,297 @@ nsMediaCache::PredictNextUseForIncomingData(nsMediaCacheStream* aStream)
PR_MIN(millisecondsAhead, PR_INT32_MAX)); PR_MIN(millisecondsAhead, PR_INT32_MAX));
} }
enum StreamAction { NONE, SEEK, RESUME, SUSPEND };
void void
nsMediaCache::Update() nsMediaCache::Update()
{ {
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
nsAutoMonitor mon(mMonitor); // The action to use for each stream. We store these so we can make
mUpdateQueued = PR_FALSE; // decisions while holding the cache lock but implement those decisions
// without holding the cache lock, since we need to call out to
// stream, decoder and element code.
nsAutoTArray<StreamAction,10> actions;
{
nsAutoMonitor mon(mMonitor);
mUpdateQueued = PR_FALSE;
#ifdef DEBUG #ifdef DEBUG
mInUpdate = PR_TRUE; mInUpdate = PR_TRUE;
#endif #endif
PRInt32 maxBlocks = GetMaxBlocks(); PRInt32 maxBlocks = GetMaxBlocks();
TimeStamp now = TimeStamp::Now(); TimeStamp now = TimeStamp::Now();
PRInt32 freeBlockCount = mFreeBlocks.GetCount(); PRInt32 freeBlockCount = mFreeBlocks.GetCount();
// Try to trim back the cache to its desired maximum size. The cache may // Try to trim back the cache to its desired maximum size. The cache may
// have overflowed simply due to data being received when we have // have overflowed simply due to data being received when we have
// no blocks in the main part of the cache that are free or lower // no blocks in the main part of the cache that are free or lower
// priority than the new data. The cache can also be overflowing because // priority than the new data. The cache can also be overflowing because
// the media.cache_size preference was reduced. // the media.cache_size preference was reduced.
// First, figure out what the least valuable block in the cache overflow // First, figure out what the least valuable block in the cache overflow
// is. We don't want to replace any blocks in the main part of the // is. We don't want to replace any blocks in the main part of the
// cache whose expected time of next use is earlier or equal to that. // cache whose expected time of next use is earlier or equal to that.
// If we allow that, we can effectively end up discarding overflowing // If we allow that, we can effectively end up discarding overflowing
// blocks (by moving an overflowing block to the main part of the cache, // blocks (by moving an overflowing block to the main part of the cache,
// and then overwriting it with another overflowing block), and we try // and then overwriting it with another overflowing block), and we try
// to avoid that since it requires HTTP seeks. // to avoid that since it requires HTTP seeks.
// We also use this loop to eliminate overflowing blocks from // We also use this loop to eliminate overflowing blocks from
// freeBlockCount. // freeBlockCount.
TimeDuration latestPredictedUseForOverflow = 0; TimeDuration latestPredictedUseForOverflow = 0;
for (PRInt32 blockIndex = mIndex.Length() - 1; blockIndex >= maxBlocks; for (PRInt32 blockIndex = mIndex.Length() - 1; blockIndex >= maxBlocks;
--blockIndex) { --blockIndex) {
if (IsBlockFree(blockIndex)) { if (IsBlockFree(blockIndex)) {
// Don't count overflowing free blocks in our free block count // Don't count overflowing free blocks in our free block count
--freeBlockCount; --freeBlockCount;
continue; continue;
} }
TimeDuration predictedUse = PredictNextUse(now, blockIndex); TimeDuration predictedUse = PredictNextUse(now, blockIndex);
latestPredictedUseForOverflow = PR_MAX(latestPredictedUseForOverflow, predictedUse); latestPredictedUseForOverflow = PR_MAX(latestPredictedUseForOverflow, predictedUse);
}
// Now try to move overflowing blocks to the main part of the cache.
for (PRInt32 blockIndex = mIndex.Length() - 1; blockIndex >= maxBlocks;
--blockIndex) {
if (IsBlockFree(blockIndex))
continue;
Block* block = &mIndex[blockIndex];
// Try to relocate the block close to other blocks for the first stream.
// There is no point in trying to make it close to other blocks in
// *all* the streams it might belong to.
PRInt32 destinationBlockIndex =
FindReusableBlock(now, block->mOwners[0].mStream,
block->mOwners[0].mStreamBlock, maxBlocks);
if (destinationBlockIndex < 0) {
// Nowhere to place this overflow block. We won't be able to
// place any more overflow blocks.
break;
} }
if (IsBlockFree(destinationBlockIndex) || // Now try to move overflowing blocks to the main part of the cache.
PredictNextUse(now, destinationBlockIndex) > latestPredictedUseForOverflow) { for (PRInt32 blockIndex = mIndex.Length() - 1; blockIndex >= maxBlocks;
// Reuse blocks in the main part of the cache that are less useful than --blockIndex) {
// the least useful overflow blocks if (IsBlockFree(blockIndex))
char buf[BLOCK_SIZE]; continue;
nsresult rv = ReadCacheFileAllBytes(blockIndex*BLOCK_SIZE, buf, sizeof(buf));
if (NS_SUCCEEDED(rv)) { Block* block = &mIndex[blockIndex];
rv = WriteCacheFile(destinationBlockIndex*BLOCK_SIZE, buf, BLOCK_SIZE); // Try to relocate the block close to other blocks for the first stream.
// There is no point in trying to make it close to other blocks in
// *all* the streams it might belong to.
PRInt32 destinationBlockIndex =
FindReusableBlock(now, block->mOwners[0].mStream,
block->mOwners[0].mStreamBlock, maxBlocks);
if (destinationBlockIndex < 0) {
// Nowhere to place this overflow block. We won't be able to
// place any more overflow blocks.
break;
}
if (IsBlockFree(destinationBlockIndex) ||
PredictNextUse(now, destinationBlockIndex) > latestPredictedUseForOverflow) {
// Reuse blocks in the main part of the cache that are less useful than
// the least useful overflow blocks
char buf[BLOCK_SIZE];
nsresult rv = ReadCacheFileAllBytes(blockIndex*BLOCK_SIZE, buf, sizeof(buf));
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
// We successfully copied the file data. rv = WriteCacheFile(destinationBlockIndex*BLOCK_SIZE, buf, BLOCK_SIZE);
LOG(PR_LOG_DEBUG, ("Swapping blocks %d and %d (trimming cache)", if (NS_SUCCEEDED(rv)) {
blockIndex, destinationBlockIndex)); // We successfully copied the file data.
// Swapping the block metadata here lets us maintain the LOG(PR_LOG_DEBUG, ("Swapping blocks %d and %d (trimming cache)",
// correct positions in the linked lists blockIndex, destinationBlockIndex));
SwapBlocks(blockIndex, destinationBlockIndex); // Swapping the block metadata here lets us maintain the
} else { // correct positions in the linked lists
// If the write fails we may have corrupted the destination SwapBlocks(blockIndex, destinationBlockIndex);
// block. Free it now. } else {
// If the write fails we may have corrupted the destination
// block. Free it now.
LOG(PR_LOG_DEBUG, ("Released block %d (trimming cache)",
destinationBlockIndex));
FreeBlock(destinationBlockIndex);
}
// Free the overflowing block even if the copy failed.
LOG(PR_LOG_DEBUG, ("Released block %d (trimming cache)", LOG(PR_LOG_DEBUG, ("Released block %d (trimming cache)",
destinationBlockIndex)); blockIndex));
FreeBlock(destinationBlockIndex); FreeBlock(blockIndex);
} }
// Free the overflowing block even if the copy failed.
LOG(PR_LOG_DEBUG, ("Released block %d (trimming cache)",
blockIndex));
FreeBlock(blockIndex);
} }
} }
} // Try chopping back the array of cache entries and the cache file.
// Try chopping back the array of cache entries and the cache file. Truncate();
Truncate();
// Count the blocks allocated for readahead of non-seekable streams // Count the blocks allocated for readahead of non-seekable streams
// (these blocks can't be freed but we don't want them to monopolize the // (these blocks can't be freed but we don't want them to monopolize the
// cache) // cache)
PRInt32 nonSeekableReadaheadBlockCount = 0; PRInt32 nonSeekableReadaheadBlockCount = 0;
for (PRUint32 i = 0; i < mStreams.Length(); ++i) { for (PRUint32 i = 0; i < mStreams.Length(); ++i) {
nsMediaCacheStream* stream = mStreams[i]; nsMediaCacheStream* stream = mStreams[i];
if (!stream->mIsSeekable) { if (!stream->mIsSeekable) {
nonSeekableReadaheadBlockCount += stream->mReadaheadBlocks.GetCount(); nonSeekableReadaheadBlockCount += stream->mReadaheadBlocks.GetCount();
}
}
// If freeBlockCount is zero, then compute the latest of
// the predicted next-uses for all blocks
TimeDuration latestNextUse;
if (freeBlockCount == 0) {
PRInt32 reusableBlock = FindReusableBlock(now, nsnull, 0, maxBlocks);
if (reusableBlock >= 0) {
latestNextUse = PredictNextUse(now, reusableBlock);
}
}
// This array holds a list of streams which need to be closed due
// to fatal errors. We can't close streams immediately since it would
// confuse iteration over mStreams and generally just be confusing.
nsTArray<nsMediaCacheStream*> streamsToClose;
for (PRUint32 i = 0; i < mStreams.Length(); ++i) {
nsMediaCacheStream* stream = mStreams[i];
if (stream->mClosed)
continue;
// Figure out where we should be reading from. It's normally the first
// uncached byte after the current mStreamOffset.
PRInt64 desiredOffset = stream->GetCachedDataEndInternal(stream->mStreamOffset);
if (stream->mIsSeekable) {
if (desiredOffset > stream->mChannelOffset &&
desiredOffset <= stream->mChannelOffset + SEEK_VS_READ_THRESHOLD) {
// Assume it's more efficient to just keep reading up to the
// desired position instead of trying to seek
desiredOffset = stream->mChannelOffset;
} }
} else { }
// We can't seek directly to the desired offset...
if (stream->mChannelOffset > desiredOffset) { // If freeBlockCount is zero, then compute the latest of
// Reading forward won't get us anywhere, we need to go backwards. // the predicted next-uses for all blocks
// Seek back to 0 (the client will reopen the stream) and then TimeDuration latestNextUse;
// read forward. if (freeBlockCount == 0) {
NS_WARNING("Can't seek backwards, so seeking to 0"); PRInt32 reusableBlock = FindReusableBlock(now, nsnull, 0, maxBlocks);
desiredOffset = 0; if (reusableBlock >= 0) {
// Flush cached blocks out, since if this is a live stream latestNextUse = PredictNextUse(now, reusableBlock);
// the cached data may be completely different next time we }
// read it. We have to assume that live streams don't }
// advertise themselves as being seekable...
ReleaseStreamBlocks(stream); for (PRUint32 i = 0; i < mStreams.Length(); ++i) {
actions.AppendElement(NONE);
nsMediaCacheStream* stream = mStreams[i];
if (stream->mClosed)
continue;
// Figure out where we should be reading from. It's normally the first
// uncached byte after the current mStreamOffset.
PRInt64 desiredOffset = stream->GetCachedDataEndInternal(stream->mStreamOffset);
if (stream->mIsSeekable) {
if (desiredOffset > stream->mChannelOffset &&
desiredOffset <= stream->mChannelOffset + SEEK_VS_READ_THRESHOLD) {
// Assume it's more efficient to just keep reading up to the
// desired position instead of trying to seek
desiredOffset = stream->mChannelOffset;
}
} else { } else {
// otherwise reading forward is looking good, so just stay where we // We can't seek directly to the desired offset...
// are and don't trigger a channel seek! if (stream->mChannelOffset > desiredOffset) {
desiredOffset = stream->mChannelOffset; // Reading forward won't get us anywhere, we need to go backwards.
} // Seek back to 0 (the client will reopen the stream) and then
} // read forward.
NS_WARNING("Can't seek backwards, so seeking to 0");
// Figure out if we should be reading data now or not. It's amazing desiredOffset = 0;
// how complex this is, but each decision is simple enough. // Flush cached blocks out, since if this is a live stream
PRBool enableReading; // the cached data may be completely different next time we
if (stream->mStreamLength >= 0 && // read it. We have to assume that live streams don't
desiredOffset >= stream->mStreamLength) { // advertise themselves as being seekable...
// We want to read at the end of the stream, where there's nothing to ReleaseStreamBlocks(stream);
// read. We don't want to try to read if we're suspended, because that } else {
// might create a new channel and seek unnecessarily (and incorrectly, // otherwise reading forward is looking good, so just stay where we
// since HTTP doesn't allow seeking to the actual EOF), and we don't want // are and don't trigger a channel seek!
// to suspend if we're not suspended and already reading at the end of desiredOffset = stream->mChannelOffset;
// the stream, since there just might be more data than the server
// advertised with Content-Length, and we may as well keep reading.
// But we don't want to seek to the end of the stream if we're not
// already there.
LOG(PR_LOG_DEBUG, ("Stream %p at end of stream", stream));
enableReading = !stream->mCacheSuspended &&
desiredOffset == stream->mChannelOffset;
} else if (desiredOffset < stream->mStreamOffset) {
// We're reading to try to catch up to where the current stream
// reader wants to be. Better not stop.
LOG(PR_LOG_DEBUG, ("Stream %p catching up", stream));
enableReading = PR_TRUE;
} else if (desiredOffset < stream->mStreamOffset + BLOCK_SIZE) {
// The stream reader is waiting for us, or nearly so. Better feed it.
LOG(PR_LOG_DEBUG, ("Stream %p feeding reader", stream));
enableReading = PR_TRUE;
} else if (!stream->mIsSeekable &&
nonSeekableReadaheadBlockCount >= maxBlocks*NONSEEKABLE_READAHEAD_MAX) {
// This stream is not seekable and there are already too many blocks
// being cached for readahead for nonseekable streams (which we can't
// free). So stop reading ahead now.
LOG(PR_LOG_DEBUG, ("Stream %p throttling non-seekable readahead", stream));
enableReading = PR_FALSE;
} else if (mIndex.Length() > PRUint32(maxBlocks)) {
// We're in the process of bringing the cache size back to the
// desired limit, so don't bring in more data yet
LOG(PR_LOG_DEBUG, ("Stream %p throttling to reduce cache size", stream));
enableReading = PR_FALSE;
} else if (freeBlockCount > 0 || mIndex.Length() < PRUint32(maxBlocks)) {
// Free blocks in the cache, so keep reading
LOG(PR_LOG_DEBUG, ("Stream %p reading since there are free blocks", stream));
enableReading = PR_TRUE;
} else if (latestNextUse <= TimeDuration(0)) {
// No reusable blocks, so can't read anything
LOG(PR_LOG_DEBUG, ("Stream %p throttling due to no reusable blocks", stream));
enableReading = PR_FALSE;
} else {
// Read ahead if the data we expect to read is more valuable than
// the least valuable block in the main part of the cache
TimeDuration predictedNewDataUse = PredictNextUseForIncomingData(stream);
LOG(PR_LOG_DEBUG, ("Stream %p predict next data in %f, current worst block is %f",
stream, predictedNewDataUse.ToSeconds(), latestNextUse.ToSeconds()));
enableReading = predictedNewDataUse < latestNextUse;
}
if (enableReading) {
for (PRUint32 j = 0; j < i; ++j) {
nsMediaCacheStream* other = mStreams[j];
if (other->mResourceID == stream->mResourceID &&
!other->mCacheSuspended &&
other->mChannelOffset/BLOCK_SIZE == stream->mChannelOffset/BLOCK_SIZE) {
// This block is already going to be read by the other stream.
// So don't try to read it from this stream as well.
enableReading = PR_FALSE;
break;
} }
} }
}
// Figure out if we should be reading data now or not. It's amazing
// how complex this is, but each decision is simple enough.
PRBool enableReading;
if (stream->mStreamLength >= 0 &&
desiredOffset >= stream->mStreamLength) {
// We want to read at the end of the stream, where there's nothing to
// read. We don't want to try to read if we're suspended, because that
// might create a new channel and seek unnecessarily (and incorrectly,
// since HTTP doesn't allow seeking to the actual EOF), and we don't want
// to suspend if we're not suspended and already reading at the end of
// the stream, since there just might be more data than the server
// advertised with Content-Length, and we may as well keep reading.
// But we don't want to seek to the end of the stream if we're not
// already there.
LOG(PR_LOG_DEBUG, ("Stream %p at end of stream", stream));
enableReading = !stream->mCacheSuspended &&
desiredOffset == stream->mChannelOffset;
} else if (desiredOffset < stream->mStreamOffset) {
// We're reading to try to catch up to where the current stream
// reader wants to be. Better not stop.
LOG(PR_LOG_DEBUG, ("Stream %p catching up", stream));
enableReading = PR_TRUE;
} else if (desiredOffset < stream->mStreamOffset + BLOCK_SIZE) {
// The stream reader is waiting for us, or nearly so. Better feed it.
LOG(PR_LOG_DEBUG, ("Stream %p feeding reader", stream));
enableReading = PR_TRUE;
} else if (!stream->mIsSeekable &&
nonSeekableReadaheadBlockCount >= maxBlocks*NONSEEKABLE_READAHEAD_MAX) {
// This stream is not seekable and there are already too many blocks
// being cached for readahead for nonseekable streams (which we can't
// free). So stop reading ahead now.
LOG(PR_LOG_DEBUG, ("Stream %p throttling non-seekable readahead", stream));
enableReading = PR_FALSE;
} else if (mIndex.Length() > PRUint32(maxBlocks)) {
// We're in the process of bringing the cache size back to the
// desired limit, so don't bring in more data yet
LOG(PR_LOG_DEBUG, ("Stream %p throttling to reduce cache size", stream));
enableReading = PR_FALSE;
} else if (freeBlockCount > 0 || mIndex.Length() < PRUint32(maxBlocks)) {
// Free blocks in the cache, so keep reading
LOG(PR_LOG_DEBUG, ("Stream %p reading since there are free blocks", stream));
enableReading = PR_TRUE;
} else if (latestNextUse <= TimeDuration(0)) {
// No reusable blocks, so can't read anything
LOG(PR_LOG_DEBUG, ("Stream %p throttling due to no reusable blocks", stream));
enableReading = PR_FALSE;
} else {
// Read ahead if the data we expect to read is more valuable than
// the least valuable block in the main part of the cache
TimeDuration predictedNewDataUse = PredictNextUseForIncomingData(stream);
LOG(PR_LOG_DEBUG, ("Stream %p predict next data in %f, current worst block is %f",
stream, predictedNewDataUse.ToSeconds(), latestNextUse.ToSeconds()));
enableReading = predictedNewDataUse < latestNextUse;
}
if (enableReading) {
for (PRUint32 j = 0; j < i; ++j) {
nsMediaCacheStream* other = mStreams[j];
if (other->mResourceID == stream->mResourceID &&
!other->mCacheSuspended &&
other->mChannelOffset/BLOCK_SIZE == stream->mChannelOffset/BLOCK_SIZE) {
// This block is already going to be read by the other stream.
// So don't try to read it from this stream as well.
enableReading = PR_FALSE;
break;
}
}
}
if (stream->mChannelOffset != desiredOffset && enableReading) {
// We need to seek now.
NS_ASSERTION(stream->mIsSeekable || desiredOffset == 0,
"Trying to seek in a non-seekable stream!");
// Round seek offset down to the start of the block. This is essential
// because we don't want to think we have part of a block already
// in mPartialBlockBuffer.
stream->mChannelOffset = (desiredOffset/BLOCK_SIZE)*BLOCK_SIZE;
actions[i] = SEEK;
} else if (enableReading && stream->mCacheSuspended) {
actions[i] = RESUME;
} else if (!enableReading && !stream->mCacheSuspended) {
actions[i] = SUSPEND;
}
}
#ifdef DEBUG
mInUpdate = PR_FALSE;
#endif
}
// Update the channel state without holding our cache lock. While we're
// doing this, decoder threads may be running and seeking, reading or changing
// other cache state. That's OK, they'll trigger new Update events and we'll
// get back here and revise our decisions. The important thing here is that
// performing these actions only depends on mChannelOffset and
// mCacheSuspended, which can only be written by the main thread (i.e., this
// thread), so we don't have races here.
for (PRUint32 i = 0; i < mStreams.Length(); ++i) {
nsMediaCacheStream* stream = mStreams[i];
nsresult rv = NS_OK; nsresult rv = NS_OK;
if (stream->mChannelOffset != desiredOffset && enableReading) { switch (actions[i]) {
// We need to seek now. case SEEK:
NS_ASSERTION(stream->mIsSeekable || desiredOffset == 0,
"Trying to seek in a non-seekable stream!");
// Round seek offset down to the start of the block
stream->mChannelOffset = (desiredOffset/BLOCK_SIZE)*BLOCK_SIZE;
LOG(PR_LOG_DEBUG, ("Stream %p CacheSeek to %lld (resume=%d)", stream, LOG(PR_LOG_DEBUG, ("Stream %p CacheSeek to %lld (resume=%d)", stream,
(long long)stream->mChannelOffset, stream->mCacheSuspended)); (long long)stream->mChannelOffset, stream->mCacheSuspended));
rv = stream->mClient->CacheClientSeek(stream->mChannelOffset, rv = stream->mClient->CacheClientSeek(stream->mChannelOffset,
stream->mCacheSuspended); stream->mCacheSuspended);
stream->mCacheSuspended = PR_FALSE; stream->mCacheSuspended = PR_FALSE;
} else if (enableReading && stream->mCacheSuspended) { break;
case RESUME:
LOG(PR_LOG_DEBUG, ("Stream %p Resumed", stream)); LOG(PR_LOG_DEBUG, ("Stream %p Resumed", stream));
rv = stream->mClient->CacheClientResume(); rv = stream->mClient->CacheClientResume();
stream->mCacheSuspended = PR_FALSE; stream->mCacheSuspended = PR_FALSE;
} else if (!enableReading && !stream->mCacheSuspended) { break;
case SUSPEND:
LOG(PR_LOG_DEBUG, ("Stream %p Suspended", stream)); LOG(PR_LOG_DEBUG, ("Stream %p Suspended", stream));
rv = stream->mClient->CacheClientSuspend(); rv = stream->mClient->CacheClientSuspend();
stream->mCacheSuspended = PR_TRUE; stream->mCacheSuspended = PR_TRUE;
break;
default:
break;
} }
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
streamsToClose.AppendElement(stream); // Close the streams that failed due to error. This will cause all
// client Read and Seek operations on those streams to fail. Blocked
// Reads will also be woken up.
nsAutoMonitor mon(mMonitor);
stream->CloseInternal(&mon);
} }
} }
// Close the streams that failed due to error. This will cause all
// client Read and Seek operations on those streams to fail. Blocked
// Reads will also be woken up.
for (PRUint32 i = 0; i < streamsToClose.Length(); ++i) {
streamsToClose[i]->CloseInternal(&mon);
}
#ifdef DEBUG
mInUpdate = PR_FALSE;
#endif
} }
class UpdateEvent : public nsRunnable class UpdateEvent : public nsRunnable

View file

@ -220,13 +220,14 @@ public:
// aClient provides the underlying transport that cache will use to read // aClient provides the underlying transport that cache will use to read
// data for this stream. // data for this stream.
nsMediaCacheStream(nsMediaChannelStream* aClient) nsMediaCacheStream(nsMediaChannelStream* aClient)
: mClient(aClient), mResourceID(0), mChannelOffset(0), : mClient(aClient), mResourceID(0), mInitialized(PR_FALSE),
mStreamOffset(0), mStreamLength(-1), mPlaybackBytesPerSecond(10000),
mPinCount(0), mCurrentMode(MODE_PLAYBACK),
mInitialized(PR_FALSE), mClosed(PR_FALSE),
mIsSeekable(PR_FALSE), mCacheSuspended(PR_FALSE), mIsSeekable(PR_FALSE), mCacheSuspended(PR_FALSE),
mUsingNullPrincipal(PR_FALSE),
mChannelOffset(0), mStreamLength(-1),
mStreamOffset(0), mPlaybackBytesPerSecond(10000),
mPinCount(0), mCurrentMode(MODE_PLAYBACK),
mMetadataInPartialBlockBuffer(PR_FALSE), mMetadataInPartialBlockBuffer(PR_FALSE),
mUsingNullPrincipal(PR_FALSE) {} mClosed(PR_FALSE) {}
~nsMediaCacheStream(); ~nsMediaCacheStream();
// Set up this stream with the cache. Can fail on OOM. One // Set up this stream with the cache. Can fail on OOM. One
@ -432,16 +433,32 @@ private:
// All streams with the same mResourceID are loading the same // All streams with the same mResourceID are loading the same
// underlying resource and should share data. // underlying resource and should share data.
PRInt64 mResourceID; PRInt64 mResourceID;
// Set to true when Init or InitAsClone has been called
PRPackedBool mInitialized;
// All other fields are all protected by the cache's monitor and // The following fields are protected by the cache's monitor but are
// can be accessed by by any thread. // only written on the main thread.
// The last reported seekability state for the underlying channel
PRPackedBool mIsSeekable;
// true if the cache has suspended our channel because the cache is
// full and the priority of the data that would be received is lower
// than the priority of the data already in the cache
PRPackedBool mCacheSuspended;
// true if mPrincipal is a null principal because we saw data from
// multiple origins
PRPackedBool mUsingNullPrincipal;
// The offset where the next data from the channel will arrive // The offset where the next data from the channel will arrive
PRInt64 mChannelOffset; PRInt64 mChannelOffset;
// The offset where the reader is positioned in the stream
PRInt64 mStreamOffset;
// The reported or discovered length of the data, or -1 if nothing is // The reported or discovered length of the data, or -1 if nothing is
// known // known
PRInt64 mStreamLength; PRInt64 mStreamLength;
// The following fields are protected by the cache's monitor can can be written
// by any thread.
// The offset where the reader is positioned in the stream
PRInt64 mStreamOffset;
// For each block in the stream data, maps to the cache entry for the // For each block in the stream data, maps to the cache entry for the
// block, or -1 if the block is not cached. // block, or -1 if the block is not cached.
nsTArray<PRInt32> mBlocks; nsTArray<PRInt32> mBlocks;
@ -460,22 +477,14 @@ private:
PRUint32 mPinCount; PRUint32 mPinCount;
// The last reported read mode // The last reported read mode
ReadMode mCurrentMode; ReadMode mCurrentMode;
// Set to true when Init or InitAsClone has been called // true if some data in mPartialBlockBuffer has been read as metadata
PRPackedBool mInitialized; PRPackedBool mMetadataInPartialBlockBuffer;
// Set to true when the stream has been closed either explicitly or // Set to true when the stream has been closed either explicitly or
// due to an internal cache error // due to an internal cache error
PRPackedBool mClosed; PRPackedBool mClosed;
// The last reported seekability state for the underlying channel
PRPackedBool mIsSeekable; // The following field is protected by the cache's monitor but are
// true if the cache has suspended our channel because the cache is // only written on the main thread.
// full and the priority of the data that would be received is lower
// than the priority of the data already in the cache
PRPackedBool mCacheSuspended;
// true if some data in mPartialBlockBuffer has been read as metadata
PRPackedBool mMetadataInPartialBlockBuffer;
// true if mPrincipal is a null principal because we saw data from
// multiple origins
PRPackedBool mUsingNullPrincipal;
// Data received for the block containing mChannelOffset. Data needs // Data received for the block containing mChannelOffset. Data needs
// to wait here so we can write back a complete block. The first // to wait here so we can write back a complete block. The first

View file

@ -251,9 +251,9 @@ protected:
// Timer used for updating progress events // Timer used for updating progress events
nsCOMPtr<nsITimer> mProgressTimer; nsCOMPtr<nsITimer> mProgressTimer;
// The element is not reference counted. Instead the decoder is // This should only ever be accessed from the main thread.
// notified when it is able to be used. It should only ever be // It is set in Init and cleared in Shutdown when the element goes away.
// accessed from the main thread. // The decoder does not add a reference the element.
nsHTMLMediaElement* mElement; nsHTMLMediaElement* mElement;
// RGB data for last decoded frame of video data. // RGB data for last decoded frame of video data.

View file

@ -540,7 +540,7 @@ PRInt64 nsMediaChannelStream::Tell()
void nsMediaChannelStream::Suspend(PRBool aCloseImmediately) void nsMediaChannelStream::Suspend(PRBool aCloseImmediately)
{ {
NS_ASSERTION(NS_IsMainThread(), "Don't call on main thread"); NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
nsHTMLMediaElement* element = mDecoder->GetMediaElement(); nsHTMLMediaElement* element = mDecoder->GetMediaElement();
if (!element) { if (!element) {
@ -569,7 +569,7 @@ void nsMediaChannelStream::Suspend(PRBool aCloseImmediately)
void nsMediaChannelStream::Resume() void nsMediaChannelStream::Resume()
{ {
NS_ASSERTION(NS_IsMainThread(), "Don't call on main thread"); NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
NS_ASSERTION(mSuspendCount > 0, "Too many resumes!"); NS_ASSERTION(mSuspendCount > 0, "Too many resumes!");
nsHTMLMediaElement* element = mDecoder->GetMediaElement(); nsHTMLMediaElement* element = mDecoder->GetMediaElement();
@ -641,7 +641,9 @@ nsMediaChannelStream::DoNotifyDataReceived()
void void
nsMediaChannelStream::CacheClientNotifyDataReceived() nsMediaChannelStream::CacheClientNotifyDataReceived()
{ {
NS_ASSERTION(NS_IsMainThread(), "Don't call on main thread"); NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
// NOTE: this can be called with the media cache lock held, so don't
// block or do anything which might try to acquire a lock!
if (mDataReceivedEvent.IsPending()) if (mDataReceivedEvent.IsPending())
return; return;
@ -667,7 +669,9 @@ private:
void void
nsMediaChannelStream::CacheClientNotifyDataEnded(nsresult aStatus) nsMediaChannelStream::CacheClientNotifyDataEnded(nsresult aStatus)
{ {
NS_ASSERTION(NS_IsMainThread(), "Don't call on main thread"); NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
// NOTE: this can be called with the media cache lock held, so don't
// block or do anything which might try to acquire a lock!
nsCOMPtr<nsIRunnable> event = new DataEnded(mDecoder, aStatus); nsCOMPtr<nsIRunnable> event = new DataEnded(mDecoder, aStatus);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
@ -676,7 +680,7 @@ nsMediaChannelStream::CacheClientNotifyDataEnded(nsresult aStatus)
nsresult nsresult
nsMediaChannelStream::CacheClientSeek(PRInt64 aOffset, PRBool aResume) nsMediaChannelStream::CacheClientSeek(PRInt64 aOffset, PRBool aResume)
{ {
NS_ASSERTION(NS_IsMainThread(), "Don't call on main thread"); NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
CloseChannel(); CloseChannel();
@ -703,12 +707,7 @@ nsMediaChannelStream::CacheClientSuspend()
} }
Suspend(PR_FALSE); Suspend(PR_FALSE);
// We have to spawn an event here since we're being called back from mDecoder->NotifySuspendedStatusChanged();
// a sensitive place in nsMediaCache, which doesn't want us to reenter
// the decoder and cause deadlocks or other unpleasantness
nsCOMPtr<nsIRunnable> event =
NS_NEW_RUNNABLE_METHOD(nsMediaDecoder, mDecoder, NotifySuspendedStatusChanged);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
return NS_OK; return NS_OK;
} }
@ -721,12 +720,7 @@ nsMediaChannelStream::CacheClientResume()
--mCacheSuspendCount; --mCacheSuspendCount;
} }
// We have to spawn an event here since we're being called back from mDecoder->NotifySuspendedStatusChanged();
// a sensitive place in nsMediaCache, which doesn't want us to reenter
// the decoder and cause deadlocks or other unpleasantness
nsCOMPtr<nsIRunnable> event =
NS_NEW_RUNNABLE_METHOD(nsMediaDecoder, mDecoder, NotifySuspendedStatusChanged);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
return NS_OK; return NS_OK;
} }

View file

@ -308,7 +308,7 @@ public:
~nsMediaChannelStream(); ~nsMediaChannelStream();
// These are called on the main thread by nsMediaCache. These must // These are called on the main thread by nsMediaCache. These must
// not block or grab locks. // not block or grab locks, because the media cache is holding its lock.
// Notify that data is available from the cache. This can happen even // Notify that data is available from the cache. This can happen even
// if this stream didn't read any data, since another stream might have // if this stream didn't read any data, since another stream might have
// received data for the same resource. // received data for the same resource.
@ -317,6 +317,10 @@ public:
// if this stream didn't read any data, since another stream might have // if this stream didn't read any data, since another stream might have
// received data for the same resource. // received data for the same resource.
void CacheClientNotifyDataEnded(nsresult aStatus); void CacheClientNotifyDataEnded(nsresult aStatus);
// These are called on the main thread by nsMediaCache. These shouldn't block,
// but they may grab locks --- the media cache is not holding its lock
// when these are called.
// Start a new load at the given aOffset. The old load is cancelled // Start a new load at the given aOffset. The old load is cancelled
// and no more data from the old load will be notified via // and no more data from the old load will be notified via
// nsMediaCacheStream::NotifyDataReceived/Ended. // nsMediaCacheStream::NotifyDataReceived/Ended.

View file

@ -397,8 +397,8 @@ protected:
// Decodes from the current position until encountering a frame with time // Decodes from the current position until encountering a frame with time
// greater or equal to aSeekTime. // greater or equal to aSeekTime.
void DecodeToFrame(nsAutoMonitor& aMonitor, PRBool DecodeToFrame(nsAutoMonitor& aMonitor,
float aSeekTime); float aSeekTime);
// Convert the OggPlay frame information into a format used by Gecko // Convert the OggPlay frame information into a format used by Gecko
// (RGB for video, float for sound, etc).The decoder monitor must be // (RGB for video, float for sound, etc).The decoder monitor must be
@ -1315,8 +1315,8 @@ nsresult nsOggDecodeStateMachine::Seek(float aTime, nsChannelReader* aReader)
return (rv < 0) ? NS_ERROR_FAILURE : NS_OK; return (rv < 0) ? NS_ERROR_FAILURE : NS_OK;
} }
void nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor, PRBool nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
float aTime) float aTime)
{ {
// Drop frames before the target time. // Drop frames before the target time.
float target = aTime - mCallbackPeriod / 2.0; float target = aTime - mCallbackPeriod / 2.0;
@ -1356,7 +1356,7 @@ void nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
if (mState == DECODER_STATE_SHUTDOWN) { if (mState == DECODER_STATE_SHUTDOWN) {
delete frame; delete frame;
return; return PR_TRUE;
} }
NS_ASSERTION(frame != nsnull, "No frame after decode!"); NS_ASSERTION(frame != nsnull, "No frame after decode!");
@ -1380,6 +1380,8 @@ void nsOggDecodeStateMachine::DecodeToFrame(nsAutoMonitor& aMonitor,
UpdatePlaybackPosition(frame->mDecodedFrameTime); UpdatePlaybackPosition(frame->mDecodedFrameTime);
PlayVideo(frame); PlayVideo(frame);
} }
return r == E_OGGPLAY_OK;
} }
void nsOggDecodeStateMachine::StopStepDecodeThread(nsAutoMonitor* aMonitor) void nsOggDecodeStateMachine::StopStepDecodeThread(nsAutoMonitor* aMonitor)
@ -1411,8 +1413,8 @@ nsresult nsOggDecodeStateMachine::Run()
nsChannelReader* reader = mDecoder->GetReader(); nsChannelReader* reader = mDecoder->GetReader();
NS_ENSURE_TRUE(reader, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(reader, NS_ERROR_NULL_POINTER);
while (PR_TRUE) { while (PR_TRUE) {
nsAutoMonitor mon(mDecoder->GetMonitor()); nsAutoMonitor mon(mDecoder->GetMonitor());
switch(mState) { switch(mState) {
case DECODER_STATE_SHUTDOWN: case DECODER_STATE_SHUTDOWN:
if (mPlaying) { if (mPlaying) {
StopPlayback(); StopPlayback();
@ -1557,7 +1559,7 @@ nsresult nsOggDecodeStateMachine::Run()
PRPackedBool reliable; PRPackedBool reliable;
double playbackRate = mDecoder->ComputePlaybackRate(&reliable); double playbackRate = mDecoder->ComputePlaybackRate(&reliable);
mBufferingEndOffset = mDecoder->mDecoderPosition + mBufferingEndOffset = mDecoder->mDecoderPosition +
BUFFERING_RATE(playbackRate) * BUFFERING_WAIT; BUFFERING_RATE(playbackRate) * BUFFERING_WAIT;
mState = DECODER_STATE_BUFFERING; mState = DECODER_STATE_BUFFERING;
if (mPlaying) { if (mPlaying) {
PausePlayback(); PausePlayback();
@ -1621,8 +1623,9 @@ nsresult nsOggDecodeStateMachine::Run()
if (mState == DECODER_STATE_SHUTDOWN) if (mState == DECODER_STATE_SHUTDOWN)
continue; continue;
PRBool atEnd = PR_FALSE;
if (NS_SUCCEEDED(res)) { if (NS_SUCCEEDED(res)) {
DecodeToFrame(mon, seekTime); atEnd = DecodeToFrame(mon, seekTime);
// mSeekTime should not have changed. While we seek, mPlayState // mSeekTime should not have changed. While we seek, mPlayState
// should always be PLAY_STATE_SEEKING and no-one will call // should always be PLAY_STATE_SEEKING and no-one will call
// nsOggDecoderStateMachine::Seek. // nsOggDecoderStateMachine::Seek.
@ -1631,29 +1634,34 @@ nsresult nsOggDecodeStateMachine::Run()
continue; continue;
} }
OggPlayErrorCode r; if (!atEnd) {
// Now try to decode another frame to see if we're at the end. OggPlayErrorCode r;
do { // Now try to decode another frame to see if we're at the end.
mon.Exit(); do {
r = DecodeFrame(); mon.Exit();
mon.Enter(); r = DecodeFrame();
} while (mState != DECODER_STATE_SHUTDOWN && r == E_OGGPLAY_TIMEOUT); mon.Enter();
HandleDecodeErrors(r); } while (mState != DECODER_STATE_SHUTDOWN && r == E_OGGPLAY_TIMEOUT);
if (mState == DECODER_STATE_SHUTDOWN) HandleDecodeErrors(r);
continue; if (mState == DECODER_STATE_SHUTDOWN)
continue;
atEnd = r == E_OGGPLAY_OK;
}
QueueDecodedFrames(); QueueDecodedFrames();
} }
// Change state to DECODING now. SeekingStopped will call // Change state to DECODING or COMPLETED now. SeekingStopped will
// nsOggDecodeStateMachine::Seek to reset our state to SEEKING // call nsOggDecodeStateMachine::Seek to reset our state to SEEKING
// if we need to seek again. // if we need to seek again.
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %f) to DECODING", mDecoder, seekTime));
mState = DECODER_STATE_DECODING;
nsCOMPtr<nsIRunnable> stopEvent; nsCOMPtr<nsIRunnable> stopEvent;
if (mDecodedFrames.GetCount() > 1) { if (!atEnd && mDecodedFrames.GetCount() > 1) {
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %f) to DECODING",
mDecoder, seekTime));
stopEvent = NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, SeekingStopped); stopEvent = NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, SeekingStopped);
mState = DECODER_STATE_DECODING; mState = DECODER_STATE_DECODING;
} else { } else {
LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %f) to COMPLETED",
mDecoder, seekTime));
stopEvent = NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, SeekingStoppedAtEnd); stopEvent = NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, SeekingStoppedAtEnd);
mState = DECODER_STATE_COMPLETED; mState = DECODER_STATE_COMPLETED;
} }

View file

@ -71,6 +71,7 @@ _TEST_FILES = \
can_play_type_wave.js \ can_play_type_wave.js \
cancellable_request.sjs \ cancellable_request.sjs \
manifest.js \ manifest.js \
reactivate_helper.html \
seek1.js \ seek1.js \
seek2.js \ seek2.js \
seek3.js \ seek3.js \
@ -85,6 +86,7 @@ _TEST_FILES = \
test_audio2.html \ test_audio2.html \
test_autobuffer.html \ test_autobuffer.html \
test_autoplay.html \ test_autoplay.html \
test_bug495300.html \
test_can_play_type.html \ test_can_play_type.html \
test_constants.html \ test_constants.html \
test_controls.html \ test_controls.html \
@ -98,6 +100,7 @@ _TEST_FILES = \
test_paused.html \ test_paused.html \
test_playback.html \ test_playback.html \
test_playback_errors.html \ test_playback_errors.html \
test_reactivate.html \
test_readyState.html \ test_readyState.html \
test_seek2.html \ test_seek2.html \
test_volume.html \ test_volume.html \
@ -144,6 +147,7 @@ _TEST_FILES += \
bug520500.ogg \ bug520500.ogg \
bug520908.ogv \ bug520908.ogv \
bug520908.ogv^headers^ \ bug520908.ogv^headers^ \
bug523816.ogv \
chain.ogv \ chain.ogv \
dirac.ogg \ dirac.ogg \
seek.ogv \ seek.ogv \
@ -181,7 +185,6 @@ _TEST_FILES += \
test_bug486646.html \ test_bug486646.html \
test_bug493187.html \ test_bug493187.html \
test_bug495145.html \ test_bug495145.html \
test_bug495300.html \
test_bug495319.html \ test_bug495319.html \
test_closing_connections.html \ test_closing_connections.html \
test_contentDuration1.html \ test_contentDuration1.html \

Binary file not shown.

View file

@ -61,6 +61,7 @@ var gPlayTests = [
{ name:"bug498855-3.ogv", type:"video/ogg", duration:0.2 }, { name:"bug498855-3.ogv", type:"video/ogg", duration:0.2 },
{ name:"bug504644.ogv", type:"video/ogg", duration:1.56 }, { name:"bug504644.ogv", type:"video/ogg", duration:1.56 },
{ name:"chain.ogv", type:"video/ogg", duration:Number.NaN }, { name:"chain.ogv", type:"video/ogg", duration:Number.NaN },
{ name:"bug523816.ogv", type:"video/ogg", duration:0.5 },
{ name:"bogus.duh", type:"bogus/duh" } { name:"bogus.duh", type:"bogus/duh" }
]; ];
@ -85,6 +86,7 @@ var gErrorTests = [
var gSeekTests = [ var gSeekTests = [
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 }, { name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
{ name:"seek.ogv", type:"video/ogg", duration:3.966 }, { name:"seek.ogv", type:"video/ogg", duration:3.966 },
{ name:"320x240.ogv", type:"video/ogg", duration:0.233 },
{ name:"bogus.duh", type:"bogus/duh", duration:123 } { name:"bogus.duh", type:"bogus/duh", duration:123 }
]; ];

View file

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<body>
<script>
var loadsWaiting = 0;
var elements = [];
function loadedData(event) {
parent.ok(elements.indexOf(event.target) == -1, "Element already loaded: " + event.target.currentSrc);
elements.push(event.target);
--loadsWaiting;
parent.ok(true, "Loaded " + event.target.currentSrc);
if (loadsWaiting == 0) {
parent.loadedAll(elements);
}
}
for (var i = 0; i < parent.gSmallTests.length; ++i) {
var test = parent.gSmallTests[i];
var elemType = /^audio/.test(test.type) ? "audio" : "video";
// Associate these elements with the subframe's document
var e = document.createElement(elemType);
if (e.canPlayType(test.type)) {
e.src = test.name;
e.addEventListener("loadeddata", loadedData, false);
e.load();
++loadsWaiting;
}
}
if (loadsWaiting == 0) {
parent.todo(false, "Can't play anything");
} else {
parent.SimpleTest.waitForExplicitFinish();
}
</script>
</body>
</html>

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