nsresult
MediaEngineRemoteVideoSource::Stop(mozilla::SourceMediaStream* aSource,
                                   mozilla::TrackID aID)
{
  LOG((__PRETTY_FUNCTION__));
  AssertIsOnOwningThread();
  {
    MonitorAutoLock lock(mMonitor);

    // Drop any cached image so we don't start with a stale image on next
    // usage.  Also, gfx gets very upset if these are held until this object
    // is gc'd in final-cc during shutdown (bug 1374164)
    mImage = nullptr;
    // we drop mImageContainer only in MediaEngineCaptureVideoSource::Shutdown()

    size_t i = mSources.IndexOf(aSource);
    if (i == mSources.NoIndex) {
      // Already stopped - this is allowed
      return NS_OK;
    }

    MOZ_ASSERT(mSources.Length() == mPrincipalHandles.Length());
    mSources.RemoveElementAt(i);
    mPrincipalHandles.RemoveElementAt(i);

    aSource->EndTrack(aID);

    if (!mSources.IsEmpty()) {
      return NS_OK;
    }
    if (mState != kStarted) {
      return NS_ERROR_FAILURE;
    }

    mState = kStopped;
  }

  mozilla::camera::GetChildAndCall(
    &mozilla::camera::CamerasChild::StopCapture,
    mCapEngine, mCaptureIndex);

  return NS_OK;
}
Beispiel #2
0
already_AddRefed<IDBTransaction>
IDBDatabase::Transaction(const StringOrStringSequence& aStoreNames,
                         IDBTransactionMode aMode,
                         ErrorResult& aRv)
{
  AssertIsOnOwningThread();

  aRv.MightThrowJSException();

  if (aMode == IDBTransactionMode::Readwriteflush &&
      !IndexedDatabaseManager::ExperimentalFeaturesEnabled()) {
    // Pretend that this mode doesn't exist. We don't have a way to annotate
    // certain enum values as depending on preferences so we just duplicate the
    // normal exception generation here.
    ThreadsafeAutoJSContext cx;

    // Disable any automatic error reporting that might be set up so that we
    // can grab the exception object.
    AutoForceSetExceptionOnContext forceExn(cx);

    MOZ_ALWAYS_FALSE(
      ThrowErrorMessage(cx,
                        MSG_INVALID_ENUM_VALUE,
                        "Argument 2 of IDBDatabase.transaction",
                        "readwriteflush",
                        "IDBTransactionMode"));
    MOZ_ASSERT(JS_IsExceptionPending(cx));

    JS::Rooted<JS::Value> exception(cx);
    MOZ_ALWAYS_TRUE(JS_GetPendingException(cx, &exception));

    aRv.ThrowJSException(cx, exception);
    return nullptr;
  }

  RefPtr<IDBTransaction> transaction;
  aRv = Transaction(aStoreNames, aMode, getter_AddRefs(transaction));
  if (NS_WARN_IF(aRv.Failed())) {
    return nullptr;
  }

  return transaction.forget();
}
Beispiel #3
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

