2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software Foundation, Inc
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program 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
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 // This file implements methods of the ActionScript Math class.
25 #include "VM.h" // get random generator
27 #include "Global_as.h"
30 #include "NativeFunction.h"
31 #include "GnashNumeric.h"
35 #include <boost/random.hpp>
39 // Forward declarations
41 typedef double (*UnaryMathFunc
) (double);
42 typedef double (*BinaryMathFunc
) (double, double);
44 void attachMathInterface(as_object
& proto
);
45 as_value
math_max(const fn_call
& fn
);
46 as_value
math_min(const fn_call
& fn
);
47 as_value
math_random(const fn_call
& fn
);
49 // There's no std::round, but Math.round behaves like all the other
51 inline double round(double d
);
53 template<UnaryMathFunc Func
> as_value
unaryFunction(const fn_call
& fn
);
54 template<BinaryMathFunc Func
> as_value
binaryFunction(const fn_call
& fn
);
55 template<> as_value binaryFunction
<std::pow
>(const fn_call
& fn
);
61 registerMathNative(as_object
& proto
)
63 VM
& vm
= getVM(proto
);
65 vm
.registerNative(unaryFunction
<std::abs
>, 200, 0);
66 vm
.registerNative(math_min
, 200, 1);
67 vm
.registerNative(math_max
, 200, 2);
68 vm
.registerNative(unaryFunction
<std::sin
>, 200, 3);
69 vm
.registerNative(unaryFunction
<std::cos
>, 200, 4);
70 vm
.registerNative(binaryFunction
<std::atan2
>, 200, 5);
71 vm
.registerNative(unaryFunction
<std::tan
>, 200, 6);
72 vm
.registerNative(unaryFunction
<std::exp
>, 200, 7);
73 vm
.registerNative(unaryFunction
<std::log
>, 200, 8);
74 vm
.registerNative(unaryFunction
<std::sqrt
>, 200, 9);
75 vm
.registerNative(unaryFunction
<round
>, 200, 10);
76 vm
.registerNative(math_random
, 200, 11);
77 vm
.registerNative(unaryFunction
<std::floor
>, 200, 12);
78 vm
.registerNative(unaryFunction
<std::ceil
>, 200, 13);
79 vm
.registerNative(unaryFunction
<std::atan
>, 200, 14);
80 vm
.registerNative(unaryFunction
<std::asin
>, 200, 15);
81 vm
.registerNative(unaryFunction
<std::acos
>, 200, 16);
82 vm
.registerNative(binaryFunction
<std::pow
>, 200, 17);
87 math_class_init(as_object
& where
, const ObjectURI
& uri
)
89 registerBuiltinObject(where
, attachMathInterface
, uri
);
95 // One-argument simple functions.
97 // All one-argument Math functions called with no args return NaN
100 // If it is called with two arguments, the valueOf method
101 // of the second method is called, but not used. Strange, but true.
102 template<UnaryMathFunc Func
>
104 unaryFunction(const fn_call
& fn
)
106 if (fn
.nargs
< 1) return as_value(NaN
);
107 double arg
= toNumber(fn
.arg(0), getVM(fn
));
108 if (fn
.nargs
> 1) toNumber(fn
.arg(1), getVM(fn
));
109 return as_value(Func(arg
));
112 /// Two-argument functions.
114 /// As a rule, two-argument functions called with no or one argument
115 /// return NaN. However, three of the four functions break this rule in
116 /// different ways. Exceptions are described below.
118 /// There is no real need for this template at present, as it only handles
119 /// Math.atan2. But it might be useful if other Math functions are added.
120 template<BinaryMathFunc Func
>
122 binaryFunction(const fn_call
& fn
)
124 if (fn
.nargs
< 2) return as_value(NaN
);
125 double arg0
= toNumber(fn
.arg(0), getVM(fn
));
126 double arg1
= toNumber(fn
.arg(1), getVM(fn
));
127 return as_value(Func(arg0
, arg1
));
132 /// Math.pow is odd in that Math.pow(1) returns 1. All other single-argument
133 /// calls return NaN.
136 binaryFunction
<std::pow
>(const fn_call
& fn
)
138 if (!fn
.nargs
) return as_value(NaN
);
140 double arg0
= toNumber(fn
.arg(0), getVM(fn
));
143 if (arg0
== 1) return as_value(1);
144 return as_value(NaN
);
147 double arg1
= toNumber(fn
.arg(1), getVM(fn
));
148 return as_value(isFinite(arg0
) ? std::pow(arg0
, arg1
) : NaN
);
153 /// Math.min() returns Infinity
155 math_min(const fn_call
& fn
)
157 if (!fn
.nargs
) return as_value(std::numeric_limits
<double>::infinity());
159 if (fn
.nargs
< 2) return as_value(NaN
);
161 double arg0
= toNumber(fn
.arg(0), getVM(fn
));
162 double arg1
= toNumber(fn
.arg(1), getVM(fn
));
164 if (isNaN(arg0
) || isNaN(arg1
))
166 return as_value(NaN
);
169 return as_value(std::min(arg0
, arg1
));
175 /// Math.max() returns -Infinity
177 math_max(const fn_call
& fn
)
179 if (!fn
.nargs
) return as_value(-std::numeric_limits
<double>::infinity());
181 if (fn
.nargs
< 2) return as_value(NaN
);
183 double arg0
= toNumber(fn
.arg(0), getVM(fn
));
184 double arg1
= toNumber(fn
.arg(1), getVM(fn
));
186 if (isNaN(arg0
) || isNaN(arg1
))
188 return as_value(NaN
);
191 return as_value(std::max(arg0
, arg1
));
196 /// The first two arguments are converted to numbers, even though
199 math_random(const fn_call
& fn
)
202 if (fn
.nargs
) toNumber(fn
.arg(0), getVM(fn
));
203 if (fn
.nargs
> 1) toNumber(fn
.arg(1), getVM(fn
));
205 VM::RNG
& rnd
= getVM(fn
).randomNumberGenerator();
207 // Produces double ( 0 <= n < 1)
208 boost::uniform_real
<> uni_dist(0, 1);
209 boost::variate_generator
<VM::RNG
&, boost::uniform_real
<> > uni(
212 return as_value(uni());
219 return std::floor(d
+ 0.5);
223 attachMathInterface(as_object
& proto
)
225 // TODO: rely on inheritance, use init_property ?
226 // All Math members are constant and non-enumerable.
228 const int flags
= PropFlags::dontDelete
229 | PropFlags::dontEnum
230 | PropFlags::readOnly
;
233 proto
.init_member("E", 2.7182818284590452354, flags
);
234 proto
.init_member("LN2", 0.69314718055994530942, flags
);
235 proto
.init_member("LOG2E", 1.4426950408889634074, flags
);
236 proto
.init_member("LN10", 2.30258509299404568402, flags
);
237 proto
.init_member("LOG10E", 0.43429448190325182765, flags
);
238 proto
.init_member("PI", 3.14159265358979323846, flags
);
239 proto
.init_member("SQRT1_2", 0.7071067811865475244, flags
);
240 proto
.init_member("SQRT2", 1.4142135623730950488, flags
);
242 VM
& vm
= getVM(proto
);
244 proto
.init_member("abs", vm
.getNative(200, 0), flags
);
245 proto
.init_member("min", vm
.getNative(200, 1), flags
);
246 proto
.init_member("max", vm
.getNative(200, 2), flags
);
247 proto
.init_member("sin", vm
.getNative(200, 3), flags
);
248 proto
.init_member("cos", vm
.getNative(200, 4), flags
);
249 proto
.init_member("atan2", vm
.getNative(200, 5), flags
);
250 proto
.init_member("tan", vm
.getNative(200, 6), flags
);
251 proto
.init_member("exp", vm
.getNative(200, 7), flags
);
252 proto
.init_member("log", vm
.getNative(200, 8), flags
);
253 proto
.init_member("sqrt", vm
.getNative(200, 9), flags
);
254 proto
.init_member("round", vm
.getNative(200, 10), flags
);
255 proto
.init_member("random", vm
.getNative(200, 11), flags
);
256 proto
.init_member("floor", vm
.getNative(200, 12), flags
);
257 proto
.init_member("ceil", vm
.getNative(200, 13), flags
);
258 proto
.init_member("atan", vm
.getNative(200, 14), flags
);
259 proto
.init_member("asin", vm
.getNative(200, 15), flags
);
260 proto
.init_member("acos", vm
.getNative(200, 16), flags
);
261 proto
.init_member("pow", vm
.getNative(200, 17), flags
);
264 } // anonymous namespace
265 } // end of gnash namespace