EncodedJSValue JSC_HOST_CALL constructJSFile(ExecState& exec) { auto* constructor = jsCast<DOMConstructorObject*>(exec.callee()); ScriptExecutionContext* context = constructor->scriptExecutionContext(); if (!context) return throwVMError(&exec, createReferenceError(&exec, "File constructor associated document is unavailable")); JSValue arg = exec.argument(0); if (arg.isUndefinedOrNull()) return throwVMTypeError(&exec, ASCIILiteral("First argument to File constructor must be a valid sequence, was undefined or null")); unsigned blobPartsLength = 0; JSObject* blobParts = toJSSequence(exec, arg, blobPartsLength); if (exec.hadException()) return JSValue::encode(jsUndefined()); ASSERT(blobParts); arg = exec.argument(1); if (arg.isUndefined()) return throwVMTypeError(&exec, ASCIILiteral("Second argument to File constructor must be a valid string, was undefined")); String filename = arg.toWTFString(&exec).replace('/', ':'); if (exec.hadException()) return JSValue::encode(jsUndefined()); String normalizedType; Optional<int64_t> lastModified; arg = exec.argument(2); if (!arg.isUndefinedOrNull()) { JSObject* filePropertyBagObject = arg.getObject(); if (!filePropertyBagObject) return throwVMTypeError(&exec, ASCIILiteral("Third argument of the constructor is not of type Object")); // Create the dictionary wrapper from the initializer object. JSDictionary dictionary(&exec, filePropertyBagObject); // Attempt to get the type property. String type; dictionary.get("type", type); if (exec.hadException()) return JSValue::encode(jsUndefined()); normalizedType = Blob::normalizedContentType(type); // Only try to parse the lastModified date if there was not an invalid type argument. if (type.isEmpty() || !normalizedType.isEmpty()) { dictionary.get("lastModified", lastModified); if (exec.hadException()) return JSValue::encode(jsUndefined()); } } if (!lastModified) lastModified = currentTimeMS(); BlobBuilder blobBuilder; for (unsigned i = 0; i < blobPartsLength; ++i) { JSValue item = blobParts->get(&exec, i); if (exec.hadException()) return JSValue::encode(jsUndefined()); if (ArrayBuffer* arrayBuffer = toArrayBuffer(item)) blobBuilder.append(arrayBuffer); else if (RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(item)) blobBuilder.append(WTFMove(arrayBufferView)); else if (Blob* blob = JSBlob::toWrapped(item)) blobBuilder.append(blob); else { String string = item.toWTFString(&exec); if (exec.hadException()) return JSValue::encode(jsUndefined()); blobBuilder.append(string, ASCIILiteral("transparent")); } } auto file = File::create(blobBuilder.finalize(), filename, normalizedType, lastModified.value()); return JSValue::encode(CREATE_DOM_WRAPPER(constructor->globalObject(), File, WTFMove(file))); }
void IntlCollator::initializeCollator(ExecState& state, JSValue locales, JSValue optionsValue) { // 10.1.1 InitializeCollator (collator, locales, options) (ECMA-402 2.0) // 1. If collator has an [[initializedIntlObject]] internal slot with value true, throw a TypeError exception. // 2. Set collator.[[initializedIntlObject]] to true. // 3. Let requestedLocales be CanonicalizeLocaleList(locales). auto requestedLocales = canonicalizeLocaleList(state, locales); // 4. ReturnIfAbrupt(requestedLocales). if (state.hadException()) return; // 5. If options is undefined, then JSObject* options; if (optionsValue.isUndefined()) { // a. Let options be ObjectCreate(%ObjectPrototype%). options = constructEmptyObject(&state); } else { // 6. Else // a. Let options be ToObject(options). options = optionsValue.toObject(&state); // b. ReturnIfAbrupt(options). if (state.hadException()) return; } // 7. Let u be GetOption(options, "usage", "string", «"sort", "search"», "sort"). String usageString = intlStringOption(state, options, state.vm().propertyNames->usage, { "sort", "search" }, "usage must be either \"sort\" or \"search\"", "sort"); // 8. ReturnIfAbrupt(u). if (state.hadException()) return; // 9. Set collator.[[usage]] to u. if (usageString == "sort") m_usage = Usage::Sort; else if (usageString == "search") m_usage = Usage::Search; else ASSERT_NOT_REACHED(); // 10. If u is "sort", then // a. Let localeData be the value of %Collator%.[[sortLocaleData]]; // 11. Else // a. Let localeData be the value of %Collator%.[[searchLocaleData]]. Vector<String> (*localeData)(const String&, size_t); if (m_usage == Usage::Sort) localeData = sortLocaleData; else localeData = searchLocaleData; // 12. Let opt be a new Record. HashMap<String, String> opt; // 13. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit"). String matcher = intlStringOption(state, options, state.vm().propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit"); // 14. ReturnIfAbrupt(matcher). if (state.hadException()) return; // 15. Set opt.[[localeMatcher]] to matcher. opt.add(ASCIILiteral("localeMatcher"), matcher); // 16. For each row in Table 1, except the header row, do: // a. Let key be the name given in the Key column of the row. // b. Let prop be the name given in the Property column of the row. // c. Let type be the string given in the Type column of the row. // d. Let list be a List containing the Strings given in the Values column of the row, or undefined if no strings are given. // e. Let value be GetOption(options, prop, type, list, undefined). // f. ReturnIfAbrupt(value). // g. If the string given in the Type column of the row is "boolean" and value is not undefined, then // i. Let value be ToString(value). // ii. ReturnIfAbrupt(value). // h. Set opt.[[<key>]] to value. { String numericString; bool usesFallback; bool numeric = intlBooleanOption(state, options, state.vm().propertyNames->numeric, usesFallback); if (state.hadException()) return; if (!usesFallback) numericString = ASCIILiteral(numeric ? "true" : "false"); opt.add(ASCIILiteral("kn"), numericString); } { String caseFirst = intlStringOption(state, options, state.vm().propertyNames->caseFirst, { "upper", "lower", "false" }, "caseFirst must be either \"upper\", \"lower\", or \"false\"", nullptr); if (state.hadException()) return; opt.add(ASCIILiteral("kf"), caseFirst); } // 17. Let relevantExtensionKeys be the value of %Collator%.[[relevantExtensionKeys]]. // 18. Let r be ResolveLocale(%Collator%.[[availableLocales]], requestedLocales, opt, relevantExtensionKeys, localeData). auto& availableLocales = state.callee()->globalObject()->intlCollatorAvailableLocales(); auto result = resolveLocale(state, availableLocales, requestedLocales, opt, relevantExtensionKeys, WTF_ARRAY_LENGTH(relevantExtensionKeys), localeData); // 19. Set collator.[[locale]] to the value of r.[[locale]]. m_locale = result.get(ASCIILiteral("locale")); // 20. Let k be 0. // 21. Let lenValue be Get(relevantExtensionKeys, "length"). // 22. Let len be ToLength(lenValue). // 23. Repeat while k < len: // a. Let Pk be ToString(k). // b. Let key be Get(relevantExtensionKeys, Pk). // c. ReturnIfAbrupt(key). // d. If key is "co", then // i. Let property be "collation". // ii. Let value be the value of r.[[co]]. // iii. If value is null, let value be "default". // e. Else use the row of Table 1 that contains the value of key in the Key column: // i. Let property be the name given in the Property column of the row. // ii. Let value be the value of r.[[<key>]]. // iii. If the name given in the Type column of the row is "boolean", let value be the result of comparing value with "true". // f. Set collator.[[<property>]] to value. // g. Increase k by 1. const String& collation = result.get(ASCIILiteral("co")); m_collation = collation.isNull() ? ASCIILiteral("default") : collation; m_numeric = (result.get(ASCIILiteral("kn")) == "true"); // 24. Let s be GetOption(options, "sensitivity", "string", «"base", "accent", "case", "variant"», undefined). String sensitivityString = intlStringOption(state, options, state.vm().propertyNames->sensitivity, { "base", "accent", "case", "variant" }, "sensitivity must be either \"base\", \"accent\", \"case\", or \"variant\"", nullptr); // 25. ReturnIfAbrupt(s). if (state.hadException()) return; // 26. If s is undefined, then // a. If u is "sort", then let s be "variant". // b. Else // i. Let dataLocale be the value of r.[[dataLocale]]. // ii. Let dataLocaleData be Get(localeData, dataLocale). // iii. Let s be Get(dataLocaleData, "sensitivity"). // 10.2.3 "[[searchLocaleData]][locale] must have a sensitivity property with a String value equal to "base", "accent", "case", or "variant" for all locale values." // 27. Set collator.[[sensitivity]] to s. if (sensitivityString == "base") m_sensitivity = Sensitivity::Base; else if (sensitivityString == "accent") m_sensitivity = Sensitivity::Accent; else if (sensitivityString == "case") m_sensitivity = Sensitivity::Case; else m_sensitivity = Sensitivity::Variant; // 28. Let ip be GetOption(options, "ignorePunctuation", "boolean", undefined, false). bool usesFallback; bool ignorePunctuation = intlBooleanOption(state, options, state.vm().propertyNames->ignorePunctuation, usesFallback); if (usesFallback) ignorePunctuation = false; // 29. ReturnIfAbrupt(ip). if (state.hadException()) return; // 30. Set collator.[[ignorePunctuation]] to ip. m_ignorePunctuation = ignorePunctuation; // 31. Set collator.[[boundCompare]] to undefined. // 32. Set collator.[[initializedCollator]] to true. m_initializedCollator = true; // 33. Return collator. }
void JSAbstractEventListener::handleEvent(Event* event, bool isWindowEvent) { JSObject* listener = listenerObj(); if (!listener) return; JSDOMWindow* window = this->window(); // Null check as clearWindow() can clear this and we still get called back by // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275 if (!window) return; Frame* frame = window->impl()->frame(); if (!frame) return; ScriptController* script = frame->script(); if (!script->isEnabled() || script->isPaused()) return; JSLock lock(false); ExecState* exec = window->globalExec(); JSValue* handleEventFunction = listener->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = handleEventFunction->getCallData(callData); if (callType == CallTypeNone) { handleEventFunction = 0; callType = listener->getCallData(callData); } if (callType != CallTypeNone) { ref(); ArgList args; args.append(toJS(exec, event)); Event* savedEvent = window->currentEvent(); window->setCurrentEvent(event); JSValue* retval; if (handleEventFunction) { window->startTimeoutCheck(); retval = call(exec, handleEventFunction, callType, callData, listener, args); } else { JSValue* thisValue; if (isWindowEvent) thisValue = window->shell(); else thisValue = toJS(exec, event->currentTarget()); window->startTimeoutCheck(); retval = call(exec, listener, callType, callData, thisValue, args); } window->stopTimeoutCheck(); window->setCurrentEvent(savedEvent); if (exec->hadException()) frame->domWindow()->console()->reportCurrentException(exec); else { if (!retval->isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(retval->toString(exec)); if (m_isHTML) { bool retvalbool; if (retval->getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } Document::updateDocumentsRendering(); deref(); } }
void JSLazyEventListener::parseCode(ScriptExecutionContext* executionContext) const { ASSERT(executionContext); ASSERT(executionContext->isDocument()); if (!executionContext) return; if (m_parsed) return; Frame* frame = static_cast<Document*>(executionContext)->frame(); if (!frame) return; ScriptController* scriptController = frame->script(); if (!scriptController->isEnabled()) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext); if (!globalObject) return; // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. if (m_originalNode) { JSLock lock(SilenceAssertionsOnly); // FIXME: Should pass the global object associated with the node toJS(globalObject->globalExec(), globalObject, m_originalNode); } if (executionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // FIXME: Is this check needed for non-Document contexts? ScriptController* script = frame->script(); if (!script->isEnabled() || script->isPaused()) return; } m_parsed = true; ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; args.append(jsNontrivialString(exec, m_eventParameterName)); args.append(jsString(exec, m_code)); m_jsFunction = constructFunction(exec, args, Identifier(exec, m_functionName), m_sourceURL, m_lineNumber); // FIXME: is globalExec ok? JSFunction* listenerAsFunction = static_cast<JSFunction*>(m_jsFunction); if (exec->hadException()) { exec->clearException(); // failed to parse, so let's just make this listener a no-op m_jsFunction = 0; } else if (m_originalNode) { // Add the event's home element to the scope // (and the document, and the form - see JSHTMLElement::eventHandlerScope) ScopeChain scope = listenerAsFunction->scope(); JSValue thisObj = toJS(exec, globalObject, m_originalNode); if (thisObj.isObject()) { static_cast<JSNode*>(asObject(thisObj))->pushEventHandlerScope(exec, scope); listenerAsFunction->setScope(scope); } } // Since we only parse once, there's no need to keep data used for parsing around anymore. m_functionName = String(); m_code = String(); m_eventParameterName = String(); m_sourceURL = String(); }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionTerminated()) return; JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get()); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>. // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in. if (frame->domWindow() != window->impl()) return; // FIXME: Is this check needed for other contexts? ScriptController* script = frame->script(); if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = handleEventFunction.getCallData(callData); if (callType == CallTypeNone) { handleEventFunction = JSValue(); callType = jsFunction->getCallData(callData); } if (callType != CallTypeNone) { ref(); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); JSGlobalData* globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject); globalData->timeoutChecker.start(); JSValue retval = handleEventFunction ? JSC::call(exec, handleEventFunction, callType, callData, jsFunction, args) : JSC::call(exec, jsFunction, callType, callData, toJS(exec, globalObject, event->currentTarget()), args); globalData->timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); if (exec->hadException()) #if PLATFORM(APOLLO) reportApolloException(globalObject); #else reportCurrentException(exec); #endif else { if (!retval.isUndefinedOrNull() && event->storesResultAsString())
JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const { ASSERT(is<Document>(executionContext)); if (!executionContext) return nullptr; ASSERT(!m_code.isNull()); ASSERT(!m_eventParameterName.isNull()); if (m_code.isNull() || m_eventParameterName.isNull()) return nullptr; Document& document = downcast<Document>(*executionContext); if (!document.frame()) return nullptr; if (!document.contentSecurityPolicy()->allowInlineEventHandlers(m_sourceURL, m_sourcePosition.m_line)) return nullptr; ScriptController& script = document.frame()->script(); if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused()) return nullptr; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld()); if (!globalObject) return nullptr; ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; args.append(jsNontrivialString(exec, m_eventParameterName)); args.append(jsStringWithCache(exec, m_code)); // We want all errors to refer back to the line on which our attribute was // declared, regardless of any newlines in our JavaScript source text. int overrideLineNumber = m_sourcePosition.m_line.oneBasedInt(); JSObject* jsFunction = constructFunctionSkippingEvalEnabledCheck( exec, exec->lexicalGlobalObject(), args, Identifier::fromString(exec, m_functionName), m_sourceURL, m_sourcePosition, overrideLineNumber); if (exec->hadException()) { reportCurrentException(exec); exec->clearException(); return nullptr; } JSFunction* listenerAsFunction = jsCast<JSFunction*>(jsFunction); if (m_originalNode) { if (!wrapper()) { // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. JSLockHolder lock(exec); // FIXME: Should pass the global object associated with the node setWrapper(exec->vm(), asObject(toJS(exec, globalObject, *m_originalNode))); } // Add the event's home element to the scope // (and the document, and the form - see JSHTMLElement::eventHandlerScope) listenerAsFunction->setScope(exec->vm(), jsCast<JSNode*>(wrapper())->pushEventHandlerScope(exec, listenerAsFunction->scope())); } return jsFunction; }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get()); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>. // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in. if (frame->domWindow() != window->impl()) return; // FIXME: Is this check needed for other contexts? ScriptController* script = frame->script(); if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction; CallData callData; CallType callType = getCallData(handleEventFunction, callData); // If jsFunction is not actually a function, see if it implements the EventListener interface and use that if (callType == CallTypeNone) { handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); callType = getCallData(handleEventFunction, callData); } if (callType != CallTypeNone) { RefPtr<JSEventListener> protect(this); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); JSGlobalData& globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(globalData, globalData.dynamicGlobalObject ? globalData.dynamicGlobalObject : globalObject); globalData.timeoutChecker.start(); JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction; JSValue retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args) : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args); globalData.timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); #if ENABLE(WORKERS) if (scriptExecutionContext->isWorkerContext()) { bool terminatorCausedException = (exec->hadException() && isTerminatedExecutionException(exec->exception())); if (terminatorCausedException || globalData.terminator.shouldTerminate()) static_cast<WorkerContext*>(scriptExecutionContext)->script()->forbidExecution(); } #endif if (exec->hadException()) { event->target()->uncaughtExceptionInEventHandler(); reportCurrentException(exec); } else { if (!retval.isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(ustringToString(retval.toString(exec)->value(exec))); if (m_isAttribute) { if (retval.isFalse()) event->preventDefault(); } } } }
JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const { ASSERT(executionContext); ASSERT(executionContext->isDocument()); if (!executionContext) return 0; Frame* frame = static_cast<Document*>(executionContext)->frame(); if (!frame) return 0; ScriptController* scriptController = frame->script(); if (!scriptController->canExecuteScripts(AboutToExecuteScript)) return 0; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld()); if (!globalObject) return 0; if (executionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return 0; // FIXME: Is this check needed for non-Document contexts? ScriptController* script = frame->script(); if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) return 0; } ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; args.append(jsNontrivialString(exec, stringToUString(m_eventParameterName))); args.append(jsString(exec, m_code)); JSObject* jsFunction = constructFunction(exec, args, Identifier(exec, stringToUString(m_functionName)), stringToUString(m_sourceURL), m_lineNumber); // FIXME: is globalExec ok? if (exec->hadException()) { exec->clearException(); return 0; } JSFunction* listenerAsFunction = static_cast<JSFunction*>(jsFunction); if (m_originalNode) { if (!wrapper()) { // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. JSLock lock(SilenceAssertionsOnly); // FIXME: Should pass the global object associated with the node setWrapper(asObject(toJS(globalObject->globalExec(), globalObject, m_originalNode))); } // Add the event's home element to the scope // (and the document, and the form - see JSHTMLElement::eventHandlerScope) ScopeChain scope = listenerAsFunction->scope(); static_cast<JSNode*>(wrapper())->pushEventHandlerScope(exec, scope); listenerAsFunction->setScope(scope); } // Since we only parse once, there's no need to keep data used for parsing around anymore. m_functionName = String(); m_code = String(); m_eventParameterName = String(); m_sourceURL = String(); return jsFunction; }
void JSEventListener::handleEvent(Event* event, bool isWindowEvent) { JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(); if (!jsFunction) return; JSDOMGlobalObject* globalObject = m_globalObject; // Null check as clearGlobalObject() can clear this and we still get called back by // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275 // FIXME: Is this check still necessary? Requests are supposed to be stopped before clearGlobalObject() is called. ASSERT(globalObject); if (!globalObject) return; ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext(); if (!scriptExecutionContext) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>. // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in. if (frame->domWindow() != window->impl()) return; // FIXME: Is this check needed for other contexts? ScriptController* script = frame->script(); if (!script->isEnabled() || script->isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = handleEventFunction.getCallData(callData); if (callType == CallTypeNone) { handleEventFunction = JSValue(); callType = jsFunction->getCallData(callData); } if (callType != CallTypeNone) { ref(); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); // If this event handler is the first JavaScript to execute, then the // dynamic global object should be set to the global object of the // window in which the event occurred. JSGlobalData* globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject); JSValue retval; if (handleEventFunction) { globalObject->globalData()->timeoutChecker.start(); retval = call(exec, handleEventFunction, callType, callData, jsFunction, args); } else { JSValue thisValue; if (isWindowEvent) thisValue = globalObject->toThisObject(exec); else thisValue = toJS(exec, globalObject, event->currentTarget()); globalObject->globalData()->timeoutChecker.start(); retval = call(exec, jsFunction, callType, callData, thisValue, args); } globalObject->globalData()->timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); if (exec->hadException()) reportCurrentException(exec); else { if (!retval.isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(retval.toString(exec)); if (m_isAttribute) { bool retvalbool; if (retval.getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } if (scriptExecutionContext->isDocument()) Document::updateStyleForAllDocuments(); deref(); } }
RefPtr<IDBRequest> IDBObjectStore::putOrAdd(ExecState& state, JSValue value, RefPtr<IDBKey> key, IndexedDB::ObjectStoreOverwriteMode overwriteMode, InlineKeyCheck inlineKeyCheck, ExceptionCodeWithMessage& ec) { LOG(IndexedDB, "IDBObjectStore::putOrAdd"); ASSERT(currentThread() == m_transaction->database().originThreadID()); auto context = scriptExecutionContextFromExecState(&state); if (!context) { ec.code = IDBDatabaseException::UnknownError; ec.message = ASCIILiteral("Unable to store record in object store because it does not have a valid script execution context"); return nullptr; } // The IDB spec for several IDBObjectStore methods states that transaction related exceptions should fire before // the exception for an object store being deleted. // However, a handful of W3C IDB tests expect the deleted exception even though the transaction inactive exception also applies. // Additionally, Chrome and Edge agree with the test, as does Legacy IDB in WebKit. // Until this is sorted out, we'll agree with the test and the majority share browsers. if (m_deleted) { ec.code = IDBDatabaseException::InvalidStateError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The object store has been deleted."); return nullptr; } if (!m_transaction->isActive()) { ec.code = IDBDatabaseException::TransactionInactiveError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The transaction is inactive or finished."); return nullptr; } if (m_transaction->isReadOnly()) { ec.code = IDBDatabaseException::ReadOnlyError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The transaction is read-only."); return nullptr; } RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(&state, value, nullptr, nullptr); if (state.hadException()) { // Clear the DOM exception from the serializer so we can give a more targeted exception. state.clearException(); ec.code = IDBDatabaseException::DataCloneError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: An object could not be cloned."); return nullptr; } bool privateBrowsingEnabled = false; if (context->isDocument()) { if (auto* page = static_cast<Document*>(context)->page()) privateBrowsingEnabled = page->sessionID().isEphemeral(); } if (serializedValue->hasBlobURLs() && privateBrowsingEnabled) { // https://bugs.webkit.org/show_bug.cgi?id=156347 - Support Blobs in private browsing. ec.code = IDBDatabaseException::DataCloneError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: BlobURLs are not yet supported."); return nullptr; } if (key && !key->isValid()) { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The parameter is not a valid key."); return nullptr; } bool usesInlineKeys = !m_info.keyPath().isNull(); bool usesKeyGenerator = autoIncrement(); if (usesInlineKeys && inlineKeyCheck == InlineKeyCheck::Perform) { if (key) { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The object store uses in-line keys and the key parameter was provided."); return nullptr; } RefPtr<IDBKey> keyPathKey = maybeCreateIDBKeyFromScriptValueAndKeyPath(state, value, m_info.keyPath()); if (keyPathKey && !keyPathKey->isValid()) { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: Evaluating the object store's key path yielded a value that is not a valid key."); return nullptr; } if (!keyPathKey) { if (usesKeyGenerator) { if (!canInjectIDBKeyIntoScriptValue(state, value, m_info.keyPath())) { ec.code = IDBDatabaseException::DataError; return nullptr; } } else { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: Evaluating the object store's key path did not yield a value."); return nullptr; } } if (keyPathKey) { ASSERT(!key); key = keyPathKey; } } else if (!usesKeyGenerator && !key) { ec.code = IDBDatabaseException::DataError; ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The object store uses out-of-line keys and has no key generator and the key parameter was not provided."); return nullptr; } return m_transaction->requestPutOrAdd(*context, *this, key.get(), *serializedValue, overwriteMode); }
// https://html.spec.whatwg.org/#dom-customelementsregistry-define JSValue JSCustomElementsRegistry::define(ExecState& state) { if (UNLIKELY(state.argumentCount() < 2)) return state.vm().throwException(&state, createNotEnoughArgumentsError(&state)); AtomicString localName(state.uncheckedArgument(0).toString(&state)->toAtomicString(&state)); if (UNLIKELY(state.hadException())) return jsUndefined(); JSValue constructorValue = state.uncheckedArgument(1); if (!constructorValue.isConstructor()) return throwTypeError(&state, ASCIILiteral("The second argument must be a constructor")); JSObject* constructor = constructorValue.getObject(); // FIXME: Throw a TypeError if constructor doesn't inherit from HTMLElement. // https://github.com/w3c/webcomponents/issues/541 switch (Document::validateCustomElementName(localName)) { case CustomElementNameValidationStatus::Valid: break; case CustomElementNameValidationStatus::ConflictsWithBuiltinNames: return throwSyntaxError(&state, ASCIILiteral("Custom element name cannot be same as one of the builtin elements")); case CustomElementNameValidationStatus::NoHyphen: return throwSyntaxError(&state, ASCIILiteral("Custom element name must contain a hyphen")); case CustomElementNameValidationStatus::ContainsUpperCase: return throwSyntaxError(&state, ASCIILiteral("Custom element name cannot contain an upper case letter")); } // FIXME: Check re-entrancy here. // https://github.com/w3c/webcomponents/issues/545 CustomElementsRegistry& registry = wrapped(); if (registry.findInterface(localName)) { throwNotSupportedError(state, ASCIILiteral("Cannot define multiple custom elements with the same tag name")); return jsUndefined(); } if (registry.containsConstructor(constructor)) { throwNotSupportedError(state, ASCIILiteral("Cannot define multiple custom elements with the same class")); return jsUndefined(); } auto& vm = globalObject()->vm(); JSValue prototypeValue = constructor->get(&state, vm.propertyNames->prototype); if (state.hadException()) return jsUndefined(); if (!prototypeValue.isObject()) return throwTypeError(&state, ASCIILiteral("Custom element constructor's prototype must be an object")); JSObject& prototypeObject = *asObject(prototypeValue); QualifiedName name(nullAtom, localName, HTMLNames::xhtmlNamespaceURI); auto elementInterface = JSCustomElementInterface::create(name, constructor, globalObject()); auto* connectedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "connectedCallback")); if (state.hadException()) return jsUndefined(); if (connectedCallback) elementInterface->setConnectedCallback(connectedCallback); auto* disconnectedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "disconnectedCallback")); if (state.hadException()) return jsUndefined(); if (disconnectedCallback) elementInterface->setDisconnectedCallback(disconnectedCallback); // FIXME: Add the support for adoptedCallback. getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "adoptedCallback")); if (state.hadException()) return jsUndefined(); auto* attributeChangedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "attributeChangedCallback")); if (state.hadException()) return jsUndefined(); if (attributeChangedCallback) { auto value = convertOptional<Vector<String>>(state, constructor->get(&state, Identifier::fromString(&state, "observedAttributes"))); if (state.hadException()) return jsUndefined(); if (value) elementInterface->setAttributeChangedCallback(attributeChangedCallback, *value); } PrivateName uniquePrivateName; globalObject()->putDirect(vm, uniquePrivateName, constructor); registry.addElementDefinition(WTFMove(elementInterface)); // FIXME: 17. Let map be registry's upgrade candidates map. // FIXME: 18. Upgrade a newly-defined element given map and definition. // FIXME: 19. Resolve whenDefined promise. return jsUndefined(); }
void JSAbstractEventListener::handleEvent(Event* ele, bool isWindowEvent) { #ifdef KJS_DEBUGGER if (KJSDebugWin::instance() && KJSDebugWin::instance()->inSession()) return; #endif Event *event = ele; JSObject* listener = listenerObj(); if (!listener) return; Window* window = windowObj(); Frame *frame = window->frame(); if (!frame) return; KJSProxy* proxy = frame->jScript(); if (!proxy) return; JSLock lock; ScriptInterpreter* interpreter = proxy->interpreter(); ExecState* exec = interpreter->globalExec(); JSValue* handleEventFuncValue = listener->get(exec, "handleEvent"); JSObject* handleEventFunc = 0; if (handleEventFuncValue->isObject()) { handleEventFunc = static_cast<JSObject*>(handleEventFuncValue); if (!handleEventFunc->implementsCall()) handleEventFunc = 0; } if (handleEventFunc || listener->implementsCall()) { ref(); List args; args.append(toJS(exec, event)); // Set the event we're handling in the Window object window->setCurrentEvent(event); // ... and in the interpreter interpreter->setCurrentEvent(event); JSValue* retval; if (handleEventFunc) { interpreter->startTimeoutCheck(); retval = handleEventFunc->call(exec, listener, args); } else { JSObject* thisObj; if (isWindowEvent) thisObj = window; else thisObj = static_cast<JSObject*>(toJS(exec, event->currentTarget())); interpreter->startTimeoutCheck(); retval = listener->call(exec, thisObj, args); } interpreter->stopTimeoutCheck(); window->setCurrentEvent(0); interpreter->setCurrentEvent(0); if (exec->hadException()) { JSObject* exception = exec->exception()->toObject(exec); String message = exception->get(exec, messagePropertyName)->toString(exec); int lineNumber = exception->get(exec, "line")->toInt32(exec); String sourceURL = exception->get(exec, "sourceURL")->toString(exec); if (Interpreter::shouldPrintExceptions()) printf("(event handler):%s\n", message.deprecatedString().utf8().data()); frame->addMessageToConsole(message, lineNumber, sourceURL); exec->clearException(); } else { if (!retval->isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(retval->toString(exec)); if (html) { bool retvalbool; if (retval->getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } Document::updateDocumentsRendering(); deref(); } }
void JSLazyEventListener::parseCode() const { if (!parsed) { KHTMLPart *part = qobject_cast<KHTMLPart*>(static_cast<Window*>(win.get())->part()); KJSProxy *proxy = 0L; if (part) proxy = part->jScript(); if (proxy) { KJS::ScriptInterpreter *interpreter = static_cast<KJS::ScriptInterpreter *>(proxy->interpreter()); ExecState *exec = interpreter->globalExec(); //KJS::Constructor constr(KJS::Global::current().get("Function").imp()); KJS::FunctionObjectImp *constr = static_cast<KJS::FunctionObjectImp*>(interpreter->builtinFunction()); KJS::List args; if (svg) args.append(jsString("evt")); else args.append(jsString("event")); args.append(jsString(code)); listener = constr->construct(exec, args, Identifier(UString(name)), url, lineNum); // ### is globalExec ok ? compareListenerImp = listener; if (exec->hadException()) { exec->clearException(); // failed to parse, so let's just make this listener a no-op listener = 0; } else if (!listener->inherits(&DeclaredFunctionImp::info)) { listener = 0;// Error creating function } else { DeclaredFunctionImp *declFunc = static_cast<DeclaredFunctionImp*>(listener.get()); if (originalNode) { // Add the event's home element to the scope // (and the document, and the form - see KJS::HTMLElement::eventHandlerScope) ScopeChain scope = declFunc->scope(); JSObject *thisObj = getDOMNode(exec, originalNode)->getObject(); if (thisObj) { static_cast<DOMNode*>(thisObj)->pushEventHandlerScope(exec, scope); declFunc->setScope(scope); } } } } // no more need to keep the unparsed code around code.clear(); if (listener) { static_cast<Window*>(win.get())->jsEventListeners.insert(QPair<void*, bool>(compareListenerImp.get(), true), (KJS::JSEventListener *)(this)); } parsed = true; } }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; JSLockHolder lock(scriptExecutionContext->vm()); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, *m_isolatedWorld); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = jsCast<JSDOMWindow*>(globalObject); if (!window->impl().isCurrentlyDisplayedInFrame()) return; // FIXME: Is this check needed for other contexts? ScriptController& script = window->impl().frame()->script(); if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction; CallData callData; CallType callType = getCallData(handleEventFunction, callData); // If jsFunction is not actually a function, see if it implements the EventListener interface and use that if (callType == CallTypeNone) { handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); callType = getCallData(handleEventFunction, callData); } if (callType != CallTypeNone) { Ref<JSEventListener> protect(*this); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); VM& vm = globalObject->vm(); VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData); JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction; JSValue retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args) : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args); InspectorInstrumentation::didCallFunction(cookie); globalObject->setCurrentEvent(savedEvent); if (scriptExecutionContext->isWorkerGlobalScope()) { bool terminatorCausedException = (exec->hadException() && isTerminatedExecutionException(exec->exception())); if (terminatorCausedException || vm.watchdog.didFire()) static_cast<WorkerGlobalScope*>(scriptExecutionContext)->script()->forbidExecution(); } if (exec->hadException()) { event->target()->uncaughtExceptionInEventHandler(); reportCurrentException(exec); } else { if (!retval.isUndefinedOrNull() && event->isBeforeUnloadEvent()) toBeforeUnloadEvent(event)->setReturnValue(retval.toString(exec)->value(exec)); if (m_isAttribute) { if (retval.isFalse()) event->preventDefault(); } } } }