Merge mozilla-central into e10s.

This commit is contained in:
Benjamin Smedberg 2009-10-28 11:32:00 -04:00
Родитель 713cc81033 ef5de93ff0
Коммит 34440c4bbc
294 изменённых файлов: 5256 добавлений и 3530 удалений

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -38,27 +38,18 @@
*
* ***** END LICENSE BLOCK ***** */
// NOTE: alphabetically ordered
#include "nsTextAccessible.h"
// ------------
// Text Accessibles
// ------------
////////////////////////////////////////////////////////////////////////////////
// nsTextAccessible
////////////////////////////////////////////////////////////////////////////////
nsTextAccessible::nsTextAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
nsLinkableAccessible(aDOMNode, aShell)
{
nsTextAccessible::
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
nsTextAccessible::GetRoleInternal(PRUint32 *aRole)
{
@ -66,33 +57,6 @@ nsTextAccessible::GetRoleInternal(PRUint32 *aRole)
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
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);
}
void
nsTextAccessible::CacheChildren()
{
// No children for text accessible.
mAccChildCount = IsDefunct() ? eChildCountUninitialized : 0;
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -41,9 +41,9 @@
#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
{
@ -54,10 +54,6 @@ public:
// nsIAccessible
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);
// nsAccessible
@ -65,6 +61,11 @@ public:
virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild);
protected:
// nsAccessible
virtual void CacheChildren();
};
#endif

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -69,7 +69,7 @@ GRE_BUILDID = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBX
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
DEFINES += -DMOZ_SOURCE_STAMP="$(SOURCE_STAMP)"
endif

Просмотреть файл

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

Просмотреть файл

