Code

fix 1243587 and misc fixes
[inkscape.git] / src / dom / js / jsmath.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * ***** BEGIN LICENSE BLOCK *****
4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5  *
6  * The contents of this file are subject to the Mozilla Public License Version
7  * 1.1 (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  * http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  *
16  * The Original Code is Mozilla Communicator client code, released
17  * March 31, 1998.
18  *
19  * The Initial Developer of the Original Code is
20  * Netscape Communications Corporation.
21  * Portions created by the Initial Developer are Copyright (C) 1998
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
40 /*
41  * JS math package.
42  */
43 #include "jsstddef.h"
44 #include "jslibmath.h"
45 #include <stdlib.h>
46 #include "jstypes.h"
47 #include "jslong.h"
48 #include "prmjtime.h"
49 #include "jsapi.h"
50 #include "jsatom.h"
51 #include "jscntxt.h"
52 #include "jsconfig.h"
53 #include "jslock.h"
54 #include "jsmath.h"
55 #include "jsnum.h"
56 #include "jsobj.h"
58 #ifndef M_E
59 #define M_E             2.7182818284590452354
60 #endif
61 #ifndef M_LOG2E
62 #define M_LOG2E         1.4426950408889634074
63 #endif
64 #ifndef M_LOG10E
65 #define M_LOG10E        0.43429448190325182765
66 #endif
67 #ifndef M_LN2
68 #define M_LN2           0.69314718055994530942
69 #endif
70 #ifndef M_LN10
71 #define M_LN10          2.30258509299404568402
72 #endif
73 #ifndef M_PI
74 #define M_PI            3.14159265358979323846
75 #endif
76 #ifndef M_SQRT2
77 #define M_SQRT2         1.41421356237309504880
78 #endif
79 #ifndef M_SQRT1_2
80 #define M_SQRT1_2       0.70710678118654752440
81 #endif
83 static JSConstDoubleSpec math_constants[] = {
84     {M_E,       "E",            0, {0,0,0}},
85     {M_LOG2E,   "LOG2E",        0, {0,0,0}},
86     {M_LOG10E,  "LOG10E",       0, {0,0,0}},
87     {M_LN2,     "LN2",          0, {0,0,0}},
88     {M_LN10,    "LN10",         0, {0,0,0}},
89     {M_PI,      "PI",           0, {0,0,0}},
90     {M_SQRT2,   "SQRT2",        0, {0,0,0}},
91     {M_SQRT1_2, "SQRT1_2",      0, {0,0,0}},
92     {0,0,0,{0,0,0}}
93 };
95 static JSClass math_class = {
96     "Math",
97     0,
98     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
99     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub,
100     JSCLASS_NO_OPTIONAL_MEMBERS
101 };
103 static JSBool
104 math_abs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
106     jsdouble x, z;
108     if (!js_ValueToNumber(cx, argv[0], &x))
109         return JS_FALSE;
110     z = fd_fabs(x);
111     return js_NewNumberValue(cx, z, rval);
114 static JSBool
115 math_acos(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
117     jsdouble x, z;
119     if (!js_ValueToNumber(cx, argv[0], &x))
120         return JS_FALSE;
121     z = fd_acos(x);
122     return js_NewNumberValue(cx, z, rval);
125 static JSBool
126 math_asin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
128     jsdouble x, z;
130     if (!js_ValueToNumber(cx, argv[0], &x))
131         return JS_FALSE;
132     z = fd_asin(x);
133     return js_NewNumberValue(cx, z, rval);
136 static JSBool
137 math_atan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
139     jsdouble x, z;
141     if (!js_ValueToNumber(cx, argv[0], &x))
142         return JS_FALSE;
143     z = fd_atan(x);
144     return js_NewNumberValue(cx, z, rval);
147 static JSBool
148 math_atan2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
150     jsdouble x, y, z;
152     if (!js_ValueToNumber(cx, argv[0], &x))
153         return JS_FALSE;
154     if (!js_ValueToNumber(cx, argv[1], &y))
155         return JS_FALSE;
156     z = fd_atan2(x, y);
157     return js_NewNumberValue(cx, z, rval);
160 static JSBool
161 math_ceil(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
163     jsdouble x, z;
165     if (!js_ValueToNumber(cx, argv[0], &x))
166         return JS_FALSE;
167     z = fd_ceil(x);
168     return js_NewNumberValue(cx, z, rval);
171 static JSBool
172 math_cos(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
174     jsdouble x, z;
176     if (!js_ValueToNumber(cx, argv[0], &x))
177         return JS_FALSE;
178     z = fd_cos(x);
179     return js_NewNumberValue(cx, z, rval);
182 static JSBool
183 math_exp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
185     jsdouble x, z;
187     if (!js_ValueToNumber(cx, argv[0], &x))
188         return JS_FALSE;
189 #ifdef _WIN32
190     if (!JSDOUBLE_IS_NaN(x)) {
191         if (x == *cx->runtime->jsPositiveInfinity) {
192             *rval = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
193             return JS_TRUE;
194         }
195         if (x == *cx->runtime->jsNegativeInfinity) {
196             *rval = JSVAL_ZERO;
197             return JS_TRUE;
198         }
199     }
200 #endif
201     z = fd_exp(x);
202     return js_NewNumberValue(cx, z, rval);
205 static JSBool
206 math_floor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
208     jsdouble x, z;
210     if (!js_ValueToNumber(cx, argv[0], &x))
211         return JS_FALSE;
212     z = fd_floor(x);
213     return js_NewNumberValue(cx, z, rval);
216 static JSBool
217 math_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
219     jsdouble x, z;
221     if (!js_ValueToNumber(cx, argv[0], &x))
222         return JS_FALSE;
223     z = fd_log(x);
224     return js_NewNumberValue(cx, z, rval);
227 static JSBool
228 math_max(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
230     jsdouble x, z = *cx->runtime->jsNegativeInfinity;
231     uintN i;
233     if (argc == 0) {
234         *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
235         return JS_TRUE;
236     }
237     for (i = 0; i < argc; i++) {
238         if (!js_ValueToNumber(cx, argv[i], &x))
239             return JS_FALSE;
240         if (JSDOUBLE_IS_NaN(x)) {
241             *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
242             return JS_TRUE;
243         }
244         if ((x==0)&&(x==z)&&(fd_copysign(1.0,z)==-1))
245             z = x;
246         else
247             z = (x > z) ? x : z;
248     }
249     return js_NewNumberValue(cx, z, rval);
252 static JSBool
253 math_min(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
255     jsdouble x, z = *cx->runtime->jsPositiveInfinity;
256     uintN i;
258     if (argc == 0) {
259         *rval = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
260         return JS_TRUE;
261     }
262     for (i = 0; i < argc; i++) {
263         if (!js_ValueToNumber(cx, argv[i], &x))
264             return JS_FALSE;
265         if (JSDOUBLE_IS_NaN(x)) {
266             *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
267             return JS_TRUE;
268         }
269         if ((x==0)&&(x==z)&&(fd_copysign(1.0,x)==-1))
270             z = x;
271         else
272             z = (x < z) ? x : z;
273     }
274     return js_NewNumberValue(cx, z, rval);
277 static JSBool
278 math_pow(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
280     jsdouble x, y, z;
282     if (!js_ValueToNumber(cx, argv[0], &x))
283         return JS_FALSE;
284     if (!js_ValueToNumber(cx, argv[1], &y))
285         return JS_FALSE;
286 #if !JS_USE_FDLIBM_MATH
287     /*
288      * Because C99 and ECMA specify different behavior for pow(),
289      * we need to wrap the libm call to make it ECMA compliant.
290      */
291     if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
292         *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
293         return JS_TRUE;
294     }
295 #endif
296     z = fd_pow(x, y);
297     return js_NewNumberValue(cx, z, rval);
300 /*
301  * Math.random() support, lifted from java.util.Random.java.
302  */
303 static void
304 random_setSeed(JSRuntime *rt, int64 seed)
306     int64 tmp;
308     JSLL_I2L(tmp, 1000);
309     JSLL_DIV(seed, seed, tmp);
310     JSLL_XOR(tmp, seed, rt->rngMultiplier);
311     JSLL_AND(rt->rngSeed, tmp, rt->rngMask);
314 static void
315 random_init(JSRuntime *rt)
317     int64 tmp, tmp2;
319     /* Do at most once. */
320     if (rt->rngInitialized)
321         return;
322     rt->rngInitialized = JS_TRUE;
324     /* rt->rngMultiplier = 0x5DEECE66DL */
325     JSLL_ISHL(tmp, 0x5, 32);
326     JSLL_UI2L(tmp2, 0xDEECE66DL);
327     JSLL_OR(rt->rngMultiplier, tmp, tmp2);
329     /* rt->rngAddend = 0xBL */
330     JSLL_I2L(rt->rngAddend, 0xBL);
332     /* rt->rngMask = (1L << 48) - 1 */
333     JSLL_I2L(tmp, 1);
334     JSLL_SHL(tmp2, tmp, 48);
335     JSLL_SUB(rt->rngMask, tmp2, tmp);
337     /* rt->rngDscale = (jsdouble)(1L << 53) */
338     JSLL_SHL(tmp2, tmp, 53);
339     JSLL_L2D(rt->rngDscale, tmp2);
341     /* Finally, set the seed from current time. */
342     random_setSeed(rt, PRMJ_Now());
345 static uint32
346 random_next(JSRuntime *rt, int bits)
348     int64 nextseed, tmp;
349     uint32 retval;
351     JSLL_MUL(nextseed, rt->rngSeed, rt->rngMultiplier);
352     JSLL_ADD(nextseed, nextseed, rt->rngAddend);
353     JSLL_AND(nextseed, nextseed, rt->rngMask);
354     rt->rngSeed = nextseed;
355     JSLL_USHR(tmp, nextseed, 48 - bits);
356     JSLL_L2I(retval, tmp);
357     return retval;
360 static jsdouble
361 random_nextDouble(JSRuntime *rt)
363     int64 tmp, tmp2;
364     jsdouble d;
366     JSLL_ISHL(tmp, random_next(rt, 26), 27);
367     JSLL_UI2L(tmp2, random_next(rt, 27));
368     JSLL_ADD(tmp, tmp, tmp2);
369     JSLL_L2D(d, tmp);
370     return d / rt->rngDscale;
373 static JSBool
374 math_random(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
376     JSRuntime *rt;
377     jsdouble z;
379     rt = cx->runtime;
380     JS_LOCK_RUNTIME(rt);
381     random_init(rt);
382     z = random_nextDouble(rt);
383     JS_UNLOCK_RUNTIME(rt);
384     return js_NewNumberValue(cx, z, rval);
387 static JSBool
388 math_round(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
390     jsdouble x, z;
392     if (!js_ValueToNumber(cx, argv[0], &x))
393         return JS_FALSE;
394     z = fd_copysign(fd_floor(x + 0.5), x);
395     return js_NewNumberValue(cx, z, rval);
398 static JSBool
399 math_sin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
401     jsdouble x, z;
403     if (!js_ValueToNumber(cx, argv[0], &x))
404         return JS_FALSE;
405     z = fd_sin(x);
406     return js_NewNumberValue(cx, z, rval);
409 static JSBool
410 math_sqrt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
412     jsdouble x, z;
414     if (!js_ValueToNumber(cx, argv[0], &x))
415         return JS_FALSE;
416     z = fd_sqrt(x);
417     return js_NewNumberValue(cx, z, rval);
420 static JSBool
421 math_tan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
423     jsdouble x, z;
425     if (!js_ValueToNumber(cx, argv[0], &x))
426         return JS_FALSE;
427     z = fd_tan(x);
428     return js_NewNumberValue(cx, z, rval);
431 #if JS_HAS_TOSOURCE
432 static JSBool
433 math_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
434               jsval *rval)
436     *rval = ATOM_KEY(cx->runtime->atomState.MathAtom);
437     return JS_TRUE;
439 #endif
441 static JSFunctionSpec math_static_methods[] = {
442 #if JS_HAS_TOSOURCE
443     {js_toSource_str,   math_toSource,          0, 0, 0},
444 #endif
445     {"abs",             math_abs,               1, 0, 0},
446     {"acos",            math_acos,              1, 0, 0},
447     {"asin",            math_asin,              1, 0, 0},
448     {"atan",            math_atan,              1, 0, 0},
449     {"atan2",           math_atan2,             2, 0, 0},
450     {"ceil",            math_ceil,              1, 0, 0},
451     {"cos",             math_cos,               1, 0, 0},
452     {"exp",             math_exp,               1, 0, 0},
453     {"floor",           math_floor,             1, 0, 0},
454     {"log",             math_log,               1, 0, 0},
455     {"max",             math_max,               2, 0, 0},
456     {"min",             math_min,               2, 0, 0},
457     {"pow",             math_pow,               2, 0, 0},
458     {"random",          math_random,            0, 0, 0},
459     {"round",           math_round,             1, 0, 0},
460     {"sin",             math_sin,               1, 0, 0},
461     {"sqrt",            math_sqrt,              1, 0, 0},
462     {"tan",             math_tan,               1, 0, 0},
463     {0,0,0,0,0}
464 };
466 JSObject *
467 js_InitMathClass(JSContext *cx, JSObject *obj)
469     JSObject *Math;
471     Math = JS_DefineObject(cx, obj, "Math", &math_class, NULL, 0);
472     if (!Math)
473         return NULL;
474     if (!JS_DefineFunctions(cx, Math, math_static_methods))
475         return NULL;
476     if (!JS_DefineConstDoubles(cx, Math, math_constants))
477         return NULL;
478     return Math;