math.c 14.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright 2008 Jacek Caban for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

19 20 21
#include "config.h"
#include "wine/port.h"

22
#include <math.h>
23
#include <limits.h>
24

25
#include "jscript.h"
26
#include "ntsecapi.h"
27 28 29 30 31 32 33

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(jscript);

static const WCHAR EW[] = {'E',0};
static const WCHAR LOG2EW[] = {'L','O','G','2','E',0};
34
static const WCHAR LOG10EW[] = {'L','O','G','1','0','E',0};
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
static const WCHAR LN2W[] = {'L','N','2',0};
static const WCHAR LN10W[] = {'L','N','1','0',0};
static const WCHAR PIW[] = {'P','I',0};
static const WCHAR SQRT2W[] = {'S','Q','R','T','2',0};
static const WCHAR SQRT1_2W[] = {'S','Q','R','T','1','_','2',0};
static const WCHAR absW[] = {'a','b','s',0};
static const WCHAR acosW[] = {'a','c','o','s',0};
static const WCHAR asinW[] = {'a','s','i','n',0};
static const WCHAR atanW[] = {'a','t','a','n',0};
static const WCHAR atan2W[] = {'a','t','a','n','2',0};
static const WCHAR ceilW[] = {'c','e','i','l',0};
static const WCHAR cosW[] = {'c','o','s',0};
static const WCHAR expW[] = {'e','x','p',0};
static const WCHAR floorW[] = {'f','l','o','o','r',0};
static const WCHAR logW[] = {'l','o','g',0};
static const WCHAR maxW[] = {'m','a','x',0};
static const WCHAR minW[] = {'m','i','n',0};
static const WCHAR powW[] = {'p','o','w',0};
static const WCHAR randomW[] = {'r','a','n','d','o','m',0};
static const WCHAR roundW[] = {'r','o','u','n','d',0};
static const WCHAR sinW[] = {'s','i','n',0};
static const WCHAR sqrtW[] = {'s','q','r','t',0};
static const WCHAR tanW[] = {'t','a','n',0};

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
static HRESULT math_constant(DOUBLE val, WORD flags, VARIANT *retv)
{
    switch(flags) {
    case DISPATCH_PROPERTYGET:
        V_VT(retv) = VT_R8;
        V_R8(retv) = val;
        return S_OK;
    case DISPATCH_PROPERTYPUT:
        return S_OK;
    }

    FIXME("unhandled flags %x\n", flags);
    return E_NOTIMPL;
}

74
/* ECMA-262 3rd Edition    15.8.1.1 */
75 76 77
static HRESULT Math_E(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
78 79
    TRACE("\n");
    return math_constant(M_E, flags, retv);
80 81
}

82
/* ECMA-262 3rd Edition    15.8.1.4 */
83 84 85
static HRESULT Math_LOG2E(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
86 87
    TRACE("\n");
    return math_constant(M_LOG2E, flags, retv);
88 89
}

90
/* ECMA-262 3rd Edition    15.8.1.4 */
91 92 93
static HRESULT Math_LOG10E(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
94 95
    TRACE("\n");
    return math_constant(M_LOG10E, flags, retv);
96 97 98 99 100
}

static HRESULT Math_LN2(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
101 102
    TRACE("\n");
    return math_constant(M_LN2, flags, retv);
103 104 105 106 107
}

static HRESULT Math_LN10(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
108 109
    TRACE("\n");
    return math_constant(M_LN10, flags, retv);
110 111
}

112
/* ECMA-262 3rd Edition    15.8.1.6 */
113 114 115
static HRESULT Math_PI(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
116 117
    TRACE("\n");
    return math_constant(M_PI, flags, retv);
118 119 120 121 122
}

static HRESULT Math_SQRT2(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
123 124
    TRACE("\n");
    return math_constant(M_SQRT2, flags, retv);
125 126 127 128 129
}

static HRESULT Math_SQRT1_2(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
130 131
    TRACE("\n");
    return math_constant(M_SQRT1_2, flags, retv);
132 133
}