@ -32,7 +32,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > hbox[type="places"] {
-moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar);
}
#wrapper-urlbar-container #urlbar {
#wrapper-urlbar-container > #urlbar-container > #urlbar {
-moz-user-input: disabled;
cursor: -moz-grab;
}
@ -55,26 +55,30 @@ toolbarpaletteitem[place="palette"] > toolbaritem > hbox[type="places"] {
display: none;
}
#feed-menu:-moz-locale-dir(rtl) > menuitem {
#feed-menu > .feed-menuitem:-moz-locale-dir(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[isempty="true"] > #urlbar-icons > #go-button {
visibility: collapse;
}
#identity-box > hbox {
#identity-box-inner {
max-width: 22em;
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 ::::: */
#back-button > dropmarker,
#forward-button > dropmarker,
#back-forward-dropmarker > image ,
#back-forward-dropmarker > label {
#back-button > .toolbarbutton-menu-dropmarker,
#forward-button > .toolbarbutton-menu-dropmarker,
#back-forward-dropmarker > .toolbarbutton-icon,
#back-forward-dropmarker > .toolbarbutton-text {
display: none;
}
.unified-nav-current {

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -806,7 +806,7 @@ WebContentConverterRegistrar.prototype = {
* 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!
*/
var vals = branch.getChildList("", {});
var vals = branch.getChildList("");
if (vals.length == 0)
return;
@ -832,7 +832,7 @@ WebContentConverterRegistrar.prototype = {
getService(Ci.nsIPrefService);
var kids = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
.getChildList("", {});
.getChildList("");
// first get the numbers of the providers by getting all ###.uri prefs
var nums = [];
@ -857,7 +857,7 @@ WebContentConverterRegistrar.prototype = {
// so that getWebContentHandlerByURI can return successfully.
try {
var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
var childPrefs = autoBranch.getChildList("", { });
var childPrefs = autoBranch.getChildList("");
for (var i = 0; i < childPrefs.length; ++i) {
var type = childPrefs[i];
var uri = autoBranch.getCharPref(type);

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -51,7 +51,8 @@ function test() {
"//textarea[1]": "",
"//textarea[2]": "Some text... " + Math.random(),
"//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) {
@ -68,6 +69,8 @@ function test() {
node.checked = aValue;
else if (typeof aValue == "number")
node.selectedIndex = aValue;
else if (node instanceof Ci.nsIDOMHTMLInputElement && node.type == "file")
node.mozSetFileNameArray(aValue, aValue.length);
else
Array.forEach(node.options, function(aOpt, aIx)
(aOpt.selected = aValue.indexOf(aIx) > -1));
@ -77,9 +80,15 @@ function test() {
let node = getElementByXPath(aTab, aQuery);
if (!node)
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" ?
node.checked : node.value);
}
if (node instanceof Ci.nsIDOMHTMLTextAreaElement)
return aValue == node.value;
if (!node.multiple)

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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;
}
.no-margin-button {
min-width:0em;
}
/**
* info pane
*/
@ -425,6 +421,6 @@ window:not([active="true"]) #placesList > treechildren::-moz-tree-row(selected)
color: GrayText;
}
#editBookmarkPanelGrid > rows > row > label {
.editBMPanel_rowLabel {
text-align: right !important;
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -21,7 +21,7 @@
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;
background-image: url(chrome://browser/skin/places/dropDown.png);
}

Просмотреть файл

@ -13,8 +13,8 @@
border: none;
}
#placesToolbar > toolbarbutton > image,
#placesToolbar > toolbarbutton > label {
#placesToolbar > toolbarbutton > .toolbarbutton-icon,
#placesToolbar > toolbarbutton > .toolbarbutton-text {
margin: 0;
padding: 0;
}
@ -89,12 +89,12 @@
padding-bottom: 1px;
}
#placesMenu > menu > label {
#placesMenu > menu > .menubar-text {
-moz-padding-end: 8px;
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;
}
@ -171,13 +171,12 @@
margin: 0 1px;
}
#organizerScopeBar > toolbarbutton > label,
#organizerScopeBar > toolbarbutton > image {
#organizerScopeBar > toolbarbutton > .toolbarbutton-icon {
padding: 0;
margin: 0;
}
#organizerScopeBar .toolbarbutton-text {
#organizerScopeBar > toolbarbutton > .toolbarbutton-text {
margin: 0;
padding: 2px 5px;
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -1008,7 +1008,7 @@ class Target(object):
makefile.context.defer(cb, error=self.error, didanything=self.didanything)
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
by the helper objects RemakeTargetSerially, RemakeTargetParallel,
@ -1051,7 +1051,8 @@ class Target(object):
try:
self.resolvedeps(makefile, targetstack, [], False)
except util.MakeError, e:
print e
if printerror:
print e
self.error = True
self.notifydone(makefile)
return
@ -1312,7 +1313,7 @@ class _RemakeContext(object):
if len(self.toremake):
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:
for t, required in self.included:
if t.wasremade:

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -73,7 +73,7 @@ while (<>) {
my @deps = split /\s+/, $rest;
push @{$alldeps{$obj}}, @deps;
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}) {
my $dep_mtime = $modtimes{$dep_file};
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;
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) {
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) {
print "Couldn't stat $dep_file for $obj\n" if DEBUG;
print STDERR "Couldn't stat $dep_file for $obj\n" if DEBUG;
}
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;
}
@ -111,17 +111,17 @@ OBJ_LOOP: foreach my $obj (keys %alldeps) {
}
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;
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) {
print "Couldn't stat $dep_file for $obj\n" if DEBUG;
print STDERR "Couldn't stat $dep_file for $obj\n" if DEBUG;
}
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;
}
@ -133,7 +133,11 @@ OBJ_LOOP: foreach my $obj (keys %alldeps) {
}
# Output objects to rebuild (if needed).
if (@objs) {
if ($outfile eq '-') {
if (@objs) {
print "@objs: FORCE\n";
}
} elsif (@objs) {
my $old_output;
my $new_output = "@objs: FORCE\n";

Просмотреть файл

@ -39,7 +39,6 @@ cmdname=`basename "$0"`
MOZ_DIST_BIN=`dirname "$0"`
MOZ_DEFAULT_NAME="./${cmdname}-bin"
MOZ_APPRUNNER_NAME="./mozilla-bin"
MOZ_VIEWER_NAME="./viewer"
MOZ_PROGRAM=""
exitcode=1
@ -62,18 +61,10 @@ echo " --debugger debugger"
echo ""
echo " Examples:"
echo ""
echo " Run the viewer"
echo ""
echo " ${cmdname} viewer"
echo ""
echo " Run the mozilla-bin binary"
echo ""
echo " ${cmdname} mozilla-bin"
echo ""
echo " Debug the viewer in a debugger"
echo ""
echo " ${cmdname} -g viewer"
echo ""
echo " Debug the mozilla-bin binary in gdb"
echo ""
echo " ${cmdname} -g mozilla-bin -d gdb"
@ -239,11 +230,6 @@ then
if [ -x "$MOZ_DEFAULT_NAME" ]
then
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
##

Просмотреть файл

@ -250,6 +250,7 @@ class JarMaker(object):
that against the l10nbases. l10nbases can either be path strings, or
callables. In the latter case, that will be called with the
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))
def resolveL10nBase(relpath):
@ -265,13 +266,18 @@ class JarMaker(object):
l10ndir = srcdir
if os.path.basename(srcdir) == 'locales':
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 = map(resolveL10nBase(rell10ndir), l10nbases)
if localedirs is not None:
l10ndirs += [os.path.normpath(os.path.abspath(s))
for s in localedirs]
l10ndirs = None
# srcdir may not be a child of topsourcedir, in which case
# we assume that the caller passed in suitable sourcedirs,
# and just skip passing in localedirs
if srcdir.startswith(topsourcedir):
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))
for s in sourcedirs] + [srcdir]
self.makeJar(infile=infile,
@ -375,7 +381,7 @@ class JarMaker(object):
if realsrc is None:
if jf is not None:
jf.close()
raise RuntimeError("file not found: " + src)
raise RuntimeError('File "%s" not found in %s' % (src, ', '.join(src_base)))
if m.group('optPreprocess'):
outf = outHelper.getOutput(out)
inf = open(realsrc)

Просмотреть файл

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

Просмотреть файл

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

66
config/mozunit.py Normal 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

Просмотреть файл

@ -360,6 +360,10 @@ endif # GNU_CC
endif # ENABLE_CXX_EXCEPTIONS
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)))
HOST_PDBFILE=$(basename $(@F)).pdb
endif
@ -2064,21 +2068,14 @@ ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
MDDEPEND_FILES := $(strip $(wildcard $(MDDEPDIR)/*.pp))
ifneq (,$(MDDEPEND_FILES))
ifdef PERL
# The script mddepend.pl checks the dependencies and writes to stdout
# one rule to force out-of-date objects. For example,
# foo.o boo.o: FORCE
# The script has an advantage over including the *.pp files directly
# 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.
ifeq (,$(MAKE_RESTARTS))
$(MDDEPDIR)/.all.pp: FORCE
@$(PERL) $(BUILD_TOOLS)/mddepend.pl $@ $(MDDEPEND_FILES)
endif
-include $(MDDEPDIR)/.all.pp
else
include $(MDDEPEND_FILES)
endif
ALL_PP_RESULTS = $(shell $(PERL) $(BUILD_TOOLS)/mddepend.pl - $(MDDEPEND_FILES))
$(eval $(ALL_PP_RESULTS))
endif
endif

Просмотреть файл

@ -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())

Просмотреть файл

@ -288,18 +288,18 @@ case "$target" in
ac_exeext=.exe
_pwdw=`pwd -W`
_pwd=`pwd`
make OGLES_SDK_DIR="$OGLES_SDK_DIR" WINCE_SDK_DIR="$WINCE_SDK_DIR" TOPSRCDIR="$_topsrcdir" OBJDIR="$_pwdw" -C $srcdir/build/wince/tools
_pwd=`pwd -W`
_topsrcdirwin=`cd \`dirname $0\`; pwd -W`
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"
CXX="$_pwd/dist/sdk/bin/arm-wince-gcc"
CPP="$_pwd/dist/sdk/bin/arm-wince-gcc -E -nologo"
CXXCPP="$_pwd/dist/sdk/bin/arm-wince-gcc -TP -E -nologo"
LD="$_pwd/dist/sdk/bin/arm-wince-link"
AR="$_pwd/dist/sdk/bin/arm-wince-lib"
AS="$_pwd/dist/sdk/bin/arm-wince-as"
RC="$_pwd/dist/sdk/bin/arm-wince-res"
CC="$_pwd/dist/sdk/bin/arm-wince-gcc.exe"
CXX="$_pwd/dist/sdk/bin/arm-wince-gcc.exe"
CPP="$_pwd/dist/sdk/bin/arm-wince-gcc.exe -E -nologo"
CXXCPP="$_pwd/dist/sdk/bin/arm-wince-gcc.exe -TP -E -nologo"
LD="$_pwd/dist/sdk/bin/arm-wince-link.exe"
AR="$_pwd/dist/sdk/bin/arm-wince-lib.exe"
AS="$_pwd/dist/sdk/bin/arm-wince-as.exe"
RC="$_pwd/dist/sdk/bin/arm-wince-res.exe"
echo -----------------------------------------------------------------------------
@ -508,7 +508,7 @@ MOZ_ARG_DISABLE_BOOL(vista-sdk-requirements,
[ --disable-vista-sdk-requirements
Do not build Vista SDK specific code],
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 "$MOZ_DISABLE_VISTA_SDK_REQUIREMENTS"; then
AC_MSG_WARN([--disable-vista-sdk-requirements is deprecated, use --with-windows-version=502 instead])
@ -2004,7 +2004,10 @@ case "$target" in
*-wince*)
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_EXTRACT="$AR -extract"
AR_DELETE="$AR d"
@ -3346,7 +3349,7 @@ AC_MSG_CHECKING(for ARM NEON support in compiler)
_SAVE_CFLAGS="$CFLAGS"
if test "$GNU_CC"; then
# gcc needs -mfpu=neon to recognize NEON instructions
CFLAGS="$CFLAGS -mfpu=neon"
CFLAGS="$CFLAGS -mfpu=neon -mfloat-abi=softfp"
fi
AC_TRY_COMPILE([],
[asm("vadd.i8 d0, d0, d0");],
@ -4743,12 +4746,16 @@ photon)
cairo-windows)
MOZ_WIDGET_TOOLKIT=windows
if test -z "$WINCE"; then
MOZ_WEBGL=1
fi
;;
cairo-gtk2|cairo-gtk2-x11)
MOZ_WIDGET_TOOLKIT=gtk2
MOZ_ENABLE_GTK2=1
MOZ_ENABLE_XREMOTE=1
MOZ_WEBGL=1
AC_DEFINE(MOZ_X11)
MOZ_X11=1
@ -4761,6 +4768,7 @@ cairo-gtk2|cairo-gtk2-x11)
cairo-gtk2-dfb)
MOZ_WIDGET_TOOLKIT=gtk2
MOZ_ENABLE_GTK2=1
MOZ_WEBGL=1
AC_DEFINE(MOZ_DFB)
MOZ_DFB=1
@ -4813,6 +4821,7 @@ cairo-cocoa)
CXXFLAGS="$CXXFLAGS $TK_CFLAGS"
LIBXUL_LIBS='$(XPCOM_FROZEN_LDOPTS) $(LIBXUL_DIST)/bin/XUL -lobjc'
MOZ_FS_LAYOUT=bundle
MOZ_WEBGL=1
;;
esac
@ -6235,6 +6244,7 @@ if test $NS_OSSO; then
fi
AC_DEFINE(NS_OSSO)
MOZ_GFX_OPTIMIZE_MOBILE=1
MOZ_WEBGL=
fi
AC_SUBST(LIBOSSO_CFLAGS)
AC_SUBST(LIBOSSO_LIBS)
@ -7848,6 +7858,7 @@ AC_SUBST(MOZ_PLACES_BOOKMARKS)
AC_SUBST(MOZ_STORAGE)
AC_SUBST(MOZ_FEEDS)
AC_SUBST(NS_PRINTING)
AC_SUBST(MOZ_WEBGL)
AC_SUBST(MOZ_JAVAXPCOM)
AC_SUBST(JAVA_INCLUDE_PATH)
@ -7901,6 +7912,7 @@ AC_SUBST(OGLES_SDK_DIR)
AC_SUBST(MOZ_APP_NAME)
AC_SUBST(MOZ_APP_DISPLAYNAME)
AC_SUBST(MOZ_APP_VERSION)
AC_SUBST(MOZ_APP_UA_EXTRA)
AC_SUBST(FIREFOX_VERSION)
AC_SUBST(MOZ_PKG_SPECIAL)
@ -8077,6 +8089,16 @@ if test "$MOZ_X11"; then
fi
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
dnl Set various defines and substitutions

Просмотреть файл

@ -45,57 +45,46 @@
#define NS_HTML_STYLE_PROPERTY_NOT_THERE \
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 */
#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 */
#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 \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 9)
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 5)
/** Error codes for content policy blocking */
#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 \
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 11)
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CONTENT, 7)
/** Success variations of content policy blocking */
#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 \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 13)
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 9)
#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 \
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 */
#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 \
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 17)
NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_CONTENT, 13)
#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___

