diff --git a/dom/indexedDB/AsyncConnectionHelper.cpp b/dom/indexedDB/AsyncConnectionHelper.cpp index 3473729a6f2e..22bd3391bbbe 100644 --- a/dom/indexedDB/AsyncConnectionHelper.cpp +++ b/dom/indexedDB/AsyncConnectionHelper.cpp @@ -471,7 +471,7 @@ AsyncConnectionHelper::OnError() if (doDefault && mTransaction && mTransaction->IsOpen() && - NS_FAILED(mTransaction->Abort())) { + NS_FAILED(mTransaction->Abort(mRequest))) { NS_WARNING("Failed to abort transaction!"); } } diff --git a/dom/indexedDB/IDBRequest.cpp b/dom/indexedDB/IDBRequest.cpp index fbe5fa1aa516..c15d7d975f03 100644 --- a/dom/indexedDB/IDBRequest.cpp +++ b/dom/indexedDB/IDBRequest.cpp @@ -274,8 +274,7 @@ IDBRequest::GetError(nsIDOMDOMError** aError) NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); if (!mHaveResultOrErrorCode) { - // XXX Need a real error code here. - return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; + return NS_ERROR_DOM_INVALID_STATE_ERR; } NS_IF_ADDREF(*aError = mError); diff --git a/dom/indexedDB/IDBTransaction.cpp b/dom/indexedDB/IDBTransaction.cpp index c6261030551f..bf04c4958689 100644 --- a/dom/indexedDB/IDBTransaction.cpp +++ b/dom/indexedDB/IDBTransaction.cpp @@ -11,6 +11,7 @@ #include "nsIAppShell.h" #include "nsIScriptContext.h" +#include "DOMError.h" #include "mozilla/storage.h" #include "nsContentUtils.h" #include "nsDOMClassInfoID.h" @@ -529,12 +530,24 @@ IDBTransaction::AbortWithCode(nsresult aAbortCode) return NS_OK; } +nsresult +IDBTransaction::Abort(IDBRequest* aRequest) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + NS_ASSERTION(aRequest, "This is undesirable."); + + aRequest->GetError(getter_AddRefs(mError)); + + return AbortWithCode(aRequest->GetErrorCode()); +} + NS_IMPL_CYCLE_COLLECTION_CLASS(IDBTransaction) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBTransaction, IDBWrapperCache) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mDatabase, nsIDOMEventTarget) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mError); NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error) NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(complete) NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(abort) @@ -548,6 +561,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBTransaction, IDBWrapperCache) // Don't unlink mDatabase! + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mError); NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error) NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(complete) NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(abort) @@ -605,6 +619,19 @@ IDBTransaction::GetMode(nsAString& aMode) return NS_OK; } +NS_IMETHODIMP +IDBTransaction::GetError(nsIDOMDOMError** aError) +{ + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); + + if (IsOpen()) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + + NS_IF_ADDREF(*aError = mError); + return NS_OK; +} + NS_IMETHODIMP IDBTransaction::GetObjectStoreNames(nsIDOMDOMStringList** aObjectStores) { @@ -777,6 +804,14 @@ CommitHelper::Run() event = CreateGenericEvent(NS_LITERAL_STRING(ABORT_EVT_STR), eDoesBubble, eNotCancelable); + + // The transaction may already have an error object (e.g. if one of the + // requests failed). If it doesn't, and it wasn't aborted + // programmatically, create one now. + if (!mTransaction->mError && + mAbortCode != NS_ERROR_DOM_INDEXEDDB_ABORT_ERR) { + mTransaction->mError = DOMError::CreateForNSResult(mAbortCode); + } } else { event = CreateGenericEvent(NS_LITERAL_STRING(COMPLETE_EVT_STR), @@ -822,12 +857,18 @@ CommitHelper::Run() if (!mAbortCode) { NS_NAMED_LITERAL_CSTRING(release, "COMMIT TRANSACTION"); - if (NS_SUCCEEDED(mConnection->ExecuteSimpleSQL(release))) { + nsresult rv = mConnection->ExecuteSimpleSQL(release); + if (NS_SUCCEEDED(rv)) { if (mUpdateFileRefcountFunction) { mUpdateFileRefcountFunction->UpdateFileInfos(); } CommitAutoIncrementCounts(); } + else if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) { + // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE, + // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR. + mAbortCode = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; + } else { mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } diff --git a/dom/indexedDB/IDBTransaction.h b/dom/indexedDB/IDBTransaction.h index 8374d470d1ee..8f26797eb411 100644 --- a/dom/indexedDB/IDBTransaction.h +++ b/dom/indexedDB/IDBTransaction.h @@ -13,6 +13,7 @@ #include "mozIStorageStatement.h" #include "mozIStorageFunction.h" #include "nsIIDBTransaction.h" +#include "nsIDOMDOMError.h" #include "nsIRunnable.h" #include "nsAutoPtr.h" @@ -30,6 +31,7 @@ BEGIN_INDEXEDDB_NAMESPACE class AsyncConnectionHelper; class CommitHelper; +class IDBRequest; class IndexedDBDatabaseChild; class IndexedDBTransactionChild; class IndexedDBTransactionParent; @@ -185,6 +187,9 @@ public: nsresult AbortWithCode(nsresult aAbortCode); + nsresult + Abort(IDBRequest* aRequest); + nsresult GetAbortCode() const { @@ -207,6 +212,7 @@ private: nsRefPtr mDatabase; nsRefPtr mDatabaseInfo; + nsCOMPtr mError; nsTArray mObjectStoreNames; ReadyState mReadyState; Mode mMode; diff --git a/dom/indexedDB/nsIIDBRequest.idl b/dom/indexedDB/nsIIDBRequest.idl index 886ff17c3a3c..19ba47d5bcc5 100644 --- a/dom/indexedDB/nsIIDBRequest.idl +++ b/dom/indexedDB/nsIIDBRequest.idl @@ -5,13 +5,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISupports.idl" -#include "nsIDOMDOMError.idl" +interface nsIDOMDOMError; interface nsIDOMEventListener; interface nsIIDBTransaction; /** - * IDBReqeust interface. See + * IDBRequest interface. See * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBRequest for more * information. */ diff --git a/dom/indexedDB/nsIIDBTransaction.idl b/dom/indexedDB/nsIIDBTransaction.idl index 51edc1ef9efb..fc29205aa822 100644 --- a/dom/indexedDB/nsIIDBTransaction.idl +++ b/dom/indexedDB/nsIIDBTransaction.idl @@ -11,13 +11,14 @@ interface nsIIDBObjectStore; interface nsIIDBRequest; interface nsIIDBDatabase; interface nsIDOMDOMStringList; +interface nsIDOMDOMError; /** * IDBDTransaction interface. See * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBTransaction * for more information. */ -[scriptable, builtinclass, uuid(e4927c76-4f1f-4d7d-80ad-8186e1677da6)] +[scriptable, builtinclass, uuid(79f73099-02ff-416d-9754-5a315e29ee4f)] interface nsIIDBTransaction : nsISupports { readonly attribute nsIIDBDatabase db; @@ -25,6 +26,8 @@ interface nsIIDBTransaction : nsISupports // "readonly", "readwrite" or "versionchange" readonly attribute DOMString mode; + readonly attribute nsIDOMDOMError error; + readonly attribute nsIDOMDOMStringList objectStoreNames; nsIIDBObjectStore diff --git a/dom/indexedDB/test/browser_quotaPrompt.html b/dom/indexedDB/test/browser_quotaPrompt.html index dc9775c57efd..85d6c7b8dbbe 100644 --- a/dom/indexedDB/test/browser_quotaPrompt.html +++ b/dom/indexedDB/test/browser_quotaPrompt.html @@ -17,7 +17,7 @@ setTimeout(testFinishedCallback, 0, "complete"); } transaction.onabort = function(event) { - setTimeout(testFinishedCallback, 0, "abort"); + setTimeout(testFinishedCallback, 0, "abort " + event.target.error.name); } let objectStore = transaction.objectStore("foo"); diff --git a/dom/indexedDB/test/browser_quotaPromptDeny.js b/dom/indexedDB/test/browser_quotaPromptDeny.js index ac0aadf51928..83646c0cffce 100644 --- a/dom/indexedDB/test/browser_quotaPromptDeny.js +++ b/dom/indexedDB/test/browser_quotaPromptDeny.js @@ -37,7 +37,7 @@ function test1() is(result, "complete", "Got 'complete' result"); } else { - is(result, "abort", "Got 'abort' result"); + is(result, "abort QuotaExceededError", "Got 'abort' result"); } if (addMoreTest1Count >= seenPopupCount + 5) { @@ -108,7 +108,7 @@ function test2() if (addMoreCount > addMoreTest1Count + 5) { setFinishedCallback(function(result) { is(result, "finished", "Got 'finished' result"); - is(lastResult, "abort", "Aborted as expected"); + is(lastResult, "abort QuotaExceededError", "Aborted as expected"); ok(!seenPopup, "No popup"); is(getPermission(testPageURL, "indexedDB-unlimited"), Components.interfaces.nsIPermissionManager.DENY_ACTION, diff --git a/dom/indexedDB/test/error_events_abort_transactions_iframe.html b/dom/indexedDB/test/error_events_abort_transactions_iframe.html index d3697e7185db..157ff67ed1a1 100644 --- a/dom/indexedDB/test/error_events_abort_transactions_iframe.html +++ b/dom/indexedDB/test/error_events_abort_transactions_iframe.html @@ -61,8 +61,10 @@ is(db.version, 1, "Correct version"); is(db.objectStoreNames.length, 0, "Correct objectStoreNames length"); - event.target.transaction.oncomplete = unexpectedSuccessHandler; - event.target.transaction.onabort = grabEventAndContinueHandler; + let trans = event.target.transaction; + + trans.oncomplete = unexpectedSuccessHandler; + trans.onabort = grabEventAndContinueHandler; let objectStore = db.createObjectStore("foo"); @@ -84,10 +86,12 @@ is(event.type, "abort", "Got a transaction abort event"); is(db.version, 1, "Correct version"); is(db.objectStoreNames.length, 1, "Correct objectStoreNames length"); + is(trans.error.name, "ConstraintError", "Right error"); + ok(trans.error === request.error, "Object identity holds"); event = yield; is(event.type, "error", "Got request error event"); - is(event.target.error.name, "AbortError", "Right error"); + is(event.target.error.name, "ConstraintError", "Right error"); let request = mozIndexedDB.open(window.location.pathname, 1); request.onerror = errorHandler; diff --git a/dom/indexedDB/test/exceptions_in_success_events_iframe.html b/dom/indexedDB/test/exceptions_in_success_events_iframe.html index a8a14193979d..3ec369d53505 100644 --- a/dom/indexedDB/test/exceptions_in_success_events_iframe.html +++ b/dom/indexedDB/test/exceptions_in_success_events_iframe.html @@ -96,11 +96,13 @@ event = yield; is(event.type, "abort", "Got transaction abort event"); + is(event.target.error, null, "Got null error object"); event = yield; is(event.type, "error", "Got IDBOpenDBRequest error event"); is(event.target, openrequest, "Right event target"); + is(event.target.error.name, "AbortError", "Right error name"); finishTest(); yield; diff --git a/dom/indexedDB/test/helpers.js b/dom/indexedDB/test/helpers.js index 99b7f5161ea2..c7f3d0c27b1d 100644 --- a/dom/indexedDB/test/helpers.js +++ b/dom/indexedDB/test/helpers.js @@ -112,17 +112,20 @@ function unexpectedSuccessHandler() finishTest(); } -function ExpectError(name) +function ExpectError(name, preventDefault) { this._name = name; + this._preventDefault = preventDefault; } ExpectError.prototype = { handleEvent: function(event) { is(event.type, "error", "Got an error event"); is(event.target.error.name, this._name, "Expected error was thrown."); - event.preventDefault(); - event.stopPropagation(); + if (this._preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } grabEventAndContinueHandler(event); } }; diff --git a/dom/indexedDB/test/test_autoIncrement.html b/dom/indexedDB/test/test_autoIncrement.html index a7097b7ed2e9..2a15fdb11dc2 100644 --- a/dom/indexedDB/test/test_autoIncrement.html +++ b/dom/indexedDB/test/test_autoIncrement.html @@ -225,26 +225,26 @@ trans.objectStore("store2").add({ unique: 1, id: "unique" }); trans.objectStore("store1").add({ error: 1, unique: 1 }).onerror = - new ExpectError("ConstraintError"); + new ExpectError("ConstraintError", true); trans.objectStore("store1").add({ error: 2 }).onsuccess = genCheck(c1++, { error: 2 }, "first" + test); yield; yield; trans.objectStore("store2").add({ error: 3, unique: 1 }).onerror = - new ExpectError("ConstraintError"); + new ExpectError("ConstraintError", true); trans.objectStore("store2").add({ error: 4 }).onsuccess = genCheck(c2, { error: 4, id: c2 }, "second" + test); c2++; yield; yield; trans.objectStore("store1").add({ error: 5, unique: 1 }, 100000).onerror = - new ExpectError("ConstraintError"); + new ExpectError("ConstraintError", true); trans.objectStore("store1").add({ error: 6 }).onsuccess = genCheck(c1++, { error: 6 }, "third" + test); yield; yield; trans.objectStore("store2").add({ error: 7, unique: 1, id: 100000 }).onerror = - new ExpectError("ConstraintError"); + new ExpectError("ConstraintError", true); trans.objectStore("store2").add({ error: 8 }).onsuccess = genCheck(c2, { error: 8, id: c2 }, "fourth" + test); c2++; diff --git a/dom/indexedDB/test/test_unique_index_update.html b/dom/indexedDB/test/test_unique_index_update.html index 30211f7ac41e..8e4040ac6bba 100644 --- a/dom/indexedDB/test/test_unique_index_update.html +++ b/dom/indexedDB/test/test_unique_index_update.html @@ -41,7 +41,7 @@ request = objectStore.put({ id: 5, index: 6 }); request.onsuccess = unexpectedSuccessHandler; - request.onerror = new ExpectError("ConstraintError"); + request.onerror = new ExpectError("ConstraintError", true); event = yield; event.preventDefault(); @@ -58,7 +58,7 @@ request = cursor.update(cursor.value); request.onsuccess = unexpectedSuccessHandler; - request.onerror = new ExpectError("ConstraintError"); + request.onerror = new ExpectError("ConstraintError", true); }; yield; diff --git a/dom/indexedDB/test/unit/test_add_twice_failure.js b/dom/indexedDB/test/unit/test_add_twice_failure.js index e69fa89f03eb..f5bb27056380 100644 --- a/dom/indexedDB/test/unit/test_add_twice_failure.js +++ b/dom/indexedDB/test/unit/test_add_twice_failure.js @@ -30,7 +30,7 @@ function testSteps() is(request.result, key, "Correct key"); request = objectStore.add({}, key); - request.onerror = new ExpectError("ConstraintError"); + request.onerror = new ExpectError("ConstraintError", true); request.onsuccess = unexpectedSuccessHandler; yield; diff --git a/dom/indexedDB/test/unit/test_index_empty_keyPath.js b/dom/indexedDB/test/unit/test_index_empty_keyPath.js index b1218d30fec9..00dc288f669f 100644 --- a/dom/indexedDB/test/unit/test_index_empty_keyPath.js +++ b/dom/indexedDB/test/unit/test_index_empty_keyPath.js @@ -70,7 +70,7 @@ function testSteps() is(event.target.result, "foopy", "Got correct result"); let request = objectStore.add("foopy", 5); - request.onerror = new ExpectError("ConstraintError"); + request.onerror = new ExpectError("ConstraintError", true); request.onsuccess = unexpectedSuccessHandler; trans.oncomplete = grabEventAndContinueHandler; diff --git a/dom/indexedDB/test/unit/test_indexes.js b/dom/indexedDB/test/unit/test_indexes.js index 3748c6d29616..b1cb4e7d3ba3 100644 --- a/dom/indexedDB/test/unit/test_indexes.js +++ b/dom/indexedDB/test/unit/test_indexes.js @@ -189,7 +189,7 @@ function testSteps() .objectStore(objectStoreName); request = objectStore.add({ name: "Bob", height: 62, weight: 170 }, "237-23-7738"); - request.onerror = new ExpectError("ConstraintError"); + request.onerror = new ExpectError("ConstraintError", true); request.onsuccess = unexpectedSuccessHandler; event = yield; diff --git a/dom/indexedDB/test/unit/test_key_requirements.js b/dom/indexedDB/test/unit/test_key_requirements.js index 03f3fb138d68..05012a765934 100644 --- a/dom/indexedDB/test/unit/test_key_requirements.js +++ b/dom/indexedDB/test/unit/test_key_requirements.js @@ -178,7 +178,7 @@ function testSteps() is(event.target.result, key1, "put gave back the same key"); request = objectStore.add({id:10}); - request.onerror = new ExpectError("ConstraintError"); + request.onerror = new ExpectError("ConstraintError", true); request.onsuccess = unexpectedSuccessHandler; event = yield; diff --git a/dom/indexedDB/test/unit/test_keys.js b/dom/indexedDB/test/unit/test_keys.js index fa930c50624d..a8229def4aee 100644 --- a/dom/indexedDB/test/unit/test_keys.js +++ b/dom/indexedDB/test/unit/test_keys.js @@ -176,14 +176,14 @@ function testSteps() if (keyI === 0) { doCompare(-0); let req = store.add(i, -0); - req.onerror = new ExpectError("ConstraintError"); + req.onerror = new ExpectError("ConstraintError", true); req.onsuccess = unexpectedSuccessHandler; yield; } else if (Array.isArray(keyI) && keyI.length === 1 && keyI[0] === 0) { doCompare([-0]); let req = store.add(i, [-0]); - req.onerror = new ExpectError("ConstraintError"); + req.onerror = new ExpectError("ConstraintError", true); req.onsuccess = unexpectedSuccessHandler; yield; } diff --git a/dom/indexedDB/test/unit/test_traffic_jam.js b/dom/indexedDB/test/unit/test_traffic_jam.js index 36a4f71bd56e..5eb8842e20ce 100644 --- a/dom/indexedDB/test/unit/test_traffic_jam.js +++ b/dom/indexedDB/test/unit/test_traffic_jam.js @@ -69,7 +69,7 @@ function testSteps() is(event.target, requests[2], "fired at the right request"); event.target.result.close(); - requests[3].onerror = new ExpectError("VersionError"); + requests[3].onerror = new ExpectError("VersionError", true); event = yield; diff --git a/dom/indexedDB/test/unit/test_transaction_abort.js b/dom/indexedDB/test/unit/test_transaction_abort.js index f08f0722a822..71bce707d2bc 100644 --- a/dom/indexedDB/test/unit/test_transaction_abort.js +++ b/dom/indexedDB/test/unit/test_transaction_abort.js @@ -7,17 +7,19 @@ var testGenerator = testSteps(); var abortFired = false; -function abortListener() { abortFired = true; } +function abortListener(evt) +{ + abortFired = true; + is(evt.target.error, null, "Expect a null error for an aborted transaction"); +} function testSteps() { const Ci = Components.interfaces; const name = this.window ? window.location.pathname : "Splendid Test"; - const description = "My Test Database"; - - let request = mozIndexedDB.open(name, 1, description); + let request = mozIndexedDB.open(name, 1); request.onerror = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; request.onsuccess = grabEventAndContinueHandler; @@ -31,6 +33,15 @@ function testSteps() let index; transaction = event.target.transaction; + + try { + let error = transaction.error; + ok(false, "Expect an exception"); + } catch(e) { + ok(true, "Got an exception."); + is(e.name, "InvalidStateError", "Got the right exception"); + } + objectStore = db.createObjectStore("foo", { autoIncrement: true }); index = objectStore.createIndex("fooindex", "indexKey", { unique: true }); diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 9fa77350b06c..c6af10e65a5b 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -7580,7 +7580,8 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame, // if frame has view, will already be invalidated if (aChange & nsChangeHint_RepaintFrame) { - if (aFrame->IsFrameOfType(nsIFrame::eSVG)) { + if (aFrame->IsFrameOfType(nsIFrame::eSVG) && + !(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) { if (aChange & nsChangeHint_UpdateEffects) { // Invalidate and update our area: nsSVGUtils::InvalidateAndScheduleBoundsUpdate(aFrame); diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 309edd9ebb7e..a608d82285bf 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -605,7 +605,8 @@ void nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate, const nsRect *aBoundsSubArea, PRUint32 aFlags) { - NS_ABORT_IF_FALSE(aFrame->IsFrameOfType(nsIFrame::eSVG), + NS_ABORT_IF_FALSE(aFrame->IsFrameOfType(nsIFrame::eSVG) && + !(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG), "Passed bad frame!"); NS_ASSERTION(aDuringUpdate == OuterSVGIsCallingUpdateBounds(aFrame),