JSObject*
IDBCursor::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
  AssertIsOnOwningThread();

  switch (mType) {
    case Type_ObjectStore:
    case Type_Index:
      return IDBCursorWithValueBinding::Wrap(aCx, this, aGivenProto);

    case Type_ObjectStoreKey:
    case Type_IndexKey:
      return IDBCursorBinding::Wrap(aCx, this, aGivenProto);

    default:
      MOZ_CRASH("Bad type!");
  }
}
nsresult
MediaEngineWebRTCMicrophoneSource::Deallocate(AllocationHandle* aHandle)
{
  AssertIsOnOwningThread();

  Super::Deallocate(aHandle);

  if (!mRegisteredHandles.Length()) {
    // If empty, no callbacks to deliver data should be occuring
    if (mState != kStopped && mState != kAllocated) {
      return NS_ERROR_FAILURE;
    }

    FreeChannel();
    LOG(("Audio device %d deallocated", mCapIndex));
  } else {
    LOG(("Audio device %d deallocated but still in use", mCapIndex));
  }
  return NS_OK;
}
Beispiel #5
0
nsresult
MediaEngineRemoteVideoSource::Stop(mozilla::SourceMediaStream* aSource,
                                   mozilla::TrackID aID)
{
  LOG((__PRETTY_FUNCTION__));
  AssertIsOnOwningThread();
  {
    MonitorAutoLock lock(mMonitor);

    // Drop any cached image so we don't start with a stale image on next
    // usage
    mImage = nullptr;

    size_t i = mSources.IndexOf(aSource);
    if (i == mSources.NoIndex) {
      // Already stopped - this is allowed
      return NS_OK;
    }

    MOZ_ASSERT(mSources.Length() == mPrincipalHandles.Length());
    mSources.RemoveElementAt(i);
    mPrincipalHandles.RemoveElementAt(i);

    aSource->EndTrack(aID);

    if (!mSources.IsEmpty()) {
      return NS_OK;
    }
    if (mState != kStarted) {
      return NS_ERROR_FAILURE;
    }

    mState = kStopped;
  }

  mozilla::camera::GetChildAndCall(
    &mozilla::camera::CamerasChild::StopCapture,
    mCapEngine, mCaptureIndex);

  return NS_OK;
}
Beispiel #6
0
void
FetchStream::Close()
{
  AssertIsOnOwningThread();

  MutexAutoLock lock(mMutex);

  if (mState == eClosed) {
    return;
  }

  AutoJSAPI jsapi;
  if (NS_WARN_IF(!jsapi.Init(mGlobal))) {
    ReleaseObjects(lock);
    return;
  }

  JSContext* cx = jsapi.cx();
  JS::Rooted<JSObject*> stream(cx, mStreamHolder->ReadableStreamBody());
  CloseAndReleaseObjects(cx, lock, stream);
}
Beispiel #7
0
already_AddRefed<DOMStringList>
IDBDatabase::ObjectStoreNames() const
{
  AssertIsOnOwningThread();
  MOZ_ASSERT(mSpec);

  const nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();

  RefPtr<DOMStringList> list = new DOMStringList();

  if (!objectStores.IsEmpty()) {
    nsTArray<nsString>& listNames = list->StringArray();
    listNames.SetCapacity(objectStores.Length());

    for (uint32_t index = 0; index < objectStores.Length(); index++) {
      listNames.InsertElementSorted(objectStores[index].metadata().name());
    }
  }

  return list.forget();
}
bool
QuotaUsageRequestChild::Recv__delete__(const UsageRequestResponse& aResponse)
{
  AssertIsOnOwningThread();
  MOZ_ASSERT(mRequest);

  switch (aResponse.type()) {
    case UsageRequestResponse::Tnsresult:
      HandleResponse(aResponse.get_nsresult());
      break;

    case UsageRequestResponse::TUsageResponse:
      HandleResponse(aResponse.get_UsageResponse());
      break;

    default:
      MOZ_CRASH("Unknown response type!");
  }

  return true;
}
Beispiel #9
0
IDBCursorDirection
IDBCursor::GetDirection() const
{
  AssertIsOnOwningThread();

  switch (mDirection) {
    case NEXT:
      return IDBCursorDirection::Next;

    case NEXT_UNIQUE:
      return IDBCursorDirection::Nextunique;

    case PREV:
      return IDBCursorDirection::Prev;

    case PREV_UNIQUE:
      return IDBCursorDirection::Prevunique;

    default:
      MOZ_CRASH("Bad direction!");
  }
}
nsresult
MediaEngineWebRTCMicrophoneSource::Stop(SourceMediaStream *aSource, TrackID aID)
{
  AssertIsOnOwningThread();
  {
    MonitorAutoLock lock(mMonitor);

    if (!mSources.RemoveElement(aSource)) {
      // Already stopped - this is allowed
      return NS_OK;
    }

    aSource->EndTrack(aID);

    if (!mSources.IsEmpty()) {
      return NS_OK;
    }
    if (mState != kStarted) {
      return NS_ERROR_FAILURE;
    }
    if (!mVoEBase) {
      return NS_ERROR_FAILURE;
    }

    mState = kStopped;
  }

  mAudioInput->StopRecording(aSource->Graph(), mListener);

  mVoERender->DeRegisterExternalMediaProcessing(mChannel, webrtc::kRecordingPerChannel);

  if (mVoEBase->StopSend(mChannel)) {
    return NS_ERROR_FAILURE;
  }
  if (mVoEBase->StopReceive(mChannel)) {
    return NS_ERROR_FAILURE;
  }
  return NS_OK;
}
Beispiel #11
0
bool
IDBTransaction::IsOpen() const
{
  AssertIsOnOwningThread();

  // If we haven't started anything then we're open.
  if (mReadyState == IDBTransaction::INITIAL) {
    return true;
  }

  // If we've already started then we need to check to see if we still have the
  // mCreating flag set. If we do (i.e. we haven't returned to the event loop
  // from the time we were created) then we are open. Otherwise check the
  // currently running transaction to see if it's the same. We only allow other
  // requests to be made if this transaction is currently running.
  if (mReadyState == IDBTransaction::LOADING &&
      (mCreating || GetCurrent() == this)) {
    return true;
  }

  return false;
}
Beispiel #12
0
void
IDBCursor::GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const
{
  AssertIsOnOwningThread();

  switch (mType) {
    case Type_ObjectStore:
    case Type_ObjectStoreKey:
      MOZ_ASSERT(mSourceObjectStore);
      aSource.SetAsIDBObjectStore() = mSourceObjectStore;
      return;

    case Type_Index:
    case Type_IndexKey:
      MOZ_ASSERT(mSourceIndex);
      aSource.SetAsIDBIndex() = mSourceIndex;
      return;

    default:
      MOZ_ASSERT_UNREACHABLE("Bad type!");
  }
}
Beispiel #13
0
nsresult
MediaEngineRemoteVideoSource::Deallocate(AllocationHandle* aHandle)
{
  LOG((__PRETTY_FUNCTION__));
  AssertIsOnOwningThread();

  Super::Deallocate(aHandle);

  if (!mRegisteredHandles.Length()) {
    if (mState != kStopped && mState != kAllocated) {
      return NS_ERROR_FAILURE;
    }
    mozilla::camera::GetChildAndCall(
      &mozilla::camera::CamerasChild::ReleaseCaptureDevice,
      mCapEngine, mCaptureIndex);
    mState = kReleased;
    LOG(("Video device %d deallocated", mCaptureIndex));
  } else {
    LOG(("Video device %d deallocated but still in use", mCaptureIndex));
  }
  return NS_OK;
}
bool
DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
{
  AssertIsOnOwningThread();
  MOZ_ASSERT(aDir);

  ErrorResult rv;
  RefPtr<FileSystemBase> fs = aDir->GetFileSystem(rv);
  if (NS_WARN_IF(rv.Failed())) {
    rv.SuppressException();
    return false;
  }

  nsAutoString fsSerialization;
  fs->SerializeDOMPath(fsSerialization);

  nsAutoString thisSerialization;
  SerializeDOMPath(thisSerialization);

  // Check if the given directory is from this storage.
  return fsSerialization == thisSerialization;
}
void
IDBKeyRange::GetUpper(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
                      ErrorResult& aRv)
{
  AssertIsOnOwningThread();

  if (!mHaveCachedUpperVal) {
    if (!mRooted) {
      mozilla::HoldJSObjects(this);
      mRooted = true;
    }

    aRv = Upper().ToJSVal(aCx, mCachedUpperVal);
    if (aRv.Failed()) {
      return;
    }

    mHaveCachedUpperVal = true;
  }

  aResult.set(mCachedUpperVal);
}
Beispiel #16
0
void
IDBRequest::DispatchNonTransactionError(nsresult aErrorCode)
{
  AssertIsOnOwningThread();
  MOZ_ASSERT(NS_FAILED(aErrorCode));
  MOZ_ASSERT(NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_DOM_INDEXEDDB);

  SetError(aErrorCode);

  // Make an error event and fire it at the target.
  nsCOMPtr<nsIDOMEvent> event =
    CreateGenericEvent(this,
                       nsDependentString(kErrorEventType),
                       eDoesBubble,
                       eCancelable);
  MOZ_ASSERT(event);

  bool ignored;
  if (NS_FAILED(DispatchEvent(event, &ignored))) {
    NS_WARNING("Failed to dispatch event!");
  }
}
Beispiel #17
0
void
IDBRequest::GetSource(
             Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const
{
  AssertIsOnOwningThread();

  MOZ_ASSERT_IF(mSourceAsObjectStore, !mSourceAsIndex);
  MOZ_ASSERT_IF(mSourceAsIndex, !mSourceAsObjectStore);
  MOZ_ASSERT_IF(mSourceAsCursor, mSourceAsObjectStore || mSourceAsIndex);

  // Always check cursor first since cursor requests hold both the cursor and
  // the objectStore or index the cursor came from.
  if (mSourceAsCursor) {
    aSource.SetValue().SetAsIDBCursor() = mSourceAsCursor;
  } else if (mSourceAsObjectStore) {
    aSource.SetValue().SetAsIDBObjectStore() = mSourceAsObjectStore;
  } else if (mSourceAsIndex) {
    aSource.SetValue().SetAsIDBIndex() = mSourceAsIndex;
  } else {
    aSource.SetNull();
  }
}
Beispiel #18
0
nsresult
MediaEngineRemoteVideoSource::Start(SourceMediaStream* aStream, TrackID aID,
                                    const PrincipalHandle& aPrincipalHandle)
{
  LOG((__PRETTY_FUNCTION__));
  AssertIsOnOwningThread();
  if (!mInitDone || !aStream) {
    LOG(("No stream or init not done"));
    return NS_ERROR_FAILURE;
  }

  {
    MonitorAutoLock lock(mMonitor);
    mSources.AppendElement(aStream);
    mPrincipalHandles.AppendElement(aPrincipalHandle);
    MOZ_ASSERT(mSources.Length() == mPrincipalHandles.Length());
  }

  aStream->AddTrack(aID, 0, new VideoSegment(), SourceMediaStream::ADDTRACK_QUEUED);

  if (mState == kStarted) {
    return NS_OK;
  }
  mImageContainer =
    layers::LayerManager::CreateImageContainer(layers::ImageContainer::ASYNCHRONOUS);

  mState = kStarted;
  mTrackID = aID;

  if (mozilla::camera::GetChildAndCall(
    &mozilla::camera::CamerasChild::StartCapture,
    mCapEngine, mCaptureIndex, mCapability, this)) {
    LOG(("StartCapture failed"));
    return NS_ERROR_FAILURE;
  }

  return NS_OK;
}
Beispiel #19
0
bool
FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
{
  AssertIsOnOwningThread();
  MOZ_ASSERT(aFile, "aFile Should not be null.");
  MOZ_ASSERT(aPath);

  nsAutoString filePath;
  ErrorResult rv;
  aFile->GetMozFullPathInternal(filePath, rv);
  if (NS_WARN_IF(rv.Failed())) {
    rv.SuppressException();
    return false;
  }

  rv = NS_NewLocalFile(filePath, true, aPath);
  if (NS_WARN_IF(rv.Failed())) {
    rv.SuppressException();
    return false;
  }

  return true;
}
Beispiel #20
0
void
IDBTransaction::OpenCursor(BackgroundCursorChild* aBackgroundActor,
                           const OpenCursorParams& aParams)
{
  AssertIsOnOwningThread();
  MOZ_ASSERT(aBackgroundActor);
  MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);

  if (mMode == VERSION_CHANGE) {
    MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor);

    mBackgroundActor.mVersionChangeBackgroundActor->
      SendPBackgroundIDBCursorConstructor(aBackgroundActor, aParams);
  } else {
    MOZ_ASSERT(mBackgroundActor.mNormalBackgroundActor);

    mBackgroundActor.mNormalBackgroundActor->
      SendPBackgroundIDBCursorConstructor(aBackgroundActor, aParams);
  }

  // Balanced in BackgroundCursorChild::RecvResponse().
  OnNewRequest();
}
Beispiel #21
0
IDBTransactionMode
IDBTransaction::GetMode(ErrorResult& aRv) const
{
  AssertIsOnOwningThread();

  switch (mMode) {
    case READ_ONLY:
      return IDBTransactionMode::Readonly;

    case READ_WRITE:
      return IDBTransactionMode::Readwrite;

    case READ_WRITE_FLUSH:
      return IDBTransactionMode::Readwriteflush;

    case VERSION_CHANGE:
      return IDBTransactionMode::Versionchange;

    case MODE_INVALID:
    default:
      MOZ_CRASH("Bad mode!");
  }
}
Beispiel #22
0
void
IDBDatabase::RefreshSpec(bool aMayDelete)
{
  AssertIsOnOwningThread();

  class MOZ_STACK_CLASS Helper final
  {
  public:
    static PLDHashOperator
    RefreshTransactionsSpec(nsPtrHashKey<IDBTransaction>* aTransaction,
                            void* aClosure)
    {
      MOZ_ASSERT(aTransaction);
      aTransaction->GetKey()->AssertIsOnOwningThread();
      MOZ_ASSERT(aClosure);

      bool mayDelete = *static_cast<bool*>(aClosure);

      nsRefPtr<IDBTransaction> transaction = aTransaction->GetKey();
      transaction->RefreshSpec(mayDelete);

      return PL_DHASH_NEXT;
    }
Beispiel #23
0
void
IDBFileHandle::HandleCompleteOrAbort(bool aAborted)
{
  AssertIsOnOwningThread();

  FileHandleBase::HandleCompleteOrAbort(aAborted);

  nsCOMPtr<nsIDOMEvent> event;
  if (aAborted) {
    event = CreateGenericEvent(this, nsDependentString(kAbortEventType),
                               eDoesBubble, eNotCancelable);
  } else {
    event = CreateGenericEvent(this, nsDependentString(kCompleteEventType),
                               eDoesNotBubble, eNotCancelable);
  }
  if (NS_WARN_IF(!event)) {
    return;
  }

  bool dummy;
  if (NS_FAILED(DispatchEvent(event, &dummy))) {
    NS_WARNING("DispatchEvent failed!");
  }
}
nsresult
MediaEngineGonkVideoSource::Deallocate(AllocationHandle* aHandle)
{
  LOG((__FUNCTION__));
  AssertIsOnOwningThread();
  MOZ_ASSERT(!aHandle);

  bool empty;
  {
    MonitorAutoLock lock(mMonitor);
    empty = mSources.IsEmpty();
  }
  if (empty) {

    ReentrantMonitorAutoEnter sync(mCallbackMonitor);

    if (mState != kStopped && mState != kAllocated) {
      return NS_ERROR_FAILURE;
    }

    // We do not register success callback here

    NS_DispatchToMainThread(WrapRunnable(RefPtr<MediaEngineGonkVideoSource>(this),
                                         &MediaEngineGonkVideoSource::DeallocImpl));
    mCallbackMonitor.Wait();
    if (mState != kReleased) {
      return NS_ERROR_FAILURE;
    }

    mState = kReleased;
    LOG(("Video device %d deallocated", mCaptureIndex));
  } else {
    LOG(("Video device %d deallocated but still in use", mCaptureIndex));
  }
  return NS_OK;
}
Beispiel #25
0
bool
IDBCursor::IsSourceDeleted() const
{
  AssertIsOnOwningThread();
  MOZ_ASSERT(mTransaction);
  MOZ_ASSERT(mTransaction->IsOpen());

  IDBObjectStore* sourceObjectStore;
  if (mType == Type_Index || mType == Type_IndexKey) {
    MOZ_ASSERT(mSourceIndex);

    if (mSourceIndex->IsDeleted()) {
      return true;
    }

    sourceObjectStore = mSourceIndex->ObjectStore();
    MOZ_ASSERT(sourceObjectStore);
  } else {
    MOZ_ASSERT(mSourceObjectStore);
    sourceObjectStore = mSourceObjectStore;
  }

  return sourceObjectStore->IsDeleted();
}
Beispiel #26
0
void
IDBDatabase::AbortTransactions(bool aShouldWarn)
{
  AssertIsOnOwningThread();

  class MOZ_STACK_CLASS Helper final
  {
    typedef nsAutoTArray<RefPtr<IDBTransaction>, 20> StrongTransactionArray;
    typedef nsAutoTArray<IDBTransaction*, 20> WeakTransactionArray;

  public:
    static void
    AbortTransactions(IDBDatabase* aDatabase, const bool aShouldWarn)
    {
      MOZ_ASSERT(aDatabase);
      aDatabase->AssertIsOnOwningThread();

      nsTHashtable<nsPtrHashKey<IDBTransaction>>& transactionTable =
        aDatabase->mTransactions;

      if (!transactionTable.Count()) {
        return;
      }

      StrongTransactionArray transactionsToAbort;
      transactionsToAbort.SetCapacity(transactionTable.Count());

      for (auto iter = transactionTable.Iter(); !iter.Done(); iter.Next()) {
        IDBTransaction* transaction = iter.Get()->GetKey();
        MOZ_ASSERT(transaction);

        transaction->AssertIsOnOwningThread();

        // Transactions that are already done can simply be ignored. Otherwise
        // there is a race here and it's possible that the transaction has not
        // been successfully committed yet so we will warn the user.
        if (!transaction->IsDone()) {
          transactionsToAbort.AppendElement(transaction);
        }
      }
      MOZ_ASSERT(transactionsToAbort.Length() <= transactionTable.Count());

      if (transactionsToAbort.IsEmpty()) {
        return;
      }

      // We want to abort transactions as soon as possible so we iterate the
      // transactions once and abort them all first, collecting the transactions
      // that need to have a warning issued along the way. Those that need a
      // warning will be a subset of those that are aborted, so we don't need
      // additional strong references here.
      WeakTransactionArray transactionsThatNeedWarning;

      for (RefPtr<IDBTransaction>& transaction : transactionsToAbort) {
        MOZ_ASSERT(transaction);
        MOZ_ASSERT(!transaction->IsDone());

        if (aShouldWarn) {
          switch (transaction->GetMode()) {
            // We ignore transactions that could not have written any data.
            case IDBTransaction::READ_ONLY:
              break;

            // We warn for any transactions that could have written data.
            case IDBTransaction::READ_WRITE:
            case IDBTransaction::READ_WRITE_FLUSH:
            case IDBTransaction::VERSION_CHANGE:
              transactionsThatNeedWarning.AppendElement(transaction);
              break;

            default:
              MOZ_CRASH("Unknown mode!");
          }
        }

        transaction->Abort(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
      }

      static const char kWarningMessage[] =
        "IndexedDBTransactionAbortNavigation";

      for (IDBTransaction* transaction : transactionsThatNeedWarning) {
        MOZ_ASSERT(transaction);

        nsString filename;
        uint32_t lineNo, column;
        transaction->GetCallerLocation(filename, &lineNo, &column);

        aDatabase->LogWarning(kWarningMessage, filename, lineNo, column);
      }
    }
Beispiel #27
0
nsresult
IDBDatabase::Transaction(const StringOrStringSequence& aStoreNames,
                         IDBTransactionMode aMode,
                         IDBTransaction** aTransaction)
{
  AssertIsOnOwningThread();

  if (NS_WARN_IF(aMode == IDBTransactionMode::Readwriteflush &&
                 !IndexedDatabaseManager::ExperimentalFeaturesEnabled())) {
    IDB_REPORT_INTERNAL_ERR();
    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  }

  if (QuotaManager::IsShuttingDown()) {
    IDB_REPORT_INTERNAL_ERR();
    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  }

  if (mClosed || RunningVersionChangeTransaction()) {
    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
  }

  nsAutoTArray<nsString, 1> stackSequence;

  if (aStoreNames.IsString()) {
    stackSequence.AppendElement(aStoreNames.GetAsString());
  } else {
    MOZ_ASSERT(aStoreNames.IsStringSequence());
    if (aStoreNames.GetAsStringSequence().IsEmpty()) {
      return NS_ERROR_DOM_INVALID_ACCESS_ERR;
    }
  }

  const nsTArray<nsString>& storeNames =
    aStoreNames.IsString() ?
    stackSequence :
    static_cast<const nsTArray<nsString>&>(aStoreNames.GetAsStringSequence());
  MOZ_ASSERT(!storeNames.IsEmpty());

  const nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();
  const uint32_t nameCount = storeNames.Length();

  nsTArray<nsString> sortedStoreNames;
  sortedStoreNames.SetCapacity(nameCount);

  // Check to make sure the object store names we collected actually exist.
  for (uint32_t nameIndex = 0; nameIndex < nameCount; nameIndex++) {
    const nsString& name = storeNames[nameIndex];

    bool found = false;

    for (uint32_t objCount = objectStores.Length(), objIndex = 0;
         objIndex < objCount;
         objIndex++) {
      if (objectStores[objIndex].metadata().name() == name) {
        found = true;
        break;
      }
    }

    if (!found) {
      return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
    }

    sortedStoreNames.InsertElementSorted(name);
  }

  // Remove any duplicates.
  for (uint32_t nameIndex = nameCount - 1; nameIndex > 0; nameIndex--) {
    if (sortedStoreNames[nameIndex] == sortedStoreNames[nameIndex - 1]) {
      sortedStoreNames.RemoveElementAt(nameIndex);
    }
  }

  IDBTransaction::Mode mode;
  switch (aMode) {
    case IDBTransactionMode::Readonly:
      mode = IDBTransaction::READ_ONLY;
      break;
    case IDBTransactionMode::Readwrite:
      mode = IDBTransaction::READ_WRITE;
      break;
    case IDBTransactionMode::Readwriteflush:
      mode = IDBTransaction::READ_WRITE_FLUSH;
      break;
    case IDBTransactionMode::Versionchange:
      return NS_ERROR_DOM_INVALID_ACCESS_ERR;

    default:
      MOZ_CRASH("Unknown mode!");
  }

  RefPtr<IDBTransaction> transaction =
    IDBTransaction::Create(this, sortedStoreNames, mode);
  if (NS_WARN_IF(!transaction)) {
    IDB_REPORT_INTERNAL_ERR();
    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  }

  BackgroundTransactionChild* actor =
    new BackgroundTransactionChild(transaction);

  IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld]: "
                 "database(%s).transaction(%s)",
               "IndexedDB %s: C T[%lld]: IDBDatabase.transaction()",
               IDB_LOG_ID_STRING(),
               transaction->LoggingSerialNumber(),
               IDB_LOG_STRINGIFY(this),
               IDB_LOG_STRINGIFY(transaction));

  MOZ_ALWAYS_TRUE(
    mBackgroundActor->SendPBackgroundIDBTransactionConstructor(actor,
                                                               sortedStoreNames,
                                                               mode));

  transaction->SetBackgroundActor(actor);

  transaction.forget(aTransaction);
  return NS_OK;
}
Beispiel #28
0
void
IDBDatabase::DeleteObjectStore(const nsAString& aName, ErrorResult& aRv)
{
  AssertIsOnOwningThread();

  IDBTransaction* transaction = IDBTransaction::GetCurrent();
  if (!transaction ||
      transaction->Database() != this ||
      transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    return;
  }

  if (!transaction->IsOpen()) {
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    return;
  }

  nsTArray<ObjectStoreSpec>& specArray = mSpec->objectStores();

  int64_t objectStoreId = 0;

  for (uint32_t specCount = specArray.Length(), specIndex = 0;
       specIndex < specCount;
       specIndex++) {
    const ObjectStoreMetadata& metadata = specArray[specIndex].metadata();
    MOZ_ASSERT(metadata.id());

    if (aName == metadata.name()) {
      objectStoreId = metadata.id();

      // Must do this before altering the metadata array!
      transaction->DeleteObjectStore(objectStoreId);

      specArray.RemoveElementAt(specIndex);

      RefreshSpec(/* aMayDelete */ false);
      break;
    }
  }

  if (!objectStoreId) {
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
    return;
  }

  // Don't do this in the macro because we always need to increment the serial
  // number to keep in sync with the parent.
  const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();

  IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
                 "database(%s).transaction(%s).deleteObjectStore(\"%s\")",
               "IndexedDB %s: C T[%lld] R[%llu]: "
                 "IDBDatabase.deleteObjectStore()",
               IDB_LOG_ID_STRING(),
               transaction->LoggingSerialNumber(),
               requestSerialNumber,
               IDB_LOG_STRINGIFY(this),
               IDB_LOG_STRINGIFY(transaction),
               NS_ConvertUTF16toUTF8(aName).get());
}
Beispiel #29
0
already_AddRefed<IDBObjectStore>
IDBDatabase::CreateObjectStore(
                            const nsAString& aName,
                            const IDBObjectStoreParameters& aOptionalParameters,
                            ErrorResult& aRv)
{
  AssertIsOnOwningThread();

  IDBTransaction* transaction = IDBTransaction::GetCurrent();
  if (!transaction ||
      transaction->Database() != this ||
      transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    return nullptr;
  }

  if (!transaction->IsOpen()) {
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    return nullptr;
  }

  KeyPath keyPath(0);
  if (NS_FAILED(KeyPath::Parse(aOptionalParameters.mKeyPath, &keyPath))) {
    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
    return nullptr;
  }

  nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores();
  for (uint32_t count = objectStores.Length(), index = 0;
       index < count;
       index++) {
    if (aName == objectStores[index].metadata().name()) {
      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
      return nullptr;
    }
  }

  if (!keyPath.IsAllowedForObjectStore(aOptionalParameters.mAutoIncrement)) {
    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
    return nullptr;
  }

  const ObjectStoreSpec* oldSpecElements =
    objectStores.IsEmpty() ? nullptr : objectStores.Elements();

  ObjectStoreSpec* newSpec = objectStores.AppendElement();
  newSpec->metadata() =
    ObjectStoreMetadata(transaction->NextObjectStoreId(), nsString(aName),
                        keyPath, aOptionalParameters.mAutoIncrement);

  if (oldSpecElements &&
      oldSpecElements != objectStores.Elements()) {
    MOZ_ASSERT(objectStores.Length() > 1);

    // Array got moved, update the spec pointers for all live objectStores and
    // indexes.
    RefreshSpec(/* aMayDelete */ false);
  }

  RefPtr<IDBObjectStore> objectStore =
    transaction->CreateObjectStore(*newSpec);
  MOZ_ASSERT(objectStore);

  // Don't do this in the macro because we always need to increment the serial
  // number to keep in sync with the parent.
  const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();

  IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
                 "database(%s).transaction(%s).createObjectStore(%s)",
               "IndexedDB %s: C T[%lld] R[%llu]: "
                 "IDBDatabase.createObjectStore()",
               IDB_LOG_ID_STRING(),
               transaction->LoggingSerialNumber(),
               requestSerialNumber,
               IDB_LOG_STRINGIFY(this),
               IDB_LOG_STRINGIFY(transaction),
               IDB_LOG_STRINGIFY(objectStore));

  return objectStore.forget();
}
Beispiel #30
0
IDBDatabase::~IDBDatabase()
{
  AssertIsOnOwningThread();
  MOZ_ASSERT(!mBackgroundActor);
}