134
/* ECMA-262 3rd Edition    15.8.2.12 */
135 136 137
static HRESULT Math_abs(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
138 139 140 141 142 143 144
    VARIANT v;
    DOUBLE d;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
145 146 147
        if(retv)
            num_set_nan(retv);
        return S_OK;
148 149 150 151 152 153 154 155 156 157
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    d = num_val(&v);
    if(retv)
        num_set_val(retv, d < 0.0 ? -d : d);
    return S_OK;
158 159 160 161 162
}

static HRESULT Math_acos(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv) num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv) num_set_val(retv, acos(num_val(&v)));
    return S_OK;
179 180 181 182 183
}

static HRESULT Math_asin(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv) num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv) num_set_val(retv, asin(num_val(&v)));
    return S_OK;
200 201 202 203 204
}

static HRESULT Math_atan(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv) num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv) num_set_val(retv, atan(num_val(&v)));
    return S_OK;
221 222 223 224 225
}

static HRESULT Math_atan2(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    VARIANT v1, v2;
    HRESULT hres;

    TRACE("\n");

    if(arg_cnt(dp)<2) {
        if(retv) num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v1);
    if(FAILED(hres))
        return hres;

    hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &v2);
    if(FAILED(hres))
        return hres;

    if(retv) num_set_val(retv, atan2(num_val(&v1), num_val(&v2)));
    return S_OK;
246 247
}

248
/* ECMA-262 3rd Edition    15.8.2.6 */
249 250 251
static HRESULT Math_ceil(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
252 253 254 255 256 257
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
258 259 260
        if(retv)
            num_set_nan(retv);
        return S_OK;
261 262 263 264 265 266 267 268 269
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv)
        num_set_val(retv, ceil(num_val(&v)));
    return S_OK;
270 271 272 273 274
}

static HRESULT Math_cos(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv) num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv) num_set_val(retv, cos(num_val(&v)));
    return S_OK;
291 292 293 294 295
}

static HRESULT Math_exp(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv) num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv) num_set_val(retv, exp(num_val(&v)));
    return S_OK;
312 313 314 315 316
}

static HRESULT Math_floor(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv)
            num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv)
        num_set_val(retv, floor(num_val(&v)));
    return S_OK;
335 336 337 338 339
}

static HRESULT Math_log(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv)
            num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv)
        num_set_val(retv, log(num_val(&v)));
    return S_OK;
358 359
}

360
/* ECMA-262 3rd Edition    15.8.2.11 */
361 362 363
static HRESULT Math_max(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
364 365 366 367 368 369 370 371
    DOUBLE max, d;
    VARIANT v;
    DWORD i;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
372 373 374
        if(retv)
            num_set_inf(retv, FALSE);
        return S_OK;
375 376 377 378 379 380 381 382 383 384 385 386 387
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    max = num_val(&v);
    for(i=1; i < arg_cnt(dp); i++) {
        hres = to_number(dispex->ctx, get_arg(dp, i), ei, &v);
        if(FAILED(hres))
            return hres;

        d = num_val(&v);
388
        if(d > max || isnan(d))
389 390 391 392 393 394
            max = d;
    }

    if(retv)
        num_set_val(retv, max);
    return S_OK;
395 396
}

397
/* ECMA-262 3rd Edition    15.8.2.12 */
398 399 400
static HRESULT Math_min(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
401 402 403 404 405 406 407 408
    DOUBLE min, d;
    VARIANT v;
    DWORD i;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
409 410 411
        if(retv)
            num_set_inf(retv, TRUE);
        return S_OK;
412 413 414 415 416 417 418 419 420 421 422 423 424
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    min = num_val(&v);
    for(i=1; i < arg_cnt(dp); i++) {
        hres = to_number(dispex->ctx, get_arg(dp, i), ei, &v);
        if(FAILED(hres))
            return hres;

        d = num_val(&v);
425
        if(d < min || isnan(d))
426 427 428 429 430 431
            min = d;
    }

    if(retv)
        num_set_val(retv, min);
    return S_OK;
432 433
}

