update copyright date
[gnash.git] / libcore / asobj / Math_as.cpp
blob78032e9dec70339646d281765a1531def50634eb
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software Foundation, Inc
4 //
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.
14 //
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
26 #include "fn_call.h"
27 #include "Global_as.h"
28 #include "Math_as.h"
29 #include "log.h"
30 #include "NativeFunction.h"
31 #include "GnashNumeric.h"
33 #include <cmath>
34 #include <string>
35 #include <boost/random.hpp>
37 namespace gnash {
39 // Forward declarations
40 namespace {
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
50 // unary functions.
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);
60 void
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);
86 void
87 math_class_init(as_object& where, const ObjectURI& uri)
89 registerBuiltinObject(where, attachMathInterface, uri);
92 namespace {
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>
103 as_value
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>
121 as_value
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));
130 /// Math.pow
132 /// Math.pow is odd in that Math.pow(1) returns 1. All other single-argument
133 /// calls return NaN.
134 template<>
135 as_value
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));
142 if (fn.nargs < 2) {
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 );
151 /// Math.min
153 /// Math.min() returns Infinity
154 as_value
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));
173 /// Math.min
175 /// Math.max() returns -Infinity
176 as_value
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));
194 /// Math.random()
196 /// The first two arguments are converted to numbers, even though
197 /// neither is used.
198 as_value
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(
210 rnd, uni_dist);
212 return as_value(uni());
216 inline double
217 round(double d)
219 return std::floor(d + 0.5);
222 void
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;
232 // constant
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