JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) { ExecState* exec = toJS(ctx); JSLock lock(exec); unsigned count = 0; UStringBuilder builder; CallFrame* callFrame = exec; UString functionName; if (exec->callee()) { if (asObject(exec->callee())->inherits(&InternalFunction::s_info)) { functionName = asInternalFunction(exec->callee())->name(exec); builder.append("#0 "); builder.append(functionName); builder.append("() "); count++; } } while (true) { ASSERT(callFrame); int signedLineNumber; intptr_t sourceID; UString urlString; JSValue function; UString levelStr = UString::number(count); exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function); if (function) functionName = asFunction(function)->name(exec); else { // Caller is unknown, but if frame is empty we should still add the frame, because // something called us, and gave us arguments. if (count) break; } unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0; if (!builder.isEmpty()) builder.append("\n"); builder.append("#"); builder.append(levelStr); builder.append(" "); builder.append(functionName); builder.append("() at "); builder.append(urlString); builder.append(":"); builder.append(UString::number(lineNumber)); if (!function || ++count == maxStackSize) break; callFrame = callFrame->callerFrame(); } return OpaqueJSString::create(builder.toUString()).leakRef(); }
EncodedJSValue JSC_HOST_CALL constructJSHTMLElement(ExecState& exec) { auto* jsConstructor = jsCast<DOMConstructorObject*>(exec.callee()); auto* context = jsConstructor->scriptExecutionContext(); if (!is<Document>(context)) return throwConstructorDocumentUnavailableError(exec, "HTMLElement"); auto& document = downcast<Document>(*context); auto* window = document.domWindow(); if (!window) return throwVMTypeError(&exec, ASCIILiteral("new.target is not a valid custom element constructor")); auto* registry = window->customElementsRegistry(); if (!registry) return throwVMTypeError(&exec, ASCIILiteral("new.target is not a valid custom element constructor")); VM& vm = exec.vm(); JSValue newTargetValue = exec.thisValue(); JSObject* newTarget = newTargetValue.getObject(); auto* elementInterface = registry->findInterface(newTarget); if (!elementInterface) return throwVMTypeError(&exec, ASCIILiteral("new.target does not define a custom element")); if (!elementInterface->isUpgradingElement()) { auto* globalObject = jsConstructor->globalObject(); Structure* baseStructure = getDOMStructure<JSHTMLElement>(vm, *globalObject); auto* newElementStructure = InternalFunction::createSubclassStructure(&exec, newTargetValue, baseStructure); if (UNLIKELY(exec.hadException())) return JSValue::encode(jsUndefined()); Ref<HTMLElement> element = HTMLElement::create(elementInterface->name(), document); element->setIsUnresolvedCustomElement(); auto* jsElement = JSHTMLElement::create(newElementStructure, globalObject, element.get()); cacheWrapper(globalObject->world(), element.ptr(), jsElement); return JSValue::encode(jsElement); } Element* elementToUpgrade = elementInterface->lastElementInConstructionStack(); if (!elementToUpgrade) { throwInvalidStateError(exec, ASCIILiteral("Cannot instantiate a custom element inside its own constrcutor during upgrades")); return JSValue::encode(jsUndefined()); } JSValue elementWrapperValue = toJS(&exec, jsConstructor->globalObject(), *elementToUpgrade); ASSERT(elementWrapperValue.isObject()); JSValue newPrototype = newTarget->get(&exec, vm.propertyNames->prototype); if (exec.hadException()) return JSValue::encode(jsUndefined()); JSObject* elementWrapperObject = asObject(elementWrapperValue); JSObject::setPrototype(elementWrapperObject, &exec, newPrototype, true /* shouldThrowIfCantSet */); if (exec.hadException()) return JSValue::encode(jsUndefined()); elementInterface->didUpgradeLastElementInConstructionStack(); return JSValue::encode(elementWrapperValue); }
EncodedJSValue JSC_HOST_CALL constructJSWorker(ExecState& exec) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); DOMConstructorObject* jsConstructor = jsCast<DOMConstructorObject*>(exec.callee()); if (!exec.argumentCount()) return throwVMError(&exec, scope, createNotEnoughArgumentsError(&exec)); String scriptURL = exec.uncheckedArgument(0).toWTFString(&exec); if (exec.hadException()) return JSValue::encode(JSValue()); // See section 4.8.2 step 14 of WebWorkers for why this is the lexicalGlobalObject. DOMWindow& window = asJSDOMWindow(exec.lexicalGlobalObject())->wrapped(); ExceptionCode ec = 0; ASSERT(window.document()); RefPtr<Worker> worker = Worker::create(*window.document(), scriptURL, ec); if (ec) { setDOMException(&exec, ec); return JSValue::encode(JSValue()); } return JSValue::encode(toJSNewlyCreated(&exec, jsConstructor->globalObject(), WTFMove(worker))); }
EncodedJSValue JSC_HOST_CALL constructJSWorker(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); ASSERT(jsCast<DOMConstructorObject*>(state.callee())); ASSERT(jsCast<DOMConstructorObject*>(state.callee())->globalObject()); auto& globalObject = *jsCast<DOMConstructorObject*>(state.callee())->globalObject(); if (!state.argumentCount()) return throwVMError(&state, scope, createNotEnoughArgumentsError(&state)); String scriptURL = state.uncheckedArgument(0).toWTFString(&state); RETURN_IF_EXCEPTION(scope, encodedJSValue()); // See section 4.8.2 step 14 of WebWorkers for why this is the lexicalGlobalObject. auto& window = asJSDOMWindow(state.lexicalGlobalObject())->wrapped(); ASSERT(window.document()); return JSValue::encode(toJSNewlyCreated(state, globalObject, scope, Worker::create(*window.document(), scriptURL, globalObject.runtimeFlags()))); }
ReadableJSStream::ReadableJSStream(ScriptExecutionContext& scriptExecutionContext, ExecState& state, JSObject* source, double highWaterMark, JSFunction* sizeFunction) : ReadableStream(scriptExecutionContext) , m_highWaterMark(highWaterMark) { m_source.set(state.vm(), source); // We do not take a Ref to the stream as this would cause a Ref cycle. // The resolution callback used jointly with m_errorFunction as promise callbacks should protect the stream instead. m_errorFunction.set(state.vm(), JSFunction::create(state.vm(), state.callee()->globalObject(), 1, String(), [this](ExecState* state) { storeError(*state, state->argument(0)); return JSValue::encode(jsUndefined()); })); if (sizeFunction) m_sizeFunction.set(state.vm(), sizeFunction); }
EncodedJSValue JSC_HOST_CALL constructJSMutationObserver(ExecState& exec) { if (exec.argumentCount() < 1) return throwVMError(&exec, createNotEnoughArgumentsError(&exec)); JSObject* object = exec.uncheckedArgument(0).getObject(); CallData callData; if (!object || object->methodTable()->getCallData(object, callData) == CallType::None) return throwVMTypeError(&exec, ASCIILiteral("Callback argument must be a function")); DOMConstructorObject* jsConstructor = jsCast<DOMConstructorObject*>(exec.callee()); auto callback = JSMutationCallback::create(object, jsConstructor->globalObject()); JSObject* jsObserver = asObject(toJSNewlyCreated(&exec, jsConstructor->globalObject(), MutationObserver::create(WTFMove(callback)))); PrivateName propertyName; jsObserver->putDirect(jsConstructor->globalObject()->vm(), propertyName, object); return JSValue::encode(jsObserver); }
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. }
RefPtr<ReadableJSStream> ReadableJSStream::create(ExecState& state, ScriptExecutionContext& scriptExecutionContext) { // FIXME: We should consider reducing the binding code herei (using Dictionary/regular binding constructor and/or improving the IDL generator). JSObject* jsSource; JSValue value = state.argument(0); if (value.isObject()) jsSource = value.getObject(); else if (!value.isUndefined()) { throwVMError(&state, createTypeError(&state, ASCIILiteral("First argument, if any, should be an object"))); return nullptr; } else jsSource = JSFinalObject::create(state.vm(), JSFinalObject::createStructure(state.vm(), state.callee()->globalObject(), jsNull(), 1)); double highWaterMark = 1; JSFunction* sizeFunction = nullptr; value = state.argument(1); if (value.isObject()) { JSObject& strategyObject = *value.getObject(); highWaterMark = normalizeHighWaterMark(state, strategyObject); if (state.hadException()) return nullptr; if (!(sizeFunction = jsDynamicCast<JSFunction*>(getPropertyFromObject(state, strategyObject, "size")))) { if (!state.hadException()) throwVMError(&state, createTypeError(&state, ASCIILiteral("size parameter should be a function"))); return nullptr; } } else if (!value.isUndefined()) { throwVMError(&state, createTypeError(&state, ASCIILiteral("Second argument, if any, should be an object"))); return nullptr; } RefPtr<ReadableJSStream> readableStream = adoptRef(*new ReadableJSStream(scriptExecutionContext, state, jsSource, highWaterMark, sizeFunction)); readableStream->doStart(state); if (state.hadException()) return nullptr; return readableStream; }
void IntlDateTimeFormat::initializeDateTimeFormat(ExecState& exec, JSValue locales, JSValue originalOptions) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 12.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options) (ECMA-402 2.0) // 1. If dateTimeFormat.[[initializedIntlObject]] is true, throw a TypeError exception. // 2. Set dateTimeFormat.[[initializedIntlObject]] to true. // 3. Let requestedLocales be CanonicalizeLocaleList(locales). Vector<String> requestedLocales = canonicalizeLocaleList(exec, locales); // 4. ReturnIfAbrupt(requestedLocales), RETURN_IF_EXCEPTION(scope, void()); // 5. Let options be ToDateTimeOptions(options, "any", "date"). JSObject* options = toDateTimeOptionsAnyDate(exec, originalOptions); // 6. ReturnIfAbrupt(options). RETURN_IF_EXCEPTION(scope, void()); // 7. Let opt be a new Record. HashMap<String, String> localeOpt; // 8. Let matcher be GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit"). String localeMatcher = intlStringOption(exec, options, vm.propertyNames->localeMatcher, { "lookup", "best fit" }, "localeMatcher must be either \"lookup\" or \"best fit\"", "best fit"); // 9. ReturnIfAbrupt(matcher). RETURN_IF_EXCEPTION(scope, void()); // 10. Set opt.[[localeMatcher]] to matcher. localeOpt.add(vm.propertyNames->localeMatcher.string(), localeMatcher); // 11. Let localeData be the value of %DateTimeFormat%.[[localeData]]. // 12. Let r be ResolveLocale( %DateTimeFormat%.[[availableLocales]], requestedLocales, opt, %DateTimeFormat%.[[relevantExtensionKeys]], localeData). const HashSet<String> availableLocales = exec.callee()->globalObject()->intlDateTimeFormatAvailableLocales(); HashMap<String, String> resolved = resolveLocale(exec, availableLocales, requestedLocales, localeOpt, relevantExtensionKeys, WTF_ARRAY_LENGTH(relevantExtensionKeys), localeData); // 13. Set dateTimeFormat.[[locale]] to the value of r.[[locale]]. m_locale = resolved.get(vm.propertyNames->locale.string()); if (m_locale.isEmpty()) { throwTypeError(&exec, scope, ASCIILiteral("failed to initialize DateTimeFormat due to invalid locale")); return; } // 14. Set dateTimeFormat.[[calendar]] to the value of r.[[ca]]. m_calendar = resolved.get(ASCIILiteral("ca")); // Switch to preferred aliases. if (m_calendar == "gregory") m_calendar = ASCIILiteral("gregorian"); else if (m_calendar == "islamicc") m_calendar = ASCIILiteral("islamic-civil"); else if (m_calendar == "ethioaa") m_calendar = ASCIILiteral("ethiopic-amete-alem"); // 15. Set dateTimeFormat.[[numberingSystem]] to the value of r.[[nu]]. m_numberingSystem = resolved.get(ASCIILiteral("nu")); // 16. Let dataLocale be the value of r.[[dataLocale]]. String dataLocale = resolved.get(ASCIILiteral("dataLocale")); // 17. Let tz be Get(options, "timeZone"). JSValue tzValue = options->get(&exec, vm.propertyNames->timeZone); // 18. ReturnIfAbrupt(tz). RETURN_IF_EXCEPTION(scope, void()); // 19. If tz is not undefined, then String tz; if (!tzValue.isUndefined()) { // a. Let tz be ToString(tz). String originalTz = tzValue.toWTFString(&exec); // b. ReturnIfAbrupt(tz). RETURN_IF_EXCEPTION(scope, void()); // c. If the result of IsValidTimeZoneName(tz) is false, then i. Throw a RangeError exception. // d. Let tz be CanonicalizeTimeZoneName(tz). tz = canonicalizeTimeZoneName(originalTz); if (tz.isNull()) { throwRangeError(&exec, scope, String::format("invalid time zone: %s", originalTz.utf8().data())); return; } } else { // 20. Else, // a. Let tz be DefaultTimeZone(). tz = defaultTimeZone(); } // 21. Set dateTimeFormat.[[timeZone]] to tz. m_timeZone = tz; // 22. Let opt be a new Record. // Rather than building a record, build the skeleton pattern. StringBuilder skeletonBuilder; // 23. For each row of Table 3, except the header row, do: // a. Let prop be the name given in the Property column of the row. // b. Let value be GetOption(options, prop, "string", «the strings given in the Values column of the row», undefined). // c. ReturnIfAbrupt(value). // d. Set opt.[[<prop>]] to value. auto narrowShortLong = { "narrow", "short", "long" }; auto twoDigitNumeric = { "2-digit", "numeric" }; auto twoDigitNumericNarrowShortLong = { "2-digit", "numeric", "narrow", "short", "long" }; auto shortLong = { "short", "long" }; String weekday = intlStringOption(exec, options, vm.propertyNames->weekday, narrowShortLong, "weekday must be \"narrow\", \"short\", or \"long\"", nullptr); RETURN_IF_EXCEPTION(scope, void()); if (!weekday.isNull()) { if (weekday == "narrow") skeletonBuilder.appendLiteral("EEEEE"); else if (weekday == "short") skeletonBuilder.appendLiteral("EEE"); else if (weekday == "long") skeletonBuilder.appendLiteral("EEEE"); } String era = intlStringOption(exec, options, vm.propertyNames->era, narrowShortLong, "era must be \"narrow\", \"short\", or \"long\"", nullptr); RETURN_IF_EXCEPTION(scope, void()); if (!era.isNull()) { if (era == "narrow") skeletonBuilder.appendLiteral("GGGGG"); else if (era == "short") skeletonBuilder.appendLiteral("GGG"); else if (era == "long") skeletonBuilder.appendLiteral("GGGG"); } String year = intlStringOption(exec, options, vm.propertyNames->year, twoDigitNumeric, "year must be \"2-digit\" or \"numeric\"", nullptr); RETURN_IF_EXCEPTION(scope, void()); if (!year.isNull()) { if (year == "2-digit") skeletonBuilder.appendLiteral("yy"); else if (year == "numeric") skeletonBuilder.append('y'); } String month = intlStringOption(exec, options, vm.propertyNames->month, twoDigitNumericNarrowShortLong, "month must be \"2-digit\", \"numeric\", \"narrow\", \"short\", or \"long\"", nullptr); RETURN_IF_EXCEPTION(scope, void()); if (!month.isNull()) { if (month == "2-digit") skeletonBuilder.appendLiteral("MM"); else if (month == "numeric") skeletonBuilder.append('M'); else if (month == "narrow") skeletonBuilder.appendLiteral("MMMMM"); else if (month == "short") skeletonBuilder.appendLiteral("MMM"); else if (month == "long") skeletonBuilder.appendLiteral("MMMM"); } String day = intlStringOption(exec, options, vm.propertyNames->day, twoDigitNumeric, "day must be \"2-digit\" or \"numeric\"", nullptr); RETURN_IF_EXCEPTION(scope, void()); if (!day.isNull()) { if (day == "2-digit") skeletonBuilder.appendLiteral("dd"); else if (day == "numeric") skeletonBuilder.append('d'); } String hour = intlStringOption(exec, options, vm.propertyNames->hour, twoDigitNumeric, "hour must be \"2-digit\" or \"numeric\"", nullptr); RETURN_IF_EXCEPTION(scope, void()); // We need hour12 to make the hour skeleton pattern decision, so do this early. // 32. Let hr12 be GetOption(options, "hour12", "boolean", undefined, undefined). bool isHour12Undefined; bool hr12 = intlBooleanOption(exec, options, vm.propertyNames->hour12, isHour12Undefined); // 33. ReturnIfAbrupt(hr12). RETURN_IF_EXCEPTION(scope, void()); if (!hour.isNull()) { if (isHour12Undefined) { if (hour == "2-digit") skeletonBuilder.appendLiteral("jj"); else if (hour == "numeric") skeletonBuilder.append('j'); } else if (hr12) { if (hour == "2-digit") skeletonBuilder.appendLiteral("hh"); else if (hour == "numeric") skeletonBuilder.append('h'); } else { if (hour == "2-digit") skeletonBuilder.appendLiteral("HH"); else if (hour == "numeric") skeletonBuilder.append('H'); } } String minute = intlStringOption(exec, options, vm.propertyNames->minute, twoDigitNumeric, "minute must be \"2-digit\" or \"numeric\"", nullptr); RETURN_IF_EXCEPTION(scope, void()); if (!minute.isNull()) { if (minute == "2-digit") skeletonBuilder.appendLiteral("mm"); else if (minute == "numeric") skeletonBuilder.append('m'); } String second = intlStringOption(exec, options, vm.propertyNames->second, twoDigitNumeric, "second must be \"2-digit\" or \"numeric\"", nullptr); RETURN_IF_EXCEPTION(scope, void()); if (!second.isNull()) { if (second == "2-digit") skeletonBuilder.appendLiteral("ss"); else if (second == "numeric") skeletonBuilder.append('s'); } String timeZoneName = intlStringOption(exec, options, vm.propertyNames->timeZoneName, shortLong, "timeZoneName must be \"short\" or \"long\"", nullptr); RETURN_IF_EXCEPTION(scope, void()); if (!timeZoneName.isNull()) { if (timeZoneName == "short") skeletonBuilder.append('z'); else if (timeZoneName == "long") skeletonBuilder.appendLiteral("zzzz"); } // 24. Let dataLocaleData be Get(localeData, dataLocale). // 25. Let formats be Get(dataLocaleData, "formats"). // 26. Let matcher be GetOption(options, "formatMatcher", "string", «"basic", "best fit"», "best fit"). intlStringOption(exec, options, vm.propertyNames->formatMatcher, { "basic", "best fit" }, "formatMatcher must be either \"basic\" or \"best fit\"", "best fit"); // 27. ReturnIfAbrupt(matcher). RETURN_IF_EXCEPTION(scope, void()); // Always use ICU date format generator, rather than our own pattern list and matcher. // Covers steps 28-36. UErrorCode status = U_ZERO_ERROR; UDateTimePatternGenerator* generator = udatpg_open(dataLocale.utf8().data(), &status); if (U_FAILURE(status)) { throwTypeError(&exec, scope, ASCIILiteral("failed to initialize DateTimeFormat")); return; } String skeleton = skeletonBuilder.toString(); StringView skeletonView(skeleton); Vector<UChar, 32> patternBuffer(32); status = U_ZERO_ERROR; auto patternLength = udatpg_getBestPattern(generator, skeletonView.upconvertedCharacters(), skeletonView.length(), patternBuffer.data(), patternBuffer.size(), &status); if (status == U_BUFFER_OVERFLOW_ERROR) { status = U_ZERO_ERROR; patternBuffer.grow(patternLength); udatpg_getBestPattern(generator, skeletonView.upconvertedCharacters(), skeletonView.length(), patternBuffer.data(), patternLength, &status); } udatpg_close(generator); if (U_FAILURE(status)) { throwTypeError(&exec, scope, ASCIILiteral("failed to initialize DateTimeFormat")); return; } StringView pattern(patternBuffer.data(), patternLength); setFormatsFromPattern(pattern); status = U_ZERO_ERROR; StringView timeZoneView(m_timeZone); m_dateFormat = std::unique_ptr<UDateFormat, UDateFormatDeleter>(udat_open(UDAT_PATTERN, UDAT_PATTERN, m_locale.utf8().data(), timeZoneView.upconvertedCharacters(), timeZoneView.length(), pattern.upconvertedCharacters(), pattern.length(), &status)); if (U_FAILURE(status)) { throwTypeError(&exec, scope, ASCIILiteral("failed to initialize DateTimeFormat")); return; } // 37. Set dateTimeFormat.[[boundFormat]] to undefined. // Already undefined. // 38. Set dateTimeFormat.[[initializedDateTimeFormat]] to true. m_initializedDateTimeFormat = true; // 39. Return dateTimeFormat. }
EncodedJSValue JSC_HOST_CALL constructJSAudioContext(ExecState& exec) { DOMConstructorObject* jsConstructor = jsCast<DOMConstructorObject*>(exec.callee()); if (!jsConstructor) return throwVMError(&exec, createReferenceError(&exec, "AudioContext constructor callee is unavailable")); ScriptExecutionContext* scriptExecutionContext = jsConstructor->scriptExecutionContext(); if (!scriptExecutionContext) return throwVMError(&exec, createReferenceError(&exec, "AudioContext constructor script execution context is unavailable")); if (!is<Document>(*scriptExecutionContext)) return throwVMError(&exec, createReferenceError(&exec, "AudioContext constructor called in a script execution context which is not a document")); Document& document = downcast<Document>(*scriptExecutionContext); RefPtr<AudioContext> audioContext; if (!exec.argumentCount()) { // Constructor for default AudioContext which talks to audio hardware. ExceptionCode ec = 0; audioContext = AudioContext::create(document, ec); if (ec) { setDOMException(&exec, ec); return JSValue::encode(JSValue()); } if (!audioContext.get()) return throwVMError(&exec, createSyntaxError(&exec, "audio resources unavailable for AudioContext construction")); } else { #if ENABLE(LEGACY_WEB_AUDIO) // Constructor for offline (render-target) AudioContext which renders into an AudioBuffer. // new AudioContext(in unsigned long numberOfChannels, in unsigned long numberOfFrames, in float sampleRate); document.addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("Deprecated AudioContext constructor: use OfflineAudioContext instead")); if (exec.argumentCount() < 3) return throwVMError(&exec, createNotEnoughArgumentsError(&exec)); int32_t numberOfChannels = exec.uncheckedArgument(0).toInt32(&exec); int32_t numberOfFrames = exec.uncheckedArgument(1).toInt32(&exec); float sampleRate = exec.uncheckedArgument(2).toFloat(&exec); if (numberOfChannels <= 0 || numberOfChannels > 10) return throwVMError(&exec, createSyntaxError(&exec, "Invalid number of channels")); if (numberOfFrames <= 0) return throwVMError(&exec, createSyntaxError(&exec, "Invalid number of frames")); if (sampleRate <= 0) return throwVMError(&exec, createSyntaxError(&exec, "Invalid sample rate")); ExceptionCode ec = 0; audioContext = OfflineAudioContext::create(document, numberOfChannels, numberOfFrames, sampleRate, ec); if (ec) { setDOMException(&exec, ec); return throwVMError(&exec, createSyntaxError(&exec, "Error creating OfflineAudioContext")); } #else return throwVMError(&exec, createSyntaxError(&exec, "Illegal AudioContext constructor")); #endif } if (!audioContext) return throwVMError(&exec, createReferenceError(&exec, "Error creating AudioContext")); return JSValue::encode(CREATE_DOM_WRAPPER(jsConstructor->globalObject(), AudioContext, audioContext.releaseNonNull())); }