Просмотреть файл

@ -1294,7 +1294,7 @@ public:
/**
* 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);
@ -1606,6 +1606,7 @@ public:
// Pop() will be a no-op if Push() or PushNull() fail
void Pop();
nsIScriptContext* GetCurrentScriptContext() { return mScx; }
private:
// Combined code for PushNull() and Push(JSContext*)
PRBool DoPush(JSContext* cx);

Просмотреть файл

@ -70,10 +70,10 @@ enum nsLinkState {
};
// IID for the nsIContent interface
// d510382f-f5eb-48bb-9ad9-b3dc4806faaf
// c726e716-a4be-4202-8a5e-32d0525903e8
#define NS_ICONTENT_IID \
{ 0xd510382f, 0xf5eb, 0x48bb, \
{ 0x9a, 0xd9, 0xb3, 0xdc, 0x48, 0x06, 0xfa, 0xaf } }
{ 0xc726e716, 0xa4be, 0x4202, \
{ 0x8a, 0x5e, 0x32, 0xd0, 0x52, 0x59, 0x03, 0xe8 } }
/**
* A node of content in a document's content model. This interface
@ -673,26 +673,6 @@ public:
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
* particularly means that it has done everything you would expect it to have

Просмотреть файл

@ -129,6 +129,8 @@ public:
mCompatMode(eCompatibility_FullStandards),
mIsInitialDocumentInWindow(PR_FALSE),
mMayStartLayout(PR_TRUE),
mVisible(PR_TRUE),
mRemovedFromDocShell(PR_FALSE),
// mAllowDNSPrefetch starts true, so that we can always reliably && it
// 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
@ -689,12 +691,10 @@ public:
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)
{
mDocumentContainer = do_GetWeakReference(aContainer);
}
virtual void SetContainer(nsISupports *aContainer);
/**
* Get the container (docshell) for this document.
@ -1120,6 +1120,16 @@ public:
* called yet.
*/
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);
PRBool UnregisterFreezableElement(nsIContent* aContent);
@ -1281,6 +1291,15 @@ protected:
// True iff IsShowing() should be returning true
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
// document has no window, DNS prefetch won't be performed no matter what.
PRPackedBool mAllowDNSPrefetch;

Просмотреть файл

@ -228,7 +228,10 @@ interface nsIXMLHttpRequest : nsISupports
* @param password (optional) A password for authentication if necessary.
* 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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -1171,14 +1171,8 @@ protected:
// True if the document has been detached from its content viewer.
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.
PRPackedBool mInDestructor:1;
// True if the document "page" is not hidden
PRPackedBool mVisible:1;
// True if document has ever had script handling object.
PRPackedBool mHasHadScriptHandlingObject:1;

Просмотреть файл

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

Просмотреть файл

@ -56,6 +56,7 @@
#endif
#include "nsBindingManager.h"
#include "nsGenericHTMLElement.h"
#include "nsHTMLMediaElement.h"
// This macro expects the ownerDocument of content_ to be in scope as
// |nsIDocument* doc|
@ -604,6 +605,8 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, PRBool aClone, PRBool aDeep,
nsIDocument* newDoc = aNode->GetOwnerDoc();
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) {
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) {
elem->RecompileScriptEventListeners();
}

Просмотреть файл

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

Просмотреть файл

@ -1753,30 +1753,14 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
/* void open (in AUTF8String method, in AUTF8String url); */
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;
PRBool async = PR_TRUE;
nsAutoString user, password;
nsAXPCNativeCallContext *cc = nsnull;
nsIXPConnect *xpc = nsContentUtils::XPConnect();
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;
if (nsContentUtils::GetCurrentJSContext()) {
// We're (likely) called from JS
// Find out if UniversalBrowserRead privileges are enabled
if (nsContentUtils::IsCallerTrustedForRead()) {
@ -1784,33 +1768,11 @@ nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url)
} else {
mState &= ~XML_HTTP_REQUEST_XSITEENABLED;
}
}
if (argc > 2) {
JSAutoRequest ar(cx);
JSBool asyncBool;
::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));
}
}
}
}
if (!optional_argc) {
// No optional arguments were passed in. Default async to true.
async = PR_TRUE;
}
return OpenRequest(method, url, async, user, password);

Просмотреть файл

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

Просмотреть файл

