mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to fx-team.
This commit is contained in:
commit
f03bbd6952
@ -326,12 +326,13 @@ let FormAssistant = {
|
||||
break;
|
||||
}
|
||||
|
||||
if (target instanceof HTMLDocument ||
|
||||
// Bug 811177, we don't support editing the entire document.
|
||||
target instanceof HTMLBodyElement ||
|
||||
target == content) {
|
||||
break;
|
||||
}
|
||||
// Focusing on Window, Document or iFrame should focus body
|
||||
if (target instanceof HTMLHtmlElement)
|
||||
target = target.document.body;
|
||||
else if (target instanceof HTMLDocument)
|
||||
target = target.body;
|
||||
else if (target instanceof HTMLIFrameElement)
|
||||
target = target.contentDocument.body;
|
||||
|
||||
if (isContentEditable(target)) {
|
||||
this.showKeyboard(this.getTopLevelEditable(target));
|
||||
@ -628,24 +629,11 @@ let FormAssistant = {
|
||||
|
||||
getTopLevelEditable: function fa_getTopLevelEditable(element) {
|
||||
function retrieveTopLevelEditable(element) {
|
||||
// Retrieve the top element that is editable
|
||||
if (element instanceof HTMLHtmlElement)
|
||||
element = element.ownerDocument.body;
|
||||
else if (element instanceof HTMLDocument)
|
||||
element = element.body;
|
||||
|
||||
while (element && !isContentEditable(element))
|
||||
element = element.parentNode;
|
||||
|
||||
// Return the container frame if we are into a nested editable frame
|
||||
if (element &&
|
||||
element instanceof HTMLBodyElement &&
|
||||
element.ownerDocument.defaultView != content.document.defaultView)
|
||||
return element.ownerDocument.defaultView.frameElement;
|
||||
}
|
||||
|
||||
if (element instanceof HTMLIFrameElement)
|
||||
return element;
|
||||
}
|
||||
|
||||
return retrieveTopLevelEditable(element) || element;
|
||||
},
|
||||
@ -712,14 +700,6 @@ function isContentEditable(element) {
|
||||
if (element.isContentEditable || element.designMode == "on")
|
||||
return true;
|
||||
|
||||
// If a body element is editable and the body is the child of an
|
||||
// iframe we can assume this is an advanced HTML editor
|
||||
if (element instanceof HTMLIFrameElement &&
|
||||
element.contentDocument &&
|
||||
(element.contentDocument.body.isContentEditable ||
|
||||
element.contentDocument.designMode == "on"))
|
||||
return true;
|
||||
|
||||
return element.ownerDocument && element.ownerDocument.designMode == "on";
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "7db3c28d7056b880b3be261f7784b5cc3e96702b",
|
||||
"revision": "ba5f179a8e557690746e88ffc8b41a8151f65b06",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ this.webappsUI = {
|
||||
localDir = app.appProfile.localDir;
|
||||
}
|
||||
|
||||
DOMApplicationRegistry.confirmInstall(aData, localDir, null,
|
||||
DOMApplicationRegistry.confirmInstall(aData, localDir,
|
||||
(aManifest) => {
|
||||
Task.spawn(function() {
|
||||
try {
|
||||
|
@ -57,6 +57,13 @@ struct ImageValue;
|
||||
/**
|
||||
* A class used to construct a nsString from a nsStringBuffer (we might
|
||||
* want to move this to nsString at some point).
|
||||
*
|
||||
* WARNING: Note that nsCheapString doesn't take an explicit length -- it
|
||||
* assumes the string is maximally large, given the nsStringBuffer's storage
|
||||
* size. This means the given string buffer *must* be sized exactly correctly
|
||||
* for the string it contains (including one byte for a null terminator). If
|
||||
* it has any unused storage space, then that will result in bogus characters
|
||||
* at the end of our nsCheapString.
|
||||
*/
|
||||
class nsCheapString : public nsString {
|
||||
public:
|
||||
|
@ -99,6 +99,19 @@ nsDOMTokenList::CheckToken(const nsAString& aStr)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMTokenList::CheckTokens(const nsTArray<nsString>& aTokens)
|
||||
{
|
||||
for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
|
||||
nsresult rv = CheckToken(aTokens[i]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDOMTokenList::Contains(const nsAString& aToken, ErrorResult& aError)
|
||||
{
|
||||
@ -113,7 +126,7 @@ nsDOMTokenList::Contains(const nsAString& aToken, ErrorResult& aError)
|
||||
|
||||
void
|
||||
nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
|
||||
const nsAString& aToken)
|
||||
const nsTArray<nsString>& aTokens)
|
||||
{
|
||||
if (!mElement) {
|
||||
return;
|
||||
@ -125,36 +138,56 @@ nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
|
||||
aAttr->ToString(resultStr);
|
||||
}
|
||||
|
||||
if (!resultStr.IsEmpty() &&
|
||||
!nsContentUtils::IsHTMLWhitespace(
|
||||
resultStr.CharAt(resultStr.Length() - 1))) {
|
||||
bool oneWasAdded = false;
|
||||
nsAutoTArray<nsString, 10> addedClasses;
|
||||
addedClasses.SetCapacity(aTokens.Length());
|
||||
|
||||
for (uint32_t i = 0, l = aTokens.Length(); i < l; ++i) {
|
||||
const nsString& aToken = aTokens[i];
|
||||
|
||||
if ((aAttr && aAttr->Contains(aToken)) ||
|
||||
addedClasses.Contains(aToken)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (oneWasAdded ||
|
||||
(!resultStr.IsEmpty() &&
|
||||
!nsContentUtils::IsHTMLWhitespace(resultStr.Last()))) {
|
||||
resultStr.Append(NS_LITERAL_STRING(" ") + aToken);
|
||||
} else {
|
||||
resultStr.Append(aToken);
|
||||
}
|
||||
|
||||
oneWasAdded = true;
|
||||
addedClasses.AppendElement(aToken);
|
||||
}
|
||||
|
||||
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMTokenList::Add(const nsAString& aToken, ErrorResult& aError)
|
||||
nsDOMTokenList::Add(const nsTArray<nsString>& aTokens, ErrorResult& aError)
|
||||
{
|
||||
aError = CheckToken(aToken);
|
||||
aError = CheckTokens(aTokens);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsAttrValue* attr = GetParsedAttr();
|
||||
AddInternal(attr, aTokens);
|
||||
}
|
||||
|
||||
if (attr && attr->Contains(aToken)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddInternal(attr, aToken);
|
||||
void
|
||||
nsDOMTokenList::Add(const nsAString& aToken, mozilla::ErrorResult& aError)
|
||||
{
|
||||
nsAutoTArray<nsString, 1> aTokens;
|
||||
aTokens.AppendElement(aToken);
|
||||
Add(aTokens, aError);
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
|
||||
const nsAString& aToken)
|
||||
const nsTArray<nsString>& aTokens)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aAttr, "Need an attribute");
|
||||
|
||||
@ -189,7 +222,7 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
|
||||
++iter;
|
||||
} while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
|
||||
|
||||
if (Substring(tokenStart, iter).Equals(aToken)) {
|
||||
if (aTokens.Contains(Substring(tokenStart, iter))) {
|
||||
|
||||
// Skip whitespace after the token, it will be collapsed.
|
||||
while (iter != end && nsContentUtils::IsHTMLWhitespace(*iter)) {
|
||||
@ -202,7 +235,7 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
|
||||
|
||||
if (lastTokenRemoved && !output.IsEmpty()) {
|
||||
NS_ABORT_IF_FALSE(!nsContentUtils::IsHTMLWhitespace(
|
||||
output.CharAt(output.Length() - 1)), "Invalid last output token");
|
||||
output.Last()), "Invalid last output token");
|
||||
output.Append(PRUnichar(' '));
|
||||
}
|
||||
lastTokenRemoved = false;
|
||||
@ -215,19 +248,27 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMTokenList::Remove(const nsAString& aToken, ErrorResult& aError)
|
||||
nsDOMTokenList::Remove(const nsTArray<nsString>& aTokens, ErrorResult& aError)
|
||||
{
|
||||
aError = CheckToken(aToken);
|
||||
aError = CheckTokens(aTokens);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsAttrValue* attr = GetParsedAttr();
|
||||
if (!attr || !attr->Contains(aToken)) {
|
||||
if (!attr) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveInternal(attr, aToken);
|
||||
RemoveInternal(attr, aTokens);
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMTokenList::Remove(const nsAString& aToken, mozilla::ErrorResult& aError)
|
||||
{
|
||||
nsAutoTArray<nsString, 1> aTokens;
|
||||
aTokens.AppendElement(aToken);
|
||||
Remove(aTokens, aError);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -245,15 +286,17 @@ nsDOMTokenList::Toggle(const nsAString& aToken,
|
||||
const bool forceOff = aForce.WasPassed() && !aForce.Value();
|
||||
|
||||
bool isPresent = attr && attr->Contains(aToken);
|
||||
nsAutoTArray<nsString, 1> aTokens;
|
||||
aTokens.AppendElement(aToken);
|
||||
|
||||
if (isPresent) {
|
||||
if (!forceOn) {
|
||||
RemoveInternal(attr, aToken);
|
||||
RemoveInternal(attr, aTokens);
|
||||
isPresent = false;
|
||||
}
|
||||
} else {
|
||||
if (!forceOff) {
|
||||
AddInternal(attr, aToken);
|
||||
AddInternal(attr, aTokens);
|
||||
isPresent = true;
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,11 @@ public:
|
||||
void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aResult);
|
||||
bool Contains(const nsAString& aToken, mozilla::ErrorResult& aError);
|
||||
void Add(const nsAString& aToken, mozilla::ErrorResult& aError);
|
||||
void Add(const nsTArray<nsString>& aTokens,
|
||||
mozilla::ErrorResult& aError);
|
||||
void Remove(const nsAString& aToken, mozilla::ErrorResult& aError);
|
||||
void Remove(const nsTArray<nsString>& aTokens,
|
||||
mozilla::ErrorResult& aError);
|
||||
bool Toggle(const nsAString& aToken,
|
||||
const mozilla::dom::Optional<bool>& force,
|
||||
mozilla::ErrorResult& aError);
|
||||
@ -69,8 +73,11 @@ protected:
|
||||
virtual ~nsDOMTokenList();
|
||||
|
||||
nsresult CheckToken(const nsAString& aStr);
|
||||
void AddInternal(const nsAttrValue* aAttr, const nsAString& aToken);
|
||||
void RemoveInternal(const nsAttrValue* aAttr, const nsAString& aToken);
|
||||
nsresult CheckTokens(const nsTArray<nsString>& aStr);
|
||||
void AddInternal(const nsAttrValue* aAttr,
|
||||
const nsTArray<nsString>& aTokens);
|
||||
void RemoveInternal(const nsAttrValue* aAttr,
|
||||
const nsTArray<nsString>& aTokens);
|
||||
inline const nsAttrValue* GetParsedAttr();
|
||||
|
||||
Element* mElement;
|
||||
|
@ -36,6 +36,10 @@ function onAttrModified(event) {
|
||||
}
|
||||
|
||||
function checkModification(e, funcName, args, expectedRes, before, after, expectedException) {
|
||||
if (!Array.isArray(args)) {
|
||||
args = [args];
|
||||
}
|
||||
|
||||
var shouldThrow = typeof(expectedException) === "string";
|
||||
if (shouldThrow) {
|
||||
// If an exception is thrown, the class attribute shouldn't change.
|
||||
@ -259,12 +263,14 @@ function testClassList(e) {
|
||||
// add() method
|
||||
|
||||
function checkAdd(before, argument, after, expectedException) {
|
||||
checkModification(e, "add", [argument], null, before, after, expectedException);
|
||||
checkModification(e, "add", argument, null, before, after, expectedException);
|
||||
}
|
||||
|
||||
checkAdd(null, "", null, "SyntaxError");
|
||||
checkAdd(null, ["a", ""], null, "SyntaxError");
|
||||
checkAdd(null, " ", null, "InvalidCharacterError");
|
||||
checkAdd(null, "aa ", null, "InvalidCharacterError");
|
||||
checkAdd(null, ["a", " "], null, "InvalidCharacterError");
|
||||
checkAdd(null, ["a", "aa "], null, "InvalidCharacterError");
|
||||
|
||||
checkAdd("a", "a", "a");
|
||||
checkAdd("aa", "AA", "aa AA");
|
||||
@ -278,6 +284,14 @@ function testClassList(e) {
|
||||
checkAdd("a b c", "d", "a b c d");
|
||||
checkAdd("a b c ", "d", "a b c d");
|
||||
|
||||
// multiple add
|
||||
checkAdd("a b c ", ["d", "e"], "a b c d e");
|
||||
checkAdd("a b c ", ["a", "a"], "a b c ");
|
||||
checkAdd("a b c ", ["d", "d"], "a b c d");
|
||||
checkAdd("a b c ", [], "a b c ");
|
||||
checkAdd(null, ["a", "b"], "a b");
|
||||
checkAdd("", ["a", "b"], "a b");
|
||||
|
||||
// Test for bug 530171
|
||||
checkAdd(null, null, "null");
|
||||
checkAdd(null, undefined, "undefined");
|
||||
@ -285,7 +299,7 @@ function testClassList(e) {
|
||||
// remove() method
|
||||
|
||||
function checkRemove(before, argument, after, expectedException) {
|
||||
checkModification(e, "remove", [argument], null, before, after, expectedException);
|
||||
checkModification(e, "remove", argument, null, before, after, expectedException);
|
||||
}
|
||||
|
||||
checkRemove(null, "", null, "SyntaxError");
|
||||
@ -317,6 +331,16 @@ function testClassList(e) {
|
||||
|
||||
checkRemove("\ra\na\ta\f", "a", "");
|
||||
|
||||
// multiple remove
|
||||
checkRemove("a b c ", ["d", "e"], "a b c ");
|
||||
checkRemove("a b c ", ["a", "b"], "c ");
|
||||
checkRemove("a b c ", ["a", "c"], "b");
|
||||
checkRemove("a b c ", ["a", "a"], "b c ");
|
||||
checkRemove("a b c ", ["d", "d"], "a b c ");
|
||||
checkRemove("a b c ", [], "a b c ");
|
||||
checkRemove(null, ["a", "b"], null);
|
||||
checkRemove("", ["a", "b"], "");
|
||||
|
||||
// Test for bug 530171
|
||||
checkRemove("null", null, "");
|
||||
checkRemove("undefined", undefined, "");
|
||||
@ -324,7 +348,7 @@ function testClassList(e) {
|
||||
// toggle() method
|
||||
|
||||
function checkToggle(before, argument, expectedRes, after, expectedException) {
|
||||
checkModification(e, "toggle", [argument], expectedRes, before, after, expectedException);
|
||||
checkModification(e, "toggle", argument, expectedRes, before, after, expectedException);
|
||||
}
|
||||
|
||||
checkToggle(null, "", null, null, "SyntaxError");
|
||||
|
@ -13,10 +13,3 @@ JSObject*
|
||||
WebGLActiveInfo::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) {
|
||||
return dom::WebGLActiveInfoBinding::Wrap(cx, scope, this);
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(WebGLActiveInfo)
|
||||
NS_IMPL_RELEASE(WebGLActiveInfo)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(WebGLActiveInfo)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
@ -19,7 +19,6 @@ template <typename T> class Handle;
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLActiveInfo MOZ_FINAL
|
||||
: public nsISupports
|
||||
{
|
||||
public:
|
||||
WebGLActiveInfo(WebGLint size, WebGLenum type, const nsACString& name) :
|
||||
@ -44,7 +43,7 @@ public:
|
||||
|
||||
JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_INLINE_DECL_REFCOUNTING(WebGLActiveInfo)
|
||||
|
||||
protected:
|
||||
WebGLint mSize;
|
||||
|
@ -61,10 +61,5 @@ WebGLBuffer::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLBuffer)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLBuffer)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLBuffer)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLBuffer)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLBuffer, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLBuffer, Release)
|
||||
|
@ -20,11 +20,10 @@ namespace mozilla {
|
||||
class WebGLElementArrayCache;
|
||||
|
||||
class WebGLBuffer MOZ_FINAL
|
||||
: public nsISupports
|
||||
: public nsWrapperCache
|
||||
, public WebGLRefCountedObject<WebGLBuffer>
|
||||
, public LinkedListElement<WebGLBuffer>
|
||||
, public WebGLContextBoundObject
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
WebGLBuffer(WebGLContext *context);
|
||||
@ -63,8 +62,8 @@ public:
|
||||
virtual JSObject* WrapObject(JSContext *cx,
|
||||
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLBuffer)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -532,9 +532,11 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
const char* aName,
|
||||
uint32_t aFlags = 0)
|
||||
{
|
||||
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
|
||||
aCallback.NoteXPCOMChild(aField.mTexturePtr);
|
||||
aCallback.NoteXPCOMChild(aField.mRenderbufferPtr);
|
||||
CycleCollectionNoteChild(aCallback, aField.mTexturePtr.get(),
|
||||
aName, aFlags);
|
||||
|
||||
CycleCollectionNoteChild(aCallback, aField.mRenderbufferPtr.get(),
|
||||
aName, aFlags);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_7(WebGLFramebuffer,
|
||||
@ -546,10 +548,5 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_7(WebGLFramebuffer,
|
||||
mDepthStencilAttachment.mTexturePtr,
|
||||
mDepthStencilAttachment.mRenderbufferPtr)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLFramebuffer)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLFramebuffer)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLFramebuffer)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release)
|
||||
|
@ -18,11 +18,10 @@ class WebGLTexture;
|
||||
class WebGLRenderbuffer;
|
||||
|
||||
class WebGLFramebuffer MOZ_FINAL
|
||||
: public nsISupports
|
||||
: public nsWrapperCache
|
||||
, public WebGLRefCountedObject<WebGLFramebuffer>
|
||||
, public LinkedListElement<WebGLFramebuffer>
|
||||
, public WebGLContextBoundObject
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
WebGLFramebuffer(WebGLContext *context);
|
||||
@ -149,8 +148,8 @@ public:
|
||||
virtual JSObject* WrapObject(JSContext *cx,
|
||||
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLFramebuffer)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
|
||||
|
||||
bool CheckAndInitializeRenderbuffers();
|
||||
|
||||
|
@ -329,8 +329,7 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
const char* aName,
|
||||
uint32_t aFlags = 0)
|
||||
{
|
||||
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
|
||||
aCallback.NoteXPCOMChild(aField);
|
||||
CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -245,10 +245,5 @@ WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name) {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(WebGLProgram, mAttachedShaders)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLProgram)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLProgram)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLProgram)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)
|
||||
|
@ -22,11 +22,10 @@ typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringMap;
|
||||
typedef nsDataHashtable<nsCStringHashKey, WebGLUniformInfo> CStringToUniformInfoMap;
|
||||
|
||||
class WebGLProgram MOZ_FINAL
|
||||
: public nsISupports
|
||||
: public nsWrapperCache
|
||||
, public WebGLRefCountedObject<WebGLProgram>
|
||||
, public LinkedListElement<WebGLProgram>
|
||||
, public WebGLContextBoundObject
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
WebGLProgram(WebGLContext *context);
|
||||
@ -107,8 +106,8 @@ public:
|
||||
virtual JSObject* WrapObject(JSContext *cx,
|
||||
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLProgram)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
|
||||
|
||||
// public post-link data
|
||||
std::map<GLint, nsCString> mActiveAttribMap;
|
||||
|
@ -67,10 +67,5 @@ WebGLRenderbuffer::MemoryUsage() const {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLRenderbuffer)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLRenderbuffer)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLRenderbuffer)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer, Release)
|
||||
|
@ -15,12 +15,11 @@
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLRenderbuffer MOZ_FINAL
|
||||
: public nsISupports
|
||||
: public nsWrapperCache
|
||||
, public WebGLRefCountedObject<WebGLRenderbuffer>
|
||||
, public LinkedListElement<WebGLRenderbuffer>
|
||||
, public WebGLRectangleObject
|
||||
, public WebGLContextBoundObject
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
WebGLRenderbuffer(WebGLContext *context);
|
||||
@ -53,8 +52,8 @@ public:
|
||||
virtual JSObject* WrapObject(JSContext *cx,
|
||||
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLRenderbuffer)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -53,10 +53,5 @@ WebGLShader::SetTranslationSuccess() {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLShader)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLShader)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLShader)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLShader)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLShader, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLShader, Release)
|
||||
|
@ -24,11 +24,10 @@ struct WebGLMappedIdentifier {
|
||||
};
|
||||
|
||||
class WebGLShader MOZ_FINAL
|
||||
: public nsISupports
|
||||
: public nsWrapperCache
|
||||
, public WebGLRefCountedObject<WebGLShader>
|
||||
, public LinkedListElement<WebGLShader>
|
||||
, public WebGLContextBoundObject
|
||||
, public nsWrapperCache
|
||||
{
|
||||
friend class WebGLContext;
|
||||
friend class WebGLProgram;
|
||||
@ -80,8 +79,8 @@ public:
|
||||
virtual JSObject* WrapObject(JSContext *cx,
|
||||
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLShader)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShader)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader)
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -9,13 +9,6 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(WebGLShaderPrecisionFormat)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(WebGLShaderPrecisionFormat)
|
||||
NS_IMPL_RELEASE(WebGLShaderPrecisionFormat)
|
||||
|
||||
JSObject*
|
||||
WebGLShaderPrecisionFormat::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
|
||||
{
|
||||
|
@ -13,8 +13,7 @@ namespace mozilla {
|
||||
class WebGLBuffer;
|
||||
|
||||
class WebGLShaderPrecisionFormat MOZ_FINAL
|
||||
: public nsISupports
|
||||
, public WebGLContextBoundObject
|
||||
: public WebGLContextBoundObject
|
||||
{
|
||||
public:
|
||||
WebGLShaderPrecisionFormat(WebGLContext *context, WebGLint rangeMin, WebGLint rangeMax, WebGLint precision) :
|
||||
@ -27,8 +26,6 @@ public:
|
||||
|
||||
JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// WebIDL WebGLShaderPrecisionFormat API
|
||||
WebGLint RangeMin() const {
|
||||
return mRangeMin;
|
||||
@ -40,6 +37,8 @@ public:
|
||||
return mPrecision;
|
||||
}
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(WebGLShaderPrecisionFormat)
|
||||
|
||||
protected:
|
||||
WebGLint mRangeMin;
|
||||
WebGLint mRangeMax;
|
||||
|
@ -360,10 +360,5 @@ WebGLTexture::NeedFakeBlack() {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLTexture)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLTexture)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLTexture)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTexture, Release)
|
||||
|
@ -24,11 +24,10 @@ inline bool is_pot_assuming_nonnegative(WebGLsizei x)
|
||||
// NOTE: When this class is switched to new DOM bindings, update the (then-slow)
|
||||
// WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
|
||||
class WebGLTexture MOZ_FINAL
|
||||
: public nsISupports
|
||||
: public nsWrapperCache
|
||||
, public WebGLRefCountedObject<WebGLTexture>
|
||||
, public LinkedListElement<WebGLTexture>
|
||||
, public WebGLContextBoundObject
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
WebGLTexture(WebGLContext *context);
|
||||
@ -51,8 +50,8 @@ public:
|
||||
virtual JSObject* WrapObject(JSContext *cx,
|
||||
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLTexture)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -29,9 +29,5 @@ WebGLUniformLocation::WebGLUniformLocation(WebGLContext *context, WebGLProgram *
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_1(WebGLUniformLocation, mProgram)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLUniformLocation)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLUniformLocation)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLUniformLocation)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLUniformLocation, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLUniformLocation, Release)
|
||||
|
@ -14,8 +14,7 @@ namespace mozilla {
|
||||
class WebGLProgram;
|
||||
|
||||
class WebGLUniformLocation MOZ_FINAL
|
||||
: public nsISupports
|
||||
, public WebGLContextBoundObject
|
||||
: public WebGLContextBoundObject
|
||||
{
|
||||
public:
|
||||
WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location, const WebGLUniformInfo& info);
|
||||
@ -36,8 +35,8 @@ public:
|
||||
|
||||
JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> scope);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(WebGLUniformLocation)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WebGLUniformLocation)
|
||||
|
||||
protected:
|
||||
// nsRefPtr, not WebGLRefPtr, so that we don't prevent the program from being explicitly deleted.
|
||||
|
@ -75,8 +75,7 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
const char* aName,
|
||||
uint32_t aFlags = 0)
|
||||
{
|
||||
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
|
||||
aCallback.NoteXPCOMChild(aField.buf);
|
||||
CycleCollectionNoteChild(aCallback, aField.buf.get(), aName, aFlags);
|
||||
}
|
||||
|
||||
#endif
|
@ -66,9 +66,8 @@
|
||||
|
||||
MochiKit.DOM.addLoadEvent(function () {
|
||||
var canvas = document.getElementById("canvas");
|
||||
try {
|
||||
gl = canvas.getContext("experimental-webgl");
|
||||
} catch (e) {
|
||||
if (!gl) {
|
||||
todo(false, "Canvas WebGL not supported");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
|
@ -17,21 +17,21 @@ pref(webgl.disabled,true) == webgl-disable-test.html wrapper.html?green.p
|
||||
# Test: {aa, alpha, preserve, readback} = 16
|
||||
random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?__&_____&________ wrapper.html?green.png
|
||||
random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?aa&_____&________ wrapper.html?green.png
|
||||
fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?__&alpha&________ wrapper.html?green.png
|
||||
fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?aa&alpha&________ wrapper.html?green.png
|
||||
fuzzy-if(B2G,256,91) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?__&alpha&________ wrapper.html?green.png
|
||||
fuzzy-if(B2G,256,91) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?aa&alpha&________ wrapper.html?green.png
|
||||
random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?__&_____&preserve wrapper.html?green.png
|
||||
random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?aa&_____&preserve wrapper.html?green.png
|
||||
fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?__&alpha&preserve wrapper.html?green.png
|
||||
fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?aa&alpha&preserve wrapper.html?green.png
|
||||
fuzzy-if(B2G,256,91) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?__&alpha&preserve wrapper.html?green.png
|
||||
fuzzy-if(B2G,256,91) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?aa&alpha&preserve wrapper.html?green.png
|
||||
|
||||
pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&__&_____&________ wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&aa&_____&________ wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&__&alpha&________ wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&aa&alpha&________ wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,91) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&__&alpha&________ wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,91) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&aa&alpha&________ wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&__&_____&preserve wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&aa&_____&preserve wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&__&alpha&preserve wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&aa&alpha&preserve wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,91) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&__&alpha&preserve wrapper.html?green.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,91) random-if(Android&&AndroidVersion<15) == webgl-clear-test.html?readback&aa&alpha&preserve wrapper.html?green.png
|
||||
|
||||
# Check that resize works:
|
||||
random-if(Android&&AndroidVersion<15) == webgl-resize-test.html wrapper.html?green.png
|
||||
@ -39,21 +39,21 @@ random-if(Android&&AndroidVersion<15) == webgl-resize-test.html wrapper.html?g
|
||||
# Check orientation:
|
||||
random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?__&_____&________ wrapper.html?white-top-left.png
|
||||
random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?aa&_____&________ wrapper.html?white-top-left.png
|
||||
fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?__&alpha&________ wrapper.html?white-top-left.png
|
||||
fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?aa&alpha&________ wrapper.html?white-top-left.png
|
||||
fuzzy-if(B2G,256,90) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?__&alpha&________ wrapper.html?white-top-left.png
|
||||
fuzzy-if(B2G,256,90) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?aa&alpha&________ wrapper.html?white-top-left.png
|
||||
random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?__&_____&preserve wrapper.html?white-top-left.png
|
||||
random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?aa&_____&preserve wrapper.html?white-top-left.png
|
||||
fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?__&alpha&preserve wrapper.html?white-top-left.png
|
||||
fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?aa&alpha&preserve wrapper.html?white-top-left.png
|
||||
fuzzy-if(B2G,256,90) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?__&alpha&preserve wrapper.html?white-top-left.png
|
||||
fuzzy-if(B2G,256,90) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?aa&alpha&preserve wrapper.html?white-top-left.png
|
||||
|
||||
pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&__&_____&________ wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&aa&_____&________ wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&__&alpha&________ wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&aa&alpha&________ wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,90) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&__&alpha&________ wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,90) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&aa&alpha&________ wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&__&_____&preserve wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&aa&_____&preserve wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&__&alpha&preserve wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,83) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&aa&alpha&preserve wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,90) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&__&alpha&preserve wrapper.html?white-top-left.png
|
||||
pref(webgl.force-layers-readback,true) fuzzy-if(B2G,256,90) random-if(Android&&AndroidVersion<15) == webgl-orientation-test.html?readback&aa&alpha&preserve wrapper.html?white-top-left.png
|
||||
|
||||
# Does we draw the correct color in the correct places with all context creation options?
|
||||
# (Note that our context creation option matrix is 2^6 = 64)
|
||||
|
@ -804,6 +804,7 @@ HTMLCanvasElement::GetContext(JSContext* aCx,
|
||||
|
||||
rv = UpdateContext(aCx, aContextOptions);
|
||||
if (rv.Failed()) {
|
||||
rv = NS_OK; // See bug 645792
|
||||
return nullptr;
|
||||
}
|
||||
mCurrentContextId.Assign(aContextId);
|
||||
|
@ -382,7 +382,8 @@ void* MediaDecoderReader::VideoQueueMemoryFunctor::operator()(void* anObject) {
|
||||
}
|
||||
|
||||
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
|
||||
: mDecoder(aDecoder)
|
||||
: mDecoder(aDecoder),
|
||||
mIgnoreAudioOutputFormat(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaDecoderReader);
|
||||
}
|
||||
|
@ -467,6 +467,14 @@ public:
|
||||
// decode thread could start up and run in future.
|
||||
virtual void OnDecodeThreadFinish() {}
|
||||
|
||||
// Tell the reader that the data decoded are not for direct playback, so it
|
||||
// can accept more files, in particular those which have more channels than
|
||||
// available in the audio output.
|
||||
void SetIgnoreAudioOutputFormat()
|
||||
{
|
||||
mIgnoreAudioOutputFormat = true;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Queue of audio frames. This queue is threadsafe, and is accessed from
|
||||
// the audio, decoder, state machine, and main threads.
|
||||
@ -543,6 +551,11 @@ protected:
|
||||
|
||||
// Stores presentation info required for playback.
|
||||
VideoInfo mInfo;
|
||||
|
||||
// Whether we should accept media that we know we can't play
|
||||
// directly, because they have a number of channel higher than
|
||||
// what we support.
|
||||
bool mIgnoreAudioOutputFormat;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -61,7 +61,8 @@ static const uint16_t WAVE_FORMAT_CHUNK_SIZE = 16;
|
||||
// supported by AudioStream.
|
||||
static const uint16_t WAVE_FORMAT_ENCODING_PCM = 1;
|
||||
|
||||
// Maximum number of channels supported
|
||||
// We reject files with more than this number of channels if we're decoding for
|
||||
// playback.
|
||||
static const uint8_t MAX_CHANNELS = 2;
|
||||
|
||||
namespace {
|
||||
@ -430,11 +431,13 @@ WaveReader::LoadFormatChunk(uint32_t aChunkSize)
|
||||
|
||||
// Make sure metadata is fairly sane. The rate check is fairly arbitrary,
|
||||
// but the channels check is intentionally limited to mono or stereo
|
||||
// because that's what the audio backend currently supports.
|
||||
// when the media is intended for direct playback because that's what the
|
||||
// audio backend currently supports.
|
||||
unsigned int actualFrameSize = sampleFormat == 8 ? 1 : 2 * channels;
|
||||
if (rate < 100 || rate > 96000 ||
|
||||
channels < 1 || channels > MAX_CHANNELS ||
|
||||
(frameSize != 1 && frameSize != 2 && frameSize != 4) ||
|
||||
(((channels < 1 || channels > MAX_CHANNELS) ||
|
||||
(frameSize != 1 && frameSize != 2 && frameSize != 4)) &&
|
||||
!mIgnoreAudioOutputFormat) ||
|
||||
(sampleFormat != 8 && sampleFormat != 16) ||
|
||||
frameSize != actualFrameSize) {
|
||||
NS_WARNING("Invalid WAVE metadata");
|
||||
|
@ -508,6 +508,11 @@ MediaDecodeTask::Decode()
|
||||
|
||||
mBufferDecoder->BeginDecoding(NS_GetCurrentThread());
|
||||
|
||||
// Tell the decoder reader that we are not going to play the data directly,
|
||||
// and that we should not reject files with more channels than the audio
|
||||
// bakend support.
|
||||
mDecoderReader->SetIgnoreAudioOutputFormat();
|
||||
|
||||
mDecoderReader->OnDecodeThreadStart();
|
||||
|
||||
VideoInfo videoInfo;
|
||||
|
@ -67,6 +67,7 @@ MOCHITEST_FILES := \
|
||||
test_gainNodeInLoop.html \
|
||||
test_maxChannelCount.html \
|
||||
test_mediaDecoding.html \
|
||||
test_decodeMultichannel.html \
|
||||
test_mediaElementAudioSourceNode.html \
|
||||
test_mediaStreamAudioDestinationNode.html \
|
||||
test_mediaStreamAudioSourceNode.html \
|
||||
@ -107,6 +108,7 @@ MOCHITEST_FILES := \
|
||||
audio-expected.wav \
|
||||
audio-mono-expected.wav \
|
||||
audio-mono-expected-2.wav \
|
||||
audio-quad.wav \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
BIN
content/media/webaudio/test/audio-quad.wav
Normal file
BIN
content/media/webaudio/test/audio-quad.wav
Normal file
Binary file not shown.
58
content/media/webaudio/test/test_decodeMultichannel.html
Normal file
58
content/media/webaudio/test/test_decodeMultichannel.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<meta charset=utf-8>
|
||||
<head>
|
||||
<title>Test that we can decode 4 channel wave file in webaudio, but not in <audio></title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
var filename = "audio-quad.wav";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function finishTest(a) {
|
||||
if (a) {
|
||||
a = null;
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function decodeUsingAudioElement() {
|
||||
var a = new Audio();
|
||||
a.addEventListener("error", function() {
|
||||
ok(true, "We should not be able to decode this file using an HTMLAudioElement");
|
||||
finishTest(a);
|
||||
});
|
||||
a.addEventListener("loadedmetadata", function() {
|
||||
ok(false, "We should not be able to decode this file using an HTMLMediaElement.");
|
||||
finishTest(a);
|
||||
});
|
||||
|
||||
a.src = filename;
|
||||
a.load();
|
||||
}
|
||||
|
||||
addLoadEvent(function() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", filename);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.onload = function() {
|
||||
var context = new AudioContext();
|
||||
context.decodeAudioData(xhr.response, function(b) {
|
||||
ok(true, "Decoding of a wave file with four channels succeded.");
|
||||
is(b.numberOfChannels, 4, "The AudioBuffer should have 4 channels.");
|
||||
decodeUsingAudioElement();
|
||||
}, function() {
|
||||
ok(false, "Decoding of a wave file with four channels failed.");
|
||||
decodeUsingAudioElement();
|
||||
});
|
||||
};
|
||||
xhr.send(null);
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -48,6 +48,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(SpeechSynthesis)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SpeechSynthesis)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCurrentTask)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechQueue)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
tmp->mVoiceCache.Clear();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
@ -55,6 +56,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SpeechSynthesis)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentTask)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechQueue)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
tmp->mVoiceCache.EnumerateRead(TraverseCachedVoices, &cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
@ -18,7 +18,10 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(SpeechSynthesisUtterance)
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(SpeechSynthesisUtterance,
|
||||
nsDOMEventTargetHelper, mVoice);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SpeechSynthesisUtterance)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
|
@ -34,7 +34,8 @@ public:
|
||||
virtual ~SpeechSynthesisUtterance();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SpeechSynthesisUtterance,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
|
@ -70,7 +70,7 @@ private:
|
||||
|
||||
// nsSpeechTask
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_1(nsSpeechTask, mSpeechSynthesis);
|
||||
NS_IMPL_CYCLE_COLLECTION_2(nsSpeechTask, mSpeechSynthesis, mUtterance);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSpeechTask)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISpeechTask)
|
||||
|
@ -1302,15 +1302,34 @@ ParseMappedAttrAnimValueCallback(void* aObject,
|
||||
void* aPropertyValue,
|
||||
void* aData)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aPropertyName != SMIL_MAPPED_ATTR_STYLERULE_ATOM,
|
||||
MOZ_ASSERT(aPropertyName != SMIL_MAPPED_ATTR_STYLERULE_ATOM,
|
||||
"animated content style rule should have been removed "
|
||||
"from properties table already (we're rebuilding it now)");
|
||||
|
||||
MappedAttrParser* mappedAttrParser =
|
||||
static_cast<MappedAttrParser*>(aData);
|
||||
MappedAttrParser* mappedAttrParser = static_cast<MappedAttrParser*>(aData);
|
||||
MOZ_ASSERT(mappedAttrParser, "parser should be non-null");
|
||||
|
||||
nsStringBuffer* valueBuf = static_cast<nsStringBuffer*>(aPropertyValue);
|
||||
mappedAttrParser->ParseMappedAttrValue(aPropertyName, nsCheapString(valueBuf));
|
||||
nsStringBuffer* animValBuf = static_cast<nsStringBuffer*>(aPropertyValue);
|
||||
MOZ_ASSERT(animValBuf, "animated value should be non-null");
|
||||
|
||||
PRUnichar* animValBufData = static_cast<PRUnichar*>(animValBuf->Data());
|
||||
uint32_t logicalStringLen = NS_strlen(animValBufData);
|
||||
// SANITY CHECK: In case the string buffer wasn't correctly
|
||||
// null-terminated, let's check the allocated size, too, and make sure we
|
||||
// don't read further than that. (Note that StorageSize() is in units of
|
||||
// bytes, so we have to convert that to units of PRUnichars, and subtract
|
||||
// 1 for the null-terminator.)
|
||||
uint32_t allocStringLen =
|
||||
(animValBuf->StorageSize() / sizeof(PRUnichar)) - 1;
|
||||
|
||||
MOZ_ASSERT(logicalStringLen <= allocStringLen,
|
||||
"The string in our string buffer wasn't null-terminated!!");
|
||||
|
||||
nsString animValStr;
|
||||
animValBuf->ToString(std::min(logicalStringLen, allocStringLen),
|
||||
animValStr);
|
||||
|
||||
mappedAttrParser->ParseMappedAttrValue(aPropertyName, animValStr);
|
||||
}
|
||||
|
||||
// Callback for freeing animated content style rule, in property table.
|
||||
|
@ -2557,15 +2557,12 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
|
||||
class NotifyOffThreadScriptCompletedRunnable : public nsRunnable
|
||||
{
|
||||
nsRefPtr<nsIOffThreadScriptReceiver> mReceiver;
|
||||
|
||||
// Note: there is no need to root the script, it is protected against GC
|
||||
// until FinishOffThreadScript is called on it.
|
||||
JSScript *mScript;
|
||||
void *mToken;
|
||||
|
||||
public:
|
||||
NotifyOffThreadScriptCompletedRunnable(already_AddRefed<nsIOffThreadScriptReceiver> aReceiver,
|
||||
JSScript *aScript)
|
||||
: mReceiver(aReceiver), mScript(aScript)
|
||||
void *aToken)
|
||||
: mReceiver(aReceiver), mToken(aToken)
|
||||
{}
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
@ -2581,23 +2578,24 @@ NotifyOffThreadScriptCompletedRunnable::Run()
|
||||
// could GC.
|
||||
nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
|
||||
NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
|
||||
|
||||
JSRuntime *rt;
|
||||
svc->GetRuntime(&rt);
|
||||
NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
|
||||
JS::FinishOffThreadScript(rt, mScript);
|
||||
JSScript *script = JS::FinishOffThreadScript(NULL, rt, mToken);
|
||||
|
||||
return mReceiver->OnScriptCompileComplete(mScript, mScript ? NS_OK : NS_ERROR_FAILURE);
|
||||
return mReceiver->OnScriptCompileComplete(script, script ? NS_OK : NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
OffThreadScriptReceiverCallback(JSScript *script, void *ptr)
|
||||
OffThreadScriptReceiverCallback(void *aToken, void *aCallbackData)
|
||||
{
|
||||
// Be careful not to adjust the refcount on the receiver, as this callback
|
||||
// may be invoked off the main thread.
|
||||
nsIOffThreadScriptReceiver* aReceiver = static_cast<nsIOffThreadScriptReceiver*>(ptr);
|
||||
nsIOffThreadScriptReceiver* aReceiver = static_cast<nsIOffThreadScriptReceiver*>(aCallbackData);
|
||||
nsRefPtr<NotifyOffThreadScriptCompletedRunnable> notify =
|
||||
new NotifyOffThreadScriptCompletedRunnable(
|
||||
already_AddRefed<nsIOffThreadScriptReceiver>(aReceiver), script);
|
||||
already_AddRefed<nsIOffThreadScriptReceiver>(aReceiver), aToken);
|
||||
NS_DispatchToMainThread(notify);
|
||||
}
|
||||
|
||||
|
@ -1130,7 +1130,7 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
if (manifest.appcache_path) {
|
||||
debug("appcache found");
|
||||
this.startOfflineCacheDownload(manifest, app, null, null, isUpdate);
|
||||
this.startOfflineCacheDownload(manifest, app, null, isUpdate);
|
||||
} else {
|
||||
// hosted app with no appcache, nothing to do, but we fire a
|
||||
// downloaded event
|
||||
@ -1280,10 +1280,7 @@ this.DOMApplicationRegistry = {
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
startOfflineCacheDownload: function startOfflineCacheDownload(aManifest, aApp,
|
||||
aProfileDir,
|
||||
aOfflineCacheObserver,
|
||||
aIsUpdate) {
|
||||
startOfflineCacheDownload: function(aManifest, aApp, aProfileDir, aIsUpdate) {
|
||||
if (!aManifest.appcache_path) {
|
||||
return;
|
||||
}
|
||||
@ -1320,9 +1317,6 @@ this.DOMApplicationRegistry = {
|
||||
AppDownloadManager.add(aApp.manifestURL, download);
|
||||
|
||||
cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
|
||||
if (aOfflineCacheObserver) {
|
||||
cacheUpdate.addObserver(aOfflineCacheObserver, false);
|
||||
}
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
@ -1928,8 +1922,7 @@ this.DOMApplicationRegistry = {
|
||||
if (cacheDownload) {
|
||||
this.startOfflineCacheDownload(cacheDownload.manifest,
|
||||
cacheDownload.app,
|
||||
cacheDownload.profileDir,
|
||||
cacheDownload.offlineCacheObserver);
|
||||
cacheDownload.profileDir);
|
||||
delete this.queuedDownload[aManifestURL];
|
||||
|
||||
return;
|
||||
@ -1987,8 +1980,7 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
},
|
||||
|
||||
confirmInstall: function(aData, aProfileDir, aOfflineCacheObserver,
|
||||
aInstallSuccessCallback) {
|
||||
confirmInstall: function(aData, aProfileDir, aInstallSuccessCallback) {
|
||||
let isReinstall = false;
|
||||
let app = aData.app;
|
||||
app.removable = true;
|
||||
@ -2025,8 +2017,6 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
appObject.installTime = app.installTime = Date.now();
|
||||
appObject.lastUpdateCheck = app.lastUpdateCheck = Date.now();
|
||||
let appNote = JSON.stringify(appObject);
|
||||
appNote.id = id;
|
||||
|
||||
appObject.id = id;
|
||||
appObject.localId = localId;
|
||||
@ -2088,8 +2078,7 @@ this.DOMApplicationRegistry = {
|
||||
this.queuedDownload[app.manifestURL] = {
|
||||
manifest: manifest,
|
||||
app: appObject,
|
||||
profileDir: aProfileDir,
|
||||
offlineCacheObserver: aOfflineCacheObserver
|
||||
profileDir: aProfileDir
|
||||
}
|
||||
}
|
||||
|
||||
@ -2099,7 +2088,6 @@ this.DOMApplicationRegistry = {
|
||||
this._saveApps((function() {
|
||||
this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
|
||||
this.broadcastMessage("Webapps:Install:Return:OK", aData);
|
||||
Services.obs.notifyObservers(this, "webapps-sync-install", appNote);
|
||||
}).bind(this));
|
||||
|
||||
if (!aData.isPackage) {
|
||||
@ -2795,7 +2783,6 @@ this.DOMApplicationRegistry = {
|
||||
Cu.reportError("DOMApplicationRegistry: Exception on app uninstall: " +
|
||||
ex + "\n" + ex.stack);
|
||||
}
|
||||
Services.obs.notifyObservers(this, "webapps-sync-uninstall", JSON.stringify(appClone));
|
||||
this.broadcastMessage("Webapps:RemoveApp", { id: id });
|
||||
}).bind(this));
|
||||
},
|
||||
|
@ -4970,7 +4970,9 @@ nsGlobalWindow::DispatchResizeEvent(const nsIntSize& aSize)
|
||||
detail.mWidth = aSize.width;
|
||||
detail.mHeight = aSize.height;
|
||||
JS::Rooted<JS::Value> detailValue(cx);
|
||||
detail.ToObject(cx, JS::NullPtr(), &detailValue);
|
||||
if (!detail.ToObject(cx, JS::NullPtr(), &detailValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CustomEvent* customEvent = static_cast<CustomEvent*>(domEvent.get());
|
||||
customEvent->InitCustomEvent(cx,
|
||||
|
@ -16,9 +16,8 @@
|
||||
function testInt64NonFinite(arg) {
|
||||
// We can use a WebGLRenderingContext to test conversion to 64-bit signed
|
||||
// ints edge cases.
|
||||
try {
|
||||
var gl = $("c").getContext("experimental-webgl");
|
||||
} catch (ex) {
|
||||
if (!gl) {
|
||||
// No WebGL support on MacOS 10.5. Just skip this test
|
||||
todo(false, "WebGL not supported");
|
||||
return;
|
||||
|
@ -20,9 +20,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=775852
|
||||
|
||||
/** Test for Bug 775852 **/
|
||||
function doTest() {
|
||||
try {
|
||||
var gl = $("c").getContext("experimental-webgl");
|
||||
} catch (e) {
|
||||
if (!gl) {
|
||||
// No WebGL support on MacOS 10.5. Just skip this test
|
||||
todo(false, "WebGL not supported");
|
||||
return;
|
||||
|
@ -63,6 +63,7 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThr
|
||||
mWindow(aWindow)
|
||||
{
|
||||
MOZ_ASSERT(aWindow, "shouldn't be created with null window!");
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,6 +148,7 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThr
|
||||
{
|
||||
MOZ_ASSERT(aWindow, "shouldn't be created with null window!");
|
||||
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
|
||||
SetIsDOMBinding();
|
||||
|
||||
/**
|
||||
* nsDOMCameraControl is a cycle-collection participant, which means it is
|
||||
|
@ -639,16 +639,16 @@ ContactDB.prototype = {
|
||||
debug("InternationalNumber: " + parsedNumber.internationalNumber);
|
||||
debug("NationalNumber: " + parsedNumber.nationalNumber);
|
||||
debug("NationalFormat: " + parsedNumber.nationalFormat);
|
||||
debug("NationalMatchingFormat: " + parsedNumber.nationalMatchingFormat);
|
||||
}
|
||||
matchSearch[parsedNumber.nationalNumber] = 1;
|
||||
matchSearch[parsedNumber.internationalNumber] = 1;
|
||||
matchSearch[PhoneNumberUtils.normalize(parsedNumber.nationalFormat)] = 1;
|
||||
matchSearch[PhoneNumberUtils.normalize(parsedNumber.internationalFormat)] = 1;
|
||||
|
||||
if (this.substringMatching && normalized.length > this.substringMatching) {
|
||||
matchSearch[PhoneNumberUtils.normalize(parsedNumber.nationalMatchingFormat)] = 1;
|
||||
} else if (this.substringMatching && normalized.length > this.substringMatching) {
|
||||
matchSearch[normalized.slice(-this.substringMatching)] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// containsSearch holds incremental search values for:
|
||||
// normalized number and national format
|
||||
@ -663,12 +663,12 @@ ContactDB.prototype = {
|
||||
}
|
||||
}
|
||||
for (let num in containsSearch) {
|
||||
if (num != "null") {
|
||||
if (num && num != "null") {
|
||||
contact.search.tel.push(num);
|
||||
}
|
||||
}
|
||||
for (let num in matchSearch) {
|
||||
if (num != "null") {
|
||||
if (num && num != "null") {
|
||||
contact.search.parsedTel.push(num);
|
||||
}
|
||||
}
|
||||
@ -1016,6 +1016,7 @@ ContactDB.prototype = {
|
||||
let filter_keys = fields.slice();
|
||||
for (let key = filter_keys.shift(); key; key = filter_keys.shift()) {
|
||||
let request;
|
||||
let substringResult = {};
|
||||
if (key == "id") {
|
||||
// store.get would return an object and not an array
|
||||
request = store.mozGetAll(options.filterValue);
|
||||
@ -1043,16 +1044,26 @@ ContactDB.prototype = {
|
||||
let normalized = PhoneNumberUtils.normalize(options.filterValue,
|
||||
/*numbersOnly*/ true);
|
||||
|
||||
// Some countries need special handling for number matching. Bug 877302
|
||||
if (this.substringMatching && normalized.length > this.substringMatching) {
|
||||
normalized = normalized.slice(-this.substringMatching);
|
||||
}
|
||||
|
||||
if (!normalized.length) {
|
||||
dump("ContactDB: normalized filterValue is empty, can't perform match search.\n");
|
||||
return txn.abort();
|
||||
}
|
||||
|
||||
// Some countries need special handling for number matching. Bug 877302
|
||||
if (this.substringMatching && normalized.length > this.substringMatching) {
|
||||
let substring = normalized.slice(-this.substringMatching);
|
||||
if (DEBUG) debug("Substring: " + substring);
|
||||
|
||||
let substringRequest = index.mozGetAll(substring, limit);
|
||||
|
||||
substringRequest.onsuccess = function (event) {
|
||||
if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
|
||||
for (let i in event.target.result) {
|
||||
substringResult[event.target.result[i].id] = event.target.result[i];
|
||||
}
|
||||
}.bind(this);
|
||||
}
|
||||
|
||||
request = index.mozGetAll(normalized, limit);
|
||||
} else {
|
||||
// XXX: "contains" should be handled separately, this is "startsWith"
|
||||
@ -1085,6 +1096,11 @@ ContactDB.prototype = {
|
||||
|
||||
request.onsuccess = function (event) {
|
||||
if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
|
||||
if (Object.keys(substringResult).length > 0) {
|
||||
for (let attrname in substringResult) {
|
||||
event.target.result[attrname] = substringResult[attrname];
|
||||
}
|
||||
}
|
||||
this.sortResults(event.target.result, options);
|
||||
for (let i in event.target.result)
|
||||
txn.result[event.target.result[i].id] = exportContact(event.target.result[i]);
|
||||
|
@ -14,6 +14,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
MOCHITEST_FILES = \
|
||||
test_contacts_basics.html \
|
||||
test_contacts_substringmatching.html \
|
||||
test_contacts_substringmatchingVE.html \
|
||||
test_contacts_events.html \
|
||||
test_contacts_blobs.html \
|
||||
test_contacts_international.html \
|
||||
@ -25,4 +26,3 @@ MOCHITEST_CHROME_FILES = \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
@ -55,6 +55,15 @@ var prop2 = {
|
||||
tel: [{value: "01187654321" }]
|
||||
};
|
||||
|
||||
var prop3 = {
|
||||
tel: [{ value: "+43332112346" }]
|
||||
};
|
||||
|
||||
var prop4 = {
|
||||
tel: [{ value: "(0414) 233-9888" }]
|
||||
};
|
||||
|
||||
|
||||
var req;
|
||||
var index = 0;
|
||||
|
||||
@ -62,6 +71,15 @@ var mozContacts = window.navigator.mozContacts;
|
||||
ok(mozContacts, "mozContacts exists");
|
||||
ok("mozContact" in window, "mozContact exists");
|
||||
var steps = [
|
||||
function () {
|
||||
ok(true, "Deleting database");
|
||||
req = mozContacts.clear()
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Deleted the database");
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding contact");
|
||||
createResult1 = new mozContact();
|
||||
@ -239,6 +257,70 @@ var steps = [
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding contact");
|
||||
createResult1 = new mozContact();
|
||||
createResult1.init(prop3);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
sample_id1 = createResult1.id;
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
if (!isAndroid) { // Bug 905927
|
||||
ok(true, "Retrieving by substring 1");
|
||||
var length = prop3.tel[0].value.length;
|
||||
var num = prop3.tel[0].value.substring(length - substringLength, length);
|
||||
var options = {filterBy: ["tel"],
|
||||
filterOp: "match",
|
||||
filterValue: num};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 0, "Found exactly 0 contacts.");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
} else {
|
||||
SpecialPowers.executeSoon(next);
|
||||
}
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding contact");
|
||||
createResult1 = new mozContact();
|
||||
createResult1.init(prop4);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
sample_id1 = createResult1.id;
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving by substring 1");
|
||||
var num = "(0424) 233-9888"
|
||||
var options = {filterBy: ["tel"],
|
||||
filterOp: "match",
|
||||
filterValue: num};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 1, "Found exactly 1 contacts.");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Deleting database");
|
||||
req = mozContacts.clear()
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Deleted the database");
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "all done!\n");
|
||||
SpecialPowers.setIntPref("dom.phonenumber.substringmatching.BR", -1);
|
||||
|
182
dom/contacts/tests/test_contacts_substringmatchingVE.html
Normal file
182
dom/contacts/tests/test_contacts_substringmatchingVE.html
Normal file
@ -0,0 +1,182 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=877302
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 877302 substring matching for WebContacts</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.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=877302">Mozilla Bug 877302</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
"use strict";
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
|
||||
}
|
||||
|
||||
var substringLength = 7;
|
||||
SpecialPowers.setIntPref("dom.phonenumber.substringmatching.VE", substringLength);
|
||||
SpecialPowers.setCharPref("ril.lastKnownSimMcc", "734");
|
||||
|
||||
SpecialPowers.addPermission("contacts-write", true, document);
|
||||
SpecialPowers.addPermission("contacts-read", true, document);
|
||||
SpecialPowers.addPermission("contacts-create", true, document);
|
||||
|
||||
var isAndroid = (navigator.userAgent.indexOf("Android") !== -1);
|
||||
var androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
|
||||
.getService(SpecialPowers.Ci.nsIPropertyBag2)
|
||||
.getProperty('version');
|
||||
|
||||
var sample_id1;
|
||||
var createResult1;
|
||||
var findResult1;
|
||||
|
||||
function onFailure() {
|
||||
ok(false, "in on Failure!");
|
||||
next();
|
||||
}
|
||||
|
||||
var prop = {
|
||||
tel: [{value: "7932012345" }, {value: "7704143727591"}]
|
||||
};
|
||||
|
||||
var prop2 = {
|
||||
tel: [{value: "7932012345" }, {value: "+58 212 5551212"}]
|
||||
};
|
||||
|
||||
var req;
|
||||
var index = 0;
|
||||
|
||||
var mozContacts = window.navigator.mozContacts;
|
||||
ok(mozContacts, "mozContacts exists");
|
||||
ok("mozContact" in window, "mozContact exists");
|
||||
var steps = [
|
||||
function () {
|
||||
ok(true, "Deleting database");
|
||||
req = mozContacts.clear()
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Deleted the database");
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding contact");
|
||||
createResult1 = new mozContact();
|
||||
createResult1.init(prop);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
sample_id1 = createResult1.id;
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving all contacts");
|
||||
req = mozContacts.find({});
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 1, "One contact.");
|
||||
findResult1 = req.result[0];
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving by substring 1");
|
||||
var length = prop.tel[0].value.length;
|
||||
var num = "04143727591"
|
||||
var options = {filterBy: ["tel"],
|
||||
filterOp: "match",
|
||||
filterValue: num};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 1, "Found exactly 1 contact.");
|
||||
findResult1 = req.result[0];
|
||||
ok(findResult1.id == sample_id1, "Same ID");
|
||||
is(findResult1.tel[1].value, "7704143727591", "Same Value");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Adding contact");
|
||||
createResult1 = new mozContact();
|
||||
createResult1.init(prop2);
|
||||
req = navigator.mozContacts.save(createResult1);
|
||||
req.onsuccess = function () {
|
||||
ok(createResult1.id, "The contact now has an ID.");
|
||||
sample_id1 = createResult1.id;
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Retrieving by substring 2");
|
||||
var num = "5551212";
|
||||
var options = {filterBy: ["tel"],
|
||||
filterOp: "match",
|
||||
filterValue: num};
|
||||
req = mozContacts.find(options);
|
||||
req.onsuccess = function () {
|
||||
is(req.result.length, 1, "Found exactly 1 contact.");
|
||||
findResult1 = req.result[0];
|
||||
ok(findResult1.id == sample_id1, "Same ID");
|
||||
is(findResult1.tel[1].value, "+58 212 5551212", "Same Value");
|
||||
next();
|
||||
};
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "Deleting database");
|
||||
req = mozContacts.clear()
|
||||
req.onsuccess = function () {
|
||||
ok(true, "Deleted the database");
|
||||
next();
|
||||
}
|
||||
req.onerror = onFailure;
|
||||
},
|
||||
function () {
|
||||
ok(true, "all done!\n");
|
||||
SpecialPowers.setIntPref("dom.phonenumber.substringmatching.VE", -1);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
];
|
||||
|
||||
function next() {
|
||||
ok(true, "Begin!");
|
||||
if (index >= steps.length) {
|
||||
ok(false, "Shouldn't get here!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
steps[index]();
|
||||
} catch(ex) {
|
||||
ok(false, "Caught exception", ex);
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
// Skip tests on Android < 4.0 due to test failures on tbpl (see bugs 897924 & 888891)
|
||||
if (!isAndroid || androidVersion >= 14) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(next);
|
||||
} else {
|
||||
ok(true, "Skip tests on Android < 4.0 (bugs 897924 & 888891");
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -671,14 +671,56 @@ ContentChild::DeallocPBlobChild(PBlobChild* aActor)
|
||||
BlobChild*
|
||||
ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aBlob, "Null pointer!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
// If the blob represents a remote blob then we can simply pass its actor back
|
||||
// here.
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
|
||||
BlobChild* actor =
|
||||
static_cast<BlobChild*>(
|
||||
static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
|
||||
MOZ_ASSERT(actor);
|
||||
return actor;
|
||||
}
|
||||
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase. If that ever changes then this will need to grow
|
||||
// a real interface or something.
|
||||
const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
|
||||
// We often pass blobs that are multipart but that only contain one sub-blob
|
||||
// (WebActivities does this a bunch). Unwrap to reduce the number of actors
|
||||
// that we have to maintain.
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
|
||||
if (subBlobs && subBlobs->Length() == 1) {
|
||||
const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
|
||||
MOZ_ASSERT(subBlob);
|
||||
|
||||
// We can only take this shortcut if the multipart and the sub-blob are both
|
||||
// Blob objects or both File objects.
|
||||
nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
|
||||
nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
|
||||
if (!multipartBlobAsFile == !subBlobAsFile) {
|
||||
// The wrapping was unnecessary, see if we can simply pass an existing
|
||||
// remote blob.
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(subBlob)) {
|
||||
BlobChild* actor =
|
||||
static_cast<BlobChild*>(
|
||||
static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
|
||||
MOZ_ASSERT(actor);
|
||||
return actor;
|
||||
}
|
||||
|
||||
// No need to add a reference here since the original blob must have a
|
||||
// strong reference in the caller and it must also have a strong reference
|
||||
// to this sub-blob.
|
||||
aBlob = subBlob;
|
||||
blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
subBlobs = blob->GetSubBlobs();
|
||||
}
|
||||
}
|
||||
|
||||
// All blobs shared between processes must be immutable.
|
||||
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
|
||||
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
|
||||
@ -686,15 +728,6 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
|
||||
if (remoteBlob) {
|
||||
BlobChild* actor =
|
||||
static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
|
||||
NS_ASSERTION(actor, "Null actor?!");
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
ParentBlobConstructorParams params;
|
||||
|
||||
if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
|
||||
@ -748,11 +781,7 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
BlobChild* actor = BlobChild::Create(this, aBlob);
|
||||
NS_ENSURE_TRUE(actor, nullptr);
|
||||
|
||||
if (!SendPBlobConstructor(actor, params)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return actor;
|
||||
return SendPBlobConstructor(actor, params) ? actor : nullptr;
|
||||
}
|
||||
|
||||
PCrashReporterChild*
|
||||
|
@ -1881,14 +1881,62 @@ ContentParent::DeallocPBlobParent(PBlobParent* aActor)
|
||||
BlobParent*
|
||||
ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
NS_ASSERTION(aBlob, "Null pointer!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aBlob);
|
||||
|
||||
// If the blob represents a remote blob for this ContentParent then we can
|
||||
// simply pass its actor back here.
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
|
||||
BlobParent* actor =
|
||||
static_cast<BlobParent*>(
|
||||
static_cast<PBlobParent*>(remoteBlob->GetPBlob()));
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
if (static_cast<ContentParent*>(actor->Manager()) == this) {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX This is only safe so long as all blob implementations in our tree
|
||||
// inherit nsDOMFileBase. If that ever changes then this will need to grow
|
||||
// a real interface or something.
|
||||
const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
|
||||
// We often pass blobs that are multipart but that only contain one sub-blob
|
||||
// (WebActivities does this a bunch). Unwrap to reduce the number of actors
|
||||
// that we have to maintain.
|
||||
const nsTArray<nsCOMPtr<nsIDOMBlob> >* subBlobs = blob->GetSubBlobs();
|
||||
if (subBlobs && subBlobs->Length() == 1) {
|
||||
const nsCOMPtr<nsIDOMBlob>& subBlob = subBlobs->ElementAt(0);
|
||||
MOZ_ASSERT(subBlob);
|
||||
|
||||
// We can only take this shortcut if the multipart and the sub-blob are both
|
||||
// Blob objects or both File objects.
|
||||
nsCOMPtr<nsIDOMFile> multipartBlobAsFile = do_QueryInterface(aBlob);
|
||||
nsCOMPtr<nsIDOMFile> subBlobAsFile = do_QueryInterface(subBlob);
|
||||
if (!multipartBlobAsFile == !subBlobAsFile) {
|
||||
// The wrapping might have been unnecessary, see if we can simply pass an
|
||||
// existing remote blob for this ContentParent.
|
||||
if (nsCOMPtr<nsIRemoteBlob> remoteSubBlob = do_QueryInterface(subBlob)) {
|
||||
BlobParent* actor =
|
||||
static_cast<BlobParent*>(
|
||||
static_cast<PBlobParent*>(remoteSubBlob->GetPBlob()));
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
if (static_cast<ContentParent*>(actor->Manager()) == this) {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
// No need to add a reference here since the original blob must have a
|
||||
// strong reference in the caller and it must also have a strong reference
|
||||
// to this sub-blob.
|
||||
aBlob = subBlob;
|
||||
blob = static_cast<nsDOMFileBase*>(aBlob);
|
||||
subBlobs = blob->GetSubBlobs();
|
||||
}
|
||||
}
|
||||
|
||||
// All blobs shared between processes must be immutable.
|
||||
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
|
||||
if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
|
||||
@ -1896,18 +1944,6 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
|
||||
if (remoteBlob) {
|
||||
BlobParent* actor =
|
||||
static_cast<BlobParent*>(
|
||||
static_cast<PBlobParent*>(remoteBlob->GetPBlob()));
|
||||
NS_ASSERTION(actor, "Null actor?!");
|
||||
|
||||
if (static_cast<ContentParent*>(actor->Manager()) == this) {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
ChildBlobConstructorParams params;
|
||||
|
||||
if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
|
||||
@ -1951,11 +1987,7 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
|
||||
BlobParent* actor = BlobParent::Create(this, aBlob);
|
||||
NS_ENSURE_TRUE(actor, nullptr);
|
||||
|
||||
if (!SendPBlobConstructor(actor, params)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return actor;
|
||||
return SendPBlobConstructor(actor, params) ? actor : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -43,10 +43,16 @@ const kMobileMessageDeletedObserverTopic = "mobile-message-deleted";
|
||||
const HTTP_STATUS_OK = 200;
|
||||
|
||||
// Non-standard HTTP status for internal use.
|
||||
const _HTTP_STATUS_ACQUIRE_CONNECTION_SUCCESS = 0;
|
||||
const _HTTP_STATUS_USER_CANCELLED = -1;
|
||||
const _HTTP_STATUS_RADIO_DISABLED = -2;
|
||||
const _HTTP_STATUS_NO_SIM_CARD = -3;
|
||||
const _HTTP_STATUS_ACQUIRE_TIMEOUT = 4;
|
||||
|
||||
// Non-standard MMS status for internal use.
|
||||
const _MMS_ERROR_MESSAGE_DELETED = -1;
|
||||
const _MMS_ERROR_RADIO_DISABLED = -2;
|
||||
const _MMS_ERROR_NO_SIM_CARD = -3;
|
||||
|
||||
const CONFIG_SEND_REPORT_NEVER = 0;
|
||||
const CONFIG_SEND_REPORT_DEFAULT_NO = 1;
|
||||
@ -167,12 +173,13 @@ XPCOMUtils.defineLazyGetter(this, "gMmsConnection", function () {
|
||||
/**
|
||||
* Callback when |connectTimer| is timeout or cancelled by shutdown.
|
||||
*/
|
||||
onConnectTimerTimeout: function onConnectTimerTimeout() {
|
||||
if (DEBUG) debug("onConnectTimerTimeout: " + this.pendingCallbacks.length
|
||||
+ " pending callbacks");
|
||||
flushPendingCallbacks: function flushPendingCallbacks(status) {
|
||||
if (DEBUG) debug("flushPendingCallbacks: " + this.pendingCallbacks.length
|
||||
+ " pending callbacks with status: " + status);
|
||||
while (this.pendingCallbacks.length) {
|
||||
let callback = this.pendingCallbacks.shift();
|
||||
callback(false);
|
||||
let connected = (status == _HTTP_STATUS_ACQUIRE_CONNECTION_SUCCESS);
|
||||
callback(connected, status);
|
||||
}
|
||||
},
|
||||
|
||||
@ -236,8 +243,8 @@ XPCOMUtils.defineLazyGetter(this, "gMmsConnection", function () {
|
||||
* timeout, or failed. Accepts a boolean value that indicates
|
||||
* whether the connection is ready.
|
||||
*
|
||||
* @return true if the MMS network connection is already acquired and the
|
||||
* callback is done; false otherwise.
|
||||
* @return true if the callback for MMS network connection is done; false
|
||||
* otherwise.
|
||||
*/
|
||||
acquire: function acquire(callback) {
|
||||
this.connectTimer.cancel();
|
||||
@ -245,14 +252,28 @@ XPCOMUtils.defineLazyGetter(this, "gMmsConnection", function () {
|
||||
// If the MMS network is not yet connected, buffer the
|
||||
// MMS request and try to setup the MMS network first.
|
||||
if (!this.connected) {
|
||||
if (DEBUG) debug("acquire: buffer the MMS request and setup the MMS data call.");
|
||||
this.pendingCallbacks.push(callback);
|
||||
|
||||
let errorStatus;
|
||||
if (this.radioDisabled) {
|
||||
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
|
||||
errorStatus = _HTTP_STATUS_RADIO_DISABLED;
|
||||
} else if (gRadioInterface.rilContext.cardState != "ready") {
|
||||
if (DEBUG) debug("Error! SIM card is not ready when sending MMS.");
|
||||
errorStatus = _HTTP_STATUS_NO_SIM_CARD;
|
||||
}
|
||||
if (errorStatus != null) {
|
||||
this.flushPendingCallbacks(errorStatus);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DEBUG) debug("acquire: buffer the MMS request and setup the MMS data call.");
|
||||
gRadioInterface.setupDataCallByType("mms");
|
||||
|
||||
// Set a timer to clear the buffered MMS requests if the
|
||||
// MMS network fails to be connected within a time period.
|
||||
this.connectTimer.
|
||||
initWithCallback(this.onConnectTimerTimeout.bind(this),
|
||||
initWithCallback(this.flushPendingCallbacks.bind(this, _HTTP_STATUS_ACQUIRE_TIMEOUT),
|
||||
TIME_TO_BUFFER_MMS_REQUESTS,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
return false;
|
||||
@ -260,7 +281,7 @@ XPCOMUtils.defineLazyGetter(this, "gMmsConnection", function () {
|
||||
|
||||
this.refCount++;
|
||||
|
||||
callback(true);
|
||||
callback(true, _HTTP_STATUS_ACQUIRE_CONNECTION_SUCCESS);
|
||||
return true;
|
||||
},
|
||||
|
||||
@ -318,7 +339,7 @@ XPCOMUtils.defineLazyGetter(this, "gMmsConnection", function () {
|
||||
Services.prefs.removeObserver(name, this);
|
||||
}, this);
|
||||
this.connectTimer.cancel();
|
||||
this.onConnectTimerTimeout();
|
||||
this.flushPendingCallbacks(_HTTP_STATUS_RADIO_DISABLED);
|
||||
this.disconnectTimer.cancel();
|
||||
this.onDisconnectTimerTimeout();
|
||||
},
|
||||
@ -339,10 +360,7 @@ XPCOMUtils.defineLazyGetter(this, "gMmsConnection", function () {
|
||||
if (DEBUG) debug("Got the MMS network connected! Resend the buffered " +
|
||||
"MMS requests: number: " + this.pendingCallbacks.length);
|
||||
this.connectTimer.cancel();
|
||||
while (this.pendingCallbacks.length) {
|
||||
let callback = this.pendingCallbacks.shift();
|
||||
callback(true);
|
||||
}
|
||||
this.flushPendingCallbacks(_HTTP_STATUS_ACQUIRE_CONNECTION_SUCCESS)
|
||||
break;
|
||||
}
|
||||
case kPrefenceChangedObserverTopic: {
|
||||
@ -470,7 +488,7 @@ XPCOMUtils.defineLazyGetter(this, "gMmsTransactionHelper", function () {
|
||||
};
|
||||
|
||||
cancellable.isAcquiringConn =
|
||||
!gMmsConnection.acquire((function (connected) {
|
||||
!gMmsConnection.acquire((function (connected, errorCode) {
|
||||
|
||||
cancellable.isAcquiringConn = false;
|
||||
|
||||
@ -479,7 +497,7 @@ XPCOMUtils.defineLazyGetter(this, "gMmsTransactionHelper", function () {
|
||||
|
||||
if (!cancellable.isDone) {
|
||||
cancellable.done(cancellable.isCancelled ?
|
||||
_HTTP_STATUS_USER_CANCELLED : 0, null);
|
||||
_HTTP_STATUS_USER_CANCELLED : errorCode, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -649,6 +667,21 @@ XPCOMUtils.defineLazyGetter(this, "gMmsTransactionHelper", function () {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
translateHttpStatusToMmsStatus: function translateHttpStatusToMmsStatus(httpStatus, defaultStatus) {
|
||||
switch(httpStatus) {
|
||||
case _HTTP_STATUS_USER_CANCELLED:
|
||||
return _MMS_ERROR_MESSAGE_DELETED;
|
||||
case _HTTP_STATUS_RADIO_DISABLED:
|
||||
return _MMS_ERROR_RADIO_DISABLED;
|
||||
case _HTTP_STATUS_NO_SIM_CARD:
|
||||
return _MMS_ERROR_NO_SIM_CARD;
|
||||
case HTTP_STATUS_OK:
|
||||
return MMS.MMS_PDU_ERROR_OK;
|
||||
default:
|
||||
return defaultStatus;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -854,12 +887,14 @@ RetrieveTransaction.prototype = Object.create(CancellableTransaction.prototype,
|
||||
this.cancellable =
|
||||
gMmsTransactionHelper.sendRequest("GET", this.contentLocation, null,
|
||||
(function (httpStatus, data) {
|
||||
if (httpStatus == _HTTP_STATUS_USER_CANCELLED) {
|
||||
callback(_MMS_ERROR_MESSAGE_DELETED, null);
|
||||
let mmsStatus = gMmsTransactionHelper
|
||||
.translateHttpStatusToMmsStatus(httpStatus,
|
||||
MMS.MMS_PDU_STATUS_DEFERRED);
|
||||
if (mmsStatus != MMS.MMS_PDU_ERROR_OK) {
|
||||
callback(mmsStatus, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((httpStatus != HTTP_STATUS_OK) || !data) {
|
||||
if (!data) {
|
||||
callback(MMS.MMS_PDU_STATUS_DEFERRED, null);
|
||||
return;
|
||||
}
|
||||
@ -1084,13 +1119,11 @@ SendTransaction.prototype = Object.create(CancellableTransaction.prototype, {
|
||||
gMmsTransactionHelper.sendRequest("POST", gMmsConnection.mmsc,
|
||||
this.istream,
|
||||
function (httpStatus, data) {
|
||||
if (httpStatus == _HTTP_STATUS_USER_CANCELLED) {
|
||||
callback(_MMS_ERROR_MESSAGE_DELETED, null);
|
||||
return;
|
||||
}
|
||||
|
||||
let mmsStatus = gMmsTransactionHelper.
|
||||
translateHttpStatusToMmsStatus(httpStatus,
|
||||
MMS.MMS_PDU_ERROR_TRANSIENT_FAILURE);
|
||||
if (httpStatus != HTTP_STATUS_OK) {
|
||||
callback(MMS.MMS_PDU_ERROR_TRANSIENT_FAILURE, null);
|
||||
callback(mmsStatus, null);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1397,17 +1430,18 @@ MmsService.prototype = {
|
||||
|
||||
let reportAllowed = this.getReportAllowed(this.confSendDeliveryReport,
|
||||
wish);
|
||||
let transactionId = retrievedMessage.headers["x-mms-transaction-id"];
|
||||
|
||||
// If the mmsStatus isn't MMS_PDU_STATUS_RETRIEVED after retrieving,
|
||||
// something must be wrong with MMSC, so stop updating the DB record.
|
||||
// We could send a message to content to notify the user the MMS
|
||||
// retrieving failed. The end user has to retrieve the MMS again.
|
||||
if (MMS.MMS_PDU_STATUS_RETRIEVED !== mmsStatus) {
|
||||
if (mmsStatus != _MMS_ERROR_RADIO_DISABLED &&
|
||||
mmsStatus != _MMS_ERROR_NO_SIM_CARD) {
|
||||
let transaction = new NotifyResponseTransaction(transactionId,
|
||||
mmsStatus,
|
||||
reportAllowed);
|
||||
transaction.run();
|
||||
}
|
||||
// Retrieved fail after retry, so we update the delivery status in DB and
|
||||
// notify this domMessage that error happen.
|
||||
gMobileMessageDatabaseService
|
||||
@ -1424,6 +1458,7 @@ MmsService.prototype = {
|
||||
|
||||
savableMessage = this.mergeRetrievalConfirmation(retrievedMessage,
|
||||
savableMessage);
|
||||
let transactionId = savableMessage.headers["x-mms-transaction-id"];
|
||||
|
||||
gMobileMessageDatabaseService.saveReceivedMessage(savableMessage,
|
||||
(function (rv, domMessage) {
|
||||
@ -1850,22 +1885,6 @@ MmsService.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// For radio disabled error.
|
||||
if (gMmsConnection.radioDisabled) {
|
||||
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
|
||||
sendTransactionCb(aDomMessage,
|
||||
Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// For SIM card is not ready.
|
||||
if (gRadioInterface.rilContext.cardState != "ready") {
|
||||
if (DEBUG) debug("Error! SIM card is not ready when sending MMS.");
|
||||
sendTransactionCb(aDomMessage,
|
||||
Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the entry point starting to send MMS.
|
||||
let sendTransaction;
|
||||
try {
|
||||
@ -1883,13 +1902,19 @@ MmsService.prototype = {
|
||||
let errorCode;
|
||||
if (aMmsStatus == _MMS_ERROR_MESSAGE_DELETED) {
|
||||
errorCode = Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR;
|
||||
} else if (aMmsStatus == _MMS_ERROR_RADIO_DISABLED) {
|
||||
errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
|
||||
} else if (aMmsStatus == _MMS_ERROR_NO_SIM_CARD) {
|
||||
errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
|
||||
} else if (aMmsStatus != MMS.MMS_PDU_ERROR_OK) {
|
||||
errorCode = Ci.nsIMobileMessageCallback.INTERNAL_ERROR;
|
||||
} else {
|
||||
errorCode = Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR;
|
||||
}
|
||||
|
||||
let envelopeId = aMsg.headers ? aMsg.headers["message-id"] : null;
|
||||
let envelopeId = null;
|
||||
if (aMsg) {
|
||||
envelopeId = aMsg.headers ? aMsg.headers["message-id"] : null;
|
||||
}
|
||||
sendTransactionCb(aDomMessage, errorCode, envelopeId);
|
||||
});
|
||||
});
|
||||
@ -1959,6 +1984,12 @@ MmsService.prototype = {
|
||||
// status to 'error'.
|
||||
if (MMS.MMS_PDU_STATUS_RETRIEVED !== mmsStatus) {
|
||||
if (DEBUG) debug("RetrieveMessage fail after retry.");
|
||||
let errorCode = Ci.nsIMobileMessageCallback.INTERNAL_ERROR;
|
||||
if (mmsStatus == _MMS_ERROR_RADIO_DISABLED) {
|
||||
errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
|
||||
} else if (mmsStatus == _MMS_ERROR_NO_SIM_CARD) {
|
||||
errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
|
||||
}
|
||||
gMobileMessageDatabaseService
|
||||
.setMessageDeliveryByMessageId(aMessageId,
|
||||
null,
|
||||
@ -1966,7 +1997,7 @@ MmsService.prototype = {
|
||||
DELIVERY_STATUS_ERROR,
|
||||
null,
|
||||
function () {
|
||||
aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
|
||||
aRequest.notifyGetMessageFailed(errorCode);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -74,6 +74,12 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
*
|
||||
*/
|
||||
|
||||
function get_platform() {
|
||||
var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Components.interfaces.nsIXULRuntime);
|
||||
return xulRuntime.OS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spin up a listening socket and associate at most one live, accepted socket
|
||||
* with ourselves.
|
||||
@ -492,8 +498,12 @@ add_test(clientCloses);
|
||||
add_test(connectSock);
|
||||
add_test(bufferedClose);
|
||||
|
||||
// - get an error on an attempt to connect to a non-listening port
|
||||
add_test(badConnect);
|
||||
if (get_platform() !== "Darwin") {
|
||||
// This test intermittently fails way too often on OS X, for unknown reasons.
|
||||
// Please, diagnose and fix it if you can.
|
||||
// - get an error on an attempt to connect to a non-listening port
|
||||
add_test(badConnect);
|
||||
}
|
||||
|
||||
// send a buffer, get a drain, send a buffer, get a drain
|
||||
add_test(connectSock);
|
||||
|
@ -221,6 +221,12 @@ this.PhoneNumber = (function (dataBase) {
|
||||
: null;
|
||||
Object.defineProperty(this, "internationalNumber", { value: value, enumerable: true });
|
||||
return value;
|
||||
},
|
||||
// country name 'US'
|
||||
get countryName() {
|
||||
var value = this.region ? this.region : null;
|
||||
Object.defineProperty(this, "countryName", { value: value, enumerable: true });
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -64,7 +64,17 @@ this.PhoneNumberUtils = {
|
||||
mcc = this._mcc;
|
||||
}
|
||||
#else
|
||||
|
||||
// Attempt to grab last known sim mcc from prefs
|
||||
if (!mcc) {
|
||||
try {
|
||||
mcc = Services.prefs.getCharPref("ril.lastKnownSimMcc");
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (!mcc) {
|
||||
mcc = this._mcc;
|
||||
}
|
||||
#endif
|
||||
|
||||
countryName = MCC_ISO3166_TABLE[mcc];
|
||||
@ -75,15 +85,32 @@ this.PhoneNumberUtils = {
|
||||
parse: function(aNumber) {
|
||||
if (DEBUG) debug("call parse: " + aNumber);
|
||||
let result = PhoneNumber.Parse(aNumber, this.getCountryName());
|
||||
if (DEBUG) {
|
||||
|
||||
if (result) {
|
||||
let countryName = result.countryName || this.getCountryName();
|
||||
let number = null;
|
||||
if (countryName) {
|
||||
if (Services.prefs.getPrefType("dom.phonenumber.substringmatching." + countryName) == Ci.nsIPrefBranch.PREF_INT) {
|
||||
let val = Services.prefs.getIntPref("dom.phonenumber.substringmatching." + countryName);
|
||||
if (val) {
|
||||
number = result.internationalNumber || result.nationalNumber;
|
||||
if (number && number.length > val) {
|
||||
number = number.slice(-val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Object.defineProperty(result, "nationalMatchingFormat", { value: number, enumerable: true });
|
||||
if (DEBUG) {
|
||||
debug("InternationalFormat: " + result.internationalFormat);
|
||||
debug("InternationalNumber: " + result.internationalNumber);
|
||||
debug("NationalNumber: " + result.nationalNumber);
|
||||
debug("NationalFormat: " + result.nationalFormat);
|
||||
} else {
|
||||
debug("No result!\n");
|
||||
debug("CountryName: " + result.countryName);
|
||||
debug("NationalMatchingFormat: " + result.nationalMatchingFormat);
|
||||
}
|
||||
} else if (DEBUG) {
|
||||
debug("NO PARSING RESULT!");
|
||||
}
|
||||
return result;
|
||||
},
|
||||
@ -116,8 +143,8 @@ this.PhoneNumberUtils = {
|
||||
let parsed1 = this.parse(aNumber1);
|
||||
let parsed2 = this.parse(aNumber2);
|
||||
if (parsed1 && parsed2) {
|
||||
if (parsed1.internationalNumber === parsed2.internationalNumber
|
||||
|| parsed1.nationalNumber === parsed2.nationalNumber) {
|
||||
if ((parsed1.internationalNumber && parsed1.internationalNumber === parsed2.internationalNumber)
|
||||
|| (parsed1.nationalNumber && parsed1.nationalNumber === parsed2.nationalNumber)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -125,7 +152,8 @@ this.PhoneNumberUtils = {
|
||||
let ssPref = "dom.phonenumber.substringmatching." + countryName;
|
||||
if (Services.prefs.getPrefType(ssPref) == Ci.nsIPrefBranch.PREF_INT) {
|
||||
let val = Services.prefs.getIntPref(ssPref);
|
||||
if (normalized1.slice(-val) === normalized2.slice(-val)) {
|
||||
if (normalized1.length > val && normalized2.length > val
|
||||
&& normalized1.slice(-val) === normalized2.slice(-val)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +115,21 @@ function TestProperties(dial, currentRegion) {
|
||||
}
|
||||
}
|
||||
|
||||
function TestPropertiesWithExpectedCountry(dial, currentRegion, expectedRegion) {
|
||||
var result = PhoneNumber.Parse(dial, currentRegion);
|
||||
if (result) {
|
||||
ok(true, "found it");
|
||||
ok(true, "InternationalFormat: " + result.internationalFormat);
|
||||
ok(true, "InternationalNumber: " + result.internationalNumber);
|
||||
ok(true, "NationalNumber: " + result.nationalNumber);
|
||||
ok(true, "NationalFormat: " + result.nationalFormat);
|
||||
ok(true, "CountryName: " + result.countryName);
|
||||
is(result.countryName, expectedRegion, "Same region");
|
||||
} else {
|
||||
ok(true, "not found");
|
||||
}
|
||||
}
|
||||
|
||||
function AllEqual(list, currentRegion) {
|
||||
var first = PhoneNumber.Parse(list.shift(), currentRegion);
|
||||
ok(!!first, "first parses");
|
||||
@ -134,6 +149,9 @@ TestProperties("+66554433");
|
||||
TestProperties("+43442075");
|
||||
TestProperties("+13442074");
|
||||
|
||||
TestPropertiesWithExpectedCountry("+4333822222", "DE", "AT");
|
||||
TestPropertiesWithExpectedCountry("+19491234567", "DE", "US");
|
||||
|
||||
// Test whether could a string be a phone number.
|
||||
IsPlain(null, false);
|
||||
IsPlain("", false);
|
||||
|
@ -23,7 +23,7 @@ Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
Services.prefs.setIntPref("dom.phonenumber.substringmatching.BR", 8);
|
||||
Services.prefs.setCharPref("ril.lastKnownSimMcc", "310");
|
||||
Services.prefs.setCharPref("ril.lastKnownSimMcc", "724");
|
||||
|
||||
var pm = SpecialPowers.Cc["@mozilla.org/permissionmanager;1"]
|
||||
.getService(SpecialPowers.Ci.nsIPermissionManager);
|
||||
|
@ -24,7 +24,7 @@ Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/PhoneNumberUtils.jsm");
|
||||
|
||||
Services.prefs.setIntPref("dom.phonenumber.substringmatching.BR", 8);
|
||||
Services.prefs.setCharPref("ril.lastKnownSimMcc", "310");
|
||||
Services.prefs.setCharPref("ril.lastKnownSimMcc", "724");
|
||||
|
||||
function CantParseWithMcc(dial, mcc) {
|
||||
var result = PhoneNumberUtils.parseWithMCC(dial, mcc);
|
||||
|
@ -625,9 +625,20 @@ this.PushService = {
|
||||
|
||||
/** |delay| should be in milliseconds. */
|
||||
_setAlarm: function(delay) {
|
||||
// Bug 909270: Since calls to AlarmService.add() are async, calls must be
|
||||
// 'queued' to ensure only one alarm is ever active.
|
||||
if (this._settingAlarm) {
|
||||
// onSuccess will handle the set. Overwriting the variable enforces the
|
||||
// last-writer-wins semantics.
|
||||
this._queuedAlarmDelay = delay;
|
||||
this._waitingForAlarmSet = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop any existing alarm.
|
||||
this._stopAlarm();
|
||||
|
||||
this._settingAlarm = true;
|
||||
AlarmService.add(
|
||||
{
|
||||
date: new Date(Date.now() + delay),
|
||||
@ -637,6 +648,12 @@ this.PushService = {
|
||||
function onSuccess(alarmID) {
|
||||
this._alarmID = alarmID;
|
||||
debug("Set alarm " + delay + " in the future " + this._alarmID);
|
||||
this._settingAlarm = false;
|
||||
|
||||
if (this._waitingForAlarmSet) {
|
||||
this._waitingForAlarmSet = false;
|
||||
this._setAlarm(this._queuedAlarmDelay);
|
||||
}
|
||||
}.bind(this)
|
||||
)
|
||||
},
|
||||
@ -1441,6 +1458,11 @@ this.PushService = {
|
||||
_getNetworkState: function() {
|
||||
debug("getNetworkState()");
|
||||
try {
|
||||
if (!prefs.get("udp.wakeupEnabled")) {
|
||||
debug("UDP support disabled, we do not send any carrier info");
|
||||
throw "UDP disabled";
|
||||
}
|
||||
|
||||
var nm = Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
|
||||
if (nm.active && nm.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
|
||||
var mcp = Cc["@mozilla.org/ril/content-helper;1"].getService(Ci.nsIMobileConnectionProvider);
|
||||
|
@ -74,6 +74,7 @@ const DOM_MOBILE_MESSAGE_DELIVERY_SENT = "sent";
|
||||
const DOM_MOBILE_MESSAGE_DELIVERY_ERROR = "error";
|
||||
|
||||
const CALL_WAKELOCK_TIMEOUT = 5000;
|
||||
const RADIO_POWER_OFF_TIMEOUT = 30000;
|
||||
|
||||
const RIL_IPC_TELEPHONY_MSG_NAMES = [
|
||||
"RIL:EnumerateCalls",
|
||||
@ -1516,14 +1517,52 @@ RadioInterface.prototype = {
|
||||
|
||||
if (this.rilContext.radioState == RIL.GECKO_RADIOSTATE_OFF &&
|
||||
this._radioEnabled) {
|
||||
this._changingRadioPower = true;
|
||||
this.setRadioEnabled(true);
|
||||
}
|
||||
if (this.rilContext.radioState == RIL.GECKO_RADIOSTATE_READY &&
|
||||
!this._radioEnabled) {
|
||||
this.setRadioEnabled(false);
|
||||
this._changingRadioPower = true;
|
||||
this.powerOffRadioSafely();
|
||||
}
|
||||
},
|
||||
|
||||
_radioOffTimer: null,
|
||||
_cancelRadioOffTimer: function _cancelRadioOffTimer() {
|
||||
if (this._radioOffTimer) {
|
||||
this._radioOffTimer.cancel();
|
||||
}
|
||||
},
|
||||
_fireRadioOffTimer: function _fireRadioOffTimer() {
|
||||
if (DEBUG) this.debug("Radio off timer expired, set radio power off right away.");
|
||||
this.setRadioEnabled(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clean up all existing data calls before turning radio off.
|
||||
*/
|
||||
powerOffRadioSafely: function powerOffRadioSafely() {
|
||||
let dataDisconnecting = false;
|
||||
for each (let apnSetting in this.apnSettings.byAPN) {
|
||||
for each (let type in apnSetting.types) {
|
||||
if (this.getDataCallStateByType(type) ==
|
||||
RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
this.deactivateDataCallByType(type);
|
||||
dataDisconnecting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dataDisconnecting) {
|
||||
if (this._radioOffTimer == null) {
|
||||
this._radioOffTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
}
|
||||
this._radioOffTimer.initWithCallback(this._fireRadioOffTimer.bind(this),
|
||||
RADIO_POWER_OFF_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
return;
|
||||
}
|
||||
this.setRadioEnabled(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* This function will do the following steps:
|
||||
* 1. Clear the old APN settings.
|
||||
@ -2086,6 +2125,29 @@ RadioInterface.prototype = {
|
||||
|
||||
this._deliverDataCallCallback("dataCallStateChanged",
|
||||
[datacall]);
|
||||
|
||||
// Process pending radio power off request after all data calls
|
||||
// are disconnected.
|
||||
if (datacall.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
|
||||
this._changingRadioPower) {
|
||||
let anyDataConnected = false;
|
||||
for each (let apnSetting in this.apnSettings.byAPN) {
|
||||
for each (let type in apnSetting.types) {
|
||||
if (this.getDataCallStateByType(type) == RIL.GECKO_NETWORK_STATE_CONNECTED) {
|
||||
anyDataConnected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (anyDataConnected) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!anyDataConnected) {
|
||||
if (DEBUG) this.debug("All data connections are disconnected, set radio off.");
|
||||
this._cancelRadioOffTimer();
|
||||
this.setRadioEnabled(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2398,7 +2460,6 @@ RadioInterface.prototype = {
|
||||
|
||||
setRadioEnabled: function setRadioEnabled(value) {
|
||||
if (DEBUG) this.debug("Setting radio power to " + value);
|
||||
this._changingRadioPower = true;
|
||||
this.workerMessenger.send("setRadioPower", { on: value });
|
||||
},
|
||||
|
||||
|
@ -16,9 +16,9 @@ interface DOMTokenList {
|
||||
[Throws]
|
||||
boolean contains(DOMString token);
|
||||
[Throws]
|
||||
void add(DOMString token);
|
||||
void add(DOMString... tokens);
|
||||
[Throws]
|
||||
void remove(DOMString token);
|
||||
void remove(DOMString... tokens);
|
||||
[Throws]
|
||||
boolean toggle(DOMString token, optional boolean force);
|
||||
stringifier DOMString ();
|
||||
|
@ -129,10 +129,123 @@ GfxTexturesReporter::UpdateAmount(MemoryUse action, GLenum format,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - we should really know the ARB/EXT variants of these
|
||||
* instead of only handling the symbol if it's exposed directly.
|
||||
static bool
|
||||
ParseGLVersion(GLContext* gl, unsigned int* version)
|
||||
{
|
||||
GLenum error = gl->fGetError();
|
||||
if (error != LOCAL_GL_NO_ERROR) {
|
||||
MOZ_ASSERT(false, "An OpenGL error has been triggered before.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* B2G emulator bug work around: The emulator implements OpenGL ES 2.0 on
|
||||
* OpenGL 3.2. The bug is that GetIntegerv(LOCAL_GL_{MAJOR,MINOR}_VERSION)
|
||||
* returns OpenGL 3.2 instead of generating an error.
|
||||
*/
|
||||
if (!gl->IsGLES())
|
||||
{
|
||||
/**
|
||||
* OpenGL 3.1 and OpenGL ES 3.0 both introduce GL_{MAJOR,MINOR}_VERSION
|
||||
* with GetIntegerv. So we first try those constants even though we
|
||||
* might not have an OpenGL context supporting them, has this is a
|
||||
* better way than parsing GL_VERSION.
|
||||
*/
|
||||
GLint majorVersion = 0;
|
||||
GLint minorVersion = 0;
|
||||
|
||||
gl->fGetIntegerv(LOCAL_GL_MAJOR_VERSION, &majorVersion);
|
||||
gl->fGetIntegerv(LOCAL_GL_MINOR_VERSION, &minorVersion);
|
||||
|
||||
// If it's not an OpenGL (ES) 3.0 context, we will have an error
|
||||
error = gl->fGetError();
|
||||
if (error == LOCAL_GL_NO_ERROR &&
|
||||
majorVersion > 0 &&
|
||||
minorVersion >= 0)
|
||||
{
|
||||
*version = majorVersion * 100 + minorVersion * 10;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We were not able to use GL_{MAJOR,MINOR}_VERSION, so we parse
|
||||
* GL_VERSION.
|
||||
*
|
||||
*
|
||||
* OpenGL 2.x, 3.x, 4.x specifications:
|
||||
* The VERSION and SHADING_LANGUAGE_VERSION strings are laid out as follows:
|
||||
*
|
||||
* <version number><space><vendor-specific information>
|
||||
*
|
||||
* The version number is either of the form major_number.minor_number or
|
||||
* major_number.minor_number.release_number, where the numbers all have
|
||||
* one or more digits.
|
||||
*
|
||||
*
|
||||
* OpenGL ES 2.0, 3.0 specifications:
|
||||
* The VERSION string is laid out as follows:
|
||||
*
|
||||
* "OpenGL ES N.M vendor-specific information"
|
||||
*
|
||||
* The version number is either of the form major_number.minor_number or
|
||||
* major_number.minor_number.release_number, where the numbers all have
|
||||
* one or more digits.
|
||||
*
|
||||
*
|
||||
* Note:
|
||||
* We don't care about release_number.
|
||||
*/
|
||||
const char* versionString = (const char*)gl->fGetString(LOCAL_GL_VERSION);
|
||||
|
||||
error = gl->fGetError();
|
||||
if (error != LOCAL_GL_NO_ERROR) {
|
||||
MOZ_ASSERT(false, "glGetString(GL_VERSION) has generated an error");
|
||||
return false;
|
||||
} else if (!versionString) {
|
||||
MOZ_ASSERT(false, "glGetString(GL_VERSION) has returned 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char kGLESVersionPrefix[] = "OpenGL ES ";
|
||||
if (strncmp(versionString, kGLESVersionPrefix, strlen(kGLESVersionPrefix)) == 0) {
|
||||
versionString += strlen(kGLESVersionPrefix);
|
||||
}
|
||||
|
||||
const char* itr = versionString;
|
||||
char* end = nullptr;
|
||||
int majorVersion = (int)strtol(itr, &end, 10);
|
||||
|
||||
if (!end) {
|
||||
MOZ_ASSERT(false, "Failed to parse the GL major version number.");
|
||||
return false;
|
||||
} else if (*end != '.') {
|
||||
MOZ_ASSERT(false, "Failed to parse GL's major-minor version number separator.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// we skip the '.' between the major and the minor version
|
||||
itr = end + 1;
|
||||
|
||||
end = nullptr;
|
||||
|
||||
int minorVersion = (int)strtol(itr, &end, 10);
|
||||
if (!end) {
|
||||
MOZ_ASSERT(false, "Failed to parse GL's minor version number.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (majorVersion <= 0 || majorVersion >= 100) {
|
||||
MOZ_ASSERT(false, "Invalid major version.");
|
||||
return false;
|
||||
} else if (minorVersion < 0 || minorVersion >= 10) {
|
||||
MOZ_ASSERT(false, "Invalid minor version.");
|
||||
return false;
|
||||
}
|
||||
|
||||
*version = (unsigned int)(majorVersion * 100 + minorVersion * 10);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
@ -293,6 +406,19 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
|
||||
mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
|
||||
|
||||
if (mInitialized) {
|
||||
unsigned int version = 0;
|
||||
|
||||
bool parseSuccess = ParseGLVersion(this, &version);
|
||||
printf_stderr("OpenGL version detected: %u\n", version);
|
||||
|
||||
if (version >= mVersion) {
|
||||
mVersion = version;
|
||||
} else if (parseSuccess) {
|
||||
MOZ_ASSERT(false, "Parsed version less than expected.");
|
||||
}
|
||||
}
|
||||
|
||||
// Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
|
||||
if (mInitialized) {
|
||||
if (IsGLES2()) {
|
||||
|
@ -258,7 +258,7 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
|
||||
|
||||
pc.construct(&parser, (GenericParseContext *) NULL, (ParseNode *) NULL, &globalsc,
|
||||
(Directives *) NULL, staticLevel, /* bodyid = */ 0);
|
||||
if (!pc.ref().init())
|
||||
if (!pc.ref().init(parser.tokenStream))
|
||||
return NULL;
|
||||
|
||||
/* If this is a direct call to eval, inherit the caller's strictness. */
|
||||
@ -325,7 +325,7 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
|
||||
pc.destroy();
|
||||
pc.construct(&parser, (GenericParseContext *) NULL, (ParseNode *) NULL,
|
||||
&globalsc, (Directives *) NULL, staticLevel, /* bodyid = */ 0);
|
||||
if (!pc.ref().init())
|
||||
if (!pc.ref().init(parser.tokenStream))
|
||||
return NULL;
|
||||
JS_ASSERT(parser.pc == pc.addr());
|
||||
pn = parser.statement();
|
||||
|
@ -16,9 +16,9 @@ namespace frontend {
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
ParseContext<ParseHandler>::init()
|
||||
ParseContext<ParseHandler>::init(TokenStream &ts)
|
||||
{
|
||||
if (!frontend::GenerateBlockId(this, this->bodyid))
|
||||
if (!frontend::GenerateBlockId(ts, this, this->bodyid))
|
||||
return false;
|
||||
|
||||
return decls_.init() && lexdeps.ensureMap(sc->context);
|
||||
|
@ -70,13 +70,10 @@ typedef Handle<StaticBlockObject*> HandleStaticBlockObject;
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
GenerateBlockId(ParseContext<ParseHandler> *pc, uint32_t &blockid)
|
||||
GenerateBlockId(TokenStream &ts, ParseContext<ParseHandler> *pc, uint32_t &blockid)
|
||||
{
|
||||
if (pc->blockidGen == JS_BIT(20)) {
|
||||
if (!pc->sc->context->isJSContext())
|
||||
return false;
|
||||
JS_ReportErrorNumber(pc->sc->context->asJSContext(),
|
||||
js_GetErrorMessage, NULL, JSMSG_NEED_DIET, "program");
|
||||
ts.reportError(JSMSG_NEED_DIET, "program");
|
||||
return false;
|
||||
}
|
||||
JS_ASSERT(pc->blockidGen < JS_BIT(20));
|
||||
@ -85,10 +82,10 @@ GenerateBlockId(ParseContext<ParseHandler> *pc, uint32_t &blockid)
|
||||
}
|
||||
|
||||
template bool
|
||||
GenerateBlockId(ParseContext<SyntaxParseHandler> *pc, uint32_t &blockid);
|
||||
GenerateBlockId(TokenStream &ts, ParseContext<SyntaxParseHandler> *pc, uint32_t &blockid);
|
||||
|
||||
template bool
|
||||
GenerateBlockId(ParseContext<FullParseHandler> *pc, uint32_t &blockid);
|
||||
GenerateBlockId(TokenStream &ts, ParseContext<FullParseHandler> *pc, uint32_t &blockid);
|
||||
|
||||
template <typename ParseHandler>
|
||||
static void
|
||||
@ -625,7 +622,7 @@ Parser<ParseHandler>::parse(JSObject *chain)
|
||||
ParseContext<ParseHandler> globalpc(this, /* parent = */ NULL, ParseHandler::null(),
|
||||
&globalsc, /* newDirectives = */ NULL,
|
||||
/* staticLevel = */ 0, /* bodyid = */ 0);
|
||||
if (!globalpc.init())
|
||||
if (!globalpc.init(tokenStream))
|
||||
return null();
|
||||
|
||||
Node pn = statements();
|
||||
@ -887,7 +884,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoN
|
||||
|
||||
ParseContext<FullParseHandler> funpc(this, pc, fn, funbox, newDirectives,
|
||||
/* staticLevel = */ 0, /* bodyid = */ 0);
|
||||
if (!funpc.init())
|
||||
if (!funpc.init(tokenStream))
|
||||
return null();
|
||||
|
||||
for (unsigned i = 0; i < formals.length(); i++) {
|
||||
@ -2143,7 +2140,7 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
||||
ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox,
|
||||
newDirectives, outerpc->staticLevel + 1,
|
||||
outerpc->blockidGen);
|
||||
if (!funpc.init())
|
||||
if (!funpc.init(tokenStream))
|
||||
return false;
|
||||
|
||||
if (!parser->functionArgsAndBodyGeneric(SyntaxParseHandler::NodeGeneric,
|
||||
@ -2175,7 +2172,7 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
|
||||
// Continue doing a full parse for this inner function.
|
||||
ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives,
|
||||
outerpc->staticLevel + 1, outerpc->blockidGen);
|
||||
if (!funpc.init())
|
||||
if (!funpc.init(tokenStream))
|
||||
return false;
|
||||
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
|
||||
@ -2214,7 +2211,7 @@ Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
|
||||
// Initialize early for possible flags mutation via destructuringExpr.
|
||||
ParseContext<SyntaxParseHandler> funpc(this, pc, handler.null(), funbox, newDirectives,
|
||||
outerpc->staticLevel + 1, outerpc->blockidGen);
|
||||
if (!funpc.init())
|
||||
if (!funpc.init(tokenStream))
|
||||
return false;
|
||||
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, type, kind, newDirectives))
|
||||
@ -2249,7 +2246,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned st
|
||||
Directives newDirectives = directives;
|
||||
ParseContext<FullParseHandler> funpc(this, /* parent = */ NULL, pn, funbox,
|
||||
&newDirectives, staticLevel, /* bodyid = */ 0);
|
||||
if (!funpc.init())
|
||||
if (!funpc.init(tokenStream))
|
||||
return null();
|
||||
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, Normal, Statement, &newDirectives)) {
|
||||
@ -2378,7 +2375,7 @@ Parser<FullParseHandler>::moduleDecl()
|
||||
ParseContext<FullParseHandler> modulepc(this, pc, /* function = */ NULL, modulebox,
|
||||
/* newDirectives = */ NULL, pc->staticLevel + 1,
|
||||
pc->blockidGen);
|
||||
if (!modulepc.init())
|
||||
if (!modulepc.init(tokenStream))
|
||||
return NULL;
|
||||
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_MODULE);
|
||||
pn->pn_body = statements();
|
||||
@ -3263,7 +3260,7 @@ Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInf
|
||||
if (!pn)
|
||||
return null();
|
||||
|
||||
if (!GenerateBlockId(pc, stmt->blockid))
|
||||
if (!GenerateBlockId(tokenStream, pc, stmt->blockid))
|
||||
return null();
|
||||
handler.setBlockId(pn, stmt->blockid);
|
||||
return pn;
|
||||
@ -3414,10 +3411,11 @@ Parser<ParseHandler>::letBlock(LetContext letContext)
|
||||
|
||||
template <typename ParseHandler>
|
||||
static bool
|
||||
PushBlocklikeStatement(StmtInfoPC *stmt, StmtType type, ParseContext<ParseHandler> *pc)
|
||||
PushBlocklikeStatement(TokenStream &ts, StmtInfoPC *stmt, StmtType type,
|
||||
ParseContext<ParseHandler> *pc)
|
||||
{
|
||||
PushStatementPC(pc, stmt, type);
|
||||
return GenerateBlockId(pc, stmt->blockid);
|
||||
return GenerateBlockId(ts, pc, stmt->blockid);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
@ -3427,7 +3425,7 @@ Parser<ParseHandler>::blockStatement()
|
||||
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
|
||||
|
||||
StmtInfoPC stmtInfo(context);
|
||||
if (!PushBlocklikeStatement(&stmtInfo, STMT_BLOCK, pc))
|
||||
if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_BLOCK, pc))
|
||||
return null();
|
||||
|
||||
Node list = statements();
|
||||
@ -4343,7 +4341,7 @@ Parser<ParseHandler>::switchStatement()
|
||||
StmtInfoPC stmtInfo(context);
|
||||
PushStatementPC(pc, &stmtInfo, STMT_SWITCH);
|
||||
|
||||
if (!GenerateBlockId(pc, pc->topStmt->blockid))
|
||||
if (!GenerateBlockId(tokenStream, pc, pc->topStmt->blockid))
|
||||
return null();
|
||||
|
||||
Node caseList = handler.newStatementList(pc->blockid(), pos());
|
||||
@ -4802,7 +4800,7 @@ Parser<ParseHandler>::tryStatement()
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
|
||||
StmtInfoPC stmtInfo(context);
|
||||
if (!PushBlocklikeStatement(&stmtInfo, STMT_TRY, pc))
|
||||
if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_TRY, pc))
|
||||
return null();
|
||||
Node innerBlock = statements();
|
||||
if (!innerBlock)
|
||||
@ -4925,7 +4923,7 @@ Parser<ParseHandler>::tryStatement()
|
||||
|
||||
if (tt == TOK_FINALLY) {
|
||||
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
|
||||
if (!PushBlocklikeStatement(&stmtInfo, STMT_FINALLY, pc))
|
||||
if (!PushBlocklikeStatement(tokenStream, &stmtInfo, STMT_FINALLY, pc))
|
||||
return null();
|
||||
finallyBlock = statements();
|
||||
if (!finallyBlock)
|
||||
@ -6126,7 +6124,7 @@ Parser<FullParseHandler>::generatorExpr(ParseNode *kid)
|
||||
ParseContext<FullParseHandler> genpc(this, outerpc, genfn, genFunbox,
|
||||
/* newDirectives = */ NULL, outerpc->staticLevel + 1,
|
||||
outerpc->blockidGen);
|
||||
if (!genpc.init())
|
||||
if (!genpc.init(tokenStream))
|
||||
return null();
|
||||
|
||||
/*
|
||||
|
@ -76,7 +76,7 @@ struct GenericParseContext
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
GenerateBlockId(ParseContext<ParseHandler> *pc, uint32_t &blockid);
|
||||
GenerateBlockId(TokenStream &ts, ParseContext<ParseHandler> *pc, uint32_t &blockid);
|
||||
|
||||
/*
|
||||
* The struct ParseContext stores information about the current parsing context,
|
||||
@ -269,7 +269,7 @@ struct ParseContext : public GenericParseContext
|
||||
|
||||
~ParseContext();
|
||||
|
||||
bool init();
|
||||
bool init(TokenStream &ts);
|
||||
|
||||
unsigned blockid() { return topStmt ? topStmt->blockid : bodyid; }
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "jscntxt.h"
|
||||
#include "jsexn.h"
|
||||
#include "jsnum.h"
|
||||
#include "jsworkers.h"
|
||||
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
@ -30,6 +31,7 @@ using namespace js;
|
||||
using namespace js::frontend;
|
||||
using namespace js::unicode;
|
||||
|
||||
using mozilla::Maybe;
|
||||
using mozilla::PodAssign;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::PodZero;
|
||||
@ -564,7 +566,7 @@ TokenStream::reportStrictModeErrorNumberVA(uint32_t offset, bool strictMode, uns
|
||||
}
|
||||
|
||||
void
|
||||
CompileError::throwError()
|
||||
CompileError::throwError(JSContext *cx)
|
||||
{
|
||||
// If there's a runtime exception type associated with this error
|
||||
// number, set that as the pending exception. For errors occuring at
|
||||
@ -622,12 +624,10 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
|
||||
warning = false;
|
||||
}
|
||||
|
||||
if (!this->cx->isJSContext())
|
||||
return warning;
|
||||
|
||||
JSContext *cx = this->cx->asJSContext();
|
||||
|
||||
CompileError err(cx);
|
||||
// On the main thread, report the error immediately. When compiling off
|
||||
// thread, save the error so that the main thread can report it later.
|
||||
CompileError tempErr;
|
||||
CompileError &err = cx->isJSContext() ? tempErr : cx->addPendingCompileError();
|
||||
|
||||
err.report.flags = flags;
|
||||
err.report.errorNumber = errorNumber;
|
||||
@ -697,7 +697,8 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
|
||||
err.report.uctokenptr = err.report.uclinebuf + windowOffset;
|
||||
}
|
||||
|
||||
err.throwError();
|
||||
if (cx->isJSContext())
|
||||
err.throwError(cx->asJSContext());
|
||||
|
||||
return warning;
|
||||
}
|
||||
|
@ -307,17 +307,16 @@ struct Token {
|
||||
};
|
||||
|
||||
struct CompileError {
|
||||
JSContext *cx;
|
||||
JSErrorReport report;
|
||||
char *message;
|
||||
ErrorArgumentsType argumentsType;
|
||||
CompileError(JSContext *cx)
|
||||
: cx(cx), message(NULL), argumentsType(ArgumentsAreUnicode)
|
||||
CompileError()
|
||||
: message(NULL), argumentsType(ArgumentsAreUnicode)
|
||||
{
|
||||
mozilla::PodZero(&report);
|
||||
}
|
||||
~CompileError();
|
||||
void throwError();
|
||||
void throwError(JSContext *cx);
|
||||
};
|
||||
|
||||
// Ideally, tokenizing would be entirely independent of context. But the
|
||||
|
26
js/src/jit-test/tests/ion/bug909401.js
Normal file
26
js/src/jit-test/tests/ion/bug909401.js
Normal file
@ -0,0 +1,26 @@
|
||||
var TZ_PST = -8;
|
||||
var TZ_DIFF = GetTimezoneOffset();
|
||||
var PST_DIFF = TZ_DIFF - TZ_PST;
|
||||
function GetTimezoneOffset() {}
|
||||
function adjustResultArray(ResultArray) {
|
||||
var t = ResultArray[TIME] - PST_DIFF;
|
||||
ResultArray[UTC_YEAR] = YearFromTime(t);
|
||||
}
|
||||
function TimeInYear( y ) {}
|
||||
function YearFromTime( t ) {
|
||||
var sign = ( t < 0 ) ? -1 : 1;
|
||||
var year = ( sign < 0 ) ? 1969 : 1970;
|
||||
for ( var timeToTimeZero = t; ; ) {
|
||||
timeToTimeZero -= sign * TimeInYear(year)
|
||||
break;
|
||||
}
|
||||
return ( year );
|
||||
}
|
||||
gczeal(4);
|
||||
evaluate("\
|
||||
var TIME = 0;\
|
||||
var UTC_YEAR = 1;\
|
||||
adjustResultArray([]);\
|
||||
adjustResultArray([946684800000-1]);\
|
||||
adjustResultArray([]);\
|
||||
", { noScriptRval : true });
|
@ -4611,7 +4611,7 @@ ParseFunction(ModuleCompiler &m, ParseNode **fnOut)
|
||||
Directives newDirectives = directives;
|
||||
AsmJSParseContext funpc(&m.parser(), outerpc, fn, funbox, &newDirectives,
|
||||
outerpc->staticLevel + 1, outerpc->blockidGen);
|
||||
if (!funpc.init())
|
||||
if (!funpc.init(m.parser().tokenStream))
|
||||
return false;
|
||||
|
||||
if (!m.parser().functionArgsAndBodyGeneric(fn, fun, Normal, Statement, &newDirectives))
|
||||
|
@ -2860,10 +2860,10 @@ MacroAssemblerARMCompat::loadValue(Address src, ValueOperand val)
|
||||
void
|
||||
MacroAssemblerARMCompat::tagValue(JSValueType type, Register payload, ValueOperand dest)
|
||||
{
|
||||
JS_ASSERT(payload != dest.typeReg());
|
||||
ma_mov(ImmType(type), dest.typeReg());
|
||||
JS_ASSERT(dest.typeReg() != dest.payloadReg());
|
||||
if (payload != dest.payloadReg())
|
||||
ma_mov(payload, dest.payloadReg());
|
||||
ma_mov(ImmType(type), dest.typeReg());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -486,7 +486,7 @@ StoreAllLiveRegs(MacroAssembler &masm, RegisterSet liveRegs)
|
||||
masm.loadJitActivation(scratch);
|
||||
|
||||
Address checkRegs(scratch, JitActivation::offsetOfCheckRegs());
|
||||
masm.store32(Imm32(1), checkRegs);
|
||||
masm.add32(Imm32(1), checkRegs);
|
||||
|
||||
StoreOp op(masm);
|
||||
HandleRegisterDump<StoreOp>(op, masm, liveRegs, scratch, allRegs.getAny());
|
||||
@ -539,6 +539,13 @@ CodeGeneratorShared::verifyOsiPointRegs(LSafepoint *safepoint)
|
||||
Address checkRegs(scratch, JitActivation::offsetOfCheckRegs());
|
||||
masm.branch32(Assembler::Equal, checkRegs, Imm32(0), &done);
|
||||
|
||||
// Having more than one VM function call made in one visit function at
|
||||
// runtime is a sec-ciritcal error, because if we conservatively assume that
|
||||
// one of the function call can re-enter Ion, then the invalidation process
|
||||
// will potentially add a call at a random location, by patching the code
|
||||
// before the return address.
|
||||
masm.branch32(Assembler::NotEqual, checkRegs, Imm32(1), &failure);
|
||||
|
||||
// Ignore temp registers. Some instructions (like LValueToInt32) modify
|
||||
// temps after calling into the VM. This is fine because no other
|
||||
// instructions (including this OsiPoint) will depend on them.
|
||||
|
@ -175,10 +175,10 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
loadValue(Operand(src), val);
|
||||
}
|
||||
void tagValue(JSValueType type, Register payload, ValueOperand dest) {
|
||||
JS_ASSERT(payload != dest.typeReg());
|
||||
movl(ImmType(type), dest.typeReg());
|
||||
JS_ASSERT(dest.typeReg() != dest.payloadReg());
|
||||
if (payload != dest.payloadReg())
|
||||
movl(payload, dest.payloadReg());
|
||||
movl(ImmType(type), dest.typeReg());
|
||||
}
|
||||
void pushValue(ValueOperand val) {
|
||||
push(val.typeReg());
|
||||
|
@ -1749,11 +1749,7 @@ JS_PUBLIC_API(char *)
|
||||
JS_strdup(JSContext *cx, const char *s)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
size_t n = strlen(s) + 1;
|
||||
void *p = cx->malloc_(n);
|
||||
if (!p)
|
||||
return NULL;
|
||||
return (char *)js_memcpy(p, s, n);
|
||||
return js_strdup(cx, s);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(char *)
|
||||
@ -4892,18 +4888,18 @@ JS::CompileOffThread(JSContext *cx, Handle<JSObject*> obj, CompileOptions option
|
||||
JS_ASSERT(CanCompileOffThread(cx, options));
|
||||
return StartOffThreadParseScript(cx, options, chars, length, obj, callback, callbackData);
|
||||
#else
|
||||
MOZ_ASSUME_UNREACHABLE("Off thread compilation is only available with JS_ION");
|
||||
MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available.");
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::FinishOffThreadScript(JSRuntime *rt, JSScript *script)
|
||||
JS_PUBLIC_API(JSScript *)
|
||||
JS::FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token)
|
||||
{
|
||||
#ifdef JS_WORKER_THREADS
|
||||
JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
|
||||
rt->workerThreadState->finishParseTaskForScript(rt, script);
|
||||
return rt->workerThreadState->finishParseTask(maybecx, rt, token);
|
||||
#else
|
||||
MOZ_ASSUME_UNREACHABLE("Off thread compilation is only available with JS_ION");
|
||||
MOZ_ASSUME_UNREACHABLE("Off thread compilation is not available.");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -3569,12 +3569,12 @@ CanCompileOffThread(JSContext *cx, const CompileOptions &options);
|
||||
* Off thread compilation control flow.
|
||||
*
|
||||
* After successfully triggering an off thread compile of a script, the
|
||||
* callback will eventually be invoked with the specified data and the result
|
||||
* script or NULL. The callback will be invoked while off the main thread, so
|
||||
* must ensure that its operations are thread safe. Afterwards,
|
||||
* FinishOffThreadScript must be invoked on the main thread to make the script
|
||||
* usable (correct compartment/zone); this method must be invoked even if the
|
||||
* off thread compilation produced a NULL script.
|
||||
* callback will eventually be invoked with the specified data and a token
|
||||
* for the compilation. The callback will be invoked while off the main thread,
|
||||
* so must ensure that its operations are thread safe. Afterwards,
|
||||
* FinishOffThreadScript must be invoked on the main thread to get the result
|
||||
* script or NULL. If maybecx is specified, this method will also report any
|
||||
* error or warnings generated during the parse.
|
||||
*
|
||||
* The characters passed in to CompileOffThread must remain live until the
|
||||
* callback is invoked, and the resulting script will be rooted until the call
|
||||
@ -3586,8 +3586,8 @@ CompileOffThread(JSContext *cx, Handle<JSObject*> obj, CompileOptions options,
|
||||
const jschar *chars, size_t length,
|
||||
OffThreadCompileCallback callback, void *callbackData);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
FinishOffThreadScript(JSRuntime *rt, JSScript *script);
|
||||
extern JS_PUBLIC_API(JSScript *)
|
||||
FinishOffThreadScript(JSContext *maybecx, JSRuntime *rt, void *token);
|
||||
|
||||
extern JS_PUBLIC_API(JSFunction *)
|
||||
CompileFunction(JSContext *cx, JS::Handle<JSObject*> obj, CompileOptions options,
|
||||
|
@ -623,6 +623,16 @@ js::PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *re
|
||||
return true;
|
||||
}
|
||||
|
||||
char *
|
||||
js_strdup(ExclusiveContext *cx, const char *s)
|
||||
{
|
||||
size_t n = strlen(s) + 1;
|
||||
void *p = cx->malloc_(n);
|
||||
if (!p)
|
||||
return NULL;
|
||||
return (char *)js_memcpy(p, s, n);
|
||||
}
|
||||
|
||||
/*
|
||||
* The arguments from ap need to be packaged up into an array and stored
|
||||
* into the report struct.
|
||||
@ -635,7 +645,7 @@ js::PrintError(JSContext *cx, FILE *file, const char *message, JSErrorReport *re
|
||||
* Returns true if the expansion succeeds (can fail if out of memory).
|
||||
*/
|
||||
bool
|
||||
js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
||||
js_ExpandErrorArguments(ExclusiveContext *cx, JSErrorCallback callback,
|
||||
void *userRef, const unsigned errorNumber,
|
||||
char **messagep, JSErrorReport *reportp,
|
||||
ErrorArgumentsType argumentsType, va_list ap)
|
||||
@ -752,7 +762,7 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
||||
*/
|
||||
if (efs->format) {
|
||||
size_t len;
|
||||
*messagep = JS_strdup(cx, efs->format);
|
||||
*messagep = js_strdup(cx, efs->format);
|
||||
if (!*messagep)
|
||||
goto error;
|
||||
len = strlen(*messagep);
|
||||
|
@ -106,6 +106,8 @@ class RegExpCompartment;
|
||||
class RegExpStatics;
|
||||
class ForkJoinSlice;
|
||||
|
||||
namespace frontend { struct CompileError; }
|
||||
|
||||
/*
|
||||
* Execution Context Overview:
|
||||
*
|
||||
@ -375,7 +377,7 @@ class ExclusiveContext : public ThreadSafeContext
|
||||
return runtime_->scriptDataTable();
|
||||
}
|
||||
|
||||
#if defined(JS_ION) && defined(JS_THREADSAFE)
|
||||
#ifdef JS_WORKER_THREADS
|
||||
// Since JSRuntime::workerThreadState is necessarily initialized from the
|
||||
// main thread before the first worker thread can access it, there is no
|
||||
// possibility for a race read/writing it.
|
||||
@ -383,6 +385,9 @@ class ExclusiveContext : public ThreadSafeContext
|
||||
return runtime_->workerThreadState;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Methods specific to any WorkerThread for the context.
|
||||
frontend::CompileError &addPendingCompileError();
|
||||
};
|
||||
|
||||
inline void
|
||||
@ -743,7 +748,7 @@ js_ReportErrorNumberUCArray(JSContext *cx, unsigned flags, JSErrorCallback callb
|
||||
#endif
|
||||
|
||||
extern bool
|
||||
js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
||||
js_ExpandErrorArguments(js::ExclusiveContext *cx, JSErrorCallback callback,
|
||||
void *userRef, const unsigned errorNumber,
|
||||
char **message, JSErrorReport *reportp,
|
||||
js::ErrorArgumentsType argumentsType, va_list ap);
|
||||
@ -809,6 +814,9 @@ js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumb
|
||||
|
||||
extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
|
||||
|
||||
char *
|
||||
js_strdup(js::ExclusiveContext *cx, const char *s);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
# define JS_ASSERT_REQUEST_DEPTH(cx) JS_ASSERT((cx)->runtime()->requestDepth >= 1)
|
||||
#else
|
||||
@ -964,11 +972,11 @@ class AutoAssertNoException
|
||||
*/
|
||||
class ContextAllocPolicy
|
||||
{
|
||||
JSContext *const cx_;
|
||||
ThreadSafeContext *const cx_;
|
||||
|
||||
public:
|
||||
ContextAllocPolicy(JSContext *cx) : cx_(cx) {}
|
||||
JSContext *context() const { return cx_; }
|
||||
ContextAllocPolicy(ThreadSafeContext *cx) : cx_(cx) {}
|
||||
ThreadSafeContext *context() const { return cx_; }
|
||||
void *malloc_(size_t bytes) { return cx_->malloc_(bytes); }
|
||||
void *calloc_(size_t bytes) { return cx_->calloc_(bytes); }
|
||||
void *realloc_(void *p, size_t oldBytes, size_t bytes) { return cx_->realloc_(p, oldBytes, bytes); }
|
||||
|
@ -857,15 +857,22 @@ js_InitExceptionClasses(JSContext *cx, HandleObject obj)
|
||||
}
|
||||
|
||||
const JSErrorFormatString*
|
||||
js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
|
||||
js_GetLocalizedErrorMessage(ExclusiveContext *cx, void *userRef, const char *locale,
|
||||
const unsigned errorNumber)
|
||||
{
|
||||
const JSErrorFormatString *errorString = NULL;
|
||||
|
||||
if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeGetErrorMessage) {
|
||||
errorString = cx->runtime()->localeCallbacks
|
||||
->localeGetErrorMessage(userRef, locale, errorNumber);
|
||||
// The locale callbacks might not be thread safe, so don't call them if
|
||||
// we're not on the main thread. When used with XPConnect,
|
||||
// |localeGetErrorMessage| will be NULL anyways.
|
||||
if (cx->isJSContext() &&
|
||||
cx->asJSContext()->runtime()->localeCallbacks &&
|
||||
cx->asJSContext()->runtime()->localeCallbacks->localeGetErrorMessage)
|
||||
{
|
||||
JSLocaleCallbacks *callbacks = cx->asJSContext()->runtime()->localeCallbacks;
|
||||
errorString = callbacks->localeGetErrorMessage(userRef, locale, errorNumber);
|
||||
}
|
||||
|
||||
if (!errorString)
|
||||
errorString = js_GetErrorMessage(userRef, locale, errorNumber);
|
||||
return errorString;
|
||||
|
@ -54,7 +54,7 @@ extern JSErrorReport *
|
||||
js_ErrorFromException(jsval exn);
|
||||
|
||||
extern const JSErrorFormatString *
|
||||
js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale,
|
||||
js_GetLocalizedErrorMessage(js::ExclusiveContext *cx, void *userRef, const char *locale,
|
||||
const unsigned errorNumber);
|
||||
|
||||
/*
|
||||
|
@ -192,7 +192,7 @@ typedef void
|
||||
|
||||
namespace JS {
|
||||
|
||||
typedef void (*OffThreadCompileCallback)(JSScript *script, void *callbackData);
|
||||
typedef void (*OffThreadCompileCallback)(void *token, void *callbackData);
|
||||
|
||||
namespace shadow {
|
||||
|
||||
|
@ -173,14 +173,14 @@ static JSClass workerGlobalClass = {
|
||||
JS_ConvertStub, NULL
|
||||
};
|
||||
|
||||
ParseTask::ParseTask(Zone *zone, ExclusiveContext *cx, const CompileOptions &options,
|
||||
ParseTask::ParseTask(ExclusiveContext *cx, const CompileOptions &options,
|
||||
const jschar *chars, size_t length, JSObject *scopeChain,
|
||||
JS::OffThreadCompileCallback callback, void *callbackData)
|
||||
: zone(zone), cx(cx), options(options), chars(chars), length(length),
|
||||
: cx(cx), options(options), chars(chars), length(length),
|
||||
alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), scopeChain(scopeChain),
|
||||
callback(callback), callbackData(callbackData), script(NULL)
|
||||
callback(callback), callbackData(callbackData), script(NULL), errors(cx)
|
||||
{
|
||||
JSRuntime *rt = zone->runtimeFromMainThread();
|
||||
JSRuntime *rt = scopeChain->runtimeFromMainThread();
|
||||
|
||||
if (options.principals())
|
||||
JS_HoldPrincipals(options.principals());
|
||||
@ -192,7 +192,7 @@ ParseTask::ParseTask(Zone *zone, ExclusiveContext *cx, const CompileOptions &opt
|
||||
|
||||
ParseTask::~ParseTask()
|
||||
{
|
||||
JSRuntime *rt = zone->runtimeFromMainThread();
|
||||
JSRuntime *rt = scopeChain->runtimeFromMainThread();
|
||||
|
||||
if (options.principals())
|
||||
JS_DropPrincipals(rt, options.principals());
|
||||
@ -263,7 +263,7 @@ js::StartOffThreadParseScript(JSContext *cx, const CompileOptions &options,
|
||||
workercx->enterCompartment(global->compartment());
|
||||
|
||||
ScopedJSDeletePtr<ParseTask> task(
|
||||
cx->new_<ParseTask>(global->zone(), workercx.get(), options, chars, length,
|
||||
cx->new_<ParseTask>(workercx.get(), options, chars, length,
|
||||
scopeChain, callback, callbackData));
|
||||
if (!task)
|
||||
return false;
|
||||
@ -372,10 +372,8 @@ WorkerThreadState::cleanup(JSRuntime *rt)
|
||||
}
|
||||
|
||||
// Clean up any parse tasks which haven't been finished yet.
|
||||
while (!parseFinishedList.empty()) {
|
||||
JSScript *script = parseFinishedList[0]->script;
|
||||
finishParseTaskForScript(rt, script);
|
||||
}
|
||||
while (!parseFinishedList.empty())
|
||||
finishParseTask(/* maybecx = */ NULL, rt, parseFinishedList[0]);
|
||||
}
|
||||
|
||||
WorkerThreadState::~WorkerThreadState()
|
||||
@ -498,15 +496,16 @@ WorkerThreadState::canStartCompressionTask()
|
||||
return !compressionWorklist.empty();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerThreadState::finishParseTaskForScript(JSRuntime *rt, JSScript *script)
|
||||
JSScript *
|
||||
WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token)
|
||||
{
|
||||
ParseTask *parseTask = NULL;
|
||||
|
||||
// The token is a ParseTask* which should be in the finished list.
|
||||
{
|
||||
AutoLockWorkerThreadState lock(*rt->workerThreadState);
|
||||
for (size_t i = 0; i < parseFinishedList.length(); i++) {
|
||||
if (parseFinishedList[i]->script == script) {
|
||||
if (parseFinishedList[i] == token) {
|
||||
parseTask = parseFinishedList[i];
|
||||
parseFinishedList[i] = parseFinishedList.back();
|
||||
parseFinishedList.popBack();
|
||||
@ -518,23 +517,16 @@ WorkerThreadState::finishParseTaskForScript(JSRuntime *rt, JSScript *script)
|
||||
|
||||
// Mark the zone as no longer in use by an ExclusiveContext, and available
|
||||
// to be collected by the GC.
|
||||
rt->clearUsedByExclusiveThread(parseTask->zone);
|
||||
|
||||
if (!script) {
|
||||
// Parsing failed and there is nothing to finish, but there still may
|
||||
// be lingering ParseTask instances holding roots which need to be
|
||||
// cleaned up. The ParseTask which we picked might not be the right
|
||||
// one but this is ok as finish calls will be 1:1 with calls that
|
||||
// create a ParseTask.
|
||||
js_delete(parseTask);
|
||||
return;
|
||||
}
|
||||
rt->clearUsedByExclusiveThread(parseTask->cx->zone());
|
||||
|
||||
// Point the prototypes of any objects in the script's compartment to refer
|
||||
// to the corresponding prototype in the new compartment. This will briefly
|
||||
// create cross compartment pointers, which will be fixed by the
|
||||
// MergeCompartments call below.
|
||||
for (gc::CellIter iter(parseTask->zone, gc::FINALIZE_TYPE_OBJECT); !iter.done(); iter.next()) {
|
||||
for (gc::CellIter iter(parseTask->cx->zone(), gc::FINALIZE_TYPE_OBJECT);
|
||||
!iter.done();
|
||||
iter.next())
|
||||
{
|
||||
types::TypeObject *object = iter.get<types::TypeObject>();
|
||||
JSObject *proto = object->proto;
|
||||
if (!proto)
|
||||
@ -551,9 +543,19 @@ WorkerThreadState::finishParseTaskForScript(JSRuntime *rt, JSScript *script)
|
||||
}
|
||||
|
||||
// Move the parsed script and all its contents into the desired compartment.
|
||||
gc::MergeCompartments(parseTask->script->compartment(), parseTask->scopeChain->compartment());
|
||||
gc::MergeCompartments(parseTask->cx->compartment(), parseTask->scopeChain->compartment());
|
||||
|
||||
// If we have a context, report any error or warnings generated during the
|
||||
// parse.
|
||||
if (maybecx) {
|
||||
AutoCompartment ac(maybecx, parseTask->scopeChain);
|
||||
for (size_t i = 0; i < parseTask->errors.length(); i++)
|
||||
parseTask->errors[i].throwError(maybecx);
|
||||
}
|
||||
|
||||
JSScript *script = parseTask->script;
|
||||
js_delete(parseTask);
|
||||
return script;
|
||||
}
|
||||
|
||||
void
|
||||
@ -672,6 +674,14 @@ ExclusiveContext::setWorkerThread(WorkerThread *workerThread)
|
||||
this->perThreadData = workerThread->threadData.addr();
|
||||
}
|
||||
|
||||
frontend::CompileError &
|
||||
ExclusiveContext::addPendingCompileError()
|
||||
{
|
||||
if (!workerThread->parseTask->errors.append(frontend::CompileError()))
|
||||
MOZ_CRASH();
|
||||
return workerThread->parseTask->errors.back();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerThread::handleParseWorkload(WorkerThreadState &state)
|
||||
{
|
||||
@ -691,7 +701,7 @@ WorkerThread::handleParseWorkload(WorkerThreadState &state)
|
||||
}
|
||||
|
||||
// The callback is invoked while we are still off the main thread.
|
||||
parseTask->callback(parseTask->script, parseTask->callbackData);
|
||||
parseTask->callback(parseTask, parseTask->callbackData);
|
||||
|
||||
// FinishOffThreadScript will need to be called on the script to
|
||||
// migrate it into the correct compartment.
|
||||
@ -1000,4 +1010,10 @@ AutoPauseWorkersForGC::~AutoPauseWorkersForGC()
|
||||
{
|
||||
}
|
||||
|
||||
frontend::CompileError &
|
||||
ExclusiveContext::addPendingCompileError()
|
||||
{
|
||||
MOZ_ASSUME_UNREACHABLE("Off thread compilation not available.");
|
||||
}
|
||||
|
||||
#endif /* JS_WORKER_THREADS */
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "jscntxt.h"
|
||||
#include "jslock.h"
|
||||
|
||||
#include "frontend/TokenStream.h"
|
||||
#include "jit/Ion.h"
|
||||
|
||||
namespace js {
|
||||
@ -119,7 +120,7 @@ class WorkerThreadState
|
||||
return asmJSFailedFunction;
|
||||
}
|
||||
|
||||
void finishParseTaskForScript(JSRuntime *rt, JSScript *script);
|
||||
JSScript *finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token);
|
||||
bool compressionInProgress(SourceCompressionTask *task);
|
||||
SourceCompressionTask *compressionTaskForSource(ScriptSource *ss);
|
||||
|
||||
@ -366,7 +367,6 @@ struct AsmJSParallelTask
|
||||
|
||||
struct ParseTask
|
||||
{
|
||||
Zone *zone;
|
||||
ExclusiveContext *cx;
|
||||
CompileOptions options;
|
||||
const jschar *chars;
|
||||
@ -387,7 +387,11 @@ struct ParseTask
|
||||
// ParseTask.
|
||||
JSScript *script;
|
||||
|
||||
ParseTask(Zone *zone, ExclusiveContext *cx, const CompileOptions &options,
|
||||
// Any errors or warnings produced during compilation. These are reported
|
||||
// when finishing the script.
|
||||
Vector<frontend::CompileError> errors;
|
||||
|
||||
ParseTask(ExclusiveContext *cx, const CompileOptions &options,
|
||||
const jschar *chars, size_t length, JSObject *scopeChain,
|
||||
JS::OffThreadCompileCallback callback, void *callbackData);
|
||||
|
||||
|
@ -3237,7 +3237,7 @@ SyntaxParse(JSContext *cx, unsigned argc, jsval *vp)
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
static void
|
||||
OffThreadCompileScriptCallback(JSScript *script, void *callbackData)
|
||||
OffThreadCompileScriptCallback(void *token, void *callbackData)
|
||||
{
|
||||
// This callback is invoked off the main thread and there isn't a good way
|
||||
// to pass the script on to the main thread. Just let the script leak.
|
||||
|
@ -26,7 +26,7 @@ StringBuffer::extractWellSized()
|
||||
JS_ASSERT(capacity >= length);
|
||||
if (length > CharBuffer::sMaxInlineStorage && capacity - length > length / 4) {
|
||||
size_t bytes = sizeof(jschar) * (length + 1);
|
||||
JSContext *cx = context();
|
||||
ExclusiveContext *cx = context();
|
||||
jschar *tmp = (jschar *)cx->realloc_(buf, bytes);
|
||||
if (!tmp) {
|
||||
js_free(buf);
|
||||
@ -41,7 +41,7 @@ StringBuffer::extractWellSized()
|
||||
JSFlatString *
|
||||
StringBuffer::finishString()
|
||||
{
|
||||
JSContext *cx = context();
|
||||
ExclusiveContext *cx = context();
|
||||
if (cb.empty())
|
||||
return cx->names().empty;
|
||||
|
||||
@ -69,7 +69,7 @@ StringBuffer::finishString()
|
||||
JSAtom *
|
||||
StringBuffer::finishAtom()
|
||||
{
|
||||
JSContext *cx = context();
|
||||
ExclusiveContext *cx = context();
|
||||
|
||||
size_t length = cb.length();
|
||||
if (length == 0)
|
||||
|
@ -33,13 +33,15 @@ class StringBuffer
|
||||
|
||||
CharBuffer cb;
|
||||
|
||||
JSContext *context() const { return cb.allocPolicy().context(); }
|
||||
ExclusiveContext *context() const {
|
||||
return cb.allocPolicy().context()->asExclusiveContext();
|
||||
}
|
||||
|
||||
StringBuffer(const StringBuffer &other) MOZ_DELETE;
|
||||
void operator=(const StringBuffer &other) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
explicit StringBuffer(JSContext *cx) : cb(cx) { }
|
||||
explicit StringBuffer(ExclusiveContext *cx) : cb(cx) { }
|
||||
|
||||
inline bool reserve(size_t len) { return cb.reserve(len); }
|
||||
inline bool resize(size_t len) { return cb.resize(len); }
|
||||
@ -121,7 +123,7 @@ StringBuffer::appendInflated(const char *cstr, size_t cstrlen)
|
||||
if (!cb.growByUninitialized(cstrlen))
|
||||
return false;
|
||||
mozilla::DebugOnly<size_t> oldcstrlen = cstrlen;
|
||||
mozilla::DebugOnly<bool> ok = InflateStringToBuffer(context(), cstr, cstrlen,
|
||||
mozilla::DebugOnly<bool> ok = InflateStringToBuffer(NULL, cstr, cstrlen,
|
||||
begin() + lengthBefore, &cstrlen);
|
||||
JS_ASSERT(ok && oldcstrlen == cstrlen);
|
||||
return true;
|
||||
|
91
js/xpconnect/tests/unit/head_watchdog.js
Normal file
91
js/xpconnect/tests/unit/head_watchdog.js
Normal file
@ -0,0 +1,91 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//
|
||||
// Pref management.
|
||||
//
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
var gPrefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
|
||||
function setWatchdogEnabled(enabled) {
|
||||
gPrefs.setBoolPref("dom.use_watchdog", enabled);
|
||||
}
|
||||
|
||||
function isWatchdogEnabled() {
|
||||
return gPrefs.getBoolPref("dom.use_watchdog");
|
||||
}
|
||||
|
||||
//
|
||||
// Utilities.
|
||||
//
|
||||
|
||||
function busyWait(ms) {
|
||||
var start = new Date();
|
||||
while ((new Date()) - start < ms) {}
|
||||
}
|
||||
|
||||
function do_log_info(aMessage)
|
||||
{
|
||||
print("TEST-INFO | " + _TEST_FILE + " | " + aMessage);
|
||||
}
|
||||
|
||||
// We don't use do_execute_soon, because that inserts a
|
||||
// do_test_{pending,finished} pair that gets screwed up when we terminate scripts
|
||||
// from the operation callback.
|
||||
function executeSoon(fn) {
|
||||
var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
||||
tm.mainThread.dispatch({run: fn}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
//
|
||||
// Asynchronous watchdog diagnostics.
|
||||
//
|
||||
// When running, the watchdog wakes up every second, and fires the operation
|
||||
// callback if the script has been running for >= one second. As such, a script
|
||||
// should never be able to run for two seconds or longer without servicing the
|
||||
// operation callback. We wait 3 seconds, just to be safe.
|
||||
//
|
||||
|
||||
function checkWatchdog(expectInterrupt, continuation) {
|
||||
var lastWatchdogWakeup = Cu.getWatchdogTimestamp("WatchdogWakeup");
|
||||
setOperationCallback(function() {
|
||||
// If the watchdog didn't actually trigger the operation callback, ignore
|
||||
// this call. This allows us to test the actual watchdog behavior without
|
||||
// interference from other sites where we trigger the operation callback.
|
||||
if (lastWatchdogWakeup == Cu.getWatchdogTimestamp("WatchdogWakeup")) {
|
||||
return true;
|
||||
}
|
||||
do_check_true(expectInterrupt);
|
||||
setOperationCallback(undefined);
|
||||
// Schedule our continuation before we kill this script.
|
||||
executeSoon(continuation);
|
||||
return false;
|
||||
});
|
||||
executeSoon(function() {
|
||||
busyWait(3000);
|
||||
do_check_true(!expectInterrupt);
|
||||
setOperationCallback(undefined);
|
||||
continuation();
|
||||
});
|
||||
}
|
||||
|
||||
var gGenerator;
|
||||
function continueTest() {
|
||||
gGenerator.next();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
||||
// Run async.
|
||||
do_test_pending();
|
||||
|
||||
// Instantiate the generator and kick it off.
|
||||
gGenerator = testBody();
|
||||
gGenerator.next();
|
||||
}
|
||||
|
@ -1,160 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//
|
||||
// Pref management.
|
||||
//
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
var gPrefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
|
||||
function setWatchdogEnabled(enabled) {
|
||||
gPrefs.setBoolPref("dom.use_watchdog", enabled);
|
||||
}
|
||||
|
||||
function isWatchdogEnabled() {
|
||||
return gPrefs.getBoolPref("dom.use_watchdog");
|
||||
}
|
||||
|
||||
//
|
||||
// Utilities.
|
||||
//
|
||||
|
||||
function busyWait(ms) {
|
||||
var start = new Date();
|
||||
while ((new Date()) - start < ms) {}
|
||||
}
|
||||
|
||||
function do_log_info(aMessage)
|
||||
{
|
||||
print("TEST-INFO | " + _TEST_FILE + " | " + aMessage);
|
||||
}
|
||||
|
||||
// We don't use do_execute_soon, because that inserts a
|
||||
// do_test_{pending,finished} pair that gets screwed up when we terminate scripts
|
||||
// from the operation callback.
|
||||
function executeSoon(fn) {
|
||||
var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
||||
tm.mainThread.dispatch({run: fn}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
//
|
||||
// Asynchronous watchdog diagnostics.
|
||||
//
|
||||
// When running, the watchdog wakes up every second, and fires the operation
|
||||
// callback if the script has been running for >= one second. As such, a script
|
||||
// should never be able to run for two seconds or longer without servicing the
|
||||
// operation callback. We wait 3 seconds, just to be safe.
|
||||
//
|
||||
|
||||
function checkWatchdog(expectInterrupt, continuation) {
|
||||
var lastWatchdogWakeup = Cu.getWatchdogTimestamp("WatchdogWakeup");
|
||||
setOperationCallback(function() {
|
||||
// If the watchdog didn't actually trigger the operation callback, ignore
|
||||
// this call. This allows us to test the actual watchdog behavior without
|
||||
// interference from other sites where we trigger the operation callback.
|
||||
if (lastWatchdogWakeup == Cu.getWatchdogTimestamp("WatchdogWakeup")) {
|
||||
return true;
|
||||
}
|
||||
do_check_true(expectInterrupt);
|
||||
setOperationCallback(undefined);
|
||||
// Schedule our continuation before we kill this script.
|
||||
executeSoon(continuation);
|
||||
return false;
|
||||
});
|
||||
executeSoon(function() {
|
||||
busyWait(3000);
|
||||
do_check_true(!expectInterrupt);
|
||||
setOperationCallback(undefined);
|
||||
continuation();
|
||||
});
|
||||
}
|
||||
|
||||
var gGenerator;
|
||||
function continueTest() {
|
||||
gGenerator.next();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
||||
// Run async.
|
||||
do_test_pending();
|
||||
|
||||
// Instantiate the generator and kick it off.
|
||||
gGenerator = testBody();
|
||||
gGenerator.next();
|
||||
}
|
||||
|
||||
function testBody() {
|
||||
|
||||
// Before munging any prefs, check that we properly implement whatever behavior
|
||||
// is specified by the default profile for this configuration.
|
||||
checkWatchdog(isWatchdogEnabled(), continueTest);
|
||||
yield;
|
||||
|
||||
// Toggle the watchdog, and check that state.
|
||||
var was = isWatchdogEnabled();
|
||||
setWatchdogEnabled(!isWatchdogEnabled());
|
||||
do_check_true(was != isWatchdogEnabled());
|
||||
checkWatchdog(isWatchdogEnabled(), continueTest);
|
||||
yield;
|
||||
|
||||
// Now, make sure the watchdog is on.
|
||||
setWatchdogEnabled(true);
|
||||
do_check_true(isWatchdogEnabled());
|
||||
checkWatchdog(true, continueTest);
|
||||
yield;
|
||||
|
||||
//
|
||||
// Now, check hibernation.
|
||||
//
|
||||
|
||||
// It's unlikely that we've ever hibernated at this point, but the timestamps
|
||||
// default to 0, so this should always be true.
|
||||
var now = Date.now() * 1000;
|
||||
var startHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStart");
|
||||
var stopHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStop");
|
||||
do_log_info("Pre-hibernation statistics:");
|
||||
do_log_info("now: " + now / 1000000);
|
||||
do_log_info("startHibernation: " + startHibernation / 1000000);
|
||||
do_log_info("stopHibernation: " + stopHibernation / 1000000);
|
||||
do_check_true(startHibernation < now);
|
||||
do_check_true(stopHibernation < now);
|
||||
|
||||
// When the watchdog runs, it hibernates if there's been no activity for the
|
||||
// last 2 seconds, otherwise it sleeps for 1 second. As such, given perfect
|
||||
// scheduling, we should never have more than 3 seconds of inactivity without
|
||||
// hibernating. To add some padding for automation, we mandate that hibernation
|
||||
// must begin between 2 and 5 seconds from now.
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(continueTest, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
simulateActivityCallback(false);
|
||||
yield;
|
||||
|
||||
simulateActivityCallback(true);
|
||||
busyWait(1000); // Give the watchdog time to wake up on the condvar.
|
||||
var stateChange = Cu.getWatchdogTimestamp("RuntimeStateChange");
|
||||
startHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStart");
|
||||
stopHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStop");
|
||||
do_log_info("Post-hibernation statistics:");
|
||||
do_log_info("stateChange: " + stateChange / 1000000);
|
||||
do_log_info("startHibernation: " + startHibernation / 1000000);
|
||||
do_log_info("stopHibernation: " + stopHibernation / 1000000);
|
||||
// XPCOM timers, JS times, and PR_Now() are apparently not directly
|
||||
// comparable, as evidenced by certain seemingly-impossible timing values
|
||||
// that occasionally get logged in windows automation. We're really just
|
||||
// making sure this behavior is roughly as expected on the macro scale,
|
||||
// so we add a 1 second fuzz factor here.
|
||||
const FUZZ_FACTOR = 1 * 1000 * 1000;
|
||||
do_check_true(stateChange > now + 10*1000*1000 - FUZZ_FACTOR);
|
||||
do_check_true(startHibernation > now + 2*1000*1000 - FUZZ_FACTOR);
|
||||
do_check_true(startHibernation < now + 5*1000*1000 + FUZZ_FACTOR);
|
||||
do_check_true(stopHibernation > now + 10*1000*1000 - FUZZ_FACTOR);
|
||||
|
||||
do_test_finished();
|
||||
yield;
|
||||
}
|
12
js/xpconnect/tests/unit/test_watchdog_default.js
Normal file
12
js/xpconnect/tests/unit/test_watchdog_default.js
Normal file
@ -0,0 +1,12 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function testBody() {
|
||||
// Check that we properly implement whatever behavior is specified by the
|
||||
// default profile for this configuration.
|
||||
checkWatchdog(isWatchdogEnabled(), continueTest);
|
||||
yield;
|
||||
do_test_finished();
|
||||
yield;
|
||||
}
|
11
js/xpconnect/tests/unit/test_watchdog_disable.js
Normal file
11
js/xpconnect/tests/unit/test_watchdog_disable.js
Normal file
@ -0,0 +1,11 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function testBody() {
|
||||
setWatchdogEnabled(false);
|
||||
checkWatchdog(false, continueTest);
|
||||
yield;
|
||||
do_test_finished();
|
||||
yield;
|
||||
}
|
11
js/xpconnect/tests/unit/test_watchdog_enable.js
Normal file
11
js/xpconnect/tests/unit/test_watchdog_enable.js
Normal file
@ -0,0 +1,11 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function testBody() {
|
||||
setWatchdogEnabled(true);
|
||||
checkWatchdog(true, continueTest);
|
||||
yield;
|
||||
do_test_finished();
|
||||
yield;
|
||||
}
|
53
js/xpconnect/tests/unit/test_watchdog_hibernate.js
Normal file
53
js/xpconnect/tests/unit/test_watchdog_hibernate.js
Normal file
@ -0,0 +1,53 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function testBody() {
|
||||
|
||||
setWatchdogEnabled(true);
|
||||
|
||||
// It's unlikely that we've ever hibernated at this point, but the timestamps
|
||||
// default to 0, so this should always be true.
|
||||
var now = Date.now() * 1000;
|
||||
var startHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStart");
|
||||
var stopHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStop");
|
||||
do_log_info("Pre-hibernation statistics:");
|
||||
do_log_info("now: " + now / 1000000);
|
||||
do_log_info("startHibernation: " + startHibernation / 1000000);
|
||||
do_log_info("stopHibernation: " + stopHibernation / 1000000);
|
||||
do_check_true(startHibernation < now);
|
||||
do_check_true(stopHibernation < now);
|
||||
|
||||
// When the watchdog runs, it hibernates if there's been no activity for the
|
||||
// last 2 seconds, otherwise it sleeps for 1 second. As such, given perfect
|
||||
// scheduling, we should never have more than 3 seconds of inactivity without
|
||||
// hibernating. To add some padding for automation, we mandate that hibernation
|
||||
// must begin between 2 and 5 seconds from now.
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(continueTest, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
simulateActivityCallback(false);
|
||||
yield;
|
||||
|
||||
simulateActivityCallback(true);
|
||||
busyWait(1000); // Give the watchdog time to wake up on the condvar.
|
||||
var stateChange = Cu.getWatchdogTimestamp("RuntimeStateChange");
|
||||
startHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStart");
|
||||
stopHibernation = Cu.getWatchdogTimestamp("WatchdogHibernateStop");
|
||||
do_log_info("Post-hibernation statistics:");
|
||||
do_log_info("stateChange: " + stateChange / 1000000);
|
||||
do_log_info("startHibernation: " + startHibernation / 1000000);
|
||||
do_log_info("stopHibernation: " + stopHibernation / 1000000);
|
||||
// XPCOM timers, JS times, and PR_Now() are apparently not directly
|
||||
// comparable, as evidenced by certain seemingly-impossible timing values
|
||||
// that occasionally get logged in windows automation. We're really just
|
||||
// making sure this behavior is roughly as expected on the macro scale,
|
||||
// so we add a 1 second fuzz factor here.
|
||||
const FUZZ_FACTOR = 1 * 1000 * 1000;
|
||||
do_check_true(stateChange > now + 10*1000*1000 - FUZZ_FACTOR);
|
||||
do_check_true(startHibernation > now + 2*1000*1000 - FUZZ_FACTOR);
|
||||
do_check_true(startHibernation < now + 5*1000*1000 + FUZZ_FACTOR);
|
||||
do_check_true(stopHibernation > now + 10*1000*1000 - FUZZ_FACTOR);
|
||||
|
||||
do_test_finished();
|
||||
yield;
|
||||
}
|
13
js/xpconnect/tests/unit/test_watchdog_toggle.js
Normal file
13
js/xpconnect/tests/unit/test_watchdog_toggle.js
Normal file
@ -0,0 +1,13 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function testBody() {
|
||||
var defaultBehavior = isWatchdogEnabled();
|
||||
setWatchdogEnabled(!defaultBehavior);
|
||||
setWatchdogEnabled(defaultBehavior);
|
||||
checkWatchdog(defaultBehavior, continueTest);
|
||||
yield;
|
||||
do_test_finished();
|
||||
yield;
|
||||
}
|
@ -52,4 +52,14 @@ fail-if = os == "android"
|
||||
[test_allowedDomainsXHR.js]
|
||||
[test_nuke_sandbox.js]
|
||||
[test_exportFunction.js]
|
||||
[test_watchdog.js]
|
||||
[test_watchdog_enable.js]
|
||||
head = head_watchdog.js
|
||||
[test_watchdog_disable.js]
|
||||
head = head_watchdog.js
|
||||
[test_watchdog_toggle.js]
|
||||
head = head_watchdog.js
|
||||
[test_watchdog_default.js]
|
||||
head = head_watchdog.js
|
||||
[test_watchdog_hibernate.js]
|
||||
head = head_watchdog.js
|
||||
|
||||
|
13
layout/reftests/svg/smil/mapped-attr-long-url-1.svg
Normal file
13
layout/reftests/svg/smil/mapped-attr-long-url-1.svg
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect height="100%" width="100%" fill="lime" />
|
||||
<rect height="100" width="100" fill="red">
|
||||
<set attributeName="fill" attributeType="XML" dur="indefinite"
|
||||
to="url(#reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaallyLongURL) transparent"/>
|
||||
</rect>
|
||||
</svg>
|
After Width: | Height: | Size: 789 B |
@ -245,6 +245,8 @@ fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,2) == anim-gradient-attr-presence-0
|
||||
== inactivate-with-active-unchanged-1.svg anim-standard-ref.svg
|
||||
== inactivate-with-active-unchanged-2.svg anim-standard-ref.svg
|
||||
|
||||
== mapped-attr-long-url-1.svg lime.svg
|
||||
|
||||
# interaction between xml mapped attributes and their css equivalents
|
||||
== mapped-attr-vs-css-prop-1.svg lime.svg
|
||||
|
||||
|
@ -6703,16 +6703,14 @@ var WebappsUI = {
|
||||
|
||||
Services.obs.addObserver(this, "webapps-ask-install", false);
|
||||
Services.obs.addObserver(this, "webapps-launch", false);
|
||||
Services.obs.addObserver(this, "webapps-sync-install", false);
|
||||
Services.obs.addObserver(this, "webapps-sync-uninstall", false);
|
||||
Services.obs.addObserver(this, "webapps-uninstall", false);
|
||||
Services.obs.addObserver(this, "webapps-install-error", false);
|
||||
},
|
||||
|
||||
uninit: function unint() {
|
||||
Services.obs.removeObserver(this, "webapps-ask-install");
|
||||
Services.obs.removeObserver(this, "webapps-launch");
|
||||
Services.obs.removeObserver(this, "webapps-sync-install");
|
||||
Services.obs.removeObserver(this, "webapps-sync-uninstall");
|
||||
Services.obs.removeObserver(this, "webapps-uninstall");
|
||||
Services.obs.removeObserver(this, "webapps-install-error");
|
||||
},
|
||||
|
||||
@ -6748,27 +6746,7 @@ var WebappsUI = {
|
||||
case "webapps-launch":
|
||||
this.openURL(data.manifestURL, data.origin);
|
||||
break;
|
||||
case "webapps-sync-install":
|
||||
// Create a system notification allowing the user to launch the app
|
||||
DOMApplicationRegistry.getManifestFor(data.manifestURL, (function(aManifest) {
|
||||
if (!aManifest)
|
||||
return;
|
||||
let manifest = new ManifestHelper(aManifest, data.origin);
|
||||
|
||||
let observer = {
|
||||
observe: function (aSubject, aTopic) {
|
||||
if (aTopic == "alertclickcallback") {
|
||||
WebappsUI.openURL(data.manifestURL, data.origin);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let message = Strings.browser.GetStringFromName("webapps.alertSuccess");
|
||||
let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
alerts.showAlertNotification("drawable://alert_app", manifest.name, message, true, "", observer, "webapp");
|
||||
}).bind(this));
|
||||
break;
|
||||
case "webapps-sync-uninstall":
|
||||
case "webapps-uninstall":
|
||||
sendMessageToJava({
|
||||
type: "WebApps:Uninstall",
|
||||
origin: data.origin
|
||||
@ -6829,7 +6807,7 @@ var WebappsUI = {
|
||||
file.initWithPath(profilePath);
|
||||
|
||||
let self = this;
|
||||
DOMApplicationRegistry.confirmInstall(aData, file, null,
|
||||
DOMApplicationRegistry.confirmInstall(aData, file,
|
||||
function (aManifest) {
|
||||
let localeManifest = new ManifestHelper(aManifest, aData.app.origin);
|
||||
|
||||
@ -6868,6 +6846,19 @@ var WebappsUI = {
|
||||
}
|
||||
}, "webapp");
|
||||
}
|
||||
|
||||
// Create a system notification allowing the user to launch the app
|
||||
let observer = {
|
||||
observe: function (aSubject, aTopic) {
|
||||
if (aTopic == "alertclickcallback") {
|
||||
WebappsUI.openURL(aData.app.manifestURL, origin);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let message = Strings.browser.GetStringFromName("webapps.alertSuccess");
|
||||
let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
alerts.showAlertNotification("drawable://alert_app", localeManifest.name, message, true, "", observer, "webapp");
|
||||
} catch(ex) {
|
||||
console.log(ex);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user