1 /* 2 * Copyright 2008 Jacek Caban for CodeWeavers 3 * Copyright 2009 Piotr Caban 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include "config.h" 21 #include "wine/port.h" 22 23 #include <math.h> 24 #include <limits.h> 25 26 #include "jscript.h" 27 #include "ntsecapi.h" 28 29 #include "wine/debug.h" 30 31 WINE_DEFAULT_DEBUG_CHANNEL(jscript); 32 33 static const WCHAR EW[] = {'E',0}; 34 static const WCHAR LOG2EW[] = {'L','O','G','2','E',0}; 35 static const WCHAR LOG10EW[] = {'L','O','G','1','0','E',0}; 36 static const WCHAR LN2W[] = {'L','N','2',0}; 37 static const WCHAR LN10W[] = {'L','N','1','0',0}; 38 static const WCHAR PIW[] = {'P','I',0}; 39 static const WCHAR SQRT2W[] = {'S','Q','R','T','2',0}; 40 static const WCHAR SQRT1_2W[] = {'S','Q','R','T','1','_','2',0}; 41 static const WCHAR absW[] = {'a','b','s',0}; 42 static const WCHAR acosW[] = {'a','c','o','s',0}; 43 static const WCHAR asinW[] = {'a','s','i','n',0}; 44 static const WCHAR atanW[] = {'a','t','a','n',0}; 45 static const WCHAR atan2W[] = {'a','t','a','n','2',0}; 46 static const WCHAR ceilW[] = {'c','e','i','l',0}; 47 static const WCHAR cosW[] = {'c','o','s',0}; 48 static const WCHAR expW[] = {'e','x','p',0}; 49 static const WCHAR floorW[] = {'f','l','o','o','r',0}; 50 static const WCHAR logW[] = {'l','o','g',0}; 51 static const WCHAR maxW[] = {'m','a','x',0}; 52 static const WCHAR minW[] = {'m','i','n',0}; 53 static const WCHAR powW[] = {'p','o','w',0}; 54 static const WCHAR randomW[] = {'r','a','n','d','o','m',0}; 55 static const WCHAR roundW[] = {'r','o','u','n','d',0}; 56 static const WCHAR sinW[] = {'s','i','n',0}; 57 static const WCHAR sqrtW[] = {'s','q','r','t',0}; 58 static const WCHAR tanW[] = {'t','a','n',0}; 59 60 /* ECMA-262 3rd Edition 15.8.2.12 */ 61 static HRESULT Math_abs(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 62 jsval_t *r) 63 { 64 double d; 65 HRESULT hres; 66 67 TRACE("\n"); 68 69 if(!argc) { 70 if(r) 71 *r = jsval_number(NAN); 72 return S_OK; 73 } 74 75 hres = to_number(ctx, argv[0], &d); 76 if(FAILED(hres)) 77 return hres; 78 79 if(r) 80 *r = jsval_number(d < 0.0 ? -d : d); 81 return S_OK; 82 } 83 84 static HRESULT Math_acos(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 85 jsval_t *r) 86 { 87 double x; 88 HRESULT hres; 89 90 TRACE("\n"); 91 92 if(!argc) { 93 if(r) 94 *r = jsval_number(NAN); 95 return S_OK; 96 } 97 98 hres = to_number(ctx, argv[0], &x); 99 if(FAILED(hres)) 100 return hres; 101 102 if(r) 103 *r = jsval_number(x < -1.0 || x > 1.0 ? NAN : acos(x)); 104 return S_OK; 105 } 106 107 static HRESULT Math_asin(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 108 jsval_t *r) 109 { 110 double x; 111 HRESULT hres; 112 113 TRACE("\n"); 114 115 if(!argc) { 116 if(r) 117 *r = jsval_number(NAN); 118 return S_OK; 119 } 120 121 hres = to_number(ctx, argv[0], &x); 122 if(FAILED(hres)) 123 return hres; 124 125 if(r) 126 *r = jsval_number(x < -1.0 || x > 1.0 ? NAN : asin(x)); 127 return S_OK; 128 } 129 130 static HRESULT Math_atan(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 131 jsval_t *r) 132 { 133 double x; 134 HRESULT hres; 135 136 TRACE("\n"); 137 138 if(!argc) { 139 if(r) 140 *r = jsval_number(NAN); 141 return S_OK; 142 } 143 144 hres = to_number(ctx, argv[0], &x); 145 if(FAILED(hres)) 146 return hres; 147 148 if(r) 149 *r = jsval_number(atan(x)); 150 return S_OK; 151 } 152 153 static HRESULT Math_atan2(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 154 jsval_t *r) 155 { 156 double x, y; 157 HRESULT hres; 158 159 TRACE("\n"); 160 161 if(argc<2) { 162 if(r) 163 *r = jsval_number(NAN); 164 return S_OK; 165 } 166 167 hres = to_number(ctx, argv[0], &y); 168 if(FAILED(hres)) 169 return hres; 170 171 hres = to_number(ctx, argv[1], &x); 172 if(FAILED(hres)) 173 return hres; 174 175 if(r) 176 *r = jsval_number(atan2(y, x)); 177 return S_OK; 178 } 179 180 /* ECMA-262 3rd Edition 15.8.2.6 */ 181 static HRESULT Math_ceil(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 182 jsval_t *r) 183 { 184 double x; 185 HRESULT hres; 186 187 TRACE("\n"); 188 189 if(!argc) { 190 if(r) 191 *r = jsval_number(NAN); 192 return S_OK; 193 } 194 195 hres = to_number(ctx, argv[0], &x); 196 if(FAILED(hres)) 197 return hres; 198 199 if(r) 200 *r = jsval_number(ceil(x)); 201 return S_OK; 202 } 203 204 static HRESULT Math_cos(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 205 jsval_t *r) 206 { 207 double x; 208 HRESULT hres; 209 210 TRACE("\n"); 211 212 if(!argc) { 213 if(r) 214 *r = jsval_number(NAN); 215 return S_OK; 216 } 217 218 hres = to_number(ctx, argv[0], &x); 219 if(FAILED(hres)) 220 return hres; 221 222 if(r) 223 *r = jsval_number(cos(x)); 224 return S_OK; 225 } 226 227 static HRESULT Math_exp(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 228 jsval_t *r) 229 { 230 double x; 231 HRESULT hres; 232 233 TRACE("\n"); 234 235 if(!argc) { 236 if(r) 237 *r = jsval_number(NAN); 238 return S_OK; 239 } 240 241 hres = to_number(ctx, argv[0], &x); 242 if(FAILED(hres)) 243 return hres; 244 245 if(r) 246 *r = jsval_number(exp(x)); 247 return S_OK; 248 } 249 250 static HRESULT Math_floor(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 251 jsval_t *r) 252 { 253 double x; 254 HRESULT hres; 255 256 TRACE("\n"); 257 258 if(!argc) { 259 if(r) 260 *r = jsval_number(NAN); 261 return S_OK; 262 } 263 264 hres = to_number(ctx, argv[0], &x); 265 if(FAILED(hres)) 266 return hres; 267 268 if(r) 269 *r = jsval_number(floor(x)); 270 return S_OK; 271 } 272 273 static HRESULT Math_log(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 274 jsval_t *r) 275 { 276 double x; 277 HRESULT hres; 278 279 TRACE("\n"); 280 281 if(!argc) { 282 if(r) 283 *r = jsval_number(NAN); 284 return S_OK; 285 } 286 287 hres = to_number(ctx, argv[0], &x); 288 if(FAILED(hres)) 289 return hres; 290 291 if(r) 292 *r = jsval_number(x < -0.0 ? NAN : log(x)); 293 return S_OK; 294 } 295 296 /* ECMA-262 3rd Edition 15.8.2.11 */ 297 static HRESULT Math_max(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 298 jsval_t *r) 299 { 300 DOUBLE max, d; 301 DWORD i; 302 HRESULT hres; 303 304 TRACE("\n"); 305 306 if(!argc) { 307 if(r) 308 *r = jsval_number(-INFINITY); 309 return S_OK; 310 } 311 312 hres = to_number(ctx, argv[0], &max); 313 if(FAILED(hres)) 314 return hres; 315 316 for(i=1; i < argc; i++) { 317 hres = to_number(ctx, argv[i], &d); 318 if(FAILED(hres)) 319 return hres; 320 321 if(d > max || isnan(d)) 322 max = d; 323 } 324 325 if(r) 326 *r = jsval_number(max); 327 return S_OK; 328 } 329 330 /* ECMA-262 3rd Edition 15.8.2.12 */ 331 static HRESULT Math_min(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 332 jsval_t *r) 333 { 334 DOUBLE min, d; 335 DWORD i; 336 HRESULT hres; 337 338 TRACE("\n"); 339 340 if(!argc) { 341 if(r) 342 *r = jsval_number(INFINITY); 343 return S_OK; 344 } 345 346 hres = to_number(ctx, argv[0], &min); 347 if(FAILED(hres)) 348 return hres; 349 350 for(i=1; i < argc; i++) { 351 hres = to_number(ctx, argv[i], &d); 352 if(FAILED(hres)) 353 return hres; 354 355 if(d < min || isnan(d)) 356 min = d; 357 } 358 359 if(r) 360 *r = jsval_number(min); 361 return S_OK; 362 } 363 364 /* ECMA-262 3rd Edition 15.8.2.13 */ 365 static HRESULT Math_pow(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 366 jsval_t *r) 367 { 368 double x, y; 369 HRESULT hres; 370 371 TRACE("\n"); 372 373 if(argc < 2) { 374 if(r) 375 *r = jsval_number(NAN); 376 return S_OK; 377 } 378 379 hres = to_number(ctx, argv[0], &x); 380 if(FAILED(hres)) 381 return hres; 382 383 hres = to_number(ctx, argv[1], &y); 384 if(FAILED(hres)) 385 return hres; 386 387 if(r) 388 *r = jsval_number(pow(x, y)); 389 return S_OK; 390 } 391 392 /* ECMA-262 3rd Edition 15.8.2.14 */ 393 static HRESULT Math_random(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 394 jsval_t *r) 395 { 396 UINT x; 397 398 TRACE("\n"); 399 400 if(!RtlGenRandom(&x, sizeof(x))) 401 return E_UNEXPECTED; 402 403 if(r) 404 *r = jsval_number((double)x/(double)UINT_MAX); 405 return S_OK; 406 } 407 408 /* ECMA-262 3rd Edition 15.8.2.15 */ 409 static HRESULT Math_round(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 410 jsval_t *r) 411 { 412 double x; 413 HRESULT hres; 414 415 TRACE("\n"); 416 417 if(!argc) { 418 if(r) 419 *r = jsval_number(NAN); 420 return S_OK; 421 } 422 423 hres = to_number(ctx, argv[0], &x); 424 if(FAILED(hres)) 425 return hres; 426 427 if(r) 428 *r = jsval_number(floor(x+0.5)); 429 return S_OK; 430 } 431 432 static HRESULT Math_sin(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 433 jsval_t *r) 434 { 435 double x; 436 HRESULT hres; 437 438 TRACE("\n"); 439 440 if(!argc) { 441 if(r) 442 *r = jsval_number(NAN); 443 return S_OK; 444 } 445 446 hres = to_number(ctx, argv[0], &x); 447 if(FAILED(hres)) 448 return hres; 449 450 if(r) 451 *r = jsval_number(sin(x)); 452 return S_OK; 453 } 454 455 static HRESULT Math_sqrt(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 456 jsval_t *r) 457 { 458 double x; 459 HRESULT hres; 460 461 TRACE("\n"); 462 463 if(!argc) { 464 if(r) 465 *r = jsval_number(NAN); 466 return S_OK; 467 } 468 469 hres = to_number(ctx, argv[0], &x); 470 if(FAILED(hres)) 471 return hres; 472 473 if(r) 474 *r = jsval_number(sqrt(x)); 475 return S_OK; 476 } 477 478 static HRESULT Math_tan(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, 479 jsval_t *r) 480 { 481 double x; 482 HRESULT hres; 483 484 TRACE("\n"); 485 486 if(!argc) { 487 if(r) 488 *r = jsval_number(NAN); 489 return S_OK; 490 } 491 492 hres = to_number(ctx, argv[0], &x); 493 if(FAILED(hres)) 494 return hres; 495 496 if(r) 497 *r = jsval_number(tan(x)); 498 return S_OK; 499 } 500 501 static const builtin_prop_t Math_props[] = { 502 {absW, Math_abs, PROPF_METHOD|1}, 503 {acosW, Math_acos, PROPF_METHOD|1}, 504 {asinW, Math_asin, PROPF_METHOD|1}, 505 {atanW, Math_atan, PROPF_METHOD|1}, 506 {atan2W, Math_atan2, PROPF_METHOD|2}, 507 {ceilW, Math_ceil, PROPF_METHOD|1}, 508 {cosW, Math_cos, PROPF_METHOD|1}, 509 {expW, Math_exp, PROPF_METHOD|1}, 510 {floorW, Math_floor, PROPF_METHOD|1}, 511 {logW, Math_log, PROPF_METHOD|1}, 512 {maxW, Math_max, PROPF_METHOD|2}, 513 {minW, Math_min, PROPF_METHOD|2}, 514 {powW, Math_pow, PROPF_METHOD|2}, 515 {randomW, Math_random, PROPF_METHOD}, 516 {roundW, Math_round, PROPF_METHOD|1}, 517 {sinW, Math_sin, PROPF_METHOD|1}, 518 {sqrtW, Math_sqrt, PROPF_METHOD|1}, 519 {tanW, Math_tan, PROPF_METHOD|1} 520 }; 521 522 static const builtin_info_t Math_info = { 523 JSCLASS_MATH, 524 {NULL, NULL, 0}, 525 ARRAY_SIZE(Math_props), 526 Math_props, 527 NULL, 528 NULL 529 }; 530 531 HRESULT create_math(script_ctx_t *ctx, jsdisp_t **ret) 532 { 533 jsdisp_t *math; 534 unsigned i; 535 HRESULT hres; 536 537 struct { 538 const WCHAR *name; 539 DOUBLE val; 540 }constants[] = { 541 {EW, M_E}, /* ECMA-262 3rd Edition 15.8.1.1 */ 542 {LN10W, M_LN10}, /* ECMA-262 3rd Edition 15.8.1.2 */ 543 {LN2W, M_LN2}, /* ECMA-262 3rd Edition 15.8.1.3 */ 544 {LOG2EW, M_LOG2E}, /* ECMA-262 3rd Edition 15.8.1.4 */ 545 {LOG10EW, M_LOG10E}, /* ECMA-262 3rd Edition 15.8.1.5 */ 546 {PIW, M_PI}, /* ECMA-262 3rd Edition 15.8.1.6 */ 547 {SQRT1_2W, M_SQRT1_2}, /* ECMA-262 3rd Edition 15.8.1.7 */ 548 {SQRT2W, M_SQRT2}, /* ECMA-262 3rd Edition 15.8.1.8 */ 549 }; 550 551 math = heap_alloc_zero(sizeof(jsdisp_t)); 552 if(!math) 553 return E_OUTOFMEMORY; 554 555 hres = init_dispex_from_constr(math, ctx, &Math_info, ctx->object_constr); 556 if(FAILED(hres)) { 557 heap_free(math); 558 return hres; 559 } 560 561 for(i=0; i < ARRAY_SIZE(constants); i++) { 562 hres = jsdisp_define_data_property(math, constants[i].name, 0, 563 jsval_number(constants[i].val)); 564 if(FAILED(hres)) { 565 jsdisp_release(math); 566 return hres; 567 } 568 } 569 570 *ret = math; 571 return S_OK; 572 } 573