// toPrecision converts a number to a string, takeing an argument specifying a // number of significant figures to round the significand to. For positive // exponent, all values that can be represented using a decimal fraction will // be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a // decimal, whilst 1000 is converted to the exponential representation 1.00e+3. // For negative exponents values >= 1e-6 are formated as decimal fractions, // with smaller values converted to exponential representation. EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec) { // Get x (the double value of this, which should be a Number). JSValue thisValue = exec->hostThisValue(); JSValue v = thisValue.getJSNumber(); if (!v) return throwVMTypeError(exec); double x = v.uncheckedGetNumber(); // Get the argument. int significantFigures; bool isUndefined; if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined)) return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21")); // To precision called with no argument is treated as ToString. if (isUndefined) return JSValue::encode(jsString(exec, UString::number(x))); // Handle NaN and Infinity. if (isnan(x) || isinf(x)) return JSValue::encode(jsString(exec, UString::number(x))); // Convert to decimal with rounding. DecimalNumber number(x, RoundingSignificantFigures, significantFigures); // If number is in the range 1e-6 <= x < pow(10, significantFigures) then format // as decimal. Otherwise, format the number as an exponential. Decimal format // demands a minimum of (exponent + 1) digits to represent a number, for example // 1234 (1.234e+3) requires 4 digits. (See ECMA-262 15.7.4.7.10.c) NumberToStringBuffer buffer; unsigned length = number.exponent() >= -6 && number.exponent() < significantFigures ? number.toStringDecimal(buffer, WTF::NumberToStringBufferLength) : number.toStringExponential(buffer, WTF::NumberToStringBufferLength); return JSValue::encode(jsString(exec, UString(buffer, length))); }
// toFixed converts a number to a string, always formatting as an a decimal fraction. // This method takes an argument specifying a number of decimal places to round the // significand to. However when converting large values (1e+21 and above) this // method will instead fallback to calling ToString. EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec) { // Get x (the double value of this, which should be a Number). JSValue thisValue = exec->hostThisValue(); JSValue v = thisValue.getJSNumber(); if (!v) return throwVMTypeError(exec); double x = v.uncheckedGetNumber(); // Get the argument. int decimalPlaces; bool isUndefined; // This is ignored; undefined treated as 0. if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined)) return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20")); // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)" // This also covers Ininity, and structure the check so that NaN // values are also handled by numberToString if (!(fabs(x) < 1e+21)) return JSValue::encode(jsString(exec, UString::number(x))); // The check above will return false for NaN or Infinity, these will be // handled by numberToString. ASSERT(!isnan(x) && !isinf(x)); // Convert to decimal with rounding, and format as decimal. NumberToStringBuffer buffer; unsigned length = DecimalNumber(x, RoundingDecimalPlaces, decimalPlaces).toStringDecimal(buffer, WTF::NumberToStringBufferLength); return JSValue::encode(jsString(exec, UString(buffer, length))); }
double valueToDate(ExecState* exec, JSValue value) { if (value.isNumber()) return value.uncheckedGetNumber(); if (!value.inherits(&DateInstance::s_info)) return std::numeric_limits<double>::quiet_NaN(); return static_cast<DateInstance*>(value.toObject(exec))->internalNumber(); }
static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double &x) { JSValue v = thisValue.getJSNumber(); if (UNLIKELY(!v)) return false; x = v.uncheckedGetNumber(); return true; }
JSValue JSSQLTransactionSync::executeSql(ExecState* exec) { if (!exec->argumentCount()) { setDOMException(exec, SYNTAX_ERR); return jsUndefined(); } String sqlStatement = ustringToString(exec->argument(0).toString(exec)); if (exec->hadException()) return jsUndefined(); // Now assemble the list of SQL arguments Vector<SQLValue> sqlValues; if (!exec->argument(1).isUndefinedOrNull()) { JSObject* object = exec->argument(1).getObject(); if (!object) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } JSValue lengthValue = object->get(exec, exec->propertyNames().length); if (exec->hadException()) return jsUndefined(); unsigned length = lengthValue.toUInt32(exec); if (exec->hadException()) return jsUndefined(); for (unsigned i = 0 ; i < length; ++i) { JSValue value = object->get(exec, i); if (exec->hadException()) return jsUndefined(); if (value.isUndefinedOrNull()) sqlValues.append(SQLValue()); else if (value.isNumber()) sqlValues.append(value.uncheckedGetNumber()); else { // Convert the argument to a string and append it sqlValues.append(ustringToString(value.toString(exec))); if (exec->hadException()) return jsUndefined(); } } } ExceptionCode ec = 0; JSValue result = toJS(exec, globalObject(), WTF::getPtr(m_impl->executeSQL(sqlStatement, sqlValues, ec))); setDOMException(exec, ec); return result; }
static PassRefPtr<InspectorValue> jsToInspectorValue(ScriptState* scriptState, JSValue value) { if (!value) { ASSERT_NOT_REACHED(); return 0; } if (value.isNull() || value.isUndefined()) return InspectorValue::null(); if (value.isBoolean()) return InspectorBasicValue::create(value.getBoolean()); if (value.isNumber()) return InspectorBasicValue::create(value.uncheckedGetNumber()); if (value.isString()) { UString s = value.getString(scriptState); return InspectorString::create(String(s.characters(), s.length())); } if (value.isObject()) { if (isJSArray(&scriptState->globalData(), value)) { RefPtr<InspectorArray> inspectorArray = InspectorArray::create(); JSArray* array = asArray(value); unsigned length = array->length(); for (unsigned i = 0; i < length; i++) { JSValue element = array->getIndex(i); RefPtr<InspectorValue> elementValue = jsToInspectorValue(scriptState, element); if (!elementValue) { ASSERT_NOT_REACHED(); elementValue = InspectorValue::null(); } inspectorArray->pushValue(elementValue); } return inspectorArray; } RefPtr<InspectorObject> inspectorObject = InspectorObject::create(); JSObject* object = value.getObject(); PropertyNameArray propertyNames(scriptState); object->getOwnPropertyNames(scriptState, propertyNames); for (size_t i = 0; i < propertyNames.size(); i++) { const Identifier& name = propertyNames[i]; JSValue propertyValue = object->get(scriptState, name); RefPtr<InspectorValue> inspectorValue = jsToInspectorValue(scriptState, propertyValue); if (!inspectorValue) { ASSERT_NOT_REACHED(); inspectorValue = InspectorValue::null(); } inspectorObject->setValue(String(name.characters(), name.length()), inspectorValue); } return inspectorObject; } ASSERT_NOT_REACHED(); return 0; }
EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); JSValue v = thisValue.getJSNumber(); if (!v) return throwVMTypeError(exec); JSValue radixValue = exec->argument(0); int radix; if (radixValue.isInt32()) radix = radixValue.asInt32(); else if (radixValue.isUndefined()) radix = 10; else radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0 if (radix == 10) return JSValue::encode(jsString(exec, v.toString(exec))); static const char* const digits = "0123456789abcdefghijklmnopqrstuvwxyz"; // Fast path for number to character conversion. if (radix == 36) { if (v.isInt32()) { int x = v.asInt32(); if (static_cast<unsigned>(x) < 36) { // Exclude negatives JSGlobalData* globalData = &exec->globalData(); return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, digits[x])); } } } if (radix < 2 || radix > 36) return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36")); // INT_MAX results in 1024 characters left of the dot with radix 2 // give the same space on the right side. safety checks are in place // unless someone finds a precise rule. char s[2048 + 3]; const char* lastCharInString = s + sizeof(s) - 1; double x = v.uncheckedGetNumber(); if (isnan(x) || isinf(x)) return JSValue::encode(jsString(exec, UString::number(x))); bool isNegative = x < 0.0; if (isNegative) x = -x; double integerPart = floor(x); char* decimalPoint = s + sizeof(s) / 2; // convert integer portion char* p = decimalPoint; double d = integerPart; do { int remainderDigit = static_cast<int>(fmod(d, radix)); *--p = digits[remainderDigit]; d /= radix; } while ((d <= -1.0 || d >= 1.0) && s < p); if (isNegative) *--p = '-'; char* startOfResultString = p; ASSERT(s <= startOfResultString); d = x - integerPart; p = decimalPoint; const double epsilon = 0.001; // TODO: guessed. base on radix ? bool hasFractionalPart = (d < -epsilon || d > epsilon); if (hasFractionalPart) { *p++ = '.'; do { d *= radix; const int digit = static_cast<int>(d); *p++ = digits[digit]; d -= digit; } while ((d < -epsilon || d > epsilon) && p < lastCharInString); } *p = '\0'; ASSERT(p < s + sizeof(s)); return JSValue::encode(jsString(exec, startOfResultString)); }
JSValue JSSQLTransaction::executeSql(ExecState* exec) { if (!exec->argumentCount()) { setDOMException(exec, SYNTAX_ERR); return jsUndefined(); } String sqlStatement = ustringToString(exec->argument(0).toString(exec)); if (exec->hadException()) return jsUndefined(); // Now assemble the list of SQL arguments Vector<SQLValue> sqlValues; if (!exec->argument(1).isUndefinedOrNull()) { JSObject* object = exec->argument(1).getObject(); if (!object) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } JSValue lengthValue = object->get(exec, exec->propertyNames().length); if (exec->hadException()) return jsUndefined(); unsigned length = lengthValue.toUInt32(exec); if (exec->hadException()) return jsUndefined(); for (unsigned i = 0 ; i < length; ++i) { JSValue value = object->get(exec, i); if (exec->hadException()) return jsUndefined(); if (value.isUndefinedOrNull()) sqlValues.append(SQLValue()); else if (value.isNumber()) sqlValues.append(value.uncheckedGetNumber()); else { // Convert the argument to a string and append it sqlValues.append(ustringToString(value.toString(exec))); if (exec->hadException()) return jsUndefined(); } } } RefPtr<SQLStatementCallback> callback; if (!exec->argument(2).isUndefinedOrNull()) { JSObject* object = exec->argument(2).getObject(); if (!object) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } callback = JSSQLStatementCallback::create(object, static_cast<JSDOMGlobalObject*>(globalObject())); } RefPtr<SQLStatementErrorCallback> errorCallback; if (!exec->argument(3).isUndefinedOrNull()) { JSObject* object = exec->argument(3).getObject(); if (!object) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } errorCallback = JSSQLStatementErrorCallback::create(object, static_cast<JSDOMGlobalObject*>(globalObject())); } ExceptionCode ec = 0; m_impl->executeSQL(sqlStatement, sqlValues, callback.release(), errorCallback.release(), ec); setDOMException(exec, ec); return jsUndefined(); }
jvalue convertValueToJValue(ExecState* exec, RootObject* rootObject, JSValue value, JavaType javaType, const char* javaClassName) { JSLock lock(SilenceAssertionsOnly); jvalue result; memset(&result, 0, sizeof(jvalue)); switch (javaType) { case JavaTypeArray: case JavaTypeObject: { // FIXME: JavaJSObject::convertValueToJObject functionality is almost exactly the same, // these functions should use common code. if (value.isObject()) { JSObject* object = asObject(value); if (object->inherits(&JavaRuntimeObject::s_info)) { // Unwrap a Java instance. JavaRuntimeObject* runtimeObject = static_cast<JavaRuntimeObject*>(object); JavaInstance* instance = runtimeObject->getInternalJavaInstance(); if (instance) result.l = instance->javaInstance(); } else if (object->classInfo() == &RuntimeArray::s_info) { // Input is a JavaScript Array that was originally created from a Java Array RuntimeArray* imp = static_cast<RuntimeArray*>(object); JavaArray* array = static_cast<JavaArray*>(imp->getConcreteArray()); result.l = array->javaArray(); } else if (object->classInfo() == &JSArray::s_info) { // Input is a Javascript Array. We need to create it to a Java Array. result.l = convertArrayInstanceToJavaArray(exec, asArray(value), javaClassName); } else if ((!result.l && (!strcmp(javaClassName, "java.lang.Object"))) || (!strcmp(javaClassName, "netscape.javascript.JSObject"))) { // Wrap objects in JSObject instances. JNIEnv* env = getJNIEnv(); jclass jsObjectClass = env->FindClass("sun/plugin/javascript/webkit/JSObject"); jmethodID constructorID = env->GetMethodID(jsObjectClass, "<init>", "(J)V"); if (constructorID) { jlong nativeHandle = ptr_to_jlong(object); rootObject->gcProtect(object); result.l = env->NewObject(jsObjectClass, constructorID, nativeHandle); } } } // Create an appropriate Java object if target type is java.lang.Object. if (!result.l && !strcmp(javaClassName, "java.lang.Object")) { if (value.isString()) { UString stringValue = asString(value)->value(exec); JNIEnv* env = getJNIEnv(); jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length()); result.l = javaString; } else if (value.isNumber()) { double doubleValue = value.uncheckedGetNumber(); JNIEnv* env = getJNIEnv(); jclass clazz = env->FindClass("java/lang/Double"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(D)V"); jobject javaDouble = env->functions->NewObject(env, clazz, constructor, doubleValue); result.l = javaDouble; } else if (value.isBoolean()) { bool boolValue = value.getBoolean(); JNIEnv* env = getJNIEnv(); jclass clazz = env->FindClass("java/lang/Boolean"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Z)V"); jobject javaBoolean = env->functions->NewObject(env, clazz, constructor, boolValue); result.l = javaBoolean; } else if (value.isUndefined()) { UString stringValue = "undefined"; JNIEnv* env = getJNIEnv(); jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length()); result.l = javaString; } } // Convert value to a string if the target type is a java.lang.String, and we're not // converting from a null. if (!result.l && !strcmp(javaClassName, "java.lang.String")) { if (!value.isNull()) { UString stringValue = value.toString(exec); JNIEnv* env = getJNIEnv(); jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length()); result.l = javaString; } } } break; case JavaTypeBoolean: { result.z = (jboolean)value.toNumber(exec); } break; case JavaTypeByte: { result.b = (jbyte)value.toNumber(exec); } break; case JavaTypeChar: { result.c = (jchar)value.toNumber(exec); } break; case JavaTypeShort: { result.s = (jshort)value.toNumber(exec); } break; case JavaTypeInt: { result.i = (jint)value.toNumber(exec); } break; case JavaTypeLong: { result.j = (jlong)value.toNumber(exec); } break; case JavaTypeFloat: { result.f = (jfloat)value.toNumber(exec); } break; case JavaTypeDouble: { result.d = (jdouble)value.toNumber(exec); } break; case JavaTypeInvalid: case JavaTypeVoid: break; } return result; }