Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2013-08-29 16:44:20 -04:00
commit f03bbd6952
114 changed files with 1936 additions and 861 deletions

View File

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

View File

@ -1,4 +1,4 @@
{
"revision": "7db3c28d7056b880b3be261f7784b5cc3e96702b",
"revision": "ba5f179a8e557690746e88ffc8b41a8151f65b06",
"repo_path": "/integration/gaia-central"
}

View File

@ -137,7 +137,7 @@ this.webappsUI = {
localDir = app.appProfile.localDir;
}
DOMApplicationRegistry.confirmInstall(aData, localDir, null,
DOMApplicationRegistry.confirmInstall(aData, localDir,
(aManifest) => {
Task.spawn(function() {
try {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -382,7 +382,8 @@ void* MediaDecoderReader::VideoQueueMemoryFunctor::operator()(void* anObject) {
}
MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
: mDecoder(aDecoder)
: mDecoder(aDecoder),
mIgnoreAudioOutputFormat(false)
{
MOZ_COUNT_CTOR(MediaDecoderReader);
}

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

View 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 &lt;audio&gt;</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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -63,6 +63,7 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId, nsIThread* aCameraThr
mWindow(aWindow)
{
MOZ_ASSERT(aWindow, "shouldn't be created with null window!");
SetIsDOMBinding();
}
/**

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
/*

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
/*

View File

@ -192,7 +192,7 @@ typedef void
namespace JS {
typedef void (*OffThreadCompileCallback)(JSScript *script, void *callbackData);
typedef void (*OffThreadCompileCallback)(void *token, void *callbackData);
namespace shadow {

View File

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

View File

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

View File

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

View File

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

View File

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

View 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();
}

View File

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

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View File

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

View 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

View File

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

View File

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