@ -488,14 +488,17 @@ protected:
* Gets the pres shell from either the canvas element or the doc shell
*/
nsIPresShell *GetPresShell() {
nsIPresShell *presShell = nsnull;
nsCOMPtr<nsIContent> content = do_QueryInterface(mCanvasElement);
if (content) {
presShell = content->GetOwnerDoc()->GetPrimaryShell();
} else if (mDocShell) {
mDocShell->GetPresShell(&presShell);
nsIDocument* ownerDoc = content->GetOwnerDoc();
return ownerDoc ? ownerDoc->GetPrimaryShell() : nsnull;
}
return presShell;
if (mDocShell) {
nsCOMPtr<nsIPresShell> shell;
mDocShell->GetPresShell(getter_AddRefs(shell));
return shell.get();
}
return nsnull;
}
// text
@ -618,14 +621,6 @@ protected:
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
void GetAppUnitsValues(PRUint32 *perDevPixel, PRUint32 *perCSSPixel) {
// 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
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;
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 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;
nsRefPtr<gfxPattern> pattern;
nsRefPtr<gfxPath> path;
@ -2997,40 +2966,36 @@ nsCanvasRenderingContext2D::DrawImage()
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;
if (argc == 3) {
GET_ARG(&dx, argv[1]);
GET_ARG(&dy, argv[2]);
if (optional_argc == 0) {
dx = a1;
dy = a2;
sx = sy = 0.0;
dw = sw = (double) imgSize.width;
dh = sh = (double) imgSize.height;
} else if (argc == 5) {
GET_ARG(&dx, argv[1]);
GET_ARG(&dy, argv[2]);
GET_ARG(&dw, argv[3]);
GET_ARG(&dh, argv[4]);
} else if (optional_argc == 2) {
dx = a1;
dy = a2;
dw = a3;
dh = a4;
sx = sy = 0.0;
sw = (double) imgSize.width;
sh = (double) imgSize.height;
} else if (argc == 9) {
GET_ARG(&sx, argv[1]);
GET_ARG(&sy, argv[2]);
GET_ARG(&sw, argv[3]);
GET_ARG(&sh, argv[4]);
GET_ARG(&dx, argv[5]);
GET_ARG(&dy, argv[6]);
GET_ARG(&dw, argv[7]);
GET_ARG(&dh, argv[8]);
} else if (optional_argc == 6) {
sx = a1;
sy = a2;
sw = a3;
sh = a4;
dx = a5;
dy = a6;
dw = a7;
dh = a8;
} else {
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
rv = NS_ERROR_INVALID_ARG;
goto FINISH;
}
#undef GET_ARG
if (dw == 0.0 || dh == 0.0) {
rv = NS_OK;
@ -3039,7 +3004,7 @@ nsCanvasRenderingContext2D::DrawImage()
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;
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
FlushLayoutForTree(nsIDOMWindow* aWindow)
{
@ -3398,6 +3308,15 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
//
// 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);
NS_IMETHODIMP
@ -3469,10 +3388,14 @@ nsCanvasRenderingContext2D::GetImageData()
if (len > (((PRUint32)0xfff00000)/sizeof(jsval)))
return NS_ERROR_INVALID_ARG;
nsAutoArrayPtr<jsval> jsvector(new (std::nothrow) jsval[w * h * 4]);
if (!jsvector)
jsval *dest;
JSObject *dataArray = js_NewArrayObjectWithCapacity(ctx, len, &dest);
if (!dataArray)
return NS_ERROR_OUT_OF_MEMORY;
jsval *dest = jsvector.get();
nsAutoGCRoot arrayGCRoot(&dataArray, &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRUint8 *row;
for (int j = 0; j < h; j++) {
row = surfaceData + surfaceDataOffset + (surfaceDataStride * j);
@ -3504,13 +3427,8 @@ nsCanvasRenderingContext2D::GetImageData()
}
}
JSObject *dataArray = JS_NewArrayObject(ctx, w*h*4, jsvector.get());
if (!dataArray)
return NS_ERROR_OUT_OF_MEMORY;
nsAutoGCRoot arrayGCRoot(&dataArray, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Allocate result object after array, so if we have to trigger gc
// we do it now.
JSObject *result = JS_NewObject(ctx, NULL, NULL, NULL);
if (!result)
return NS_ERROR_OUT_OF_MEMORY;
@ -3531,13 +3449,6 @@ nsCanvasRenderingContext2D::GetImageData()
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)
{
if (PRUint32(aInput) > 255)
@ -3803,21 +3714,19 @@ nsCanvasRenderingContext2D::CreateImageData()
if (len / 4 != len0)
return NS_ERROR_DOM_INDEX_SIZE_ERR;
nsAutoArrayPtr<jsval> jsvector(new (std::nothrow) jsval[w * h * 4]);
if (!jsvector)
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());
jsval *dest;
JSObject *dataArray = js_NewArrayObjectWithCapacity(ctx, len, &dest);
if (!dataArray)
return NS_ERROR_OUT_OF_MEMORY;
nsAutoGCRoot arrayGCRoot(&dataArray, &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);
if (!result)
return NS_ERROR_OUT_OF_MEMORY;

Просмотреть файл

@ -3649,18 +3649,20 @@ isPixel(ctx, 50,25, 0,255,0,255, 2);
function test_2d_drawImage_wrongtype() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var canvas = document.getElementById('c127');
var ctx = canvas.getContext('2d');
var _thrown = undefined; try {
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 {
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 {
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 {
ctx.drawImage(document.createElement('p'), 0, 0);
} 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 imgdata2 = ctx.getImageData(0, 0, 10.01, 10.99);
ok(imgdata1.width == imgdata2.width, "imgdata1.width == imgdata2.width");
ok(imgdata1.height == imgdata2.height, "imgdata1.height == imgdata2.height");
is(imgdata1.width, imgdata2.width, "imgdata1.width == imgdata2.width");
is(imgdata1.height, imgdata2.height, "imgdata1.height == imgdata2.height");
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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>

Просмотреть файл

@ -88,6 +88,8 @@ public:
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
PRBool aNotify);
virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
PRBool aNotify);
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
@ -97,7 +99,12 @@ public:
virtual PRBool IsDoneAddingChildren();
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,
// when it has read the metadata containing video dimensions,
@ -180,6 +187,9 @@ public:
// events can be fired.
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.
// If the element is 'autoplay' and is ready to play back (not paused,
// autoplay pref enabled, etc), it should start playing back.
@ -204,11 +214,6 @@ public:
// main thread when/if the size changes.
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.
// If it returns true, then it also returns a null-terminated list
// of supported codecs in *aSupportedCodecs. This
@ -277,10 +282,10 @@ protected:
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.
*/
PRBool CreateDecoder(const nsACString& aMIMEType);
already_AddRefed<nsMediaDecoder> CreateDecoder(const nsACString& aMIMEType);
/**
* 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.
*/
nsresult FinishDecoderSetup();
nsresult FinishDecoderSetup(nsMediaDecoder* aDecoder);
/**
* Execute the initial steps of the load algorithm that ensure existing
@ -371,6 +376,18 @@ protected:
nsIChannel *aNewChannel,
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;
// 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.
PRPackedBool mPlayingBeforeSeek;
// PR_TRUE if the video was paused before Freeze was called. This is checked
// to ensure that the playstate doesn't change when the user goes Forward/Back
// from the bfcache.
PRPackedBool mPausedBeforeFreeze;
// PR_TRUE iff this element is paused because the document is inactive
PRPackedBool mPausedForInactiveDocument;
// PR_TRUE if we've reported a "waiting" event since the last
// 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
// when the poster frame should be shown.
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;
};

Просмотреть файл

@ -40,7 +40,11 @@
#define nsIFileControlElement_h___
#include "nsISupports.h"
class nsAString;
#include "nsTArray.h"
#include "nsString.h"
#include "nsCOMArray.h"
class nsIFile;
// IID for the nsIFileControl interface
#define NS_IFILECONTROLELEMENT_IID \
@ -57,14 +61,23 @@ public:
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,

Просмотреть файл

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

Просмотреть файл

@ -142,7 +142,7 @@ public:
nsresult GetOffsetParent(nsIDOMElement** aOffsetParent);
virtual nsresult GetInnerHTML(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(),
// SetSpellcheck(), and GetDraggable() such that classes that inherit interfaces
// with those methods properly override them

Просмотреть файл

@ -295,66 +295,23 @@ nsHTMLCanvasElement::ParseAttribute(PRInt32 aNamespaceID,
// nsHTMLCanvasElement::toDataURL
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
// 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;
}
// 0-arg case; convert to png
if (argc == 0) {
return ToDataURLImpl(NS_LITERAL_STRING("image/png"), EmptyString(), aDataURL);
nsAutoString type(aType);
if (type.IsEmpty()) {
type.AssignLiteral("image/png");
}
JSAutoRequest ar(ctx);
// 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;
return ToDataURLImpl(type, aParams, aDataURL);
}

Просмотреть файл

@ -192,24 +192,23 @@ class nsHTMLInputElementState : public nsISupports
mValue = aValue;
}
const nsString& GetFilename() {
return mFilename;
const nsTArray<nsString>& GetFilenames() {
return mFilenames;
}
void SetFilename(const nsAString &aFilename) {
mFilename = aFilename;
void SetFilenames(const nsTArray<nsString> &aFilenames) {
mFilenames = aFilenames;
}
nsHTMLInputElementState()
: mValue()
, mFilename()
, mChecked(PR_FALSE)
, mCheckedSet(PR_FALSE)
{};
protected:
nsString mValue;
nsString mFilename;
nsTArray<nsString> mFilenames;
PRPackedBool mChecked;
PRPackedBool mCheckedSet;
};
@ -298,8 +297,9 @@ public:
NS_IMETHOD SetValueChanged(PRBool aValueChanged);
// nsIFileControlElement
virtual void GetFileName(nsAString& aFileName);
virtual void SetFileName(const nsAString& aFileName);
virtual void GetDisplayFileName(nsAString& aFileName);
virtual void GetFileArray(nsCOMArray<nsIFile> &aFile);
virtual void SetFileNames(const nsTArray<nsString>& aFileNames);
// nsIRadioControlElement
NS_IMETHOD RadioSetChecked(PRBool aNotify);
@ -331,6 +331,17 @@ protected:
nsITextControlFrame* aFrame,
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,
PRBool aShouldInvalidate);
@ -404,11 +415,6 @@ protected:
*/
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.
*/
@ -431,16 +437,16 @@ protected:
*/
char* mValue;
/**
* The value of the input if it is a file input. This is the filename used
* when uploading a file. It is vital that this is kept separate from mValue
* so that it won't be possible to 'leak' the value from a text-input to a
* file-input. Additionally, the logic for this value is kept as simple 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.
* Whenever the frame wants to change the filename it has to call
* SetFileName to update this member.
* The value of the input if it is a file input. This is the list of filenames
* used when uploading a file. It is vital that this is kept separate from
* mValue so that it won't be possible to 'leak' the value from a text-input
* to a file-input. Additionally, the logic for this value is kept as simple
* as possible to avoid accidental errors where the wrong filename is used.
* Therefor the list of filenames is always owned by this member, never by
* the frame. Whenever the frame wants to change the filename it has to call
* SetFileNames to update this member.
*/
nsAutoPtr<nsString> mFileName;
nsTArray<nsString> mFileNames;
nsRefPtr<nsDOMFileList> mFileList;
};
@ -537,9 +543,7 @@ nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
}
break;
case NS_FORM_INPUT_FILE:
if (mFileName) {
it->mFileName = new nsString(*mFileName);
}
it->mFileNames = mFileNames;
break;
case NS_FORM_INPUT_RADIO:
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_BOOL_ATTR(nsHTMLInputElement, Checked, checked)
NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Disabled, disabled)
NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Multiple, multiple)
NS_IMPL_INT_ATTR(nsHTMLInputElement, MaxLength, maxlength)
NS_IMPL_STRING_ATTR(nsHTMLInputElement, Name, name)
NS_IMPL_BOOL_ATTR(nsHTMLInputElement, ReadOnly, readonly)
@ -868,17 +873,17 @@ nsHTMLInputElement::GetValue(nsAString& aValue)
if (mType == NS_FORM_INPUT_FILE) {
if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) {
if (mFileName) {
aValue = *mFileName;
if (!mFileNames.IsEmpty()) {
aValue = mFileNames[0];
}
else {
aValue.Truncate();
}
} else {
// Just return the leaf name
nsCOMPtr<nsIFile> file;
GetFile(getter_AddRefs(file));
if (!file || NS_FAILED(file->GetLeafName(aValue))) {
nsCOMArray<nsIFile> files;
GetFileArray(files);
if (files.Count() == 0 || NS_FAILED(files[0]->GetLeafName(aValue))) {
aValue.Truncate();
}
}
@ -912,8 +917,11 @@ nsHTMLInputElement::SetValue(const nsAString& aValue)
// UniversalFileRead privilege
return NS_ERROR_DOM_SECURITY_ERR;
}
SetSingleFileName(aValue);
}
else {
ClearFileNames();
}
SetFileName(aValue);
}
else {
SetValueInternal(aValue, nsnull, PR_FALSE);
@ -922,6 +930,47 @@ nsHTMLInputElement::SetValue(const nsAString& aValue)
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
nsHTMLInputElement::SetUserInput(const nsAString& aValue)
{
@ -931,7 +980,7 @@ nsHTMLInputElement::SetUserInput(const nsAString& aValue)
if (mType == NS_FORM_INPUT_FILE)
{
SetFileName(aValue);
SetSingleFileName(aValue);
} else {
SetValueInternal(aValue, nsnull, PR_TRUE);
}
@ -949,28 +998,36 @@ nsHTMLInputElement::TakeTextFrameValue(const nsAString& aValue)
}
void
nsHTMLInputElement::GetFileName(nsAString& aValue)
nsHTMLInputElement::GetDisplayFileName(nsAString& aValue)
{
if (mFileName) {
aValue = *mFileName;
}
else {
aValue.Truncate();
aValue.Truncate();
for (PRUint32 i = 0; i < mFileNames.Length(); ++i) {
if (i == 0) {
aValue.Append(mFileNames[i]);
}
else {
aValue.Append(NS_LITERAL_STRING(", ") + mFileNames[i]);
}
}
}
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
mFileName = aValue.IsEmpty() ? nsnull : new nsString(aValue);
mFileNames = aFileNames;
#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
// 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.
nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
if (formControlFrame) {
formControlFrame->SetFormProperty(nsGkAtoms::value, aValue);
nsAutoString readableValue;
GetDisplayFileName(readableValue);
formControlFrame->SetFormProperty(nsGkAtoms::value, readableValue);
}
UpdateFileList();
@ -978,32 +1035,37 @@ nsHTMLInputElement::SetFileName(const nsAString& aValue)
SetValueChanged(PR_TRUE);
}
nsresult
nsHTMLInputElement::GetFile(nsIFile** aFile)
void
nsHTMLInputElement::GetFileArray(nsCOMArray<nsIFile> &aFiles)
{
*aFile = nsnull;
aFiles.Clear();
if (!mFileName || mType != NS_FORM_INPUT_FILE) {
return NS_ERROR_NOT_AVAILABLE;
if (mType != NS_FORM_INPUT_FILE) {
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:"),
nsCaseInsensitiveStringComparator())) {
// Converts the URL string into the corresponding nsIFile if possible.
// A local file will be created if the URL string begins with file://.
rv = NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(*mFileName), aFile);
if (!file) {
// this is no "file://", try as local file
nsCOMPtr<nsILocalFile> localFile;
NS_NewLocalFile(mFileNames[i], PR_FALSE, getter_AddRefs(localFile));
// 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
@ -1012,12 +1074,10 @@ nsHTMLInputElement::UpdateFileList()
if (mFileList) {
mFileList->Clear();
if (mType == NS_FORM_INPUT_FILE && mFileName) {
nsCOMPtr<nsIFile> file;
nsresult rv = GetFile(getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsDOMFile> domFile = new nsDOMFile(file);
nsCOMArray<nsIFile> files;
GetFileArray(files);
for (PRUint32 i = 0; i < (PRUint32)files.Count(); ++i) {
nsRefPtr<nsDOMFile> domFile = new nsDOMFile(files[i]);
if (domFile) {
if (!mFileList->Append(domFile)) {
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
// had time to recreate frames yet -- that happens later in the
// SetAttr() process).
if (newType == NS_FORM_INPUT_FILE) {
// These calls aren't strictly needed any more since we'll never
// confuse values and filenames. However they're there for backwards
if (newType == NS_FORM_INPUT_FILE || mType == NS_FORM_INPUT_FILE) {
// This call isn't strictly needed any more since we'll never
// confuse values and filenames. However it's there for backwards
// compat.
SetFileName(EmptyString());
SetValueInternal(EmptyString(), nsnull, PR_FALSE);
} else if (mType == NS_FORM_INPUT_FILE) {
SetFileName(EmptyString());
ClearFileNames();
}
mType = newType;
@ -2471,7 +2528,7 @@ nsHTMLInputElement::Reset()
case NS_FORM_INPUT_FILE:
{
// Resetting it to blank should not perform security check
SetFileName(EmptyString());
ClearFileNames();
break;
}
// 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
//
if (mType == NS_FORM_INPUT_FILE) {
//
// Open the file
//
nsCOMPtr<nsIFile> file;
rv = GetFile(getter_AddRefs(file));
// Submit files
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)
//
PRBool fileSent = PR_FALSE;
nsAutoString filename;
rv = file->GetLeafName(filename);
if (NS_FAILED(rv)) {
filename.Truncate();
}
if (NS_SUCCEEDED(rv) && !filename.IsEmpty()) {
PRBool acceptsFiles = aFormSubmission->AcceptsFiles();
if (acceptsFiles) {
//
// Get content type
//
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;
}
}
if (!filename.IsEmpty() && aFormSubmission->AcceptsFiles()) {
// Get content type
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);
// 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.
//
aFormSubmission->AddNameFilePair(this, name, filename,
nsnull, NS_LITERAL_CSTRING("application/octet-stream"),
PR_FALSE);
return rv;
} else {
// Ignore error returns from GetLeafName. See bug 199053
rv = NS_OK;
nsnull, NS_LITERAL_CSTRING("application/octet-stream"),
PR_FALSE);
}
}
//
// 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;
return NS_OK;
}
// Submit
@ -2740,13 +2775,13 @@ nsHTMLInputElement::SaveState()
}
case NS_FORM_INPUT_FILE:
{
if (mFileName) {
if (!mFileNames.IsEmpty()) {
inputState = new nsHTMLInputElementState();
if (!inputState) {
return NS_ERROR_OUT_OF_MEMORY;
}
inputState->SetFilename(*mFileName);
inputState->SetFilenames(mFileNames);
}
break;
}
@ -2859,7 +2894,7 @@ nsHTMLInputElement::RestoreState(nsPresState* aState)
}
case NS_FORM_INPUT_FILE:
{
SetFileName(inputState->GetFilename());
SetFileNames(inputState->GetFilenames());
break;
}
}

Просмотреть файл

@ -96,6 +96,48 @@ static PRLogModuleInfo* gMediaElementEventsLog;
#define LOG_EVENT(type, msg)
#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
{
public:
@ -414,14 +456,21 @@ void nsHTMLMediaElement::AbortExistingLoads()
DispatchSimpleEvent(NS_LITERAL_STRING("emptied"));
}
// We may have changed mPaused, mAutoplaying, mNetworkState and other
// things which can affect AddRemoveSelfReference
AddRemoveSelfReference();
mIsRunningSelectResource = PR_FALSE;
}
void nsHTMLMediaElement::NoSupportedMediaSourceError()
{
NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during source selection?");
mError = new nsHTMLMediaError(nsIDOMHTMLMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
ChangeDelayLoadStatus(PR_FALSE);
}
@ -465,16 +514,21 @@ static PRBool HasPotentialResource(nsIContent *aElement)
void nsHTMLMediaElement::SelectResource()
{
NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during resource selection?");
if (!HasPotentialResource(this)) {
// While the media element has neither a src attribute nor any source
// element children, wait. (This steps might wait forever.)
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
mLoadWaitStatus = WAITING_FOR_SRC_OR_SOURCE;
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
ChangeDelayLoadStatus(PR_FALSE);
return;
}
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"));
nsAutoString src;
@ -508,8 +562,8 @@ void nsHTMLMediaElement::NotifyLoadError()
void nsHTMLMediaElement::LoadFromSourceChildren()
{
NS_ASSERTION(!IsInDoc() || mDelayingLoadEvent,
"Should delay load event while loading in document");
NS_ASSERTION(mDelayingLoadEvent,
"Should delay load event (if in document) during load");
while (PR_TRUE) {
nsresult rv;
nsCOMPtr<nsIURI> uri = GetNextSource();
@ -534,8 +588,8 @@ void nsHTMLMediaElement::LoadFromSourceChildren()
nsresult nsHTMLMediaElement::LoadResource(nsIURI* aURI)
{
NS_ASSERTION(!IsInDoc() || mDelayingLoadEvent,
"Should delay load event while loading in document");
NS_ASSERTION(mDelayingLoadEvent,
"Should delay load event (if in document) during load");
nsresult rv;
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.
LOG(PR_LOG_DEBUG, ("%p SetCurrentTime(%f) starting seek", this, aCurrentTime));
nsresult rv = mDecoder->Seek(clampedTime);
// We changed whether we're seeking so we need to AddRemoveSelfReference
AddRemoveSelfReference();
return rv;
}
@ -752,6 +810,8 @@ NS_IMETHODIMP nsHTMLMediaElement::Pause()
PRBool oldPaused = mPaused;
mPaused = PR_TRUE;
mAutoplaying = PR_FALSE;
// We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
AddRemoveSelfReference();
if (!oldPaused) {
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("timeupdate"));
@ -827,7 +887,7 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
mMuted(PR_FALSE),
mIsDoneAddingChildren(!aFromParser),
mPlayingBeforeSeek(PR_FALSE),
mPausedBeforeFreeze(PR_FALSE),
mPausedForInactiveDocument(PR_FALSE),
mWaitingFired(PR_FALSE),
mIsBindingToTree(PR_FALSE),
mIsRunningLoadMethod(PR_FALSE),
@ -836,7 +896,8 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
mIsRunningSelectResource(PR_FALSE),
mSuspendedAfterFirstFrame(PR_FALSE),
mAllowSuspendAfterFirstFrame(PR_TRUE),
mHasPlayedOrSeeked(PR_FALSE)
mHasPlayedOrSeeked(PR_FALSE),
mHasSelfReference(PR_FALSE)
{
#ifdef PR_LOGGING
if (!gMediaElementLog) {
@ -848,10 +909,14 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
#endif
RegisterFreezableElement();
NotifyOwnerDocumentActivityChanged();
}
nsHTMLMediaElement::~nsHTMLMediaElement()
{
NS_ASSERTION(!mHasSelfReference,
"How can we be destroyed if we're still holding a self reference?");
UnregisterFreezableElement();
if (mDecoder) {
mDecoder->Shutdown();
@ -905,8 +970,10 @@ NS_IMETHODIMP nsHTMLMediaElement::Play()
if (mDecoder->IsEnded()) {
SetCurrentTime(0);
}
nsresult rv = mDecoder->Play();
NS_ENSURE_SUCCESS(rv, rv);
if (!mPausedForInactiveDocument) {
nsresult rv = mDecoder->Play();
NS_ENSURE_SUCCESS(rv, rv);
}
}
// TODO: If the playback has ended, then the user agent must set
@ -928,6 +995,8 @@ NS_IMETHODIMP nsHTMLMediaElement::Play()
mPaused = PR_FALSE;
mAutoplaying = PR_FALSE;
// We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
AddRemoveSelfReference();
return NS_OK;
}
@ -979,6 +1048,8 @@ nsresult nsHTMLMediaElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
NotifyAutoplayDataReady();
}
// This attribute can affect AddRemoveSelfReference
AddRemoveSelfReference();
} else if (aName == nsGkAtoms::autobuffer) {
StopSuspendingAfterFirstFrame();
}
@ -987,6 +1058,22 @@ nsresult nsHTMLMediaElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
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()
{
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
if (IsOggType(aType)) {
mDecoder = new nsOggDecoder();
if (mDecoder && !mDecoder->Init(this)) {
mDecoder = nsnull;
nsRefPtr<nsOggDecoder> decoder = new nsOggDecoder();
if (decoder && decoder->Init(this)) {
return decoder.forget().get();
}
}
#endif
#ifdef MOZ_WAVE
if (IsWaveType(aType)) {
mDecoder = new nsWaveDecoder();
if (mDecoder && !mDecoder->Init(this)) {
mDecoder = nsnull;
nsRefPtr<nsWaveDecoder> decoder = new nsWaveDecoder();
if (decoder && decoder->Init(this)) {
return decoder.forget().get();
}
}
#endif
return mDecoder != nsnull;
return nsnull;
}
nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
@ -1253,38 +1341,35 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
nsMediaStream* originalStream = aOriginal->GetCurrentStream();
if (!originalStream)
return NS_ERROR_FAILURE;
mDecoder = aOriginal->Clone();
if (!mDecoder)
nsRefPtr<nsMediaDecoder> decoder = aOriginal->Clone();
if (!decoder)
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)) {
mDecoder = nsnull;
if (!decoder->Init(this)) {
return NS_ERROR_FAILURE;
}
float duration = aOriginal->GetDuration();
if (duration >= 0) {
mDecoder->SetDuration(PRInt64(NS_round(duration * 1000)));
mDecoder->SetSeekable(aOriginal->GetSeekable());
decoder->SetDuration(PRInt64(NS_round(duration * 1000)));
decoder->SetSeekable(aOriginal->GetSeekable());
}
nsMediaStream* stream = originalStream->CloneData(mDecoder);
nsMediaStream* stream = originalStream->CloneData(decoder);
if (!stream) {
mDecoder = nsnull;
return NS_ERROR_FAILURE;
}
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
nsresult rv = mDecoder->Load(stream, nsnull);
nsresult rv = decoder->Load(stream, nsnull);
if (NS_FAILED(rv)) {
mDecoder = nsnull;
return rv;
}
return FinishDecoderSetup();
return FinishDecoderSetup(decoder);
}
nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
@ -1293,20 +1378,21 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
nsCAutoString mimeType;
aChannel->GetContentType(mimeType);
if (!CreateDecoder(mimeType))
nsRefPtr<nsMediaDecoder> decoder = CreateDecoder(mimeType);
if (!decoder) {
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;
nsMediaStream* stream = nsMediaStream::Create(mDecoder, aChannel);
nsMediaStream* stream = nsMediaStream::Create(decoder, aChannel);
if (!stream)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = mDecoder->Load(stream, aListener);
nsresult rv = decoder->Load(stream, aListener);
if (NS_FAILED(rv)) {
mDecoder = nsnull;
return rv;
}
@ -1314,18 +1400,28 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
// which owns the channel.
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;
mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
if (!mPaused) {
SetPlayedOrSeeked(PR_TRUE);
rv = mDecoder->Play();
if (!mPausedForInactiveDocument) {
rv = mDecoder->Play();
}
}
mBegun = PR_TRUE;
@ -1393,6 +1489,7 @@ void nsHTMLMediaElement::ResourceLoaded()
{
mBegun = PR_FALSE;
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
AddRemoveSelfReference();
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
// The download has stopped
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("suspend"));
@ -1404,6 +1501,7 @@ void nsHTMLMediaElement::NetworkError()
mBegun = PR_FALSE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
AddRemoveSelfReference();
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied"));
ChangeDelayLoadStatus(PR_FALSE);
}
@ -1414,6 +1512,7 @@ void nsHTMLMediaElement::DecodeError()
mBegun = PR_FALSE;
DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
AddRemoveSelfReference();
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied"));
ChangeDelayLoadStatus(PR_FALSE);
}
@ -1421,6 +1520,9 @@ void nsHTMLMediaElement::DecodeError()
void nsHTMLMediaElement::PlaybackEnded()
{
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"));
}
@ -1434,12 +1536,15 @@ void nsHTMLMediaElement::SeekCompleted()
mPlayingBeforeSeek = PR_FALSE;
SetPlayedOrSeeked(PR_TRUE);
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("seeked"));
// We changed whether we're seeking so we need to AddRemoveSelfReference
AddRemoveSelfReference();
}
void nsHTMLMediaElement::DownloadSuspended()
{
if (mBegun) {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
AddRemoveSelfReference();
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("suspend"));
}
}
@ -1448,6 +1553,7 @@ void nsHTMLMediaElement::DownloadResumed()
{
if (mBegun) {
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()
{
if (mAutoplaying &&
mPaused &&
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
mAutoplayEnabled) {
if (CanActivateAutoplay()) {
mPaused = PR_FALSE;
// We changed mPaused which can affect AddRemoveSelfReference
AddRemoveSelfReference();
if (mDecoder) {
SetPlayedOrSeeked(PR_TRUE);
mDecoder->Play();
@ -1685,7 +1799,7 @@ PRBool nsHTMLMediaElement::IsPotentiallyPlaying() const
// TODO:
// playback has not stopped due to errors,
// and the element has not paused for user interaction
return
return
!mPaused &&
(mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA ||
mReadyState == nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) &&
@ -1714,38 +1828,61 @@ void nsHTMLMediaElement::UpdateMediaSize(nsIntSize size)
mMediaSize = size;
}
void nsHTMLMediaElement::DestroyContent()
void nsHTMLMediaElement::NotifyOwnerDocumentActivityChanged()
{
if (mDecoder) {
mDecoder->Shutdown();
mDecoder = nsnull;
nsIDocument* ownerDoc = GetOwnerDoc();
// Don't pause if we have no ownerDoc. Something native must have created
// 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);
mChannel = nsnull;
}
nsGenericHTMLElement::DestroyContent();
AddRemoveSelfReference();
}
void nsHTMLMediaElement::Freeze()
void nsHTMLMediaElement::AddRemoveSelfReference()
{
mPausedBeforeFreeze = mPaused;
if (!mPaused) {
Pause();
}
if (mDecoder) {
mDecoder->Suspend();
}
}
// XXX we could release earlier here in many situations if we examined
// which event listeners are attached. Right now we assume there is a
// potential listener for every event. We would also have to keep the
// element alive if it was playing and producing audio output --- right now
// that's covered by the !mPaused check.
nsIDocument* ownerDoc = GetOwnerDoc();
void nsHTMLMediaElement::Thaw()
{
if (!mPausedBeforeFreeze) {
Play();
}
// See the comment at the top of this file for the explanation of this
// boolean expression.
PRBool needSelfReference = (!ownerDoc || ownerDoc->IsActive()) &&
(mDelayingLoadEvent ||
(!mPaused && mDecoder && !mDecoder->IsEnded()) ||
(mDecoder && mDecoder->IsSeeking()) ||
CanActivateAutoplay() ||
mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
if (mDecoder) {
mDecoder->Resume();
if (needSelfReference != mHasSelfReference) {
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 = nsnull;
}
// We changed mDelayingLoadEvent which can affect AddRemoveSelfReference
AddRemoveSelfReference();
}
already_AddRefed<nsILoadGroup> nsHTMLMediaElement::GetDocumentLoadGroup()

Просмотреть файл

@ -1945,3 +1945,36 @@ nsHTMLOptionCollection::GetSelect(nsIDOMHTMLSelectElement **aReturn)
NS_IF_ADDREF(*aReturn = mSelect);
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);
}

Просмотреть файл

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

Просмотреть файл

@ -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));
}

Просмотреть файл

@ -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>

Просмотреть файл

@ -465,6 +465,8 @@ nsMediaCacheStream::BlockList::NotifyBlockSwapped(PRInt32 aBlockIndex1,
e1Prev = e1->mPrevBlock;
e1Next = e1->mNextBlock;
mEntries.RemoveEntry(aBlockIndex1);
// Refresh pointer after hashtable mutation.
e2 = mEntries.GetEntry(aBlockIndex2);
}
if (e2) {
e2Prev = e2->mPrevBlock;
@ -973,263 +975,297 @@ nsMediaCache::PredictNextUseForIncomingData(nsMediaCacheStream* aStream)
PR_MIN(millisecondsAhead, PR_INT32_MAX));
}
enum StreamAction { NONE, SEEK, RESUME, SUSPEND };
void
nsMediaCache::Update()
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
nsAutoMonitor mon(mMonitor);
mUpdateQueued = PR_FALSE;
// The action to use for each stream. We store these so we can make
// 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
mInUpdate = PR_TRUE;
mInUpdate = PR_TRUE;
#endif
PRInt32 maxBlocks = GetMaxBlocks();
TimeStamp now = TimeStamp::Now();
PRInt32 maxBlocks = GetMaxBlocks();
TimeStamp now = TimeStamp::Now();
PRInt32 freeBlockCount = mFreeBlocks.GetCount();
// 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
// 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
// the media.cache_size preference was reduced.
// 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
// cache whose expected time of next use is earlier or equal to that.
// If we allow that, we can effectively end up discarding overflowing
// blocks (by moving an overflowing block to the main part of the cache,
// and then overwriting it with another overflowing block), and we try
// to avoid that since it requires HTTP seeks.
// We also use this loop to eliminate overflowing blocks from
// freeBlockCount.
TimeDuration latestPredictedUseForOverflow = 0;
for (PRInt32 blockIndex = mIndex.Length() - 1; blockIndex >= maxBlocks;
--blockIndex) {
if (IsBlockFree(blockIndex)) {
// Don't count overflowing free blocks in our free block count
--freeBlockCount;
continue;
}
TimeDuration predictedUse = PredictNextUse(now, blockIndex);
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;
PRInt32 freeBlockCount = mFreeBlocks.GetCount();
// 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
// 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
// the media.cache_size preference was reduced.
// 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
// cache whose expected time of next use is earlier or equal to that.
// If we allow that, we can effectively end up discarding overflowing
// blocks (by moving an overflowing block to the main part of the cache,
// and then overwriting it with another overflowing block), and we try
// to avoid that since it requires HTTP seeks.
// We also use this loop to eliminate overflowing blocks from
// freeBlockCount.
TimeDuration latestPredictedUseForOverflow = 0;
for (PRInt32 blockIndex = mIndex.Length() - 1; blockIndex >= maxBlocks;
--blockIndex) {
if (IsBlockFree(blockIndex)) {
// Don't count overflowing free blocks in our free block count
--freeBlockCount;
continue;
}
TimeDuration predictedUse = PredictNextUse(now, blockIndex);
latestPredictedUseForOverflow = PR_MAX(latestPredictedUseForOverflow, predictedUse);
}
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)) {
rv = WriteCacheFile(destinationBlockIndex*BLOCK_SIZE, buf, BLOCK_SIZE);
// 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) ||
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)) {
// We successfully copied the file data.
LOG(PR_LOG_DEBUG, ("Swapping blocks %d and %d (trimming cache)",
blockIndex, destinationBlockIndex));
// Swapping the block metadata here lets us maintain the
// correct positions in the linked lists
SwapBlocks(blockIndex, destinationBlockIndex);
} else {
// If the write fails we may have corrupted the destination
// block. Free it now.
rv = WriteCacheFile(destinationBlockIndex*BLOCK_SIZE, buf, BLOCK_SIZE);
if (NS_SUCCEEDED(rv)) {
// We successfully copied the file data.
LOG(PR_LOG_DEBUG, ("Swapping blocks %d and %d (trimming cache)",
blockIndex, destinationBlockIndex));
// Swapping the block metadata here lets us maintain the
// correct positions in the linked lists
SwapBlocks(blockIndex, destinationBlockIndex);
} 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)",
destinationBlockIndex));
FreeBlock(destinationBlockIndex);
blockIndex));
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.
Truncate();
// Try chopping back the array of cache entries and the cache file.
Truncate();
// 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
// cache)
PRInt32 nonSeekableReadaheadBlockCount = 0;
for (PRUint32 i = 0; i < mStreams.Length(); ++i) {
nsMediaCacheStream* stream = mStreams[i];
if (!stream->mIsSeekable) {
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;
// 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
// cache)
PRInt32 nonSeekableReadaheadBlockCount = 0;
for (PRUint32 i = 0; i < mStreams.Length(); ++i) {
nsMediaCacheStream* stream = mStreams[i];
if (!stream->mIsSeekable) {
nonSeekableReadaheadBlockCount += stream->mReadaheadBlocks.GetCount();
}
} else {
// We can't seek directly to the desired offset...
if (stream->mChannelOffset > desiredOffset) {
// 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");
desiredOffset = 0;
// Flush cached blocks out, since if this is a live stream
// 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);
}
// 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);
}
}
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 {
// otherwise reading forward is looking good, so just stay where we
// are and don't trigger a channel seek!
desiredOffset = stream->mChannelOffset;
}
}
// 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;
// We can't seek directly to the desired offset...
if (stream->mChannelOffset > desiredOffset) {
// 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");
desiredOffset = 0;
// Flush cached blocks out, since if this is a live stream
// 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);
} else {
// otherwise reading forward is looking good, so just stay where we
// are and don't trigger a channel seek!
desiredOffset = stream->mChannelOffset;
}
}
}
// 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;
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
stream->mChannelOffset = (desiredOffset/BLOCK_SIZE)*BLOCK_SIZE;
switch (actions[i]) {
case SEEK:
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,
stream->mCacheSuspended);
stream->mCacheSuspended = PR_FALSE;
} else if (enableReading && stream->mCacheSuspended) {
break;
case RESUME:
LOG(PR_LOG_DEBUG, ("Stream %p Resumed", stream));
rv = stream->mClient->CacheClientResume();
stream->mCacheSuspended = PR_FALSE;
} else if (!enableReading && !stream->mCacheSuspended) {
break;
case SUSPEND:
LOG(PR_LOG_DEBUG, ("Stream %p Suspended", stream));
rv = stream->mClient->CacheClientSuspend();
stream->mCacheSuspended = PR_TRUE;
break;
default:
break;
}
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

