mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge backout of 59d848818fd8.
This commit is contained in:
commit
3facbf1d48
@ -1991,7 +1991,7 @@ nsAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
|
||||
if (role == nsIAccessibleRole::ROLE_ENTRY ||
|
||||
role == nsIAccessibleRole::ROLE_COMBOBOX) {
|
||||
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
|
||||
nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
|
||||
NS_ENSURE_STATE(content);
|
||||
|
||||
nsAutoString autocomplete;
|
||||
|
@ -27,20 +27,13 @@
|
||||
testStates(frameDoc, STATE_READONLY);
|
||||
testStates(frameDocArticle, STATE_READONLY);
|
||||
testStates(frameDocCheckbox, 0, 0, STATE_READONLY);
|
||||
|
||||
var works = true;
|
||||
try {
|
||||
testStates(frameDocTextbox, 0, 0, STATE_READONLY);
|
||||
}
|
||||
catch (e) {
|
||||
works = false;
|
||||
}
|
||||
todo(works, "Checking states of a textbox frame doc should not throw (Bug 478810)");
|
||||
|
||||
testStates(frameDocTextbox, 0, EXT_STATE_EDITABLE);
|
||||
|
||||
frameDoc.designMode = "on";
|
||||
testStates(frameDoc, 0, EXT_STATE_EDITABLE);
|
||||
testStates(frameDocArticle, STATE_READONLY);
|
||||
testStates(frameDocCheckbox, 0, 0, STATE_READONLY);
|
||||
testStates(frameDocTextbox, 0, EXT_STATE_EDITABLE);
|
||||
|
||||
frameDocArticle.designMode = "on";
|
||||
testStates(frameDocArticle, 0, EXT_STATE_EDITABLE);
|
||||
|
@ -63,6 +63,13 @@ public:
|
||||
// nsIDOMHTMLVideoElement
|
||||
NS_DECL_NSIDOMHTMLVIDEOELEMENT
|
||||
|
||||
virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult);
|
||||
NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
|
||||
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
|
||||
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
|
||||
// Returns the current video frame width and height.
|
||||
|
@ -113,3 +113,48 @@ nsIntSize nsHTMLVideoElement::GetVideoSize(nsIntSize aDefaultSize)
|
||||
{
|
||||
return mMediaSize.width == -1 && mMediaSize.height == -1 ? aDefaultSize : mMediaSize;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHTMLVideoElement::ParseAttribute(PRInt32 aNamespaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height) {
|
||||
return aResult.ParseSpecialIntValue(aValue, PR_TRUE);
|
||||
}
|
||||
|
||||
return nsHTMLMediaElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aResult);
|
||||
}
|
||||
|
||||
static void
|
||||
MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData)
|
||||
{
|
||||
nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
|
||||
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsHTMLVideoElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
||||
{
|
||||
static const MappedAttributeEntry attributes[] = {
|
||||
{ &nsGkAtoms::width },
|
||||
{ &nsGkAtoms::height },
|
||||
{ nsnull }
|
||||
};
|
||||
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
attributes,
|
||||
sCommonAttributeMap
|
||||
};
|
||||
|
||||
return FindAttributeDependence(aAttribute, map, NS_ARRAY_LENGTH(map));
|
||||
}
|
||||
|
||||
nsMapRuleToAttributesFunc
|
||||
nsHTMLVideoElement::GetAttributeMappingFunction() const
|
||||
{
|
||||
return &MapAttributesIntoRule;
|
||||
}
|
||||
|
Binary file not shown.
@ -1139,7 +1139,7 @@ SetGlyphsForCharacterGroup(ATSLayoutRecord *aGlyphs, PRUint32 aGlyphCount,
|
||||
aAppUnitsPerDevUnit);
|
||||
}
|
||||
details->mYOffset = !aBaselineDeltas ? 0.0f
|
||||
: FixedToFloat(aBaselineDeltas[i])*aAppUnitsPerDevUnit;
|
||||
: - FixedToFloat(aBaselineDeltas[i])*aAppUnitsPerDevUnit;
|
||||
}
|
||||
}
|
||||
if (detailedGlyphs.Length() == 0) {
|
||||
|
@ -1323,6 +1323,19 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
return mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, newDirty, aLists);
|
||||
}
|
||||
|
||||
// Now display the scrollbars and scrollcorner. These parts are drawn
|
||||
// in the border-background layer, on top of our own background and
|
||||
// borders and underneath borders and backgrounds of later elements
|
||||
// in the tree.
|
||||
nsIFrame* kid = mOuter->GetFirstChild(nsnull);
|
||||
while (kid) {
|
||||
if (kid != mScrolledFrame) {
|
||||
rv = mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
kid = kid->GetNextSibling();
|
||||
}
|
||||
|
||||
// Overflow clipping can never clip frames outside our subtree, so there
|
||||
// is no need to worry about whether we are a moving frame that might clip
|
||||
// non-moving frames.
|
||||
@ -1347,18 +1360,6 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
rv = mOuter->OverflowClip(aBuilder, set, aLists, clip, PR_TRUE, mIsRoot);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Now display the scrollbars and scrollcorner
|
||||
nsIFrame* kid = mOuter->GetFirstChild(nsnull);
|
||||
// Put each child's background directly onto the content list
|
||||
nsDisplayListSet scrollbarSet(aLists, aLists.Content());
|
||||
while (kid) {
|
||||
if (kid != mScrolledFrame) {
|
||||
rv = mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, scrollbarSet,
|
||||
nsIFrame::DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
kid = kid->GetNextSibling();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -330,20 +330,6 @@ nsSize nsVideoFrame::GetIntrinsicSize(nsIRenderingContext *aRenderingContext)
|
||||
nsresult rv;
|
||||
|
||||
size = element->GetVideoSize(size);
|
||||
if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::width)) {
|
||||
PRInt32 width = -1;
|
||||
rv = element->GetWidth(&width);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
size.width = width;
|
||||
}
|
||||
}
|
||||
if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::height)) {
|
||||
PRInt32 height = -1;
|
||||
rv = element->GetHeight(&height);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
size.height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsSize(nsPresContext::CSSPixelsToAppUnits(size.width),
|
||||
|
8
layout/reftests/ogg-video/aspect-ratio-3-ref.html
Normal file
8
layout/reftests/ogg-video/aspect-ratio-3-ref.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;">
|
||||
<video id="v" src="black140x100.ogv"
|
||||
style="width:280px; height:200px;"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
</body>
|
||||
</html>
|
7
layout/reftests/ogg-video/aspect-ratio-3a.html
Normal file
7
layout/reftests/ogg-video/aspect-ratio-3a.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;">
|
||||
<video id="v" src="black140x100.ogv" width="280"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
</body>
|
||||
</html>
|
7
layout/reftests/ogg-video/aspect-ratio-3b.html
Normal file
7
layout/reftests/ogg-video/aspect-ratio-3b.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait">
|
||||
<body style="background:white;">
|
||||
<video id="v" src="black140x100.ogv" height="200"
|
||||
onloadeddata="document.documentElement.removeAttribute('class')"></video>
|
||||
</body>
|
||||
</html>
|
@ -2,6 +2,8 @@
|
||||
== aspect-ratio-1b.html aspect-ratio-1-ref.html
|
||||
== aspect-ratio-2a.html aspect-ratio-2-ref.html
|
||||
== aspect-ratio-2b.html aspect-ratio-2-ref.html
|
||||
== aspect-ratio-3a.html aspect-ratio-3-ref.html
|
||||
== aspect-ratio-3b.html aspect-ratio-3-ref.html
|
||||
== basic-1.html basic-1-ref.html
|
||||
== canvas-1a.html basic-1-ref.html
|
||||
== canvas-1b.html basic-1-ref.html
|
||||
|
7
layout/reftests/z-index/480053-1-ref.html
Normal file
7
layout/reftests/z-index/480053-1-ref.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div style="overflow:scroll; width:300px; height:100px; background-color:lime;"></div>
|
||||
<div style="background-color:yellow; width:300px; height:100px; margin-top:-50px; position:relative; z-index:1;"></div>
|
||||
</body>
|
||||
</html>
|
7
layout/reftests/z-index/480053-1.html
Normal file
7
layout/reftests/z-index/480053-1.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div style="overflow:scroll; width:300px; height:100px; background-color:lime;"></div>
|
||||
<div style="background-color:yellow; width:300px; height:100px; margin-top:-50px"></div>
|
||||
</body>
|
||||
</html>
|
@ -1 +1,2 @@
|
||||
== 480053-1.html 480053-1-ref.html
|
||||
== z-index-1.html z-index-1-ref.html
|
||||
|
@ -46,6 +46,7 @@ XPIDL_MODULE = loginmgr
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsILoginInfo.idl \
|
||||
nsILoginMetaInfo.idl \
|
||||
nsILoginManager.idl \
|
||||
nsILoginManagerStorage.idl \
|
||||
nsILoginManagerPrompter.idl \
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(9c87a9bd-bf8b-4fae-bdb8-70513b2877df)]
|
||||
[scriptable, uuid(c41b7dff-6b9b-42fe-b78d-113051facb05)]
|
||||
|
||||
/**
|
||||
* An object containing information for a login stored by the
|
||||
@ -134,6 +134,15 @@ interface nsILoginInfo : nsISupports {
|
||||
* If true, ignore the password when checking for match.
|
||||
*/
|
||||
boolean matches(in nsILoginInfo aLoginInfo, in boolean ignorePassword);
|
||||
|
||||
/**
|
||||
* Create an identical copy of the login, duplicating all of the login's
|
||||
* nsILoginInfo and nsILoginMetaInfo properties.
|
||||
*
|
||||
* This allows code to be forwards-compatible, when additional properties
|
||||
* are added to nsILoginMetaInfo (or nsILoginInfo) in the future.
|
||||
*/
|
||||
nsILoginInfo clone();
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -43,7 +43,7 @@ interface nsIAutoCompleteResult;
|
||||
interface nsIDOMHTMLInputElement;
|
||||
interface nsIDOMHTMLFormElement;
|
||||
|
||||
[scriptable, uuid(04dbfa30-4238-11dd-ae16-0800200c9a66)]
|
||||
[scriptable, uuid(9c78bfc1-422b-4f4f-ba09-f7eb3c4e72b2)]
|
||||
|
||||
interface nsILoginManager : nsISupports {
|
||||
|
||||
@ -52,6 +52,10 @@ interface nsILoginManager : nsISupports {
|
||||
*
|
||||
* @param aLogin
|
||||
* The login to be added.
|
||||
*
|
||||
* Default values for the login's nsILoginMetaInfo properties will be
|
||||
* created. However, if the caller specifies non-default values, they will
|
||||
* be used instead.
|
||||
*/
|
||||
void addLogin(in nsILoginInfo aLogin);
|
||||
|
||||
@ -61,6 +65,9 @@ interface nsILoginManager : nsISupports {
|
||||
*
|
||||
* @param aLogin
|
||||
* The login to be removed.
|
||||
*
|
||||
* The specified login must exactly match a stored login. However, the
|
||||
* values of any nsILoginMetaInfo properties are ignored.
|
||||
*/
|
||||
void removeLogin(in nsILoginInfo aLogin);
|
||||
|
||||
@ -68,10 +75,20 @@ interface nsILoginManager : nsISupports {
|
||||
/**
|
||||
* Modify an existing login in the login manager.
|
||||
*
|
||||
* @param aLogin
|
||||
* @param oldLogin
|
||||
* The login to be modified.
|
||||
* @param newLoginData
|
||||
* The new login values (either a nsILoginInfo or nsIProperyBag)
|
||||
*
|
||||
* If newLoginData is a nsILoginInfo, all of the old login's nsILoginInfo
|
||||
* properties are changed to the values from newLoginData (but the old
|
||||
* login's nsILoginMetaInfo properties are unmodified).
|
||||
*
|
||||
* If newLoginData is a nsIPropertyBag, only the specified properties
|
||||
* will be changed. The nsILoginMetaInfo properties of oldLogin can be
|
||||
* changed in this manner.
|
||||
*/
|
||||
void modifyLogin(in nsILoginInfo oldLogin, in nsILoginInfo newLogin);
|
||||
void modifyLogin(in nsILoginInfo oldLogin, in nsISupports newLoginData);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -40,7 +40,7 @@
|
||||
interface nsIFile;
|
||||
interface nsILoginInfo;
|
||||
|
||||
[scriptable, uuid(dec624d1-18ea-40ea-8ca5-69002153c8b8)]
|
||||
[scriptable, uuid(199ebbff-4656-4a18-8da9-9401c64619f9)]
|
||||
|
||||
/*
|
||||
* NOTE: This interface is intended to be implemented by modules
|
||||
@ -71,30 +71,47 @@ interface nsILoginManagerStorage : nsISupports {
|
||||
|
||||
|
||||
/**
|
||||
* Store a new login.
|
||||
* Store a new login in the storage module.
|
||||
*
|
||||
* @param aLogin
|
||||
* The login to be added.
|
||||
*
|
||||
* Default values for the login's nsILoginMetaInfo properties will be
|
||||
* created. However, if the caller specifies non-default values, they will
|
||||
* be used instead.
|
||||
*/
|
||||
void addLogin(in nsILoginInfo aLogin);
|
||||
|
||||
|
||||
/**
|
||||
* Remove a login from the login manager.
|
||||
* Remove a login from the storage module.
|
||||
*
|
||||
* @param aLogin
|
||||
* The login to be removed.
|
||||
*
|
||||
* The specified login must exactly match a stored login. However, the
|
||||
* values of any nsILoginMetaInfo properties are ignored.
|
||||
*/
|
||||
void removeLogin(in nsILoginInfo aLogin);
|
||||
|
||||
|
||||
/**
|
||||
* Modify an existing login in the login manager.
|
||||
* Modify an existing login in the storage module.
|
||||
*
|
||||
* @param aLogin
|
||||
* @param oldLogin
|
||||
* The login to be modified.
|
||||
* @param newLoginData
|
||||
* The new login values (either a nsILoginInfo or nsIProperyBag)
|
||||
*
|
||||
* If newLoginData is a nsILoginInfo, all of the old login's nsILoginInfo
|
||||
* properties are changed to the values from newLoginData (but the old
|
||||
* login's nsILoginMetaInfo properties are unmodified).
|
||||
*
|
||||
* If newLoginData is a nsIPropertyBag, only the specified properties
|
||||
* will be changed. The nsILoginMetaInfo properties of oldLogin can be
|
||||
* changed in this manner.
|
||||
*/
|
||||
void modifyLogin(in nsILoginInfo oldLogin, in nsILoginInfo newLogin);
|
||||
void modifyLogin(in nsILoginInfo oldLogin, in nsISupports newLoginData);
|
||||
|
||||
|
||||
/**
|
||||
|
62
toolkit/components/passwordmgr/public/nsILoginMetaInfo.idl
Normal file
62
toolkit/components/passwordmgr/public/nsILoginMetaInfo.idl
Normal file
@ -0,0 +1,62 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Justin Dolske <dolske@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(867407d5-10e0-43a0-bc81-a324740534ca)]
|
||||
|
||||
/**
|
||||
* An object containing metainfo for a login stored by the login manager.
|
||||
*
|
||||
* Code using login manager can generally ignore this interface. When adding
|
||||
* logins, default value will be created. When modifying logins, these
|
||||
* properties will be unchanged unless a change is explicitly requested [by
|
||||
* using modifyLogin() with a nsIPropertyBag]. When deleting a login or
|
||||
* comparing logins, these properties are ignored.
|
||||
*/
|
||||
interface nsILoginMetaInfo : nsISupports {
|
||||
/**
|
||||
* The GUID to uniquely identify the login. This can be any arbitrary
|
||||
* string, but a format as created by nsIUUIDGenerator is recommended.
|
||||
* For example, "{d4e1a1f6-5ea0-40ee-bff5-da57982f21cf}"
|
||||
*
|
||||
* addLogin will generate a random value unless a value is provided.
|
||||
*
|
||||
* addLogin and modifyLogin will throw if the GUID already exists.
|
||||
*/
|
||||
attribute AString guid;
|
||||
};
|
@ -47,7 +47,7 @@ nsLoginInfo.prototype = {
|
||||
classDescription : "LoginInfo",
|
||||
contractID : "@mozilla.org/login-manager/loginInfo;1",
|
||||
classID : Components.ID("{0f2f347c-1e4f-40cc-8efd-792dea70a85e}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsILoginInfo]),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsILoginInfo, Ci.nsILoginMetaInfo]),
|
||||
|
||||
// Allow storage-Legacy.js to get at the JS object so it can
|
||||
// slap on a few extra properties for internal use.
|
||||
@ -55,6 +55,10 @@ nsLoginInfo.prototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
//
|
||||
// nsILoginInfo interfaces...
|
||||
//
|
||||
|
||||
hostname : null,
|
||||
formSubmitURL : null,
|
||||
httpRealm : null,
|
||||
@ -105,7 +109,27 @@ nsLoginInfo.prototype = {
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
clone : function() {
|
||||
let clone = Cc["@mozilla.org/login-manager/loginInfo;1"].
|
||||
createInstance(Ci.nsILoginInfo);
|
||||
clone.init(this.hostname, this.formSubmitURL, this.httpRealm,
|
||||
this.username, this.password,
|
||||
this.usernameField, this.passwordField);
|
||||
|
||||
// Copy nsILoginMetaInfo props
|
||||
clone.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
clone.guid = this.guid;
|
||||
|
||||
return clone;
|
||||
},
|
||||
|
||||
//
|
||||
// nsILoginMetaInfo interfaces...
|
||||
//
|
||||
|
||||
guid : null
|
||||
|
||||
}; // end of nsLoginInfo implementation
|
||||
|
||||
|
@ -311,6 +311,9 @@ LoginManagerStorage_legacy.prototype = {
|
||||
*
|
||||
*/
|
||||
modifyLogin : function (oldLogin, newLogin) {
|
||||
if (newLogin instanceof Ci.nsIPropertyBag)
|
||||
throw "legacy modifyLogin with propertybag not implemented.";
|
||||
newLogin.QueryInterface(Ci.nsILoginInfo);
|
||||
// Throws if there are bogus values.
|
||||
this._checkLoginValues(newLogin);
|
||||
|
||||
|
@ -109,6 +109,15 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
return this.__uuidService;
|
||||
},
|
||||
|
||||
__observerService : null,
|
||||
get _observerService() {
|
||||
if (!this.__observerService)
|
||||
this.__observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
return this.__observerService;
|
||||
},
|
||||
|
||||
|
||||
// The current database schema
|
||||
_dbSchema: {
|
||||
tables: {
|
||||
@ -271,7 +280,17 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
throw "User canceled master password entry, login not added.";
|
||||
}
|
||||
|
||||
let guid = this._uuidService.generateUUID().toString();
|
||||
// Clone the login, so we don't modify the caller's object.
|
||||
let loginClone = login.clone();
|
||||
|
||||
// Initialize the nsILoginMetaInfo fields, unless the caller gave us values
|
||||
loginClone.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
if (loginClone.guid) {
|
||||
if (!this._isGuidUnique(loginClone.guid))
|
||||
throw "specified GUID already exists";
|
||||
} else {
|
||||
loginClone.guid = this._uuidService.generateUUID().toString();
|
||||
}
|
||||
|
||||
let query =
|
||||
"INSERT INTO moz_logins " +
|
||||
@ -283,14 +302,14 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
":guid)";
|
||||
|
||||
let params = {
|
||||
hostname: login.hostname,
|
||||
httpRealm: login.httpRealm,
|
||||
formSubmitURL: login.formSubmitURL,
|
||||
usernameField: login.usernameField,
|
||||
passwordField: login.passwordField,
|
||||
hostname: loginClone.hostname,
|
||||
httpRealm: loginClone.httpRealm,
|
||||
formSubmitURL: loginClone.formSubmitURL,
|
||||
usernameField: loginClone.usernameField,
|
||||
passwordField: loginClone.passwordField,
|
||||
encryptedUsername: encUsername,
|
||||
encryptedPassword: encPassword,
|
||||
guid: guid
|
||||
guid: loginClone.guid
|
||||
};
|
||||
|
||||
let stmt;
|
||||
@ -303,6 +322,10 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
} finally {
|
||||
stmt.reset();
|
||||
}
|
||||
|
||||
// Send a notification that a login was added.
|
||||
if (!isEncrypted)
|
||||
this._sendNotification("addLogin", loginClone);
|
||||
},
|
||||
|
||||
|
||||
@ -311,7 +334,7 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
*
|
||||
*/
|
||||
removeLogin : function (login) {
|
||||
let idToDelete = this._getIdForLogin(login);
|
||||
let [idToDelete, storedLogin] = this._getIdForLogin(login);
|
||||
if (!idToDelete)
|
||||
throw "No matching logins";
|
||||
|
||||
@ -328,6 +351,8 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
} finally {
|
||||
stmt.reset();
|
||||
}
|
||||
|
||||
this._sendNotification("removeLogin", storedLogin);
|
||||
},
|
||||
|
||||
|
||||
@ -335,13 +360,60 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
* modifyLogin
|
||||
*
|
||||
*/
|
||||
modifyLogin : function (oldLogin, newLogin) {
|
||||
// Throws if there are bogus values.
|
||||
this._checkLoginValues(newLogin);
|
||||
|
||||
let idToModify = this._getIdForLogin(oldLogin);
|
||||
modifyLogin : function (oldLogin, newLoginData) {
|
||||
let [idToModify, oldStoredLogin] = this._getIdForLogin(oldLogin);
|
||||
if (!idToModify)
|
||||
throw "No matching logins";
|
||||
oldStoredLogin.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
|
||||
let newLogin;
|
||||
if (newLoginData instanceof Ci.nsILoginInfo) {
|
||||
// Clone the existing login to get its nsILoginMetaInfo, then init it
|
||||
// with the replacement nsILoginInfo data from the new login.
|
||||
newLogin = oldStoredLogin.clone();
|
||||
newLogin.init(newLoginData.hostname,
|
||||
newLoginData.formSubmitURL, newLoginData.httpRealm,
|
||||
newLoginData.username, newLoginData.password,
|
||||
newLoginData.usernameField, newLoginData.passwordField);
|
||||
newLogin.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
} else if (newLoginData instanceof Ci.nsIPropertyBag) {
|
||||
// Clone the existing login, along with all its properties.
|
||||
newLogin = oldStoredLogin.clone();
|
||||
newLogin.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
|
||||
let propEnum = newLoginData.enumerator;
|
||||
while (propEnum.hasMoreElements()) {
|
||||
let prop = propEnum.getNext().QueryInterface(Ci.nsIProperty);
|
||||
switch (prop.name) {
|
||||
// nsILoginInfo properties...
|
||||
case "hostname":
|
||||
case "httpRealm":
|
||||
case "formSubmitURL":
|
||||
case "username":
|
||||
case "password":
|
||||
case "usernameField":
|
||||
case "passwordField":
|
||||
newLogin[prop.name] = prop.value;
|
||||
break;
|
||||
|
||||
// nsILoginMetaInfo properties...
|
||||
case "guid":
|
||||
newLogin.guid = prop.value;
|
||||
if (!this._isGuidUnique(newLogin.guid))
|
||||
throw "specified GUID already exists";
|
||||
break;
|
||||
|
||||
// Fail if caller requests setting an unknown property.
|
||||
default:
|
||||
throw "Unexpected propertybag item: " + prop.name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw "newLoginData needs an expected interface!";
|
||||
}
|
||||
|
||||
// Throws if there are bogus values.
|
||||
this._checkLoginValues(newLogin);
|
||||
|
||||
// Get the encrypted value of the username and password.
|
||||
let [encUsername, encPassword, userCanceled] = this._encryptLogin(newLogin);
|
||||
@ -356,10 +428,12 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
"usernameField = :usernameField, " +
|
||||
"passwordField = :passwordField, " +
|
||||
"encryptedUsername = :encryptedUsername, " +
|
||||
"encryptedPassword = :encryptedPassword " +
|
||||
"encryptedPassword = :encryptedPassword, " +
|
||||
"guid = :guid " +
|
||||
"WHERE id = :id";
|
||||
|
||||
let params = {
|
||||
id: idToModify,
|
||||
hostname: newLogin.hostname,
|
||||
httpRealm: newLogin.httpRealm,
|
||||
formSubmitURL: newLogin.formSubmitURL,
|
||||
@ -367,8 +441,7 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
passwordField: newLogin.passwordField,
|
||||
encryptedUsername: encUsername,
|
||||
encryptedPassword: encPassword,
|
||||
id: idToModify
|
||||
// guid not changed
|
||||
guid: newLogin.guid
|
||||
};
|
||||
|
||||
let stmt;
|
||||
@ -381,6 +454,8 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
} finally {
|
||||
stmt.reset();
|
||||
}
|
||||
|
||||
this._sendNotification("modifyLogin", [oldStoredLogin, newLogin]);
|
||||
},
|
||||
|
||||
|
||||
@ -427,6 +502,8 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
} finally {
|
||||
stmt.reset();
|
||||
}
|
||||
|
||||
this._sendNotification("removeAllLogins", null);
|
||||
},
|
||||
|
||||
|
||||
@ -458,16 +535,6 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
*
|
||||
*/
|
||||
setLoginSavingEnabled : function (hostname, enabled) {
|
||||
this._setLoginSavingEnabled(hostname, enabled);
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* _setLoginSavingEnabled
|
||||
*
|
||||
* Private function wrapping core setLoginSavingEnabled functionality.
|
||||
*/
|
||||
_setLoginSavingEnabled : function (hostname, enabled) {
|
||||
// Throws if there are bogus values.
|
||||
this._checkHostnameValue(hostname);
|
||||
|
||||
@ -486,11 +553,13 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
stmt = this._dbCreateStatement(query, params);
|
||||
stmt.execute();
|
||||
} catch (e) {
|
||||
this.log("_setLoginSavingEnabled failed: " + e.name + " : " + e.message);
|
||||
this.log("setLoginSavingEnabled failed: " + e.name + " : " + e.message);
|
||||
throw "Couldn't write to database"
|
||||
} finally {
|
||||
stmt.reset();
|
||||
}
|
||||
|
||||
this._sendNotification(enabled ? "hostSavingEnabled" : "hostSavingDisabled", hostname);
|
||||
},
|
||||
|
||||
|
||||
@ -549,16 +618,40 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* _sendNotification
|
||||
*
|
||||
* Send a notification when stored data is changed.
|
||||
*/
|
||||
_sendNotification : function (changeType, data) {
|
||||
let dataObject = data;
|
||||
// Can't pass a raw JS string or array though notifyObservers(). :-(
|
||||
if (data instanceof Array) {
|
||||
dataObject = Cc["@mozilla.org/array;1"].
|
||||
createInstance(Ci.nsIMutableArray);
|
||||
for (let i = 0; i < data.length; i++)
|
||||
dataObject.appendElement(data[i], false);
|
||||
} else if (typeof(data) == "string") {
|
||||
dataObject = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
dataObject.data = data;
|
||||
}
|
||||
this._observerService.notifyObservers(dataObject, "passwordmgr-storage-changed", changeType);
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* _getIdForLogin
|
||||
*
|
||||
* Returns the |id| for the specified login, or null if the login was not
|
||||
* found.
|
||||
* Returns an array with two items: [id, login]. If the login was not
|
||||
* found, both items will be null. The returned login contains the actual
|
||||
* stored login (useful for looking at the actual nsILoginMetaInfo values).
|
||||
*/
|
||||
_getIdForLogin : function (login) {
|
||||
let [logins, ids] =
|
||||
this._queryLogins(login.hostname, login.formSubmitURL, login.httpRealm);
|
||||
let id = null;
|
||||
let foundLogin = null;
|
||||
|
||||
// The specified login isn't encrypted, so we need to ensure
|
||||
// the logins we're comparing with are decrypted. We decrypt one entry
|
||||
@ -575,11 +668,12 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
continue;
|
||||
|
||||
// We've found a match, set id and break
|
||||
foundLogin = decryptedLogin;
|
||||
id = ids[i];
|
||||
break;
|
||||
}
|
||||
|
||||
return id;
|
||||
return [id, foundLogin];
|
||||
},
|
||||
|
||||
|
||||
@ -614,6 +708,9 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
stmt.row.httpRealm, stmt.row.encryptedUsername,
|
||||
stmt.row.encryptedPassword, stmt.row.usernameField,
|
||||
stmt.row.passwordField);
|
||||
// set nsILoginMetaInfo values
|
||||
login.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
login.guid = stmt.row.guid;
|
||||
logins.push(login);
|
||||
ids.push(stmt.row.id);
|
||||
}
|
||||
@ -758,6 +855,30 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* _isGuidUnique
|
||||
*
|
||||
* Checks to see if the specified GUID already exists.
|
||||
*/
|
||||
_isGuidUnique : function (guid) {
|
||||
let query = "SELECT COUNT(1) AS numLogins FROM moz_logins WHERE guid = :guid";
|
||||
let params = { guid: guid };
|
||||
|
||||
let stmt, numLogins;
|
||||
try {
|
||||
stmt = this._dbCreateStatement(query, params);
|
||||
stmt.step();
|
||||
numLogins = stmt.row.numLogins;
|
||||
} catch (e) {
|
||||
this.log("_isGuidUnique failed: " + e.name + " : " + e.message);
|
||||
} finally {
|
||||
stmt.reset();
|
||||
}
|
||||
|
||||
return (numLogins == 0);
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
* _importLegacySignons
|
||||
*
|
||||
@ -784,7 +905,7 @@ LoginManagerStorage_mozStorage.prototype = {
|
||||
this._addLogin(login, true);
|
||||
let disabledHosts = legacy.getAllDisabledHosts({});
|
||||
for each (let hostname in disabledHosts)
|
||||
this._setLoginSavingEnabled(hostname, false);
|
||||
this.setLoginSavingEnabled(hostname, false);
|
||||
} catch (e) {
|
||||
this.log("_importLegacySignons failed: " + e.name + " : " + e.message);
|
||||
throw "Import failed";
|
||||
|
@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Test suite for storage-mozStorage.js
|
||||
*
|
||||
* This test interfaces directly with the mozStorage password storage module,
|
||||
* bypassing the normal password manager usage.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
const STORAGE_TYPE = "mozStorage";
|
||||
|
||||
function run_test() {
|
||||
|
||||
try {
|
||||
|
||||
var testnum = 0;
|
||||
var testdesc = "Setup of nsLoginInfo test-users";
|
||||
var nsLoginInfo = new Components.Constructor(
|
||||
"@mozilla.org/login-manager/loginInfo;1",
|
||||
Components.interfaces.nsILoginInfo);
|
||||
do_check_true(nsLoginInfo != null);
|
||||
|
||||
var testuser1 = new nsLoginInfo;
|
||||
testuser1.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
testuser1.init("http://testhost1", "", null,
|
||||
"dummydude", "itsasecret", "put_user_here", "put_pw_here");
|
||||
var guid1;
|
||||
|
||||
var testuser2 = new nsLoginInfo;
|
||||
testuser2.init("http://testhost2", "", null,
|
||||
"dummydude2", "itsasecret2", "put_user2_here", "put_pw2_here");
|
||||
testuser2.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
var guid2 = "{12345678-abcd-1234-abcd-987654321000}";
|
||||
testuser2.guid = guid2;
|
||||
|
||||
var testuser3 = new nsLoginInfo;
|
||||
testuser3.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
testuser3.init("http://testhost3", "", null,
|
||||
"dummydude3", "itsasecret3", "put_user3_here", "put_pw3_here");
|
||||
var guid3 = "{99999999-abcd-9999-abcd-999999999999}";
|
||||
|
||||
// This login is different than testuser2, except it has the same guid.
|
||||
var testuser2dupeguid = new nsLoginInfo;
|
||||
testuser2dupeguid.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
testuser2dupeguid.init("http://dupe-testhost2", "", null,
|
||||
"dupe-dummydude2", "dupe-itsasecret2", "put_user2_here", "put_pw2_here");
|
||||
testuser2dupeguid.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
testuser2dupeguid.guid = guid2;
|
||||
|
||||
var isGUID = /^\{[0-9a-f\d]{8}-[0-9a-f\d]{4}-[0-9a-f\d]{4}-[0-9a-f\d]{4}-[0-9a-f\d]{12}\}$/;
|
||||
|
||||
/* ========== 1 ========== */
|
||||
var testnum = 1;
|
||||
var testdesc = "Initial connection to storage module"
|
||||
|
||||
LoginTest.deleteFile(OUTDIR, "signons-unittest6.sqlite");
|
||||
|
||||
var storage;
|
||||
storage = LoginTest.initStorage(INDIR, "signons-empty.txt", OUTDIR, "signons-unittest6.sqlite");
|
||||
var logins = storage.getAllLogins({});
|
||||
do_check_eq(logins.length, 0, "Checking for no initial logins");
|
||||
var disabledHosts = storage.getAllDisabledHosts({});
|
||||
do_check_eq(disabledHosts.length, 0, "Checking for no initial disabled hosts");
|
||||
|
||||
|
||||
/* ========== 2 ========== */
|
||||
testnum++;
|
||||
testdesc = "add user1 w/o guid";
|
||||
|
||||
storage.addLogin(testuser1);
|
||||
LoginTest.checkStorageData(storage, [], [testuser1]);
|
||||
|
||||
// Check guid
|
||||
do_check_eq(testuser1.guid, null, "caller's login shouldn't be modified");
|
||||
logins = storage.findLogins({}, "http://testhost1", "", null);
|
||||
do_check_eq(logins.length, 1, "expecting 1 login");
|
||||
logins[0].QueryInterface(Ci.nsILoginMetaInfo);
|
||||
do_check_true(isGUID.test(logins[0].guid), "testuser1 guid is set");
|
||||
guid1 = logins[0].guid;
|
||||
|
||||
/* ========== 3 ========== */
|
||||
testnum++;
|
||||
testdesc = "add user2 WITH guid";
|
||||
|
||||
storage.addLogin(testuser2);
|
||||
LoginTest.checkStorageData(storage, [], [testuser1, testuser2]);
|
||||
|
||||
// Check guid
|
||||
do_check_eq(testuser2.guid, guid2, "caller's login shouldn't be modified");
|
||||
logins = storage.findLogins({}, "http://testhost2", "", null);
|
||||
do_check_eq(logins.length, 1, "expecting 1 login");
|
||||
logins[0].QueryInterface(Ci.nsILoginMetaInfo);
|
||||
do_check_true(isGUID.test(logins[0].guid), "testuser2 guid is set");
|
||||
do_check_eq(logins[0].guid, guid2, "checking guid2");
|
||||
|
||||
/* ========== 4 ========== */
|
||||
testnum++;
|
||||
testdesc = "add user3 w/o guid";
|
||||
|
||||
storage.addLogin(testuser3);
|
||||
LoginTest.checkStorageData(storage, [], [testuser1, testuser2, testuser3]);
|
||||
logins = storage.findLogins({}, "http://testhost3", "", null);
|
||||
do_check_eq(logins.length, 1, "expecting 1 login");
|
||||
logins[0].QueryInterface(Ci.nsILoginMetaInfo);
|
||||
do_check_true(isGUID.test(logins[0].guid), "testuser3 guid is set");
|
||||
do_check_neq(logins[0].guid, guid3, "testuser3 guid is different");
|
||||
|
||||
/* ========== 5 ========== */
|
||||
testnum++;
|
||||
testdesc = "(don't) modify user1";
|
||||
|
||||
// When newlogin.guid is blank, the GUID shouldn't be changed.
|
||||
testuser1.guid = "";
|
||||
storage.modifyLogin(testuser1, testuser1);
|
||||
|
||||
// Check it
|
||||
do_check_eq(testuser1.guid, "", "caller's login shouldn't be modified");
|
||||
logins = storage.findLogins({}, "http://testhost1", "", null);
|
||||
do_check_eq(logins.length, 1, "expecting 1 login");
|
||||
logins[0].QueryInterface(Ci.nsILoginMetaInfo);
|
||||
do_check_eq(logins[0].guid, guid1, "checking guid1");
|
||||
|
||||
/* ========== 6 ========== */
|
||||
testnum++;
|
||||
testdesc = "modify user3";
|
||||
|
||||
// change the GUID to our known value
|
||||
var propbag = Cc["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Ci.nsIWritablePropertyBag);
|
||||
propbag.setProperty("guid", guid3);
|
||||
storage.modifyLogin(testuser3, propbag);
|
||||
|
||||
// Check it
|
||||
logins = storage.findLogins({}, "http://testhost3", "", null);
|
||||
do_check_eq(logins.length, 1, "expecting 1 login");
|
||||
logins[0].QueryInterface(Ci.nsILoginMetaInfo);
|
||||
do_check_eq(logins[0].guid, guid3, "checking guid3");
|
||||
|
||||
/* ========== 7 ========== */
|
||||
testnum++;
|
||||
testdesc = "try adding a duplicate guid";
|
||||
|
||||
var ex = null;
|
||||
try {
|
||||
storage.addLogin(testuser2dupeguid);
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
}
|
||||
do_check_true(/specified GUID already exists/.test(ex), "ensuring exception thrown when adding duplicate GUID");
|
||||
LoginTest.checkStorageData(storage, [], [testuser1, testuser2, testuser3]);
|
||||
|
||||
/* ========== 8 ========== */
|
||||
testnum++;
|
||||
testdesc = "try modifing to a duplicate guid";
|
||||
|
||||
propbag = Cc["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Ci.nsIWritablePropertyBag);
|
||||
propbag.setProperty("guid", testuser2dupeguid.guid);
|
||||
|
||||
ex = null;
|
||||
try {
|
||||
storage.modifyLogin(testuser1, propbag);
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
}
|
||||
do_check_true(/specified GUID already exists/.test(ex), "ensuring exception thrown when modifying to duplicate GUID");
|
||||
LoginTest.checkStorageData(storage, [], [testuser1, testuser2, testuser3]);
|
||||
|
||||
|
||||
/* ========== 9 ========== */
|
||||
testnum++;
|
||||
testdesc = "check propertybag nulls/empty strings";
|
||||
|
||||
// Set formSubmitURL to a null, and usernameField to a empty-string.
|
||||
do_check_eq(testuser3.formSubmitURL, "");
|
||||
do_check_eq(testuser3.httpRealm, null);
|
||||
do_check_eq(testuser3.usernameField, "put_user3_here");
|
||||
propbag = Cc["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Ci.nsIWritablePropertyBag);
|
||||
propbag.setProperty("formSubmitURL", null);
|
||||
propbag.setProperty("httpRealm", "newRealm");
|
||||
propbag.setProperty("usernameField", "");
|
||||
|
||||
storage.modifyLogin(testuser3, propbag);
|
||||
|
||||
// Fixup testuser3 to match the new values.
|
||||
testuser3.formSubmitURL = null;
|
||||
testuser3.httpRealm = "newRealm";
|
||||
testuser3.usernameField = "";
|
||||
LoginTest.checkStorageData(storage, [], [testuser1, testuser2, testuser3]);
|
||||
|
||||
|
||||
/* ========== 10 ========== */
|
||||
testnum++;
|
||||
testdesc = "[reinit storage, look for expected guids]";
|
||||
|
||||
storage = LoginTest.reloadStorage(OUTDIR, "signons-unittest6.sqlite");
|
||||
LoginTest.checkStorageData(storage, [], [testuser1, testuser2, testuser3]);
|
||||
|
||||
logins = storage.findLogins({}, "http://testhost1", "", null);
|
||||
do_check_eq(logins.length, 1, "expecting 1 login");
|
||||
logins[0].QueryInterface(Ci.nsILoginMetaInfo);
|
||||
do_check_eq(logins[0].guid, guid1, "checking guid1");
|
||||
|
||||
logins = storage.findLogins({}, "http://testhost2", "", null);
|
||||
do_check_eq(logins.length, 1, "expecting 1 login");
|
||||
logins[0].QueryInterface(Ci.nsILoginMetaInfo);
|
||||
do_check_eq(logins[0].guid, guid2, "checking guid2");
|
||||
|
||||
logins = storage.findLogins({}, "http://testhost3", null, "newRealm");
|
||||
do_check_eq(logins.length, 1, "expecting 1 login");
|
||||
logins[0].QueryInterface(Ci.nsILoginMetaInfo);
|
||||
do_check_eq(logins[0].guid, guid3, "checking guid3");
|
||||
|
||||
|
||||
/* ========== 11 ========== */
|
||||
testnum++;
|
||||
testdesc = "login w/o nsILoginMetaInfo impl";
|
||||
|
||||
var wonkyDelegate = new nsLoginInfo;
|
||||
wonkyDelegate.init("http://wonky", null, "wonkyness",
|
||||
"wonkyuser", "wonkypass", "u", "p");
|
||||
|
||||
var wonkyLogin = {
|
||||
QueryInterface : function (iid) {
|
||||
var interfaces = [Ci.nsILoginInfo, Ci.nsISupports];
|
||||
if (!interfaces.some( function(v) { return iid.equals(v) }))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
},
|
||||
hostname: wonkyDelegate.hostname,
|
||||
formSubmitURL: wonkyDelegate.formSubmitURL,
|
||||
httpRealm: wonkyDelegate.httpRealm,
|
||||
username: wonkyDelegate.username,
|
||||
password: wonkyDelegate.password,
|
||||
usernameField: wonkyDelegate.usernameField,
|
||||
passwordField: wonkyDelegate.passwordField,
|
||||
equals: wonkyDelegate.equals,
|
||||
matches: wonkyDelegate.matches,
|
||||
clone: wonkyDelegate.clone
|
||||
};
|
||||
|
||||
storage.addLogin(wonkyLogin);
|
||||
LoginTest.checkStorageData(storage, [], [testuser1, testuser2, testuser3, wonkyLogin]);
|
||||
|
||||
logins = storage.findLogins({}, "http://wonky", null, "");
|
||||
do_check_eq(logins.length, 1, "expecting 1 login");
|
||||
logins[0].QueryInterface(Ci.nsILoginMetaInfo);
|
||||
do_check_true(isGUID.test(logins[0].guid), "wonky guid is set");
|
||||
|
||||
storage.modifyLogin(wonkyLogin, wonkyLogin);
|
||||
LoginTest.checkStorageData(storage, [], [testuser1, testuser2, testuser3, wonkyLogin]);
|
||||
storage.removeLogin(wonkyLogin);
|
||||
LoginTest.checkStorageData(storage, [], [testuser1, testuser2, testuser3]);
|
||||
|
||||
|
||||
LoginTest.deleteFile(OUTDIR, "signons-unittest6.sqlite");
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + testdesc + ": " + e;
|
||||
}
|
||||
};
|
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Test suite for storage-mozStorage.js
|
||||
*
|
||||
* Tests notifications dispatched when modifying stored logins.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
const STORAGE_TYPE = "mozStorage";
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
var expectedNotification;
|
||||
var TestObserver = {
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
||||
|
||||
observe : function (subject, topic, data) {
|
||||
do_check_eq(expectedNotification, data);
|
||||
expectedNotification = null; // ensure a duplicate is flagged as unexpected.
|
||||
|
||||
switch (data) {
|
||||
case "addLogin":
|
||||
case "modifyLogin":
|
||||
case "removeLogin":
|
||||
case "removeAllLogins":
|
||||
case "hostSavingEnabled":
|
||||
case "hostSavingDisabled":
|
||||
break;
|
||||
default:
|
||||
do_throw("Unexpected observer topic: " + topic);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
|
||||
try {
|
||||
|
||||
var testnum = 0;
|
||||
var testdesc = "Setup of nsLoginInfo test-users";
|
||||
var nsLoginInfo = new Components.Constructor(
|
||||
"@mozilla.org/login-manager/loginInfo;1",
|
||||
Components.interfaces.nsILoginInfo);
|
||||
do_check_true(nsLoginInfo != null);
|
||||
|
||||
var testuser1 = new nsLoginInfo;
|
||||
testuser1.QueryInterface(Ci.nsILoginMetaInfo);
|
||||
testuser1.init("http://testhost1", "", null,
|
||||
"dummydude", "itsasecret", "put_user_here", "put_pw_here");
|
||||
|
||||
var testuser2 = new nsLoginInfo;
|
||||
testuser2.init("http://testhost2", "", null,
|
||||
"dummydude2", "itsasecret2", "put_user2_here", "put_pw2_here");
|
||||
|
||||
|
||||
|
||||
|
||||
// Add the observer
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
os.addObserver(TestObserver, "passwordmgr-storage-changed", false);
|
||||
|
||||
|
||||
/* ========== 1 ========== */
|
||||
var testnum = 1;
|
||||
var testdesc = "Initial connection to storage module"
|
||||
|
||||
LoginTest.deleteFile(OUTDIR, "signons-unittest-notify.sqlite");
|
||||
|
||||
var storage;
|
||||
storage = LoginTest.initStorage(INDIR, "signons-empty.txt", OUTDIR, "signons-unittest-notify.sqlite");
|
||||
var logins = storage.getAllLogins({});
|
||||
do_check_eq(logins.length, 0);
|
||||
var disabledHosts = storage.getAllDisabledHosts({});
|
||||
do_check_eq(disabledHosts.length, 0, "Checking for no initial disabled hosts");
|
||||
|
||||
/* ========== 2 ========== */
|
||||
testnum++;
|
||||
testdesc = "addLogin";
|
||||
|
||||
expectedNotification = "addLogin";
|
||||
storage.addLogin(testuser1);
|
||||
LoginTest.checkStorageData(storage, [], [testuser1]);
|
||||
do_check_eq(expectedNotification, null); // check that observer got a notification
|
||||
|
||||
/* ========== 3 ========== */
|
||||
testnum++;
|
||||
testdesc = "modifyLogin";
|
||||
|
||||
expectedNotification = "modifyLogin";
|
||||
storage.modifyLogin(testuser1, testuser2);
|
||||
do_check_eq(expectedNotification, null);
|
||||
LoginTest.checkStorageData(storage, [], [testuser2]);
|
||||
|
||||
/* ========== 4 ========== */
|
||||
testnum++;
|
||||
testdesc = "removeLogin";
|
||||
|
||||
expectedNotification = "removeLogin";
|
||||
storage.removeLogin(testuser2);
|
||||
do_check_eq(expectedNotification, null);
|
||||
LoginTest.checkStorageData(storage, [], []);
|
||||
|
||||
/* ========== 5 ========== */
|
||||
testnum++;
|
||||
testdesc = "removeAllLogins";
|
||||
|
||||
expectedNotification = "removeAllLogins";
|
||||
storage.removeAllLogins();
|
||||
do_check_eq(expectedNotification, null);
|
||||
LoginTest.checkStorageData(storage, [], []);
|
||||
|
||||
/* ========== 6 ========== */
|
||||
testnum++;
|
||||
testdesc = "removeAllLogins (again)";
|
||||
|
||||
expectedNotification = "removeAllLogins";
|
||||
storage.removeAllLogins();
|
||||
do_check_eq(expectedNotification, null);
|
||||
LoginTest.checkStorageData(storage, [], []);
|
||||
|
||||
/* ========== 7 ========== */
|
||||
testnum++;
|
||||
testdesc = "setLoginSavingEnabled / false";
|
||||
|
||||
expectedNotification = "hostSavingDisabled";
|
||||
storage.setLoginSavingEnabled("http://site.com", false);
|
||||
do_check_eq(expectedNotification, null);
|
||||
LoginTest.checkStorageData(storage, ["http://site.com"], []);
|
||||
|
||||
/* ========== 8 ========== */
|
||||
testnum++;
|
||||
testdesc = "setLoginSavingEnabled / false (again)";
|
||||
|
||||
expectedNotification = "hostSavingDisabled";
|
||||
storage.setLoginSavingEnabled("http://site.com", false);
|
||||
do_check_eq(expectedNotification, null);
|
||||
LoginTest.checkStorageData(storage, ["http://site.com"], []);
|
||||
|
||||
/* ========== 9 ========== */
|
||||
testnum++;
|
||||
testdesc = "setLoginSavingEnabled / true";
|
||||
|
||||
expectedNotification = "hostSavingEnabled";
|
||||
storage.setLoginSavingEnabled("http://site.com", true);
|
||||
do_check_eq(expectedNotification, null);
|
||||
LoginTest.checkStorageData(storage, [], []);
|
||||
|
||||
/* ========== 10 ========== */
|
||||
testnum++;
|
||||
testdesc = "setLoginSavingEnabled / true (again)";
|
||||
|
||||
expectedNotification = "hostSavingEnabled";
|
||||
storage.setLoginSavingEnabled("http://site.com", true);
|
||||
do_check_eq(expectedNotification, null);
|
||||
LoginTest.checkStorageData(storage, [], []);
|
||||
|
||||
|
||||
LoginTest.deleteFile(OUTDIR, "signons-unittest-notify.sqlite");
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + testdesc + ": " + e;
|
||||
}
|
||||
};
|
@ -9,3 +9,8 @@
|
||||
.scrubber {
|
||||
-moz-binding: url("chrome://global/content/bindings/videocontrols.xml#suppressChangeEvent");
|
||||
}
|
||||
|
||||
.throbberOverlay {
|
||||
visibility: hidden;
|
||||
opacity: 0.0;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
if (!userChanged && !this._userChanged)
|
||||
return;
|
||||
this.setAttribute("value", newValue);
|
||||
this.parentNode.parentNode.parentNode.Utils.seekToPosition();
|
||||
document.getBindingParent(this.parentNode).Utils.seekToPosition();
|
||||
break;
|
||||
|
||||
case "minpos":
|
||||
@ -51,17 +51,25 @@
|
||||
</resources>
|
||||
|
||||
<xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<spacer flex="1"/>
|
||||
<hbox class="controlBar">
|
||||
<button class="playButton" oncommand="this.parentNode.parentNode.Utils.togglePause();"/>
|
||||
<stack class="scrubberStack" flex="1">
|
||||
<box class="backgroundBar" flex="1"/>
|
||||
<progressmeter class="bufferBar" flex="1"/>
|
||||
<progressmeter class="progressBar" flex="1" max="10000"/>
|
||||
<scale class="scrubber" flex="1"/>
|
||||
</stack>
|
||||
<button class="muteButton" oncommand="this.parentNode.parentNode.Utils.toggleMute();"/>
|
||||
</hbox>
|
||||
<stack flex="1">
|
||||
<vbox class="throbberOverlay">
|
||||
<box class="throbber" flex="1"/>
|
||||
</vbox>
|
||||
|
||||
<vbox>
|
||||
<spacer flex="1"/>
|
||||
<hbox class="controlBar">
|
||||
<button class="playButton" oncommand="document.getBindingParent(this).Utils.togglePause();"/>
|
||||
<stack class="scrubberStack" flex="1">
|
||||
<box class="backgroundBar"/>
|
||||
<progressmeter class="bufferBar"/>
|
||||
<progressmeter class="progressBar" max="10000"/>
|
||||
<scale class="scrubber"/>
|
||||
</stack>
|
||||
<button class="muteButton" oncommand="document.getBindingParent(this).Utils.toggleMute();"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</stack>
|
||||
</xbl:content>
|
||||
|
||||
<implementation implements="nsISecurityCheckedComponent">
|
||||
@ -114,12 +122,13 @@
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
<field name="randomID">0</field>
|
||||
|
||||
<field name="Utils">
|
||||
<![CDATA[ ({
|
||||
debug : false,
|
||||
video : null,
|
||||
videocontrols : null,
|
||||
controlBar : null,
|
||||
playButton : null,
|
||||
muteButton : null,
|
||||
|
||||
@ -128,18 +137,80 @@
|
||||
bufferBar : null,
|
||||
thumbWidth : 0,
|
||||
|
||||
FADE_TIME_MAX : 200, // ms
|
||||
FADE_TIME_STEP : 30, // ms
|
||||
randomID : 0,
|
||||
videoEvents : ["play", "pause", "ended", "volumechange", "loadeddata",
|
||||
"loadstart", "durationchange", "timeupdate", "progress",
|
||||
"playing", "waiting", "canplaythrough", "seeking",
|
||||
"seeked", "emptied"],
|
||||
|
||||
fadeTime : 0, // duration of active fade animation
|
||||
fadingIn: false, // are we fading in, or fading out?
|
||||
fadeTimer : null,
|
||||
controlsVisible : false,
|
||||
controlFader : {
|
||||
name : "controls", // shorthand for debugging
|
||||
element : null, // the element to fade in/out
|
||||
runtime : 0, // duration of active animation
|
||||
fadingIn : false, // are we fading in, or fading out?
|
||||
isVisible : false, // is it at all visible?
|
||||
timer : null, // handle from setInterval()
|
||||
delayTimer : null, // handle from setTimeout()
|
||||
START_DELAY : 0, // ms, delay before fading in
|
||||
RUNTIME_MAX : 200, // ms
|
||||
RUNTIME_STEP : 30 // ms
|
||||
},
|
||||
|
||||
throbberFader : {
|
||||
name : "throbber",
|
||||
element : null,
|
||||
runtime : 0,
|
||||
fadingIn : false,
|
||||
isVisible : false,
|
||||
timer : null,
|
||||
delayTimer : null,
|
||||
START_DELAY : 750,
|
||||
RUNTIME_MAX : 300,
|
||||
RUNTIME_STEP : 20
|
||||
},
|
||||
|
||||
firstFrameShown : false,
|
||||
lastTimeUpdate : 0,
|
||||
maxCurrentTimeSeen : 0,
|
||||
|
||||
/*
|
||||
* Set the initial state of the controls. The binding is normally created along
|
||||
* with video element, but could be attached at any point (eg, if the video is
|
||||
* removed from the document and then reinserted). Thus, some one-time events may
|
||||
* have already fired, and so we'll need to explicitly check the initial state.
|
||||
*/
|
||||
setupInitialState : function() {
|
||||
this.randomID = Math.random();
|
||||
this.videocontrols.randomID = this.randomID;
|
||||
|
||||
this.playButton.setAttribute("paused", this.video.paused);
|
||||
this.muteButton.setAttribute("muted", this.video.muted);
|
||||
|
||||
var duration = Math.round(this.video.duration * 1000); // in ms
|
||||
var currentTime = Math.round(this.video.currentTime * 1000); // in ms
|
||||
this.log("Initial playback position is at " + currentTime + " of " + duration);
|
||||
// It would be nice to retain maxCurrentTimeSeen, but it would be difficult
|
||||
// to determine if the media source changed while we were detached.
|
||||
this.maxCurrentTimeSeen = currentTime;
|
||||
this.durationChange(duration);
|
||||
this.showPosition(currentTime, duration);
|
||||
|
||||
// If the first frame hasn't loaded, kick off a throbber fade-in.
|
||||
if (this.video.readyState >= this.video.HAVE_CURRENT_DATA)
|
||||
this.firstFrameShown = true;
|
||||
else
|
||||
this.startFadeIn(this.throbberFader);
|
||||
|
||||
// We can't determine the exact buffering status, but do know if it's
|
||||
// fully loaded. (If it's still loading, it will fire a progress event
|
||||
// and we'll figure out the exact state then.)
|
||||
this.bufferBar.setAttribute("max", 100);
|
||||
if (this.video.networkState == this.video.NETWORK_LOADED)
|
||||
this.bufferBar.setAttribute("value", 100);
|
||||
else
|
||||
this.bufferBar.setAttribute("value", 0);
|
||||
},
|
||||
|
||||
get dynamicControls() {
|
||||
// Don't fade controls for <audio> elements.
|
||||
var enabled = this.video instanceof HTMLVideoElement;
|
||||
@ -152,7 +223,13 @@
|
||||
},
|
||||
|
||||
handleEvent : function (aEvent) {
|
||||
this.log("Got " + aEvent.type + " media event");
|
||||
this.log("Got media event ----> " + aEvent.type);
|
||||
|
||||
// If the binding is detached (or has been replaced by a
|
||||
// newer instance of the binding), nuke our event-listeners.
|
||||
if (this.videocontrols.randomID != this.randomID)
|
||||
this.terminateEventListeners();
|
||||
|
||||
switch (aEvent.type) {
|
||||
case "play":
|
||||
this.playButton.setAttribute("paused", false);
|
||||
@ -200,11 +277,40 @@
|
||||
case "emptied":
|
||||
this.bufferBar.value = 0;
|
||||
break;
|
||||
case "seeking":
|
||||
case "waiting":
|
||||
this.startFadeIn(this.throbberFader);
|
||||
break;
|
||||
case "seeked":
|
||||
// Normally we'd expect canplaythough to fire, but if we already
|
||||
// have the data cached it shouldn't fire again.
|
||||
if (this.video.readyState == this.video.HAVE_ENOUGH_DATA)
|
||||
this.startFadeOut(this.throbberFader);
|
||||
break;
|
||||
case "playing":
|
||||
case "canplaythrough":
|
||||
this.startFadeOut(this.throbberFader);
|
||||
break;
|
||||
default:
|
||||
this.log("!!! event " + aEvent.type + " not handled!");
|
||||
}
|
||||
},
|
||||
|
||||
terminateEventListeners : function () {
|
||||
for each (var event in this.videoEvents)
|
||||
this.video.removeEventListener(event, this, false);
|
||||
|
||||
if (this.controlFader.timer)
|
||||
clearInterval(this.controlFader.timer);
|
||||
if (this.controlFader.delayTimer)
|
||||
clearInterval(this.controlFader.delayTimer);
|
||||
if (this.throbberFader.timer)
|
||||
clearInterval(this.throbberFader.timer);
|
||||
if (this.throbberFader.delayTimer)
|
||||
clearTimeout(this.throbberFader.delayTimer);
|
||||
this.log("--- videocontrols terminated ---");
|
||||
},
|
||||
|
||||
durationChange : function (duration) {
|
||||
if (isNaN(duration))
|
||||
duration = this.maxCurrentTimeSeen;
|
||||
@ -276,64 +382,102 @@
|
||||
!(this.video.autoplay && this.video.mozAutoplayEnabled))
|
||||
return;
|
||||
|
||||
this.startFade(this.controlFader, isMouseOver);
|
||||
},
|
||||
|
||||
startFadeIn : function (fader) {
|
||||
this.startFade(fader, true);
|
||||
},
|
||||
|
||||
startFadeOut : function (fader) {
|
||||
this.startFade(fader, false);
|
||||
},
|
||||
|
||||
startFade : function (fader, fadeIn, immediate) {
|
||||
// If the fader specifies a start delay, don't immediately fade in...
|
||||
// Unless there's already a fade underway, in which case we want to be
|
||||
// able to immediately reverse it (eg, a seeking event right after seeked).
|
||||
if (fadeIn && fader.START_DELAY && !immediate && !fader.timer) {
|
||||
function delayedFadeStart(self, fader) {
|
||||
self.log("Delated start timer fired.");
|
||||
fader.delayTimer = null;
|
||||
self.startFade(fader, true, true);
|
||||
}
|
||||
|
||||
// If there's already a timer running, let it handle things.
|
||||
if (fader.delayTimer)
|
||||
return;
|
||||
|
||||
this.log("Delaying " + fader.name + " fade-in...");
|
||||
fader.delayTimer = setTimeout(delayedFadeStart, fader.START_DELAY, this, fader);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cancel any delay timer (eg, if we start fading-out before it fires)
|
||||
if (fader.delayTimer) {
|
||||
this.log("Canceling " + fader.name + " fade-in delay...");
|
||||
clearTimeout(fader.delayTimer);
|
||||
fader.delayTimer = null;
|
||||
}
|
||||
|
||||
|
||||
// If we're already fading towards the desired state (or are
|
||||
// already there), then we don't need to do anything more.
|
||||
var directionChange = (this.fadingIn != isMouseOver);
|
||||
var directionChange = (fader.fadingIn != fadeIn);
|
||||
if (!directionChange)
|
||||
return;
|
||||
|
||||
this.fadingIn = isMouseOver;
|
||||
this.log("Fading controls " + (this.fadingIn ? "in" : "out"));
|
||||
fader.fadingIn = fadeIn;
|
||||
this.log("Fading " + fader.name + (fader.fadingIn ? " in" : " out"));
|
||||
|
||||
// When switching direction mid-fade, we want the reversed fade
|
||||
// to complete in the same amount of time as the current fade has
|
||||
// been running. So we invert fadeTime.
|
||||
// been running. So we invert the runtime.
|
||||
//
|
||||
// For example, if we're 20ms into a 100ms fade-in, then we want to
|
||||
// fade-out over 20ms. This is done by setting fadeTime to 80ms
|
||||
// (100-20), so that fadeControls will only animate for 20ms more.
|
||||
if (this.fadeTime)
|
||||
this.fadeTime = this.FADE_TIME_MAX - this.fadeTime;
|
||||
// fade-out over 20ms. This is done by setting the .runtime to 80ms
|
||||
// (100-20), so that doFade will only animate for 20ms more.
|
||||
if (fader.runtime)
|
||||
fader.runtime = fader.RUNTIME_MAX - fader.runtime;
|
||||
|
||||
if (!this.fadeTimer)
|
||||
this.fadeTimer = setInterval(this.fadeControls, this.FADE_TIME_STEP, this);
|
||||
|
||||
// If we're fading in, immediately make the controls clickable.
|
||||
// Otherwise they might not activate until the first fadeTimer
|
||||
// fires, which is hard to test reliably.
|
||||
if (this.fadingIn)
|
||||
this.controlBar.style.visibility = "visible";
|
||||
if (!fader.timer) {
|
||||
fader.timer = setInterval(this.doFade, fader.RUNTIME_STEP, this, fader);
|
||||
// Perform the first fade step now, notably to make a fade-in
|
||||
// immediately activate the controls.
|
||||
this.doFade(this, fader, -(fader.RUNTIME_STEP - 1));
|
||||
}
|
||||
},
|
||||
|
||||
fadeControls : function (self, lateness) {
|
||||
doFade : function (self, fader, lateness) {
|
||||
// Update elapsed time, and compute position as a percent
|
||||
// of total. Last frame could run over, so clamp to 1.
|
||||
self.fadeTime += self.FADE_TIME_STEP + lateness;
|
||||
var pos = self.fadeTime / self.FADE_TIME_MAX;
|
||||
fader.runtime += fader.RUNTIME_STEP + lateness;
|
||||
var pos = fader.runtime / fader.RUNTIME_MAX;
|
||||
if (pos > 1)
|
||||
pos = 1;
|
||||
|
||||
// Calculate the opacity for our position in the animation.
|
||||
var opacity;
|
||||
if (self.fadingIn)
|
||||
if (fader.fadingIn)
|
||||
opacity = Math.pow(pos, 0.5);
|
||||
else
|
||||
opacity = Math.pow(1 - pos, 0.5);
|
||||
self.controlsVisible = (opacity ? true : false);
|
||||
fader.isVisible = (opacity ? true : false);
|
||||
//self.log("Fading " + fader.name + " to opacity " + opacity);
|
||||
|
||||
self.controlBar.style.opacity = opacity;
|
||||
fader.element.style.opacity = opacity;
|
||||
|
||||
// Use .visibility to ignore mouse clicks when hidden.
|
||||
if (self.controlsVisible)
|
||||
self.controlBar.style.visibility = "visible";
|
||||
if (fader.isVisible)
|
||||
fader.element.style.visibility = "visible";
|
||||
else
|
||||
self.controlBar.style.visibility = "hidden";
|
||||
fader.element.style.visibility = "hidden";
|
||||
|
||||
// Is the animation done?
|
||||
if (pos == 1) {
|
||||
clearInterval(self.fadeTimer);
|
||||
self.fadeTimer = null;
|
||||
self.fadeTime = 0;
|
||||
clearInterval(fader.timer);
|
||||
fader.timer = null;
|
||||
fader.runtime = 0;
|
||||
}
|
||||
},
|
||||
|
||||
@ -379,7 +523,9 @@
|
||||
this.Utils.video = video;
|
||||
this.Utils.videocontrols = this;
|
||||
|
||||
this.Utils.controlBar = document.getAnonymousElementByAttribute(this, "class", "controlBar");
|
||||
this.Utils.controlFader.element = document.getAnonymousElementByAttribute(this, "class", "controlBar");
|
||||
this.Utils.throbberFader.element = document.getAnonymousElementByAttribute(this, "class", "throbberOverlay");
|
||||
|
||||
this.Utils.playButton = document.getAnonymousElementByAttribute(this, "class", "playButton");
|
||||
this.Utils.muteButton = document.getAnonymousElementByAttribute(this, "class", "muteButton");
|
||||
this.Utils.progressBar = document.getAnonymousElementByAttribute(this, "class", "progressBar");
|
||||
@ -391,8 +537,7 @@
|
||||
if (thumb)
|
||||
this.Utils.thumbWidth = thumb.clientWidth;
|
||||
|
||||
// Set initial state of play/pause button.
|
||||
this.Utils.playButton.setAttribute("paused", video.paused);
|
||||
this.Utils.setupInitialState();
|
||||
|
||||
// videocontrols.css hides the control bar by default, because if script
|
||||
// is disabled our binding's script is disabled too (bug 449358). Thus,
|
||||
@ -405,23 +550,16 @@
|
||||
//
|
||||
// (Note: the |controls| attribute is already handled via layout/style/html.css)
|
||||
if (!(video.autoplay && video.mozAutoplayEnabled) || !this.Utils.dynamicControls) {
|
||||
this.Utils.controlBar.style.visibility = "visible";
|
||||
this.Utils.controlBar.style.opacity = 1.0;
|
||||
this.Utils.controlsVisible = true;
|
||||
this.Utils.fadingIn = true;
|
||||
var fader = this.Utils.controlFader;
|
||||
fader.element.style.visibility = "visible";
|
||||
fader.element.style.opacity = 1.0;
|
||||
fader.isVisible = true;
|
||||
fader.fadingIn = true;
|
||||
}
|
||||
|
||||
// Use Utils.handleEvent() callback for all media events.
|
||||
video.addEventListener("play", this.Utils, false);
|
||||
video.addEventListener("pause", this.Utils, false);
|
||||
video.addEventListener("ended", this.Utils, false);
|
||||
video.addEventListener("volumechange", this.Utils, false);
|
||||
video.addEventListener("loadeddata", this.Utils, false);
|
||||
video.addEventListener("loadstart", this.Utils, false);
|
||||
video.addEventListener("durationchange", this.Utils, false);
|
||||
video.addEventListener("timeupdate", this.Utils, false);
|
||||
video.addEventListener("progress", this.Utils, false);
|
||||
video.addEventListener("emptied", this.Utils, false);
|
||||
// Use the Utils.handleEvent() callback for all media events.
|
||||
for each (var event in this.Utils.videoEvents)
|
||||
video.addEventListener(event, this.Utils, false);
|
||||
|
||||
this.Utils.log("--- videocontrols initialized ---");
|
||||
]]>
|
||||
|
@ -179,6 +179,7 @@ classic.jar:
|
||||
+ skin/classic/global/media/muteButton.png (media/muteButton.png)
|
||||
+ skin/classic/global/media/unmuteButton.png (media/unmuteButton.png)
|
||||
+ skin/classic/global/media/scrubberThumb.png (media/scrubberThumb.png)
|
||||
+ skin/classic/global/media/throbber.png (media/throbber.png)
|
||||
+ skin/classic/global/menu/menu-arrow-dis.gif (menu/menu-arrow-dis.gif)
|
||||
+ skin/classic/global/menu/menu-arrow-hov.gif (menu/menu-arrow-hov.gif)
|
||||
+ skin/classic/global/menu/menu-arrow.gif (menu/menu-arrow.gif)
|
||||
|
BIN
toolkit/themes/pinstripe/global/media/throbber.png
Normal file
BIN
toolkit/themes/pinstripe/global/media/throbber.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
@ -79,3 +79,14 @@
|
||||
min-width: 11px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.throbberOverlay {
|
||||
background-color: rgba(0,0,0,0.55);
|
||||
}
|
||||
|
||||
.throbber {
|
||||
background: url(chrome://global/skin/media/throbber.png) no-repeat center;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
margin-bottom: 28px; /* same height as .controlBar, to keep throbber centered above it */
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ classic.jar:
|
||||
skin/classic/global/media/muteButton.png (media/muteButton.png)
|
||||
skin/classic/global/media/unmuteButton.png (media/unmuteButton.png)
|
||||
skin/classic/global/media/scrubberThumb.png (media/scrubberThumb.png)
|
||||
skin/classic/global/media/throbber.png (media/throbber.png)
|
||||
skin/classic/global/radio/radio-check.gif (radio/radio-check.gif)
|
||||
skin/classic/global/radio/radio-check-dis.gif (radio/radio-check-dis.gif)
|
||||
skin/classic/global/scrollbar/slider.gif (scrollbar/slider.gif)
|
||||
@ -324,6 +325,7 @@ classic.jar:
|
||||
skin/classic/aero/global/media/muteButton.png (media/muteButton.png)
|
||||
skin/classic/aero/global/media/unmuteButton.png (media/unmuteButton.png)
|
||||
skin/classic/aero/global/media/scrubberThumb.png (media/scrubberThumb.png)
|
||||
skin/classic/aero/global/media/throbber.png (media/throbber.png)
|
||||
skin/classic/aero/global/radio/radio-check.gif (radio/radio-check.gif)
|
||||
skin/classic/aero/global/radio/radio-check-dis.gif (radio/radio-check-dis.gif)
|
||||
skin/classic/aero/global/scrollbar/slider.gif (scrollbar/slider.gif)
|
||||
|
BIN
toolkit/themes/winstripe/global/media/throbber.png
Normal file
BIN
toolkit/themes/winstripe/global/media/throbber.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
@ -86,3 +86,14 @@
|
||||
min-width: 11px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.throbberOverlay {
|
||||
background-color: rgba(0,0,0,0.55);
|
||||
}
|
||||
|
||||
.throbber {
|
||||
background: url(chrome://global/skin/media/throbber.png) no-repeat center;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
margin-bottom: 28px; /* same height as .controlBar, to keep throbber centered above it */
|
||||
}
|
||||
|
@ -149,6 +149,8 @@ ah_crap_handler(int signum)
|
||||
sleep(_gdb_sleep_duration);
|
||||
|
||||
printf("Done sleeping...\n");
|
||||
|
||||
_exit(signum);
|
||||
}
|
||||
#endif // CRAWL_STACK_ON_SIGSEGV
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user