Code

moving trunk for module inkscape
[inkscape.git] / src / extension / script / 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 #ifdef XP_MAC
133     if (x == 0)
134         return js_NewNumberValue(cx, x, rval);
135 #endif    
136     z = fd_asin(x);
137     return js_NewNumberValue(cx, z, rval);
140 static JSBool
141 math_atan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
143     jsdouble x, z;
145     if (!js_ValueToNumber(cx, argv[0], &x))
146         return JS_FALSE;
147 #ifdef XP_MAC
148     if (x == 0)
149         return js_NewNumberValue(cx, x, rval);
150 #endif    
151     z = fd_atan(x);
152     return js_NewNumberValue(cx, z, rval);
155 static JSBool
156 math_atan2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
158     jsdouble x, y, z;
160     if (!js_ValueToNumber(cx, argv[0], &x))
161         return JS_FALSE;
162     if (!js_ValueToNumber(cx, argv[1], &y))
163         return JS_FALSE;
164     z = fd_atan2(x, y);
165     return js_NewNumberValue(cx, z, rval);
168 static JSBool
169 math_ceil(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
171     jsdouble x, z;
173     if (!js_ValueToNumber(cx, argv[0], &x))
174         return JS_FALSE;
175     z = fd_ceil(x);
176     return js_NewNumberValue(cx, z, rval);
179 static JSBool
180 math_cos(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
182     jsdouble x, z;
184     if (!js_ValueToNumber(cx, argv[0], &x))
185         return JS_FALSE;
186     z = fd_cos(x);
187     return js_NewNumberValue(cx, z, rval);
190 static JSBool
191 math_exp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
193     jsdouble x, z;
195     if (!js_ValueToNumber(cx, argv[0], &x))
196         return JS_FALSE;
197 #ifdef _WIN32
198     if (!JSDOUBLE_IS_NaN(x)) {
199         if (x == *cx->runtime->jsPositiveInfinity) {
200             *rval = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
201             return JS_TRUE;
202         }
203         if (x == *cx->runtime->jsNegativeInfinity) {
204             *rval = JSVAL_ZERO;
205             return JS_TRUE;
206         }
207     }
208 #endif
209     z = fd_exp(x);
210     return js_NewNumberValue(cx, z, rval);
213 static JSBool
214 math_floor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
216     jsdouble x, z;
218     if (!js_ValueToNumber(cx, argv[0], &x))
219         return JS_FALSE;
220     z = fd_floor(x);
221     return js_NewNumberValue(cx, z, rval);
224 static JSBool
225 math_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
227     jsdouble x, z;
229     if (!js_ValueToNumber(cx, argv[0], &x))
230         return JS_FALSE;
231     z = fd_log(x);
232     return js_NewNumberValue(cx, z, rval);
235 static JSBool
236 math_max(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
238     jsdouble x, z = *cx->runtime->jsNegativeInfinity;
239     uintN i;
241     if (argc == 0) {
242         *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
243         return JS_TRUE;
244     }
245     for (i = 0; i < argc; i++) {
246         if (!js_ValueToNumber(cx, argv[i], &x))
247             return JS_FALSE;
248         if (JSDOUBLE_IS_NaN(x)) {
249             *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
250             return JS_TRUE;
251         }
252         if ((x==0)&&(x==z)&&(fd_copysign(1.0,z)==-1))
253             z = x;
254         else
255             z = (x > z) ? x : z;
256     }
257     return js_NewNumberValue(cx, z, rval);
260 static JSBool
261 math_min(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
263     jsdouble x, z = *cx->runtime->jsPositiveInfinity;
264     uintN i;
266     if (argc == 0) {
267         *rval = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
268         return JS_TRUE;
269     }
270     for (i = 0; i < argc; i++) {
271         if (!js_ValueToNumber(cx, argv[i], &x))
272             return JS_FALSE;
273         if (JSDOUBLE_IS_NaN(x)) {
274             *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
275             return JS_TRUE;
276         }
277         if ((x==0)&&(x==z)&&(fd_copysign(1.0,x)==-1))
278             z = x;
279         else
280             z = (x < z) ? x : z;
281     }
282     return js_NewNumberValue(cx, z, rval);
285 static JSBool
286 math_pow(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
288     jsdouble x, y, z;
290     if (!js_ValueToNumber(cx, argv[0], &x))
291         return JS_FALSE;
292     if (!js_ValueToNumber(cx, argv[1], &y))
293         return JS_FALSE;
294     z = fd_pow(x, y);
295     return js_NewNumberValue(cx, z, rval);
298 /*
299  * Math.random() support, lifted from java.util.Random.java.
300  */
301 static void
302 random_setSeed(JSRuntime *rt, int64 seed)
304     int64 tmp;
306     JSLL_I2L(tmp, 1000);
307     JSLL_DIV(seed, seed, tmp);
308     JSLL_XOR(tmp, seed, rt->rngMultiplier);
309     JSLL_AND(rt->rngSeed, tmp, rt->rngMask);
312 static void
313 random_init(JSRuntime *rt)
315     int64 tmp, tmp2;
317     /* Do at most once. */
318     if (rt->rngInitialized)
319         return;
320     rt->rngInitialized = JS_TRUE;
322     /* rt->rngMultiplier = 0x5DEECE66DL */
323     JSLL_ISHL(tmp, 0x5, 32);
324     JSLL_UI2L(tmp2, 0xDEECE66DL);
325     JSLL_OR(rt->rngMultiplier, tmp, tmp2);
327     /* rt->rngAddend = 0xBL */
328     JSLL_I2L(rt->rngAddend, 0xBL);
330     /* rt->rngMask = (1L << 48) - 1 */
331     JSLL_I2L(tmp, 1);
332     JSLL_SHL(tmp2, tmp, 48);
333     JSLL_SUB(rt->rngMask, tmp2, tmp);
335     /* rt->rngDscale = (jsdouble)(1L << 53) */
336     JSLL_SHL(tmp2, tmp, 53);
337     JSLL_L2D(rt->rngDscale, tmp2);
339     /* Finally, set the seed from current time. */
340     random_setSeed(rt, PRMJ_Now());
343 static uint32
344 random_next(JSRuntime *rt, int bits)
346     int64 nextseed, tmp;
347     uint32 retval;
349     JSLL_MUL(nextseed, rt->rngSeed, rt->rngMultiplier);
350     JSLL_ADD(nextseed, nextseed, rt->rngAddend);
351     JSLL_AND(nextseed, nextseed, rt->rngMask);
352     rt->rngSeed = nextseed;
353     JSLL_USHR(tmp, nextseed, 48 - bits);
354     JSLL_L2I(retval, tmp);
355     return retval;
358 static jsdouble
359 random_nextDouble(JSRuntime *rt)
361     int64 tmp, tmp2;
362     jsdouble d;
364     JSLL_ISHL(tmp, random_next(rt, 26), 27);
365     JSLL_UI2L(tmp2, random_next(rt, 27));
366     JSLL_ADD(tmp, tmp, tmp2);
367     JSLL_L2D(d, tmp);
368     return d / rt->rngDscale;
371 static JSBool
372 math_random(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
374     JSRuntime *rt;
375     jsdouble z;
377     rt = cx->runtime;
378     JS_LOCK_RUNTIME(rt);
379     random_init(rt);
380     z = random_nextDouble(rt);
381     JS_UNLOCK_RUNTIME(rt);
382     return js_NewNumberValue(cx, z, rval);
385 static JSBool
386 math_round(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
388     jsdouble x, z;
390     if (!js_ValueToNumber(cx, argv[0], &x))
391         return JS_FALSE;
392     z = fd_copysign(fd_floor(x + 0.5), x);
393     return js_NewNumberValue(cx, z, rval);
396 static JSBool
397 math_sin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
399     jsdouble x, z;
401     if (!js_ValueToNumber(cx, argv[0], &x))
402         return JS_FALSE;
403     z = fd_sin(x);
404     return js_NewNumberValue(cx, z, rval);
407 static JSBool
408 math_sqrt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
410     jsdouble x, z;
412     if (!js_ValueToNumber(cx, argv[0], &x))
413         return JS_FALSE;
414     z = fd_sqrt(x);
415     return js_NewNumberValue(cx, z, rval);
418 static JSBool
419 math_tan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
421     jsdouble x, z;
423     if (!js_ValueToNumber(cx, argv[0], &x))
424         return JS_FALSE;
425     z = fd_tan(x);
426     return js_NewNumberValue(cx, z, rval);
429 #if JS_HAS_TOSOURCE
430 static JSBool
431 math_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
432               jsval *rval)
434     *rval = ATOM_KEY(cx->runtime->atomState.MathAtom);
435     return JS_TRUE;
437 #endif
439 static JSFunctionSpec math_static_methods[] = {
440 #if JS_HAS_TOSOURCE
441     {js_toSource_str,   math_toSource,          0, 0, 0},
442 #endif
443     {"abs",             math_abs,               1, 0, 0},
444     {"acos",            math_acos,              1, 0, 0},
445     {"asin",            math_asin,              1, 0, 0},
446     {"atan",            math_atan,              1, 0, 0},
447     {"atan2",           math_atan2,             2, 0, 0},
448     {"ceil",            math_ceil,              1, 0, 0},
449     {"cos",             math_cos,               1, 0, 0},
450     {"exp",             math_exp,               1, 0, 0},
451     {"floor",           math_floor,             1, 0, 0},
452     {"log",             math_log,               1, 0, 0},
453     {"max",             math_max,               2, 0, 0},
454     {"min",             math_min,               2, 0, 0},
455     {"pow",             math_pow,               2, 0, 0},
456     {"random",          math_random,            0, 0, 0},
457     {"round",           math_round,             1, 0, 0},
458     {"sin",             math_sin,               1, 0, 0},
459     {"sqrt",            math_sqrt,              1, 0, 0},
460     {"tan",             math_tan,               1, 0, 0},
461     {0,0,0,0,0}
462 };
464 JSObject *
465 js_InitMathClass(JSContext *cx, JSObject *obj)
467     JSObject *Math;
468     
469     Math = JS_DefineObject(cx, obj, "Math", &math_class, NULL, 0);
470     if (!Math)
471         return NULL;
472     if (!JS_DefineFunctions(cx, Math, math_static_methods))
473         return NULL;
474     if (!JS_DefineConstDoubles(cx, Math, math_constants))
475         return NULL;
476     return Math;