ScriptPromise SubtleCrypto::importKey(const String& rawFormat, ArrayBufferView* keyData, const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& es) { WebKit::WebCryptoKeyFormat format; if (!Key::parseFormat(rawFormat, format, es)) return ScriptPromise(); if (!keyData) { es.throwTypeError("Invalid keyData argument"); return ScriptPromise(); } WebKit::WebCryptoKeyUsageMask keyUsages; if (!Key::parseUsageMask(rawKeyUsages, keyUsages, es)) return ScriptPromise(); WebKit::WebCryptoAlgorithm algorithm; if (!normalizeAlgorithm(rawAlgorithm, ImportKey, algorithm, es)) return ScriptPromise(); const unsigned char* keyDataBytes = static_cast<unsigned char*>(keyData->baseAddress()); RefPtr<CryptoResult> result = CryptoResult::create(); WebKit::Platform::current()->crypto()->importKey(format, keyDataBytes, keyData->byteLength(), algorithm, extractable, keyUsages, result->result()); return result->promise(); }
ScriptPromise ScriptPromise::then(PassOwnPtr<ScriptFunction> onFulfilled, PassOwnPtr<ScriptFunction> onRejected) { if (m_promise.isEmpty()) return ScriptPromise(); v8::Local<v8::Object> promise = m_promise.v8Value().As<v8::Object>(); v8::Local<v8::Function> v8OnFulfilled = ScriptFunction::adoptByGarbageCollector(onFulfilled); v8::Local<v8::Function> v8OnRejected = ScriptFunction::adoptByGarbageCollector(onRejected); if (V8PromiseCustom::isPromise(promise, m_scriptState->isolate())) return ScriptPromise(m_scriptState.get(), V8PromiseCustom::then(promise, v8OnFulfilled, v8OnRejected, m_scriptState->isolate())); ASSERT(promise->IsPromise()); // Return this Promise if no handlers are given. // In fact it is not the exact bahavior of Promise.prototype.then // but that is not a problem in this case. v8::Local<v8::Promise> resultPromise = promise.As<v8::Promise>(); // FIXME: Use Then once it is introduced. if (!v8OnFulfilled.IsEmpty()) { resultPromise = resultPromise->Chain(v8OnFulfilled); if (resultPromise.IsEmpty()) { // v8::Promise::Chain may return an empty value, for example when // the stack is exhausted. return ScriptPromise(); } } if (!v8OnRejected.IsEmpty()) resultPromise = resultPromise->Catch(v8OnRejected); return ScriptPromise(m_scriptState.get(), resultPromise); }
ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, HTMLImageElement* image, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) { // This variant does not work in worker threads. ASSERT(eventTarget.toDOMWindow()); if (!image->cachedImage()) { exceptionState.throwDOMException(InvalidStateError, "No image can be retrieved from the provided element."); return ScriptPromise(); } if (image->cachedImage()->image()->isSVGImage()) { exceptionState.throwDOMException(InvalidStateError, "The image element contains an SVG image, which is unsupported."); return ScriptPromise(); } if (!sw || !sh) { exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); return ScriptPromise(); } if (!image->cachedImage()->image()->currentFrameHasSingleSecurityOrigin()) { exceptionState.throwSecurityError("The source image contains image data from multiple origins."); return ScriptPromise(); } Document* document = eventTarget.toDOMWindow()->document(); if (!image->cachedImage()->passesAccessControlCheck(document->securityOrigin()) && document->securityOrigin()->taintsCanvas(image->src())) { exceptionState.throwSecurityError("Cross-origin access to the source image is denied."); return ScriptPromise(); } // FIXME: make ImageBitmap creation asynchronous crbug.com/258082 return fulfillImageBitmap(scriptState, ImageBitmap::create(image, IntRect(sx, sy, sw, sh))); }
ScriptPromise ScriptPromise::then(PassOwnPtr<ScriptFunction> onFulfilled, PassOwnPtr<ScriptFunction> onRejected) { if (m_promise.hasNoValue() || !m_promise.isObject()) return ScriptPromise(); v8::Handle<v8::Object> promise = m_promise.v8Value().As<v8::Object>(); return ScriptPromise(V8PromiseCustom::then(promise, adoptByGarbageCollector(onFulfilled), adoptByGarbageCollector(onRejected), isolate()), isolate()); }
ScriptPromise ScriptPromise::then(v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected) { if (m_promise.isEmpty()) return ScriptPromise(); v8::Local<v8::Object> promise = m_promise.v8Value().As<v8::Object>(); ASSERT(promise->IsPromise()); // Return this Promise if no handlers are given. // In fact it is not the exact bahavior of Promise.prototype.then // but that is not a problem in this case. v8::Local<v8::Promise> resultPromise = promise.As<v8::Promise>(); if (!onFulfilled.IsEmpty()) { resultPromise = resultPromise->Then(onFulfilled); if (resultPromise.IsEmpty()) { // v8::Promise::Then may return an empty value, for example when // the stack is exhausted. return ScriptPromise(); } } if (!onRejected.IsEmpty()) resultPromise = resultPromise->Catch(onRejected); return ScriptPromise(m_scriptState.get(), resultPromise); }
ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, HTMLVideoElement* video, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) { // This variant does not work in worker threads. ASSERT(eventTarget.toDOMWindow()); if (video->networkState() == HTMLMediaElement::NETWORK_EMPTY) { exceptionState.throwDOMException(InvalidStateError, "The provided element has not retrieved data."); return ScriptPromise(); } if (video->readyState() <= HTMLMediaElement::HAVE_METADATA) { exceptionState.throwDOMException(InvalidStateError, "The provided element's player has no current data."); return ScriptPromise(); } if (!sw || !sh) { exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); return ScriptPromise(); } if (!video->hasSingleSecurityOrigin()) { exceptionState.throwSecurityError("The source video contains image data from multiple origins."); return ScriptPromise(); } if (!video->webMediaPlayer()->didPassCORSAccessCheck() && eventTarget.toDOMWindow()->document()->securityOrigin()->taintsCanvas(video->currentSrc())) { exceptionState.throwSecurityError("Cross-origin access to the source video is denied."); return ScriptPromise(); } // FIXME: make ImageBitmap creation asynchronous crbug.com/258082 return fulfillImageBitmap(scriptState, ImageBitmap::create(video, IntRect(sx, sy, sw, sh))); }
ScriptPromise ScriptPromise::cast(ScriptState* scriptState, v8::Local<v8::Value> value) { if (value.IsEmpty()) return ScriptPromise(); if (value->IsPromise()) { return ScriptPromise(scriptState, value); } InternalResolver resolver(scriptState); ScriptPromise promise = resolver.promise(); resolver.resolve(value); return promise; }
ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) { if (!sw || !sh) { exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); return ScriptPromise(); } if (data()->bufferBase()->isNeutered()) { exceptionState.throwDOMException(InvalidStateError, "The source data has been neutered."); return ScriptPromise(); } return ImageBitmapSource::fulfillImageBitmap(scriptState, ImageBitmap::create(this, IntRect(sx, sy, sw, sh))); }
ScriptPromise ScriptPromise::cast(ScriptState* scriptState, v8::Handle<v8::Value> value) { if (value.IsEmpty()) return ScriptPromise(); if (value->IsPromise()) { return ScriptPromise(scriptState, value); } RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); resolver->resolve(value); return promise; }
ScriptPromise SubtleCrypto::generateKey(const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& es) { WebKit::WebCryptoKeyUsageMask keyUsages; if (!Key::parseUsageMask(rawKeyUsages, keyUsages, es)) return ScriptPromise(); WebKit::WebCryptoAlgorithm algorithm; if (!normalizeAlgorithm(rawAlgorithm, GenerateKey, algorithm, es)) return ScriptPromise(); RefPtr<CryptoResult> result = CryptoResult::create(); WebKit::Platform::current()->crypto()->generateKey(algorithm, extractable, keyUsages, result->result()); return result->promise(); }
ScriptPromise Cache::keys(ScriptState* scriptState, const String& requestString, const CacheQueryOptions& options, ExceptionState& exceptionState) { Request* request = Request::create(scriptState->executionContext(), requestString, exceptionState); if (exceptionState.hadException()) return ScriptPromise(); return keysImpl(scriptState, request, options); }
void revoke() { ExecutionContext* executionContext = m_scriptState->getExecutionContext(); if (!executionContext) return; ScriptState::Scope scope(m_scriptState); v8::Local<v8::Value> value = m_promise.newLocal(m_scriptState->isolate()); v8::Local<v8::Value> reason = m_exception.newLocal(m_scriptState->isolate()); // Either collected or https://crbug.com/450330 if (value.IsEmpty() || !value->IsPromise()) return; EventTarget* target = executionContext->errorEventTarget(); if (target && !executionContext->shouldSanitizeScriptError(m_resourceName, m_corsStatus)) { PromiseRejectionEventInit init; init.setPromise(ScriptPromise(m_scriptState, value)); init.setReason(ScriptValue(m_scriptState, reason)); PromiseRejectionEvent* event = PromiseRejectionEvent::create( m_scriptState, EventTypeNames::rejectionhandled, init); target->dispatchEvent(event); } if (m_shouldLogToConsole && m_promiseRejectionId) { V8PerIsolateData* data = V8PerIsolateData::from(m_scriptState->isolate()); if (data->threadDebugger()) data->threadDebugger()->promiseRejectionRevoked( m_scriptState->context(), m_promiseRejectionId); } }
ScriptPromise Cache::add(ScriptState* scriptState, const String& requestString, ExceptionState& exceptionState) { Request* request = Request::create(scriptState->executionContext(), requestString, exceptionState); if (exceptionState.hadException()) return ScriptPromise(); return addImpl(scriptState, request); }
ScriptPromise FontFaceSet::load(ScriptState* scriptState, const String& fontString, const String& text) { if (!inActiveDocumentContext()) return ScriptPromise(); Font font; if (!resolveFontStyle(fontString, font)) { ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); resolver->reject(DOMException::create(SyntaxError, "Could not resolve '" + fontString + "' as a font.")); return promise; } FontFaceCache* fontFaceCache = document()->styleEngine().fontSelector()->fontFaceCache(); FontFaceArray faces; for (const FontFamily* f = &font.fontDescription().family(); f; f = f->next()) { CSSSegmentedFontFace* segmentedFontFace = fontFaceCache->get(font.fontDescription(), f->family()); if (segmentedFontFace) segmentedFontFace->match(text, faces); } RefPtrWillBeRawPtr<LoadFontPromiseResolver> resolver = LoadFontPromiseResolver::create(faces, scriptState); ScriptPromise promise = resolver->promise(); resolver->loadFonts(executionContext()); // After this, resolver->promise() may return null. return promise; }
ScriptPromise Cache::put(ScriptState* scriptState, const String& requestString, Response* response, ExceptionState& exceptionState) { Request* request = Request::create(scriptState->executionContext(), requestString, exceptionState); if (exceptionState.hadException()) return ScriptPromise(); return putImpl(scriptState, request, response); }
void revoke() { ExecutionContext* executionContext = m_scriptState->executionContext(); if (!executionContext) return; ScriptState::Scope scope(m_scriptState); v8::Local<v8::Value> value = m_promise.newLocal(m_scriptState->isolate()); v8::Local<v8::Value> reason = m_exception.newLocal(m_scriptState->isolate()); // Either collected or https://crbug.com/450330 if (value.IsEmpty() || !value->IsPromise()) return; EventTarget* target = executionContext->errorEventTarget(); if (RuntimeEnabledFeatures::promiseRejectionEventEnabled() && target && !executionContext->shouldSanitizeScriptError(m_resourceName, m_corsStatus)) { PromiseRejectionEventInit init; init.setPromise(ScriptPromise(m_scriptState, value)); init.setReason(ScriptValue(m_scriptState, reason)); RefPtrWillBeRawPtr<PromiseRejectionEvent> event = PromiseRejectionEvent::create(m_scriptState, EventTypeNames::rejectionhandled, init); target->dispatchEvent(event); } if (m_shouldLogToConsole) { RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, RevokedErrorMessageLevel, "Handler added to rejected promise"); consoleMessage->setRelatedMessageId(m_consoleMessageId); executionContext->addConsoleMessage(consoleMessage.release()); } }
ScriptPromise ScriptPromise::createPending() { v8::Isolate* isolate = v8::Isolate::GetCurrent(); ASSERT(isolate->InContext()); v8::Handle<v8::Object> promise = V8PromiseCustom::createPromise(v8::Object::New(isolate), isolate); return ScriptPromise(promise, isolate); }
ScriptPromise ImageBitmapSource::createImageBitmap( ScriptState* scriptState, EventTarget& eventTarget, Optional<IntRect> cropRect, const ImageBitmapOptions& options, ExceptionState& exceptionState) { return ScriptPromise(); }
ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, HTMLCanvasElement* canvas, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) { // This variant does not work in worker threads. ASSERT(eventTarget.toDOMWindow()); if (!canvas->originClean()) { exceptionState.throwSecurityError("The canvas element provided is tainted with cross-origin data."); return ScriptPromise(); } if (!sw || !sh) { exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); return ScriptPromise(); } // FIXME: make ImageBitmap creation asynchronous crbug.com/258082 return fulfillImageBitmap(scriptState, canvas->isPaintable() ? ImageBitmap::create(canvas, IntRect(sx, sy, sw, sh)) : nullptr); }
ScriptPromise Body::rejectInvalidConsumption(ScriptState* scriptState) { if (m_opaque) return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "The body is opaque.")); if (bodyUsed()) return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read")); return ScriptPromise(); }
ScriptPromise OfflineAudioContext::suspendContext(ScriptState* scriptState) { // This CANNOT be called on OfflineAudioContext; this is only to implement // the pure virtual interface from AbstractAudioContext. RELEASE_ASSERT_NOT_REACHED(); return ScriptPromise(); }
ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, ImageBitmap* bitmap, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) { if (!sw || !sh) { exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); return ScriptPromise(); } // FIXME: make ImageBitmap creation asynchronous crbug.com/258082 return fulfillImageBitmap(scriptState, ImageBitmap::create(bitmap, IntRect(sx, sy, sw, sh))); }
ScriptPromise ScriptPromise::reject(ScriptState* scriptState, v8::Local<v8::Value> value) { if (value.IsEmpty()) return ScriptPromise(); InternalResolver resolver(scriptState); ScriptPromise promise = resolver.promise(); resolver.reject(value); return promise; }
ScriptPromise ScriptPromiseResolver::promise() { ASSERT(m_isolate->InContext()); if (!m_resolver.hasNoValue()) { v8::Local<v8::Promise::Resolver> v8Resolver = m_resolver.v8Value().As<v8::Promise::Resolver>(); return ScriptPromise(v8Resolver->GetPromise(), m_isolate); } return m_promise; }
ScriptPromise Notification::requestPermission(ScriptState* scriptState, NotificationPermissionCallback* deprecatedCallback) { ExecutionContext* context = scriptState->executionContext(); if (NotificationPermissionClient* permissionClient = NotificationPermissionClient::from(context)) return permissionClient->requestPermission(scriptState, deprecatedCallback); // The context has been detached. Return a promise that will never settle. ASSERT(context->activeDOMObjectsAreStopped()); return ScriptPromise(); }
ScriptPromise ScriptPromise::createPending(ExecutionContext* context) { ASSERT(context); v8::Isolate* isolate = toIsolate(context); ASSERT(isolate->InContext()); v8::Handle<v8::Context> v8Context = toV8Context(context, DOMWrapperWorld::current()); v8::Handle<v8::Object> creationContext = v8Context.IsEmpty() ? v8::Object::New(isolate) : v8Context->Global(); v8::Handle<v8::Object> promise = V8PromiseCustom::createPromise(creationContext, isolate); return ScriptPromise(promise, isolate); }
ScriptPromise FontFaceSet::ready(ScriptState* scriptState) { if (!inActiveDocumentContext()) return ScriptPromise(); OwnPtr<FontsReadyPromiseResolver> resolver = FontsReadyPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); m_readyResolvers.append(resolver.release()); handlePendingEventsAndPromisesSoon(); return promise; }
ScriptPromiseResolver::ScriptPromiseResolver(v8::Isolate* isolate) : m_isolate(isolate) { ASSERT(isolate->InContext()); if (RuntimeEnabledFeatures::scriptPromiseOnV8PromiseEnabled()) { m_resolver = ScriptValue(v8::Promise::Resolver::New(isolate), isolate); } else { m_promise = ScriptPromise(V8PromiseCustom::createPromise(v8::Object::New(isolate), isolate), isolate); } }
ScriptPromise SubtleCrypto::exportKey(const String& rawFormat, Key* key, ExceptionState& es) { WebKit::WebCryptoKeyFormat format; if (!Key::parseFormat(rawFormat, format, es)) return ScriptPromise(); if (!key) { es.throwTypeError("Invalid key argument"); return ScriptPromise(); } if (!key->extractable()) { es.throwDOMException(NotSupportedError, "key is not extractable"); return ScriptPromise(); } RefPtr<CryptoResult> result = CryptoResult::create(); WebKit::Platform::current()->crypto()->exportKey(format, key->key(), result->result()); return result->promise(); }
void report() { if (!m_scriptState->contextIsValid()) return; // If execution termination has been triggered, quietly bail out. if (v8::V8::IsExecutionTerminating(m_scriptState->isolate())) return; ExecutionContext* executionContext = m_scriptState->executionContext(); if (!executionContext) return; ScriptState::Scope scope(m_scriptState); v8::Local<v8::Value> value = m_promise.newLocal(m_scriptState->isolate()); v8::Local<v8::Value> reason = m_exception.newLocal(m_scriptState->isolate()); // Either collected or https://crbug.com/450330 if (value.IsEmpty() || !value->IsPromise()) return; ASSERT(!hasHandler()); EventTarget* target = executionContext->errorEventTarget(); if (RuntimeEnabledFeatures::promiseRejectionEventEnabled() && target && !executionContext->shouldSanitizeScriptError(m_resourceName, m_corsStatus)) { PromiseRejectionEventInit init; init.setPromise(ScriptPromise(m_scriptState, value)); init.setReason(ScriptValue(m_scriptState, reason)); init.setCancelable(true); RefPtrWillBeRawPtr<PromiseRejectionEvent> event = PromiseRejectionEvent::create(m_scriptState, EventTypeNames::unhandledrejection, init); // Log to console if event was not preventDefault()'ed. m_shouldLogToConsole = target->dispatchEvent(event); } if (m_shouldLogToConsole) { const String errorMessage = "Uncaught (in promise)"; Vector<ScriptValue> args; args.append(ScriptValue(m_scriptState, v8String(m_scriptState->isolate(), errorMessage))); args.append(ScriptValue(m_scriptState, reason)); RefPtrWillBeRawPtr<ScriptArguments> arguments = ScriptArguments::create(m_scriptState, args); String embedderErrorMessage = m_errorMessage; if (embedderErrorMessage.isEmpty()) embedderErrorMessage = errorMessage; else if (embedderErrorMessage.startsWith("Uncaught ")) embedderErrorMessage.insert(" (in promise)", 8); RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, embedderErrorMessage, m_resourceName, m_lineNumber, m_columnNumber); consoleMessage->setScriptArguments(arguments); consoleMessage->setCallStack(m_callStack); consoleMessage->setScriptId(m_scriptId); m_consoleMessageId = consoleMessage->assignMessageId(); executionContext->addConsoleMessage(consoleMessage.release()); } m_callStack.clear(); }