Просмотреть файл

@ -220,13 +220,14 @@ public:
// aClient provides the underlying transport that cache will use to read
// data for this stream.
nsMediaCacheStream(nsMediaChannelStream* aClient)
: mClient(aClient), mResourceID(0), mChannelOffset(0),
mStreamOffset(0), mStreamLength(-1), mPlaybackBytesPerSecond(10000),
mPinCount(0), mCurrentMode(MODE_PLAYBACK),
mInitialized(PR_FALSE), mClosed(PR_FALSE),
: mClient(aClient), mResourceID(0), mInitialized(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),
mUsingNullPrincipal(PR_FALSE) {}
mClosed(PR_FALSE) {}
~nsMediaCacheStream();
// 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
// underlying resource and should share data.
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
// can be accessed by by any thread.
// The following fields are protected by the cache's monitor but are
// 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
PRInt64 mChannelOffset;
// The offset where the reader is positioned in the stream
PRInt64 mStreamOffset;
PRInt64 mChannelOffset;
// The reported or discovered length of the data, or -1 if nothing is
// 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
// block, or -1 if the block is not cached.
nsTArray<PRInt32> mBlocks;
@ -460,22 +477,14 @@ private:
PRUint32 mPinCount;
// The last reported read mode
ReadMode mCurrentMode;
// Set to true when Init or InitAsClone has been called
PRPackedBool mInitialized;
// true if some data in mPartialBlockBuffer has been read as metadata
PRPackedBool mMetadataInPartialBlockBuffer;
// Set to true when the stream has been closed either explicitly or
// due to an internal cache error
PRPackedBool mClosed;
// 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 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;
// The following field is protected by the cache's monitor but are
// only written on the main thread.
// Data received for the block containing mChannelOffset. Data needs
// to wait here so we can write back a complete block. The first