434
/* ECMA-262 3rd Edition    15.8.2.13 */
435 436 437
static HRESULT Math_pow(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
438 439 440 441 442 443
    VARIANT x, y;
    HRESULT hres;

    TRACE("\n");

    if(arg_cnt(dp) < 2) {
444 445
        if(retv) num_set_nan(retv);
        return S_OK;
446 447 448 449 450 451 452 453 454 455 456 457 458
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &x);
    if(FAILED(hres))
        return hres;

    hres = to_number(dispex->ctx, get_arg(dp, 1), ei, &y);
    if(FAILED(hres))
        return hres;

    if(retv)
        num_set_val(retv, pow(num_val(&x), num_val(&y)));
    return S_OK;
459 460
}

461
/* ECMA-262 3rd Edition    15.8.2.14 */
462 463 464
static HRESULT Math_random(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
465 466 467 468 469 470 471 472 473 474 475
    UINT r;

    TRACE("\n");

    if(!RtlGenRandom(&r, sizeof(r)))
        return E_UNEXPECTED;

    if(retv)
        num_set_val(retv, (DOUBLE)r/(DOUBLE)UINT_MAX);

    return S_OK;
476 477
}

478
/* ECMA-262 3rd Edition    15.8.2.15 */
479 480 481
static HRESULT Math_round(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
482 483 484 485 486 487
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
488 489
        num_set_nan(retv);
        return S_OK;
490 491 492 493 494 495 496 497 498
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv)
        num_set_val(retv, floor(num_val(&v)+0.5));
    return S_OK;
499 500 501 502 503
}

static HRESULT Math_sin(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv) num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv) num_set_val(retv, sin(num_val(&v)));
    return S_OK;
520 521 522 523 524
}

static HRESULT Math_sqrt(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv) num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv) num_set_val(retv, sqrt(num_val(&v)));
    return S_OK;
541 542 543 544 545
}

static HRESULT Math_tan(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
{
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
    VARIANT v;
    HRESULT hres;

    TRACE("\n");

    if(!arg_cnt(dp)) {
        if(retv) num_set_nan(retv);
        return S_OK;
    }

    hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
    if(FAILED(hres))
        return hres;

    if(retv) num_set_val(retv, tan(num_val(&v)));
    return S_OK;
562 563 564 565 566
}

static const builtin_prop_t Math_props[] = {
    {EW,        Math_E,        0},
    {LN10W,     Math_LN10,     0},
567 568 569
    {LN2W,      Math_LN2,      0},
    {LOG10EW,   Math_LOG10E,   0},
    {LOG2EW,    Math_LOG2E,    0},
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
    {PIW,       Math_PI,       0},
    {SQRT1_2W,  Math_SQRT1_2,  0},
    {SQRT2W,    Math_SQRT2,    0},
    {absW,      Math_abs,      PROPF_METHOD},
    {acosW,     Math_acos,     PROPF_METHOD},
    {asinW,     Math_asin,     PROPF_METHOD},
    {atanW,     Math_atan,     PROPF_METHOD},
    {atan2W,    Math_atan2,    PROPF_METHOD},
    {ceilW,     Math_ceil,     PROPF_METHOD},
    {cosW,      Math_cos,      PROPF_METHOD},
    {expW,      Math_exp,      PROPF_METHOD},
    {floorW,    Math_floor,    PROPF_METHOD},
    {logW,      Math_log,      PROPF_METHOD},
    {maxW,      Math_max,      PROPF_METHOD},
    {minW,      Math_min,      PROPF_METHOD},
    {powW,      Math_pow,      PROPF_METHOD},
    {randomW,   Math_random,   PROPF_METHOD},
    {roundW,    Math_round,    PROPF_METHOD},
    {sinW,      Math_sin,      PROPF_METHOD},
    {sqrtW,     Math_sqrt,     PROPF_METHOD},
    {tanW,      Math_tan,      PROPF_METHOD}
};

static const builtin_info_t Math_info = {
    JSCLASS_MATH,
    {NULL, NULL, 0},
    sizeof(Math_props)/sizeof(*Math_props),
    Math_props,
    NULL,
    NULL
};

HRESULT create_math(script_ctx_t *ctx, DispatchEx **ret)
{
    return create_dispex(ctx, &Math_info, NULL, ret);
}