예제 #1
0
NS_IMETHODIMP
InsertNodeTransaction::DoTransaction()
{
  if (NS_WARN_IF(!mEditorBase) ||
      NS_WARN_IF(!mContentToInsert) ||
      NS_WARN_IF(!mPointToInsert.IsSet())) {
    return NS_ERROR_NOT_INITIALIZED;
  }

  if (!mPointToInsert.IsSetAndValid()) {
    // It seems that DOM tree has been changed after first DoTransaction()
    // and current RedoTranaction() call.
    if (mPointToInsert.GetChild()) {
      EditorDOMPoint newPointToInsert(mPointToInsert.GetChild());
      if (!newPointToInsert.IsSet()) {
        // The insertion point has been removed from the DOM tree.
        // In this case, we should append the node to the container instead.
        newPointToInsert.SetToEndOf(mPointToInsert.GetContainer());
        if (NS_WARN_IF(!newPointToInsert.IsSet())) {
          return NS_ERROR_FAILURE;
        }
      }
      mPointToInsert = newPointToInsert;
    } else {
      mPointToInsert.SetToEndOf(mPointToInsert.GetContainer());
      if (NS_WARN_IF(!mPointToInsert.IsSet())) {
        return NS_ERROR_FAILURE;
      }
    }
  }

  mEditorBase->MarkNodeDirty(GetAsDOMNode(mContentToInsert));

  ErrorResult error;
  mPointToInsert.GetContainer()->InsertBefore(*mContentToInsert,
                                              mPointToInsert.GetChild(),
                                              error);
  error.WouldReportJSException();
  if (NS_WARN_IF(error.Failed())) {
    return error.StealNSResult();
  }

  // Only set selection to insertion point if editor gives permission
  if (mEditorBase->GetShouldTxnSetSelection()) {
    RefPtr<Selection> selection = mEditorBase->GetSelection();
    if (NS_WARN_IF(!selection)) {
      return NS_ERROR_FAILURE;
    }
    // Place the selection just after the inserted element
    EditorRawDOMPoint afterInsertedNode(mContentToInsert);
    DebugOnly<bool> advanced = afterInsertedNode.AdvanceOffset();
    NS_WARNING_ASSERTION(advanced,
      "Failed to advance offset after the inserted node");
    selection->Collapse(afterInsertedNode, error);
    if (NS_WARN_IF(error.Failed())) {
      error.SuppressException();
    }
  }
  return NS_OK;
}
예제 #2
0
/* static */ already_AddRefed<Promise>
Promise::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
                     PromiseInit& aInit, ErrorResult& aRv)
{
  MOZ_ASSERT(PrefEnabled());

  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
  if (!window) {
    aRv.Throw(NS_ERROR_UNEXPECTED);
    return nullptr;
  }

  nsRefPtr<Promise> promise = new Promise(window);

  aInit.Call(promise, *promise->mResolver, aRv,
             CallbackObject::eRethrowExceptions);
  aRv.WouldReportJSException();

  if (aRv.IsJSException()) {
    Optional<JS::Handle<JS::Value> > value(aCx);
    aRv.StealJSException(aCx, &value.Value());

    Maybe<JSAutoCompartment> ac;
    EnterCompartment(ac, aCx, value);
    promise->mResolver->Reject(aCx, value);
  }

  return promise.forget();
}
void
WrapperPromiseCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
{
  AutoJSContext cx;
  Maybe<JSAutoCompartment> ac;
  EnterCompartment(ac, cx, aValue);

  ErrorResult rv;

  // If invoking callback threw an exception, run resolver's reject with the
  // thrown exception as argument and the synchronous flag set.
  Optional<JS::Handle<JS::Value> > value(cx,
    mCallback->Call(mNextResolver->GetParentObject(), aValue, rv,
                    CallbackObject::eRethrowExceptions));

  rv.WouldReportJSException();

  if (rv.Failed() && rv.IsJSException()) {
    Optional<JS::Handle<JS::Value> > value(cx);
    rv.StealJSException(cx, &value.Value());

    Maybe<JSAutoCompartment> ac2;
    EnterCompartment(ac2, cx, value);
    mNextResolver->RejectInternal(cx, value, PromiseResolver::SyncTask);
    return;
  }

  // Otherwise, run resolver's resolve with value and the synchronous flag
  // set.
  Maybe<JSAutoCompartment> ac2;
  EnterCompartment(ac2, cx, value);
  mNextResolver->ResolveInternal(cx, value, PromiseResolver::SyncTask);
}
예제 #4
0
void
WrapperPromiseCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
{
  AutoJSContext cx;
  // FIXME Bug 878849
  Maybe<JSAutoCompartment> ac;
  if (aValue.WasPassed() && aValue.Value().isObject()) {
    JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
    ac.construct(cx, rooted);
  }

  ErrorResult rv;

  // If invoking callback threw an exception, run resolver's reject with the
  // thrown exception as argument and the synchronous flag set.
  Optional<JS::Handle<JS::Value> > value(cx,
    mCallback->Call(mNextResolver->GetParentObject(), aValue, rv,
                    CallbackObject::eRethrowExceptions));

  rv.WouldReportJSException();

  if (rv.Failed() && rv.IsJSException()) {
    Optional<JS::Handle<JS::Value> > value(cx);
    rv.StealJSException(cx, &value.Value());
    mNextResolver->RejectInternal(cx, value, PromiseResolver::SyncTask);
    return;
  }

  // Otherwise, run resolver's resolve with value and the synchronous flag
  // set.
  mNextResolver->ResolveInternal(cx, value, PromiseResolver::SyncTask);
}
예제 #5
0
void
WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
{
  // AutoCxPusher and co. interact with xpconnect, which crashes on
  // workers. On workers we'll get the right context from
  // GetDefaultJSContextForThread(), and since there is only one context, we
  // don't need to push or pop it from the stack.
  JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();

  Maybe<AutoCxPusher> pusher;
  if (NS_IsMainThread()) {
    pusher.construct(cx);
  }

  Maybe<JSAutoCompartment> ac;
  EnterCompartment(ac, cx, aValue);

  ErrorResult rv;

  // If invoking callback threw an exception, run resolver's reject with the
  // thrown exception as argument and the synchronous flag set.
  JS::Rooted<JS::Value> value(cx,
    mCallback->Call(mNextPromise->GetParentObject(), aValue, rv,
                    CallbackObject::eRethrowExceptions));

  rv.WouldReportJSException();

  if (rv.Failed() && rv.IsJSException()) {
    JS::Rooted<JS::Value> value(cx);
    rv.StealJSException(cx, &value);

    Maybe<JSAutoCompartment> ac2;
    EnterCompartment(ac2, cx, value);
    mNextPromise->RejectInternal(cx, value, Promise::SyncTask);
    return;
  }

  // Otherwise, run resolver's resolve with value and the synchronous flag
  // set.
  Maybe<JSAutoCompartment> ac2;
  EnterCompartment(ac2, cx, value);
  mNextPromise->ResolveInternal(cx, value, Promise::SyncTask);
}
void
WrapperPromiseCallback::Call(JSContext* aCx,
                             JS::Handle<JS::Value> aValue)
{
  JSAutoCompartment ac(aCx, mGlobal);
  JS::Rooted<JS::Value> value(aCx, aValue);
  if (!JS_WrapValue(aCx, &value)) {
    NS_WARNING("Failed to wrap value into the right compartment.");
    return;
  }

  ErrorResult rv;

  // If invoking callback threw an exception, run resolver's reject with the
  // thrown exception as argument and the synchronous flag set.
  JS::Rooted<JS::Value> retValue(aCx);
  mCallback->Call(value, &retValue, rv, CallbackObject::eRethrowExceptions);

  rv.WouldReportJSException();

  if (rv.Failed() && rv.IsJSException()) {
    JS::Rooted<JS::Value> value(aCx);
    rv.StealJSException(aCx, &value);

    if (!JS_WrapValue(aCx, &value)) {
      NS_WARNING("Failed to wrap value into the right compartment.");
      return;
    }

    mNextPromise->RejectInternal(aCx, value, Promise::SyncTask);
    return;
  }

  // If the return value is the same as the promise itself, throw TypeError.
  if (retValue.isObject()) {
    JS::Rooted<JSObject*> valueObj(aCx, &retValue.toObject());
    Promise* returnedPromise;
    nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise);

    if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) {
      const char* fileName = nullptr;
      uint32_t lineNumber = 0;

      // Try to get some information about the callback to report a sane error,
      // but don't try too hard (only deals with scripted functions).
      JS::Rooted<JSObject*> unwrapped(aCx,
        js::CheckedUnwrap(mCallback->Callback()));

      if (unwrapped) {
        JSAutoCompartment ac(aCx, unwrapped);
        if (JS_ObjectIsFunction(aCx, unwrapped)) {
          JS::Rooted<JS::Value> asValue(aCx, JS::ObjectValue(*unwrapped));
          JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, asValue));

          MOZ_ASSERT(func);
          JSScript* script = JS_GetFunctionScript(aCx, func);
          if (script) {
            fileName = JS_GetScriptFilename(script);
            lineNumber = JS_GetScriptBaseLineNumber(aCx, script);
          }
        }
      }

      // We're back in aValue's compartment here.
      JS::Rooted<JSString*> stack(aCx, JS_GetEmptyString(JS_GetRuntime(aCx)));
      JS::Rooted<JSString*> fn(aCx, JS_NewStringCopyZ(aCx, fileName));
      if (!fn) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(aCx);
        return;
      }

      JS::Rooted<JSString*> message(aCx,
        JS_NewStringCopyZ(aCx,
          "then() cannot return same Promise that it resolves."));
      if (!message) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(aCx);
        return;
      }

      JS::Rooted<JS::Value> typeError(aCx);
      if (!JS::CreateTypeError(aCx, stack, fn, lineNumber, 0,
                               nullptr, message, &typeError)) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(aCx);
        return;
      }

      mNextPromise->RejectInternal(aCx, typeError, Promise::SyncTask);
      return;
    }
  }

  // Otherwise, run resolver's resolve with value and the synchronous flag
  // set.
  if (!JS_WrapValue(aCx, &retValue)) {
    NS_WARNING("Failed to wrap value into the right compartment.");
    return;
  }

  mNextPromise->ResolveInternal(aCx, retValue, Promise::SyncTask);
}
예제 #7
0
void
WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
{
  // AutoCxPusher and co. interact with xpconnect, which crashes on
  // workers. On workers we'll get the right context from
  // GetDefaultJSContextForThread(), and since there is only one context, we
  // don't need to push or pop it from the stack.
  JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();

  Maybe<AutoCxPusher> pusher;
  if (NS_IsMainThread()) {
    pusher.construct(cx);
  }

  Maybe<JSAutoCompartment> ac;
  EnterCompartment(ac, cx, aValue);

  ErrorResult rv;

  // If invoking callback threw an exception, run resolver's reject with the
  // thrown exception as argument and the synchronous flag set.
  JS::Rooted<JS::Value> value(cx,
    mCallback->Call(aValue, rv, CallbackObject::eRethrowExceptions));

  rv.WouldReportJSException();

  if (rv.Failed() && rv.IsJSException()) {
    JS::Rooted<JS::Value> value(cx);
    rv.StealJSException(cx, &value);

    Maybe<JSAutoCompartment> ac2;
    EnterCompartment(ac2, cx, value);
    mNextPromise->RejectInternal(cx, value, Promise::SyncTask);
    return;
  }

  // If the return value is the same as the promise itself, throw TypeError.
  if (value.isObject()) {
    JS::Rooted<JSObject*> valueObj(cx, &value.toObject());
    Promise* returnedPromise;
    nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise);

    if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) {
      const char* fileName = nullptr;
      uint32_t lineNumber = 0;

      // Try to get some information about the callback to report a sane error,
      // but don't try too hard (only deals with scripted functions).
      JS::Rooted<JSObject*> unwrapped(cx,
        js::CheckedUnwrap(mCallback->Callback()));

      if (unwrapped) {
        JSAutoCompartment ac(cx, unwrapped);
        if (JS_ObjectIsFunction(cx, unwrapped)) {
          JS::Rooted<JS::Value> asValue(cx, JS::ObjectValue(*unwrapped));
          JS::Rooted<JSFunction*> func(cx, JS_ValueToFunction(cx, asValue));

          MOZ_ASSERT(func);
          JSScript* script = JS_GetFunctionScript(cx, func);
          if (script) {
            fileName = JS_GetScriptFilename(cx, script);
            lineNumber = JS_GetScriptBaseLineNumber(cx, script);
          }
        }
      }

      // We're back in aValue's compartment here.
      JS::Rooted<JSString*> stack(cx, JS_GetEmptyString(JS_GetRuntime(cx)));
      JS::Rooted<JSString*> fn(cx, JS_NewStringCopyZ(cx, fileName));
      if (!fn) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(cx);
        return;
      }

      JS::Rooted<JSString*> message(cx,
        JS_NewStringCopyZ(cx,
          "then() cannot return same Promise that it resolves."));
      if (!message) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(cx);
        return;
      }

      JS::Rooted<JS::Value> typeError(cx);
      if (!JS::CreateTypeError(cx, stack, fn, lineNumber, 0,
                               nullptr, message, &typeError)) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(cx);
        return;
      }

      mNextPromise->RejectInternal(cx, typeError, Promise::SyncTask);
      return;
    }
  }

  // Otherwise, run resolver's resolve with value and the synchronous flag
  // set.
  Maybe<JSAutoCompartment> ac2;
  EnterCompartment(ac2, cx, value);
  mNextPromise->ResolveInternal(cx, value, Promise::SyncTask);
}
nsresult
WrapperPromiseCallback::Call(JSContext* aCx,
                             JS::Handle<JS::Value> aValue)
{
  JS::ExposeObjectToActiveJS(mGlobal);
  JS::ExposeValueToActiveJS(aValue);

  JSAutoCompartment ac(aCx, mGlobal);
  JS::Rooted<JS::Value> value(aCx, aValue);
  if (!JS_WrapValue(aCx, &value)) {
    NS_WARNING("Failed to wrap value into the right compartment.");
    return NS_ERROR_FAILURE;
  }

  ErrorResult rv;

  // PromiseReactionTask step 6
  JS::Rooted<JS::Value> retValue(aCx);
  JSCompartment* compartment;
  if (mNextPromise) {
    compartment = mNextPromise->Compartment();
  } else {
    MOZ_ASSERT(mNextPromiseObj);
    compartment = js::GetObjectCompartment(mNextPromiseObj);
  }
  mCallback->Call(value, &retValue, rv, "promise callback",
                  CallbackObject::eRethrowExceptions,
                  compartment);

  rv.WouldReportJSException();

  // PromiseReactionTask step 7
  if (rv.Failed()) {
    JS::Rooted<JS::Value> value(aCx);
    { // Scope for JSAutoCompartment
      // Convert the ErrorResult to a JS exception object that we can reject
      // ourselves with.  This will be exactly the exception that would get
      // thrown from a binding method whose ErrorResult ended up with whatever
      // is on "rv" right now.  Do this in the promise reflector compartment.
      Maybe<JSAutoCompartment> ac;
      if (mNextPromise) {
        ac.emplace(aCx, mNextPromise->GlobalJSObject());
      } else {
        ac.emplace(aCx, mNextPromiseObj);
      }
      DebugOnly<bool> conversionResult = ToJSValue(aCx, rv, &value);
      MOZ_ASSERT(conversionResult);
    }

    if (mNextPromise) {
      mNextPromise->RejectInternal(aCx, value);
    } else {
      JS::Rooted<JS::Value> ignored(aCx);
      ErrorResult rejectRv;
      mRejectFunc->Call(value, &ignored, rejectRv);
      // This reported any JS exceptions; we just have a pointless exception on
      // there now.
      rejectRv.SuppressException();
    }
    return NS_OK;
  }

  // If the return value is the same as the promise itself, throw TypeError.
  if (retValue.isObject()) {
    JS::Rooted<JSObject*> valueObj(aCx, &retValue.toObject());
    valueObj = js::CheckedUnwrap(valueObj);
    JS::Rooted<JSObject*> nextPromiseObj(aCx);
    if (mNextPromise) {
      nextPromiseObj = mNextPromise->GetWrapper();
    } else {
      MOZ_ASSERT(mNextPromiseObj);
      nextPromiseObj = mNextPromiseObj;
    }
    // XXXbz shouldn't this check be over in ResolveInternal anyway?
    if (valueObj == nextPromiseObj) {
      const char* fileName = nullptr;
      uint32_t lineNumber = 0;

      // Try to get some information about the callback to report a sane error,
      // but don't try too hard (only deals with scripted functions).
      JS::Rooted<JSObject*> unwrapped(aCx,
        js::CheckedUnwrap(mCallback->Callback()));

      if (unwrapped) {
        JSAutoCompartment ac(aCx, unwrapped);
        if (JS_ObjectIsFunction(aCx, unwrapped)) {
          JS::Rooted<JS::Value> asValue(aCx, JS::ObjectValue(*unwrapped));
          JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, asValue));

          MOZ_ASSERT(func);
          JSScript* script = JS_GetFunctionScript(aCx, func);
          if (script) {
            fileName = JS_GetScriptFilename(script);
            lineNumber = JS_GetScriptBaseLineNumber(aCx, script);
          }
        }
      }

      // We're back in aValue's compartment here.
      JS::Rooted<JSString*> fn(aCx, JS_NewStringCopyZ(aCx, fileName));
      if (!fn) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(aCx);
        return NS_ERROR_OUT_OF_MEMORY;
      }

      JS::Rooted<JSString*> message(aCx,
        JS_NewStringCopyZ(aCx,
          "then() cannot return same Promise that it resolves."));
      if (!message) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(aCx);
        return NS_ERROR_OUT_OF_MEMORY;
      }

      JS::Rooted<JS::Value> typeError(aCx);
      if (!JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, fn, lineNumber, 0,
                           nullptr, message, &typeError)) {
        // Out of memory. Promise will stay unresolved.
        JS_ClearPendingException(aCx);
        return NS_ERROR_OUT_OF_MEMORY;
      }

      if (mNextPromise) {
        mNextPromise->RejectInternal(aCx, typeError);
      } else {
        JS::Rooted<JS::Value> ignored(aCx);
        ErrorResult rejectRv;
        mRejectFunc->Call(typeError, &ignored, rejectRv);
        // This reported any JS exceptions; we just have a pointless exception
        // on there now.
        rejectRv.SuppressException();
      }
      return NS_OK;
    }
  }

  // Otherwise, run resolver's resolve with value.
  if (!JS_WrapValue(aCx, &retValue)) {
    NS_WARNING("Failed to wrap value into the right compartment.");
    return NS_ERROR_FAILURE;
  }

  if (mNextPromise) {
    mNextPromise->ResolveInternal(aCx, retValue);
  } else {
    JS::Rooted<JS::Value> ignored(aCx);
    ErrorResult resolveRv;
    mResolveFunc->Call(retValue, &ignored, resolveRv);
    // This reported any JS exceptions; we just have a pointless exception
    // on there now.
    resolveRv.SuppressException();
  }
    
  return NS_OK;
}