Просмотреть файл

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

Просмотреть файл

@ -540,7 +540,7 @@ PRInt64 nsMediaChannelStream::Tell()
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();
if (!element) {
@ -569,7 +569,7 @@ void nsMediaChannelStream::Suspend(PRBool aCloseImmediately)
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!");
nsHTMLMediaElement* element = mDecoder->GetMediaElement();
@ -641,7 +641,9 @@ nsMediaChannelStream::DoNotifyDataReceived()
void
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())
return;
@ -667,7 +669,9 @@ private:
void
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);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
@ -676,7 +680,7 @@ nsMediaChannelStream::CacheClientNotifyDataEnded(nsresult aStatus)
nsresult
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();
@ -703,12 +707,7 @@ nsMediaChannelStream::CacheClientSuspend()
}
Suspend(PR_FALSE);
// We have to spawn an event here since we're being called back from
// 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);
mDecoder->NotifySuspendedStatusChanged();
return NS_OK;
}
@ -721,12 +720,7 @@ nsMediaChannelStream::CacheClientResume()
--mCacheSuspendCount;
}
// We have to spawn an event here since we're being called back from
// 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);
mDecoder->NotifySuspendedStatusChanged();
return NS_OK;
}

Просмотреть файл

@ -308,7 +308,7 @@ public:
~nsMediaChannelStream();
// 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
// if this stream didn't read any data, since another stream might have
// received data for the same resource.
@ -317,6 +317,10 @@ public:
// if this stream didn't read any data, since another stream might have
// received data for the same resource.
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
// and no more data from the old load will be notified via
// nsMediaCacheStream::NotifyDataReceived/Ended.

Просмотреть файл

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

Просмотреть файл

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

Двоичные данные
content/media/test/bug523816.ogv Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -61,6 +61,7 @@ var gPlayTests = [
{ name:"bug498855-3.ogv", type:"video/ogg", duration:0.2 },
{ name:"bug504644.ogv", type:"video/ogg", duration:1.56 },
{ name:"chain.ogv", type:"video/ogg", duration:Number.NaN },
{ name:"bug523816.ogv", type:"video/ogg", duration:0.5 },
{ name:"bogus.duh", type:"bogus/duh" }
];
@ -85,6 +86,7 @@ var gErrorTests = [
var gSeekTests = [
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
{ 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 }
];

Просмотреть файл

@ -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>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше